use jaylink::{CommunicationSpeed, JayLink};
use log::trace;
use std::cmp;
use structopt::StructOpt;
const IDLE_CYCLES_BEFORE_ACCESS: usize = 2;
#[derive(StructOpt)]
struct Opts {
#[structopt(long = "serial")]
serial: Option<String>,
#[structopt(long = "speed")]
speed: Option<u16>,
}
fn main() {
env_logger::init();
let opts = Opts::from_args();
if let Err(e) = run(opts) {
eprintln!("error: {:?}", e);
std::process::exit(1);
}
}
enum Port {
Debug,
#[allow(unused)] Access,
}
#[derive(Debug)]
enum SwdError {
Probe(jaylink::Error),
Fault,
NoResponse,
Parity,
}
impl From<jaylink::Error> for SwdError {
fn from(e: jaylink::Error) -> Self {
SwdError::Probe(e)
}
}
enum Ack {
Ok,
Wait,
Fault,
}
fn parse_ack(sl: &[bool]) -> Option<Ack> {
assert_eq!(sl.len(), 3);
trace!("ACK: {:?}", sl);
Some(match (sl[0], sl[1], sl[2]) {
(true, false, false) => Ack::Ok,
(false, true, false) => Ack::Wait,
(false, false, true) => Ack::Fault,
_ => return None,
})
}
trait JayLinkExt {
fn swj_seq(&mut self) -> jaylink::Result<()>;
fn raw_read(&mut self, port: Port, a: u32) -> Result<u32, SwdError>;
fn raw_write(&mut self, port: Port, a: u32, value: u32) -> Result<(), SwdError>;
}
impl JayLinkExt for JayLink {
fn swj_seq(&mut self) -> jaylink::Result<()> {
let mut dir = Vec::new();
let mut swdio = Vec::new();
swdio.resize(64, true);
dir.resize(64, true);
let mut seq = 0xE79E; for _ in 0..16 {
swdio.push(seq & 0b1 != 0);
seq >>= 1;
}
dir.resize(dir.len() + 16, true);
swdio.resize(swdio.len() + 64, true);
dir.resize(dir.len() + 64, true);
swdio.resize(swdio.len() + 10, false);
dir.resize(dir.len() + 10, true);
self.swd_io(dir, swdio)?;
Ok(())
}
fn raw_read(&mut self, port: Port, a: u32) -> Result<u32, SwdError> {
let mut dir = Vec::new();
let mut swdio = Vec::new();
swdio.resize(swdio.len() + IDLE_CYCLES_BEFORE_ACCESS, false);
dir.resize(dir.len() + IDLE_CYCLES_BEFORE_ACCESS, true);
let a2 = a & 0b0100 != 0;
let a3 = a & 0b1000 != 0;
swdio.push(true); swdio.push(match port {
Port::Debug => false,
Port::Access => true,
});
swdio.push(true); swdio.push(a2);
swdio.push(a3);
let even_parity = (swdio.iter().filter(|b| **b == true).count() - 1) % 2 != 0;
swdio.push(even_parity);
swdio.push(false); swdio.push(true); dir.resize(dir.len() + 8, true);
swdio.push(false); swdio.push(false); swdio.push(false);
for _ in 0..32 {
swdio.push(false); }
swdio.push(false);
dir.resize(dir.len() + 3 + 33, false);
loop {
let mut response = self.swd_io(dir.iter().copied(), swdio.iter().copied())?;
response.split_off(IDLE_CYCLES_BEFORE_ACCESS + 8);
trace!("response: {:?}", response);
let ack = response.split_off(3).collect::<Vec<_>>();
let value = response.split_off(32).collect::<Vec<_>>();
let parity = response.next().unwrap();
if let Some(ack) = parse_ack(&ack) {
match ack {
Ack::Ok => {
let value = value
.iter()
.fold(0u32, |accum, bit| (accum >> 1) | (u32::from(*bit) << 31));
trace!("value=0x{:08X}, parity={:?}", value, parity);
let expected_parity = value.count_ones() % 2 != 0;
if expected_parity == parity {
return Ok(value);
} else {
return Err(SwdError::Parity);
}
}
Ack::Wait => {
trace!("WAIT - retrying read access");
continue;
}
Ack::Fault => {
return Err(SwdError::Fault);
}
}
}
return Err(SwdError::NoResponse);
}
}
fn raw_write(&mut self, port: Port, a: u32, value: u32) -> Result<(), SwdError> {
let mut dir = Vec::new();
let mut swdio = Vec::new();
swdio.resize(swdio.len() + IDLE_CYCLES_BEFORE_ACCESS, false);
dir.resize(dir.len() + IDLE_CYCLES_BEFORE_ACCESS, true);
let a2 = a & 0b0100 != 0;
let a3 = a & 0b1000 != 0;
swdio.push(true); swdio.push(match port {
Port::Debug => false,
Port::Access => true,
});
swdio.push(false); swdio.push(a2);
swdio.push(a3);
let even_parity = (swdio.iter().filter(|b| **b == true).count() - 1) % 2 != 0;
swdio.push(even_parity);
swdio.push(false); swdio.push(true); dir.resize(dir.len() + 8, true);
swdio.push(false); swdio.push(false); swdio.push(false); dir.resize(dir.len() + 3, false);
swdio.push(false);
swdio.push(false);
dir.resize(dir.len() + 2, false);
{
let mut value = value;
for _ in 0..32 {
swdio.push(value & 1 != 0);
value >>= 1;
}
swdio.push(value.count_ones() % 2 != 0); dir.resize(dir.len() + 33, true);
}
loop {
let mut response = self.swd_io(dir.iter().copied(), swdio.iter().copied())?;
response.split_off(IDLE_CYCLES_BEFORE_ACCESS + 8);
trace!("response: {:?}", response);
let ack = response.split_off(3).collect::<Vec<_>>();
if let Some(ack) = parse_ack(&ack) {
match ack {
Ack::Ok => {
return Ok(());
}
Ack::Wait => {
trace!("WAIT - retrying write access");
continue;
}
Ack::Fault => {
return Err(SwdError::Fault);
}
}
}
return Err(SwdError::NoResponse);
}
}
}
fn run(opts: Opts) -> Result<(), SwdError> {
let mut probe = JayLink::open_by_serial(opts.serial.as_ref().map(|s| &**s))?;
let khz = cmp::min(opts.speed.unwrap_or(200), 0xfffe);
probe.set_speed(CommunicationSpeed::khz(khz).unwrap())?;
probe.swj_seq()?;
let dpidr = probe.raw_read(Port::Debug, 0b0000)?;
println!("DPIDR=0x{:08X}", dpidr);
probe.raw_write(Port::Debug, 0b0000, 0x1e)?;
let errmask = 0b10100010;
let ctrl_stat = probe.raw_read(Port::Debug, 0b0100)?;
println!("CTRL/STAT=0x{:08X}", ctrl_stat);
if ctrl_stat & errmask != 0 {
eprintln!("errors bits set in CTRL/STAT");
}
Ok(())
}