Browse Source

feat: impl more commands

pull/1/head
Andelf 2 years ago
parent
commit
e395554278
  1. 111
      src/commands.rs
  2. 4
      src/commands/control.rs
  3. 20
      src/main.rs
  4. 30
      src/transport.rs

111
src/commands.rs

@ -1,6 +1,8 @@
// pub mod dmi; // pub mod dmi;
use crate::error::Result; use std::fmt;
use crate::error::{Error, Result};
pub mod control; pub mod control;
pub trait Command { pub trait Command {
@ -16,19 +18,44 @@ pub trait Command {
} }
pub trait Response { pub trait Response {
fn from_bytes(bytes: &[u8]) -> Result<Self> /// parse the PAYLOAD part only
fn from_payload(bytes: &[u8]) -> Result<Self>
where where
Self: Sized; Self: Sized;
/// default implementation for parsing [0x82 CMD LEN PAYLOAD] style response
fn from_raw(resp: &[u8]) -> Result<Self>
where
Self: Sized,
{
if resp[0] == 0x81 {
let reason = resp[1];
let len = resp[2] as usize;
if len != resp[3..].len() {
return Err(Error::InvalidPayloadLength);
}
let payload = resp[3..3 + len].to_vec();
return Err(Error::Protocol(reason, payload));
} else if resp[0] == 0x82 {
let len = resp[2] as usize;
if len != resp[3..].len() {
return Err(Error::InvalidPayloadLength);
}
let payload = resp[3..3 + len].to_vec();
Self::from_payload(&payload)
} else {
Err(Error::InvalidPayload)
}
}
} }
impl Response for () { impl Response for () {
fn from_bytes(bytes: &[u8]) -> Result<Self> { fn from_payload(bytes: &[u8]) -> Result<Self> {
Ok(()) Ok(())
} }
} }
impl Response for Vec<u8> { impl Response for Vec<u8> {
fn from_bytes(bytes: &[u8]) -> Result<Self> { fn from_payload(bytes: &[u8]) -> Result<Self> {
Ok(bytes.to_vec()) Ok(bytes.to_vec())
} }
} }
@ -42,32 +69,75 @@ impl Command for GetChipProtected {
} }
} }
impl Response for bool { impl Response for bool {
fn from_bytes(bytes: &[u8]) -> Result<Self> { fn from_payload(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 1 { if bytes.len() != 1 {
return Err(crate::error::Error::InvalidPayloadLength); return Err(Error::InvalidPayloadLength);
} }
if bytes[0] == 0x01 { if bytes[0] == 0x01 {
Ok(true) Ok(true)
} else if bytes[0] == 0x02 { } else if bytes[0] == 0x02 {
Ok(false) Ok(false)
} else { } else {
Err(crate::error::Error::InvalidPayload) Err(Error::InvalidPayload)
} }
} }
} }
/// Does not use standard response. /// Get Chip UID, the UID is also avaliable in the `wchisp` command.
/// ffff00 20 aeb4abcd 16c6bc45 e339e339e339e339
/// cd-ab-b4-ae-45-bc-c6-16
pub struct GetChipId; pub struct GetChipId;
impl Command for GetChipId { impl Command for GetChipId {
type Response = Vec<u8>; type Response = ChipId;
const COMMAND_ID: u8 = 0x11; const COMMAND_ID: u8 = 0x11;
fn payload(&self) -> Vec<u8> { fn payload(&self) -> Vec<u8> {
vec![0x09] vec![0x09]
} }
} }
// This does not use standard response format:
// raw response: ffff00 20 aeb4abcd 16c6bc45 e339e339e339e339
// UID in wchisp: cd-ab-b4-ae-45-bc-c6-16
// FIXME: no idea of what the remaining bytes mean
pub struct ChipId(pub [u8; 8]);
impl Response for ChipId {
fn from_raw(resp: &[u8]) -> Result<Self> {
if resp.len() <= 12 {
return Err(Error::InvalidPayloadLength);
}
if &resp[..2] == b"\xff\xff" {
let mut bytes = [0u8; 8];
bytes[0..4]
.copy_from_slice(&u32::from_be_bytes(resp[4..8].try_into().unwrap()).to_le_bytes());
bytes[4..8].copy_from_slice(
&u32::from_be_bytes(resp[8..12].try_into().unwrap()).to_le_bytes(),
);
Ok(Self(bytes))
} else {
Err(Error::InvalidPayload)
}
}
fn from_payload(bytes: &[u8]) -> Result<Self> {
unreachable!("ChipId is not be parsed from payload; qed")
}
}
impl fmt::Display for ChipId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(
&self
.0
.iter()
.map(|b| format!("{:02x}", b))
.collect::<Vec<_>>()
.join("-"),
)
}
}
impl fmt::Debug for ChipId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&format!("ChipId({:02x?})", &self.0[..]))
}
}
pub enum Reset { pub enum Reset {
Quit, Quit,
} }
@ -127,9 +197,9 @@ pub struct DmiOpResponse {
pub op: u8, pub op: u8,
} }
impl Response for DmiOpResponse { impl Response for DmiOpResponse {
fn from_bytes(bytes: &[u8]) -> Result<Self> { fn from_payload(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 6 { if bytes.len() != 6 {
return Err(crate::error::Error::InvalidPayloadLength); return Err(Error::InvalidPayloadLength);
} }
let addr = bytes[0]; let addr = bytes[0];
let op = bytes[5]; let op = bytes[5];
@ -137,3 +207,18 @@ impl Response for DmiOpResponse {
Ok(DmiOpResponse { addr, data, op }) Ok(DmiOpResponse { addr, data, op })
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn chip_id_parsing() {
let raw = hex::decode("ffff0020aeb4abcd16c6bc45e339e339e339e339").unwrap();
let uid = ChipId::from_raw(&raw).unwrap();
println!("=> {:?}", uid);
assert_eq!("cd-ab-b4-ae-45-bc-c6-16", uid.to_string());
}
}

4
src/commands/control.rs

@ -19,7 +19,7 @@ pub struct ProbeInfo {
link_variant: WchLinkVariant, link_variant: WchLinkVariant,
} }
impl Response for ProbeInfo { impl Response for ProbeInfo {
fn from_bytes(bytes: &[u8]) -> Result<Self> { fn from_payload(bytes: &[u8]) -> Result<Self> {
if bytes.len() < 3 { if bytes.len() < 3 {
return Err(crate::error::Error::InvalidPayloadLength); return Err(crate::error::Error::InvalidPayloadLength);
} }
@ -49,7 +49,7 @@ pub struct ChipInfo {
pub chip_type: u32, pub chip_type: u32,
} }
impl Response for ChipInfo { impl Response for ChipInfo {
fn from_bytes(bytes: &[u8]) -> Result<Self> { fn from_payload(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 5 { if bytes.len() != 5 {
return Err(crate::error::Error::InvalidPayloadLength); return Err(crate::error::Error::InvalidPayloadLength);
} }

20
src/main.rs

@ -18,10 +18,10 @@ fn main() -> Result<()> {
let protected = link.send_command(commands::GetChipProtected)?; let protected = link.send_command(commands::GetChipProtected)?;
println!("protected => {:?}", protected); println!("protected => {:?}", protected);
let _ = link.send_command(commands::GetChipId); let uid = link.send_command(commands::GetChipId);
// println!("=> {:02x?}", r); println!("=> {}", uid);
/// reset csr // read csr
link.send_command(DmiOp::write(0x10, 0x80000001))?; link.send_command(DmiOp::write(0x10, 0x80000001))?;
link.send_command(DmiOp::write(0x10, 0x80000001))?; link.send_command(DmiOp::write(0x10, 0x80000001))?;
link.send_command(DmiOp::write(0x10, 0x00000001))?; link.send_command(DmiOp::write(0x10, 0x00000001))?;
@ -30,8 +30,18 @@ fn main() -> Result<()> {
link.send_command(DmiOp::read(0x16))?; link.send_command(DmiOp::read(0x16))?;
let marchid = link.send_command(DmiOp::read(0x04))?; let marchid = link.send_command(DmiOp::read(0x04))?;
println!("marchid => {:08x}", marchid.data); println!("marchid => {:08x}", marchid.data);
let marchid = marchid.data;
/// resume sequence println!(
"{}{}{}-{}{}{}",
(((marchid >> 26) & 0x1F) + 64) as u8 as char,
(((marchid >> 21) & 0x1F) + 64) as u8 as char,
(((marchid >> 16) & 0x1F) + 64) as u8 as char,
(((marchid >> 10) & 0x1F) + 64) as u8 as char,
((((marchid >> 5) & 0x1F) as u8) + b'0') as char,
((marchid & 0x1F) + 64) as u8 as char,
);
// resume sequence
link.send_command(DmiOp::write(0x10, 0x80000001))?; link.send_command(DmiOp::write(0x10, 0x80000001))?;
link.send_command(DmiOp::write(0x10, 0x80000001))?; link.send_command(DmiOp::write(0x10, 0x80000001))?;
link.send_command(DmiOp::write(0x10, 0x00000001))?; link.send_command(DmiOp::write(0x10, 0x00000001))?;

30
src/transport.rs

@ -2,7 +2,10 @@ use std::time::Duration;
use rusb::{DeviceHandle, UsbContext}; use rusb::{DeviceHandle, UsbContext};
use crate::{error::{Error, Result}, commands::{Command, Response}}; use crate::{
commands::{Command, Response},
error::{Error, Result},
};
const USB_TIMEOUT_MS: u64 = 5000; const USB_TIMEOUT_MS: u64 = 5000;
@ -105,24 +108,7 @@ pub trait Transport {
self.write_bytes(&raw)?; self.write_bytes(&raw)?;
let resp = self.read_bytes()?; let resp = self.read_bytes()?;
if resp[0] == 0x81 { C::Response::from_raw(&resp)
let reason = resp[1];
let len = resp[2] as usize;
if len != resp[3..].len() {
return Err(Error::InvalidPayloadLength);
}
let payload = resp[3..3 + len].to_vec();
return Err(Error::Protocol(reason, payload));
} else if resp[0] == 0x82 {
let len = resp[2] as usize;
if len != resp[3..].len() {
return Err(Error::InvalidPayloadLength);
}
let payload = resp[3..3 + len].to_vec();
C::Response::from_bytes(&payload)
} else {
Err(Error::Custom("Invalid response".to_string()))
}
} }
} }
@ -137,7 +123,11 @@ impl Transport for WchLink {
)?; )?;
let resp = buf[..bytes_read].to_vec(); let resp = buf[..bytes_read].to_vec();
log::debug!("recv {} {}", hex::encode(&resp[..3]), hex::encode(&resp[3..])); log::debug!(
"recv {} {}",
hex::encode(&resp[..3]),
hex::encode(&resp[3..])
);
Ok(resp) Ok(resp)
} }

Loading…
Cancel
Save