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;
use crate::error::Result;
use std::fmt;
use crate::error::{Error, Result};
pub mod control;
pub trait Command {
@ -16,19 +18,44 @@ pub trait Command {
}
pub trait Response {
fn from_bytes(bytes: &[u8]) -> Result<Self>
/// parse the PAYLOAD part only
fn from_payload(bytes: &[u8]) -> Result<Self>
where
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 () {
fn from_bytes(bytes: &[u8]) -> Result<Self> {
fn from_payload(bytes: &[u8]) -> Result<Self> {
Ok(())
}
}
impl Response for Vec<u8> {
fn from_bytes(bytes: &[u8]) -> Result<Self> {
fn from_payload(bytes: &[u8]) -> Result<Self> {
Ok(bytes.to_vec())
}
}
@ -42,32 +69,75 @@ impl Command for GetChipProtected {
}
}
impl Response for bool {
fn from_bytes(bytes: &[u8]) -> Result<Self> {
fn from_payload(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 1 {
return Err(crate::error::Error::InvalidPayloadLength);
return Err(Error::InvalidPayloadLength);
}
if bytes[0] == 0x01 {
Ok(true)
} else if bytes[0] == 0x02 {
Ok(false)
} else {
Err(crate::error::Error::InvalidPayload)
Err(Error::InvalidPayload)
}
}
}
/// Does not use standard response.
/// ffff00 20 aeb4abcd 16c6bc45 e339e339e339e339
/// cd-ab-b4-ae-45-bc-c6-16
/// Get Chip UID, the UID is also avaliable in the `wchisp` command.
pub struct GetChipId;
impl Command for GetChipId {
type Response = Vec<u8>;
type Response = ChipId;
const COMMAND_ID: u8 = 0x11;
fn payload(&self) -> Vec<u8> {
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 {
Quit,
}
@ -127,9 +197,9 @@ pub struct DmiOpResponse {
pub op: u8,
}
impl Response for DmiOpResponse {
fn from_bytes(bytes: &[u8]) -> Result<Self> {
fn from_payload(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 6 {
return Err(crate::error::Error::InvalidPayloadLength);
return Err(Error::InvalidPayloadLength);
}
let addr = bytes[0];
let op = bytes[5];
@ -137,3 +207,18 @@ impl Response for DmiOpResponse {
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,
}
impl Response for ProbeInfo {
fn from_bytes(bytes: &[u8]) -> Result<Self> {
fn from_payload(bytes: &[u8]) -> Result<Self> {
if bytes.len() < 3 {
return Err(crate::error::Error::InvalidPayloadLength);
}
@ -49,7 +49,7 @@ pub struct ChipInfo {
pub chip_type: u32,
}
impl Response for ChipInfo {
fn from_bytes(bytes: &[u8]) -> Result<Self> {
fn from_payload(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 5 {
return Err(crate::error::Error::InvalidPayloadLength);
}

20
src/main.rs

@ -18,10 +18,10 @@ fn main() -> Result<()> {
let protected = link.send_command(commands::GetChipProtected)?;
println!("protected => {:?}", protected);
let _ = link.send_command(commands::GetChipId);
// println!("=> {:02x?}", r);
let uid = link.send_command(commands::GetChipId);
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, 0x00000001))?;
@ -30,8 +30,18 @@ fn main() -> Result<()> {
link.send_command(DmiOp::read(0x16))?;
let marchid = link.send_command(DmiOp::read(0x04))?;
println!("marchid => {:08x}", marchid.data);
/// resume sequence
let marchid = marchid.data;
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, 0x00000001))?;

30
src/transport.rs

@ -2,7 +2,10 @@ use std::time::Duration;
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;
@ -105,24 +108,7 @@ pub trait Transport {
self.write_bytes(&raw)?;
let resp = self.read_bytes()?;
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();
C::Response::from_bytes(&payload)
} else {
Err(Error::Custom("Invalid response".to_string()))
}
C::Response::from_raw(&resp)
}
}
@ -137,7 +123,11 @@ impl Transport for WchLink {
)?;
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)
}

Loading…
Cancel
Save