pub mod erase_flash;
pub mod ram_command;
pub mod read_flash;
pub mod reset;
pub mod sifli_debug;
pub mod speed;
pub mod write_flash;
use crate::common::sifli_debug::{
ChipFrameFormat, RecvError, START_WORD, SifliDebug, SifliUartCommand, SifliUartResponse,
common_debug,
};
use crate::sf32lb56::ram_command::DownloadStub;
use crate::{SifliTool, SifliToolBase, SifliToolTrait};
use serialport::SerialPort;
use std::io::{BufReader, Read};
use std::time::Duration;
pub struct SF32LB56FrameFormat;
impl ChipFrameFormat for SF32LB56FrameFormat {
fn create_header(len: u16) -> Vec<u8> {
let mut header = vec![];
header.extend_from_slice(&START_WORD);
header.extend_from_slice(&len.to_be_bytes());
header.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
header.push(0x10);
header.push(0x00);
header.extend_from_slice(&[0x00, 0x00]);
header
}
fn parse_frame_header(
reader: &mut BufReader<Box<dyn Read + Send>>,
) -> Result<usize, RecvError> {
let mut length_bytes = [0; 2];
if let Err(e) = reader.read_exact(&mut length_bytes) {
tracing::error!("Failed to read length bytes: {}", e);
return Err(RecvError::InvalidHeaderLength);
}
let payload_size = u16::from_be_bytes(length_bytes) as usize;
let mut timestamp_bytes = [0; 4];
if let Err(e) = reader.read_exact(&mut timestamp_bytes) {
tracing::error!("Failed to read timestamp bytes: {}", e);
return Err(RecvError::InvalidHeaderChannel);
}
let mut channel_crc = [0; 2];
if let Err(e) = reader.read_exact(&mut channel_crc) {
tracing::error!("Failed to read channel and CRC bytes: {}", e);
return Err(RecvError::InvalidHeaderChannel);
}
let mut reserved_bytes = [0; 2];
if let Err(e) = reader.read_exact(&mut reserved_bytes) {
tracing::error!("Failed to read reserved bytes: {}", e);
return Err(RecvError::ReadError(e));
}
Ok(payload_size)
}
fn encode_command_data(command: &SifliUartCommand) -> Vec<u8> {
let mut send_data = vec![];
match command {
SifliUartCommand::Enter => {
let temp = [0x41, 0x54, 0x53, 0x46, 0x33, 0x32, 0x05, 0x21];
send_data.extend_from_slice(&temp);
}
SifliUartCommand::Exit => {
let temp = [0x41, 0x54, 0x53, 0x46, 0x33, 0x32, 0x18, 0x21];
send_data.extend_from_slice(&temp);
}
SifliUartCommand::MEMRead { addr, len } => {
send_data.push(0x40);
send_data.push(0x72);
send_data.extend_from_slice(&addr.to_be_bytes());
send_data.extend_from_slice(&len.to_be_bytes());
}
SifliUartCommand::MEMWrite { addr, data } => {
send_data.push(0x40);
send_data.push(0x77);
send_data.extend_from_slice(&addr.to_be_bytes());
send_data.extend_from_slice(&(data.len() as u16).to_be_bytes());
for d in data.iter() {
send_data.extend_from_slice(&d.to_be_bytes());
}
}
}
send_data
}
fn decode_response_data(data: &[u8]) -> u32 {
u32::from_be_bytes([data[0], data[1], data[2], data[3]])
}
fn map_address(addr: u32) -> u32 {
let mut l_addr = addr;
if addr >= 0xE0000000 && addr < 0xF0000000 {
l_addr = (addr & 0x0fffffff) | 0xF0000000;
} else if addr >= 0x00400000 && addr <= 0x0041FFFF {
l_addr += 0x20000000;
} else if addr >= 0x20C00000 && addr <= 0x20C1FFFF {
l_addr -= 0x00800000;
} else if addr >= 0x20000000 && addr <= 0x200C7FFF {
l_addr += 0x0A000000;
} else if addr >= 0x20800000 && addr <= 0x20BFFFFF {
l_addr -= 0x20800000;
} else if addr >= 0x10000000 && addr <= 0x1FFFFFFF {
l_addr += 0x50000000;
}
l_addr
}
}
pub struct SF32LB56Tool {
pub base: SifliToolBase,
pub port: Box<dyn SerialPort>,
}
unsafe impl Send for SF32LB56Tool {}
unsafe impl Sync for SF32LB56Tool {}
impl SifliDebug for SF32LB56Tool {
fn debug_command(
&mut self,
command: SifliUartCommand,
) -> Result<SifliUartResponse, std::io::Error> {
common_debug::debug_command_impl::<SF32LB56Tool, SF32LB56FrameFormat>(self, command)
}
fn debug_read_word32(&mut self, addr: u32) -> Result<u32, std::io::Error> {
common_debug::debug_read_word32_impl::<SF32LB56Tool, SF32LB56FrameFormat>(self, addr)
}
fn debug_write_word32(&mut self, addr: u32, data: u32) -> Result<(), std::io::Error> {
common_debug::debug_write_word32_impl::<SF32LB56Tool, SF32LB56FrameFormat>(self, addr, data)
}
fn debug_write_memory(&mut self, addr: u32, data: &[u8]) -> Result<(), std::io::Error> {
common_debug::debug_write_memory_impl::<SF32LB56Tool, SF32LB56FrameFormat>(self, addr, data)
}
fn debug_write_core_reg(&mut self, reg: u16, data: u32) -> Result<(), std::io::Error> {
common_debug::debug_write_core_reg_impl::<SF32LB56Tool, SF32LB56FrameFormat>(
self, reg, data,
)
}
fn debug_step(&mut self) -> Result<(), std::io::Error> {
common_debug::debug_step_impl::<SF32LB56Tool, SF32LB56FrameFormat>(self)
}
fn debug_run(&mut self) -> Result<(), std::io::Error> {
common_debug::debug_run_impl::<SF32LB56Tool, SF32LB56FrameFormat>(self)
}
fn debug_halt(&mut self) -> Result<(), std::io::Error> {
common_debug::debug_halt_impl::<SF32LB56Tool, SF32LB56FrameFormat>(self)
}
}
impl SF32LB56Tool {
pub fn internal_erase_all(&mut self, address: u32) -> Result<(), std::io::Error> {
use ram_command::{Command, RamCommand};
let progress = self.progress();
let spinner =
progress.create_spinner(format!("Erasing entire flash at 0x{:08X}...", address));
let _ = self.command(Command::EraseAll { address });
let mut buffer = Vec::new();
let now = std::time::SystemTime::now();
loop {
let elapsed = now.elapsed().unwrap().as_millis();
if elapsed > 30000 {
tracing::error!("response string is {}", String::from_utf8_lossy(&buffer));
return Err(std::io::Error::new(
std::io::ErrorKind::TimedOut,
"Erase timeout",
));
}
let mut byte = [0];
let ret = self.port().read_exact(&mut byte);
if ret.is_err() {
continue;
}
buffer.push(byte[0]);
if buffer.windows(2).any(|window| window == b"OK") {
break;
}
}
spinner.finish_with_message(format!("Erase flash successfully: 0x{:08X}", address));
Ok(())
}
pub fn internal_erase_region(&mut self, address: u32, len: u32) -> Result<(), std::io::Error> {
use ram_command::{Command, RamCommand};
let progress = self.progress();
let spinner = progress.create_spinner(format!(
"Erasing region at 0x{:08X} (size: 0x{:08X})...",
address, len
));
let _ = self.command(Command::Erase { address, len });
let mut buffer = Vec::new();
let now = std::time::SystemTime::now();
loop {
let elapsed = now.elapsed().unwrap().as_millis();
if elapsed > 30000 {
tracing::error!("response string is {}", String::from_utf8_lossy(&buffer));
return Err(std::io::Error::new(
std::io::ErrorKind::TimedOut,
"Erase timeout",
));
}
let mut byte = [0];
let ret = self.port().read_exact(&mut byte);
if ret.is_err() {
continue;
}
buffer.push(byte[0]);
if buffer.windows(2).any(|window| window == b"OK") {
break;
}
}
spinner.finish_with_message(format!(
"Erase region successfully: 0x{:08X} (length: 0x{:08X})",
address, len
));
Ok(())
}
pub fn attempt_connect(&mut self) -> Result<(), std::io::Error> {
use crate::Operation;
use crate::common::sifli_debug::{SifliUartCommand, SifliUartResponse};
let infinite_attempts = self.base.connect_attempts <= 0;
let mut remaining_attempts = if infinite_attempts {
None
} else {
Some(self.base.connect_attempts)
};
loop {
if self.base.before == Operation::DefaultReset {
self.port.write_request_to_send(true)?;
std::thread::sleep(Duration::from_millis(100));
self.port.write_request_to_send(false)?;
std::thread::sleep(Duration::from_millis(100));
}
let value = match self.debug_command(SifliUartCommand::Enter) {
Ok(SifliUartResponse::Enter) => Ok(()),
_ => Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Failed to enter debug mode",
)),
};
if let Some(ref mut attempts) = remaining_attempts {
if *attempts == 0 {
break; }
*attempts -= 1;
}
let progress = self.progress();
let spinner = progress.create_spinner("Connecting to chip...");
match value {
Ok(_) => {
spinner.finish_with_message("Connected success!");
return Ok(());
}
Err(_) => {
spinner.finish_with_message("Failed to connect to the chip, retrying...");
std::thread::sleep(Duration::from_millis(500));
}
}
}
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Failed to connect to the chip",
))
}
pub fn download_stub_impl(&mut self) -> Result<(), std::io::Error> {
use crate::common::sifli_debug::SifliUartCommand;
use crate::ram_stub::{self, CHIP_FILE_NAME};
use probe_rs::MemoryMappedRegister;
use probe_rs::architecture::arm::core::armv7m::{Aircr, Demcr};
use probe_rs::architecture::arm::core::registers::cortex_m::{PC, SP};
let progress = self.progress();
let spinner = progress.create_spinner("Download stub...");
self.debug_halt()?;
let mut data = self.debug_read_word32(0x4004_0028)?;
if data & 0x20 != 0 {
data = 0xa05f0003;
self.debug_write_word32(0x3000_EDF0, data)?;
}
let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
let mut demcr = Demcr(demcr);
demcr.set_vc_corereset(true);
self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
let mut aircr = Aircr(0);
aircr.vectkey();
aircr.set_sysresetreq(true);
let _ = self.debug_write_word32(Aircr::get_mmio_address() as u32, aircr.into()); std::thread::sleep(std::time::Duration::from_millis(10));
self.debug_command(SifliUartCommand::Enter)?;
self.debug_halt()?;
let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
let mut demcr = Demcr(demcr);
demcr.set_vc_corereset(false);
self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
std::thread::sleep(std::time::Duration::from_millis(100));
let stub = ram_stub::RamStubFile::get(
CHIP_FILE_NAME
.get(format!("sf32lb56_{}", self.base.memory_type).as_str())
.expect("REASON"),
);
let Some(stub) = stub else {
spinner.finish_with_message("No stub file found for the given chip and memory type");
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"No stub file found for the given chip and memory type",
));
};
let packet_size = if self.base.compat { 256 } else { 64 * 1024 };
let mut addr = 0x2006_7000;
let mut data = &stub.data[..];
while !data.is_empty() {
let chunk = &data[..std::cmp::min(data.len(), packet_size)];
self.debug_write_memory(addr, chunk)?;
addr += chunk.len() as u32;
data = &data[chunk.len()..];
}
let sp = u32::from_le_bytes(
stub.data[0..4]
.try_into()
.expect("slice with exactly 4 bytes"),
);
let pc = u32::from_le_bytes(
stub.data[4..8]
.try_into()
.expect("slice with exactly 4 bytes"),
);
self.debug_write_core_reg(PC.id.0, pc)?;
self.debug_write_core_reg(SP.id.0, sp)?;
self.debug_run()?;
spinner.finish_with_message("Download stub success!");
Ok(())
}
}
impl SifliTool for SF32LB56Tool {
fn create_tool(base: SifliToolBase) -> Box<dyn SifliTool> {
let mut port = serialport::new(&base.port_name, 1000000)
.timeout(Duration::from_secs(5))
.open()
.unwrap();
port.write_request_to_send(false).unwrap();
std::thread::sleep(Duration::from_millis(100));
let mut tool = Box::new(Self { base, port });
tool.download_stub().expect("Failed to download stub");
tool
}
}
impl SifliToolTrait for SF32LB56Tool {
fn port(&mut self) -> &mut Box<dyn SerialPort> {
&mut self.port
}
fn base(&self) -> &SifliToolBase {
&self.base
}
fn set_speed(&mut self, baud: u32) -> Result<(), std::io::Error> {
use crate::speed::SpeedTrait;
SpeedTrait::set_speed(self, baud)
}
fn soft_reset(&mut self) -> Result<(), std::io::Error> {
use crate::reset::Reset;
Reset::soft_reset(self)
}
}