use std::fmt::Display; use crate::download_wrapper::DownloadError::JlinkNotFindError; use std::fs; use std::path::PathBuf; use std::process::Command; use std::io::Write; pub struct DownloadWrapper { commander_path: PathBuf, bin_path: PathBuf, bootloader_name: String, app_name: String, rail_name: String, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DownloadType { Bootloader, App, Rail, } impl Display for DownloadType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let str = match self { DownloadType::Bootloader => "BootLoader".to_string(), DownloadType::App => "App".to_string(), DownloadType::Rail => "Rail".to_string(), }; write!(f, "{}", str) } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DownloadError { JlinkNotFindError, DeviceNotFindError, EraseError, DownloadBootloaderError, DownloadAppError, DownloadRailError, NoLabel, } impl Default for DownloadWrapper { fn default() -> Self { Self { commander_path: PathBuf::from(std::env::current_dir().unwrap()) .join("commander/Simplicity Commander/commander.exe"), bin_path: PathBuf::from(std::env::current_dir().unwrap()).join("bin/"), bootloader_name: String::from("RAWM00-2-0-0_silicon-wisun_bootloader_D20241008.s37"), app_name: String::from("RAWM00-2-0-0_silicon-combine-V1-D20241230-BZ.hex"), rail_name: String::from("rail_soc_railtest_sisdk(silabs).hex"), } } } impl DownloadWrapper { pub(crate) fn new() -> Self { Self::default() } pub fn check_jlink(&self) -> Result, DownloadError> { let commander_path_str = self.commander_path.to_str().unwrap(); let output = Command::new(commander_path_str) .arg("adapter") .arg("list") .output() .expect("Failed to execute command"); if output.status.success() { let result_str = String::from_utf8_lossy(&output.stdout).to_string(); let result = result_str.split("\r\n").collect::>(); let device_index_str: Vec = result .iter() .filter(|&&str| str.starts_with("deviceCount")) .map(|&str| str.to_string()) .collect(); if device_index_str.is_empty() || device_index_str[0].split("=").collect::>()[1] == "0" { Err(JlinkNotFindError) } else { let device_ids = result .iter() .filter(|&&str| str.trim().starts_with("serialNumber")) .map(|&str| { let temp = str.to_string(); return temp.split("=").collect::>()[1].to_string(); }) .collect::>(); Ok(device_ids) } } else { Err(JlinkNotFindError) } } pub fn check_device(&self) -> Result<(), DownloadError> { let commander_path_str = self.commander_path.to_str().unwrap(); let output = Command::new(commander_path_str) .arg("device") .arg("info") .arg("--device") .arg("Cortex-M4") .output() .expect("Failed to execute command"); let stdout = String::from_utf8_lossy(&output.stdout).to_string(); let result = stdout.split("\r\n").collect::>(); let error_log = result .iter() .filter(|&&str| str.trim().starts_with("ERROR")) .collect::>(); if error_log.is_empty() { Ok(()) } else { Err(DownloadError::DeviceNotFindError) } } pub fn erase(&self, label: Option) -> Result { let commander_path_str = self.commander_path.to_str().unwrap(); let output = Command::new(commander_path_str) .arg("device") .arg("masserase") .arg("--device") .arg("Cortex-M4") .output() .expect("Failed to execute command"); let result_str = String::from_utf8_lossy(&output.stdout).to_string(); let result = result_str.split("\r\n").collect::>(); if !result .iter() .filter(|&&str| str.trim().starts_with("ERROR")) .collect::>() .is_empty() || result .iter() .filter(|&&str| str.trim().contains("successfully")) .collect::>() .is_empty() { Err(DownloadError::EraseError) } else { let Some(label) = label else { return Err(DownloadError::NoLabel) }; match self.save_log(label, result_str.clone()) { Ok(_) => { Ok(result_str) } Err(_) => { Err(DownloadError::DownloadBootloaderError) } } } } pub fn download(&self, download_type: DownloadType, label: Option) -> Result { let mut binding: PathBuf; match download_type { DownloadType::Bootloader => { binding = self.bin_path.join(&self.bootloader_name); } DownloadType::App => { binding = self.bin_path.join(&self.app_name); } DownloadType::Rail => { binding = self.bin_path.join(&self.rail_name); } } let bin_path = binding.to_str().unwrap(); println!("{:?}", bin_path); let commander_path_str = self.commander_path.to_str().unwrap(); let output = Command::new(commander_path_str) .arg("flash") .arg(bin_path) .arg("--device") .arg("Cortex-M4") .output() .expect("Failed to execute command"); let result_str = String::from_utf8_lossy(&output.stdout).to_string(); let result = result_str.split("\r\n").collect::>(); println!("{:?}", result); if !result .iter() .filter(|&&str| str.trim().starts_with("ERROR")) .collect::>() .is_empty() || result .iter() .filter(|&&str| str.trim().contains("successfully")) .collect::>() .is_empty() { Err(DownloadError::DownloadBootloaderError) } else { let Some(label) = label else { return Err(DownloadError::NoLabel) }; match self.save_log(label, result_str.clone()) { Ok(_) => { Ok(result_str) } Err(_) => { Err(DownloadError::DownloadBootloaderError) } } } } fn save_log(& self, label: String, log: String) -> Result { if !fs::exists("./log").unwrap() { fs::create_dir("./log").expect("Cant Create Log Folder"); } let mut file = fs::OpenOptions::new() .create(true) .append(true) .open(format!("./log/{label}.txt")) .expect("file not found"); writeln!(file, "{}",log).expect("write failed"); Ok(true) } } #[cfg(test)] mod test { use crate::download_wrapper::DownloadType; use crate::download_wrapper::DownloadWrapper; #[test] fn test_download_wrapper() { let dw = DownloadWrapper::new(); println!("{:?}", dw.commander_path); println!("{:?}", dw.bin_path); println!("{:?}", dw.bootloader_name); println!("{:?}", dw.app_name); println!("{:?}", dw.rail_name); } #[test] fn test_check_jlink() { let dw = DownloadWrapper::new(); let result = dw.check_jlink(); assert_eq!(result.is_ok(), true); println!("ids:{:?}", result.unwrap()); } #[test] fn test_check_device() { let dw = DownloadWrapper::new(); let result = dw.check_device(); assert_eq!(result.is_ok(), true); } #[test] fn test_erase_device() { let dw = DownloadWrapper::new(); let result = dw.erase(Some("111".to_string())); assert_eq!(result.is_ok(), true); } #[test] fn test_download_bootloader() { let dw = DownloadWrapper::new(); let result = dw.download(DownloadType::Bootloader, Some("111".to_string())); assert_eq!(result.is_ok(), true); } #[test] fn test_download_app() { let dw = DownloadWrapper::new(); let result = dw.download(DownloadType::App, Some("111".to_string())); assert_eq!(result.is_ok(), true); } #[test] fn test_download_rail() { let dw = DownloadWrapper::new(); let result = dw.download(DownloadType::Rail, Some("111".to_string())); assert_eq!(result.is_ok(), true); } }