use std::ops::RangeInclusive;
use std::thread;
use std::time;
use crate::command::{self, Command};
use crate::target::{OperatingMode, Target};
use crate::{Error, ErrorKind, Result};
#[derive(Debug)]
pub enum ConnectError {
NoResponse,
BadResponse,
Failed,
}
pub struct Programmer {
target: Box<dyn Target>,
}
impl Programmer {
pub fn new(target: Box<dyn Target>) -> Programmer {
Programmer { target }
}
pub fn connect(mut self) -> Result<ProgrammerConnected> {
self.target.reset_into(OperatingMode::Boot);
self.target.clear_buffers()?;
for baud_rate in &[9600, 4800, 2400, 1200, 0] {
if *baud_rate == 0 {
return Err(Error::new(ErrorKind::Connect, "no response from target"));
}
self.target.set_baud_rate(*baud_rate)?;
let mut attempts = 0;
while self.target.bytes_to_read()? < 1 && attempts < 30 {
self.target.write(&[0x00])?;
thread::sleep(time::Duration::from_millis(10));
attempts += 1;
}
if self.target.bytes_to_read()? >= 1 {
break;
}
}
let mut response1 = [0u8; 1];
self.target.read_exact(&mut response1)?;
let response1 = response1[0];
if response1 != 0x00 {
return Err(Error::new(ErrorKind::Connect, "bad response from target"));
}
self.target.write(&[0x55])?;
let mut response2 = [0u8; 1];
self.target.read_exact(&mut response2)?;
let response2 = response2[0];
match response2 {
0xE6 => Ok(ProgrammerConnected {
target: self.target,
}),
0xFF => Err(Error::new(ErrorKind::Connect, "failed to connect")),
_ => Err(Error::new(ErrorKind::Connect, "bad response from target")),
}
}
}
pub struct ProgrammerConnected {
target: Box<dyn Target>,
}
impl ProgrammerConnected {
pub fn supported_devices(&mut self) -> Result<Vec<command::data::SupportedDevice>> {
let cmd = command::commands::SupportedDeviceInquiry {};
cmd.execute(&mut self.target)
}
pub fn select_device(
mut self,
device_code: &String,
) -> Result<ProgrammerConnectedDeviceSelected> {
let cmd = command::commands::DeviceSelection {
device_code: device_code.clone(),
};
cmd.execute(&mut self.target)?;
Ok(ProgrammerConnectedDeviceSelected {
target: self.target,
})
}
}
pub struct ProgrammerConnectedDeviceSelected {
target: Box<dyn Target>,
}
impl ProgrammerConnectedDeviceSelected {
pub fn clock_modes(&mut self) -> Result<Vec<u8>> {
let cmd = command::commands::ClockModeInquiry {};
cmd.execute(&mut self.target)
}
pub fn select_clock_mode(
mut self,
clock_mode: u8,
) -> Result<ProgrammerConnectedClockModeSelected> {
let cmd = command::commands::ClockModeSelection { mode: clock_mode };
cmd.execute(&mut self.target)?;
Ok(ProgrammerConnectedClockModeSelected {
target: self.target,
})
}
}
pub struct ProgrammerConnectedClockModeSelected {
target: Box<dyn Target>,
}
impl ProgrammerConnectedClockModeSelected {
pub fn multiplication_ratios(
&mut self,
) -> Result<Vec<Vec<command::data::MultiplicationRatio>>> {
let cmd = command::commands::MultiplicationRatioInquiry {};
cmd.execute(&mut self.target)
}
pub fn operating_frequencies(&mut self) -> Result<Vec<RangeInclusive<u16>>> {
let cmd = command::commands::OperatingFrequencyInquiry {};
cmd.execute(&mut self.target)
}
pub fn set_new_bit_rate(
mut self,
bit_rate: u16,
input_frequency: u16,
multiplication_ratios: Vec<command::data::MultiplicationRatio>,
) -> Result<ProgrammerConnectedNewBitRateSelected> {
let cmd = command::commands::NewBitRateSelection {
bit_rate: bit_rate,
input_frequency: input_frequency,
multiplication_ratios: multiplication_ratios,
};
cmd.execute(&mut self.target)?;
let baud_rate: u32 = (bit_rate as u32) * 100;
self.target.set_baud_rate(baud_rate)?;
let cmd = command::commands::NewBitRateSelectionConfirmation {};
cmd.execute(&mut self.target)?;
Ok(ProgrammerConnectedNewBitRateSelected {
target: self.target,
})
}
}
pub struct ProgrammerConnectedNewBitRateSelected {
target: Box<dyn Target>,
}
impl ProgrammerConnectedNewBitRateSelected {
pub fn user_boot_area(&mut self) -> Result<Vec<RangeInclusive<u32>>> {
let cmd = command::commands::UserBootAreaInformationInquiry {};
cmd.execute(&mut self.target)
}
pub fn user_area(&mut self) -> Result<Vec<RangeInclusive<u32>>> {
let cmd = command::commands::UserAreaInformationInquiry {};
cmd.execute(&mut self.target)
}
pub fn erasure_block(&mut self) -> Result<Vec<RangeInclusive<u32>>> {
let cmd = command::commands::ErasureBlockInformationInquiry {};
cmd.execute(&mut self.target)
}
pub fn programming_erasure_state_transition(
mut self,
) -> Result<ProgrammerConnectedProgrammingErasureState> {
let cmd = command::commands::ProgrammingErasureStateTransition {};
let response = cmd.execute(&mut self.target)?;
match response {
command::commands::IDCodeProtectionStatus::Disabled => {
Ok(ProgrammerConnectedProgrammingErasureState {
target: self.target,
})
}
command::commands::IDCodeProtectionStatus::Enabled => {
panic!("Support for ID codes not implemented")
}
}
}
}
pub struct ProgrammerConnectedProgrammingErasureState {
target: Box<dyn Target>,
}
impl ProgrammerConnectedProgrammingErasureState {
pub fn program_user_or_data_area(mut self) -> Result<ProgrammerConnectedWaitingForData> {
let cmd = command::commands::UserDataAreaProgrammingSelection {};
cmd.execute(&mut self.target)?;
Ok(ProgrammerConnectedWaitingForData {
target: self.target,
})
}
pub fn read_memory(
&mut self,
area: command::data::MemoryArea,
start_address: u32,
size: u32,
) -> Result<Vec<u8>> {
let cmd = command::commands::MemoryRead {
area,
start_address,
size,
};
cmd.execute(&mut self.target)
}
pub fn user_boot_area_checksum(&mut self) -> Result<u32> {
let cmd = command::commands::UserBootAreaChecksum {};
cmd.execute(&mut self.target)
}
pub fn user_area_checksum(&mut self) -> Result<u32> {
let cmd = command::commands::UserAreaChecksum {};
cmd.execute(&mut self.target)
}
}
pub struct ProgrammerConnectedWaitingForData {
target: Box<dyn Target>,
}
impl ProgrammerConnectedWaitingForData {
pub fn program_block(&mut self, address: u32, data: [u8; 256]) -> Result<()> {
let cmd = command::commands::X256ByteProgramming {
address: address,
data: data,
};
cmd.execute(&mut self.target)
}
pub fn end(mut self) -> Result<ProgrammerConnectedProgrammingErasureState> {
let cmd = command::commands::X256ByteProgramming {
address: 0xFFFFFFFF,
data: [0u8; 256],
};
cmd.execute(&mut self.target)?;
Ok(ProgrammerConnectedProgrammingErasureState {
target: self.target,
})
}
}