Skip to content
This repository has been archived by the owner on Mar 26, 2024. It is now read-only.

Commit

Permalink
Add API for (un)registering connections
Browse files Browse the repository at this point in the history
At least the J-Link clone I have (serial 123456, HW 7.00, FW
"J-Link ARM-OB STM32 compiled Aug 22 2012 19:52:04") absolutely requires
a registered connection, at least for SWD usage. Nothing ever gets ACKed otherwise.

OpenOCD always calls jaylink_register (with all zeros for info)
when the REGISTER capability is present, and jaylink_unregister on exit.
  • Loading branch information
valpackett committed Jul 22, 2021
1 parent 09de031 commit ef3956b
Showing 1 changed file with 71 additions and 0 deletions.
71 changes: 71 additions & 0 deletions src/lib.rs
Expand Up @@ -162,6 +162,15 @@ enum Command {

ReadConfig = 0xF2,
WriteConfig = 0xF3,

Register = 0x09,
}

#[repr(u8)]
#[allow(dead_code)]
enum RegisterCommand {
Register = 0x64,
Unregister = 0x65,
}

#[repr(u8)]
Expand Down Expand Up @@ -208,6 +217,15 @@ impl SwoStatus {
}
}

#[derive(Default, Debug)]
pub struct Connection {
pub handle: u16,
pub pid: u32,
pub hid: Option<std::net::Ipv4Addr>,
pub iid: u8,
pub cid: u8,
}

/// A handle to a J-Link USB device.
///
/// This is the main interface type of this library. There are multiple ways of obtaining an
Expand Down Expand Up @@ -882,6 +900,59 @@ impl JayLink {
Ok(())
}

/// Registers a connection on the device.
/// Updates the Connection with the returned handle number.
///
/// This requires the [`Register`] capability.
///
/// **Note**: This may be **required** on some devices for SWD to work at all.
///
/// [`Register`]: Capability::Register
pub fn register(&self, conn: &mut Connection) -> Result<()> {
let handle = self.raw_register(conn, RegisterCommand::Register)?;
conn.handle = handle;
Ok(())
}

/// Unregisters a connection on the device.
///
/// This requires the [`Register`] capability.
///
/// [`Register`]: Capability::Register
pub fn unregister(&self, conn: &Connection) -> Result<()> {
self.raw_register(conn, RegisterCommand::Unregister)
.map(|_| ())
}

fn raw_register(&self, conn: &Connection, cmd: RegisterCommand) -> Result<u16> {
self.require_capability(Capability::Register)?;
let mut buf = [0; 14];
buf[0] = Command::Register as u8;
buf[1] = cmd as u8;
buf[2..6].copy_from_slice(&conn.pid.to_le_bytes());
buf[6..10].copy_from_slice(
&u32::from(conn.hid.unwrap_or(std::net::Ipv4Addr::UNSPECIFIED)).to_be_bytes(),
);
buf[10] = conn.iid;
buf[11] = conn.cid;
buf[12..14].copy_from_slice(&conn.handle.to_le_bytes());
self.write_cmd(&buf)?;

// Receive connection table
let mut buf = [0; 76];
self.read(&mut buf)?;
let new_handle = u16::from_le_bytes([buf[0], buf[1]]);
let num_entries = u16::from_le_bytes([buf[2], buf[3]]);
let entry_size = u16::from_le_bytes([buf[4], buf[5]]);
let info_size = u16::from_le_bytes([buf[6], buf[7]]);
let all_size = 8 + (num_entries * entry_size) + info_size;
if all_size > 76 {
let mut extra_buf = vec![0; (all_size - 76) as usize];
self.read(&mut extra_buf)?;
}
Ok(new_handle)
}

/// Performs a JTAG I/O operation.
///
/// This will shift out data on `TMS` (pin 7) and `TDI` (pin 5), while reading data shifted
Expand Down

0 comments on commit ef3956b

Please sign in to comment.