use crate::download_wrapper::DownloadError::JlinkNotFindError; use anyhow::Error; use std::path::{Path, PathBuf}; use std::process::Command; 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 ToString for DownloadType { fn to_string(&self) -> String { match self { DownloadType::Bootloader => "BootLoader".to_string(), DownloadType::App => "App".to_string(), DownloadType::Rail => "Rail".to_string(), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DownloadError { JlinkNotFindError, DeviceNotFindError, EraseError, DownloadBootloaderError, DownloadAppError, DownloadRailError, } 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-wisun_APP-V1_D20240927.s37"), rail_name: String::from("rail_soc_railtest_sisdk.s37"), } } } 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) -> Result<(), DownloadError> { 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 { Ok(()) } } pub fn download(&self, download_type: DownloadType) -> Result<(), DownloadError> { 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 { Ok(()) } } pub fn download_app(&self) -> Result { todo!() } pub fn download_rail(&self) -> Result { todo!() } } #[cfg(test)] mod test { use crate::download_wrapper::DownloadWrapper; use crate::download_wrapper::DownloadType; #[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(); assert_eq!(result.is_ok(), true); } #[test] fn test_download_bootloader(){ let dw = DownloadWrapper::new(); let result = dw.download(DownloadType::Bootloader); assert_eq!(result.is_ok(), true); } #[test] fn test_download_app(){ let dw = DownloadWrapper::new(); let result = dw.download(DownloadType::App); assert_eq!(result.is_ok(), true); } #[test] fn test_download_rail(){ let dw = DownloadWrapper::new(); let result = dw.download(DownloadType::Rail); assert_eq!(result.is_ok(), true); } }