Browse Source

refactor: add --chip for chip type check; fix 0x0c command; refine error handling

pull/28/head
Andelf 1 year ago
parent
commit
e1f1fc1384
  1. 7
      CHANGELOG.md
  2. 24
      src/commands.rs
  3. 4
      src/commands/control.rs
  4. 21
      src/device.rs
  5. 8
      src/error.rs
  6. 34
      src/lib.rs
  7. 8
      src/main.rs
  8. 23
      src/operations.rs

7
CHANGELOG.md

@ -13,10 +13,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support WCH-Link firmware 2.9, some raw commands are changed
- Support Flash protect and unprotect (#14)
- Fix stuck for CH5xx devices, due to unsppported read ram rom split command
- Add `--chip` option to specify chip type
- Check probe type when doing mode-switch
### Fixed
- Constraint regs for riscv32ec variant
- Wrong 0x0c command interpretation, this should be a set chip speed command
### Changed
- Refine error messages
## [0.0.4] - 2023-07-01

24
src/commands.rs

@ -181,6 +181,7 @@ impl Command for SetFlashProtected {
}
/// Get Chip UID, the UID is also avaliable in the `wchisp` command.
// ??? 0x11, 0x01, _ (riscvchip)
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum QueryChipInfo {
V1 = 0x09,
@ -261,6 +262,29 @@ impl Command for Reset {
}
}
/// (0x0c, [riscvchip, 1/2/3])
pub struct SetTwoLineMode {
pub riscvchip: u8,
pub speed: u8, // 1, 2, 3
}
impl Command for SetTwoLineMode {
type Response = bool;
const COMMAND_ID: u8 = 0x0c;
fn payload(&self) -> Vec<u8> {
vec![self.riscvchip, self.speed]
}
}
impl Response for bool {
fn from_payload(resp: &[u8]) -> Result<Self> {
if resp.len() != 1 {
return Err(Error::InvalidPayloadLength);
}
Ok(resp[0] == 0x01) // 1 means success
}
}
/// DMI operations
pub enum DmiOp {
Nop,

4
src/commands/control.rs

@ -54,7 +54,7 @@ impl fmt::Display for ProbeInfo {
}
}
/// (0x0d, 0x02)
/// ?SetChipType (0x0d, 0x02)
pub struct AttachChip;
impl Command for AttachChip {
type Response = AttachChipResponse;
@ -64,7 +64,7 @@ impl Command for AttachChip {
}
}
#[derive(Debug)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AttachChipResponse {
pub chip_family: RiscvChip,
pub riscvchip: u8,

21
src/device.rs

@ -60,7 +60,18 @@ impl WchLink {
.unwrap_or(false)
})
.nth(nth)
.map_or(Err(crate::error::Error::ProbeNotFound), Ok)?;
.map_or(Err(crate::error::Error::ProbeNotFound), Ok);
// check if there's a device with the DAP VID/PID
let device = match device {
Ok(device) => device,
Err(e) => {
if let Ok(_) = open_usb_device(VENDOR_ID_DAP, PRODUCT_ID_DAP, nth) {
return Err(crate::error::Error::ProbeModeNotSupported);
}
return Err(e);
}
};
let mut device_handle = device.open()?;
@ -130,9 +141,15 @@ pub fn try_switch_from_rv_to_dap(nth: usize) -> Result<()> {
};
let info = dev.probe_info()?;
info!("probe info: {:?}", info);
if info.variant.can_switch_mode() {
let _ = dev.send_command(RawCommand::<0xff>(vec![0x41]));
Ok(())
} else {
log::error!("Cannot switch mode for WCH-LinkRV: not supported");
return Err(crate::Error::Custom(
"WCH-Link-CH549 does not support mode switch".into(),
));
}
}
/// Switch from RV mode to DAP mode

8
src/error.rs

@ -1,5 +1,7 @@
use thiserror::Error;
use crate::RiscvChip;
/// Alias for a `Result` with the error type `wlink::Error`.
pub type Result<T> = std::result::Result<T, Error>;
@ -9,14 +11,18 @@ pub enum Error {
Custom(String),
#[error("USB error: {0}")]
Rusb(#[from] rusb::Error),
#[error("WCH-Link not found or not in RV mode, please check your connection or use mode-switch tool to switch to RV mode")]
#[error("WCH-Link not found, please check your connection")]
ProbeNotFound,
#[error("WCH-Link is connected, but is not in RV mode")]
ProbeModeNotSupported,
#[error("Unknown WCH-Link variant: {0}")]
UnknownLinkVariant(u8),
#[error("Unknown RISC-V Chip: 0x{0:02x}")]
UnknownChip(u8),
#[error("Probe is not attached to an MCU, or debug is not enabled. (hint: use wchisp to enable debug)")]
NotAttached,
#[error("Chip mismatch: expected {0:?}, got {1:?}")]
ChipMismatch(RiscvChip, RiscvChip),
#[error("WCH-Link underlying protocol error: {0:#04x} {1:#04x?}")]
Protocol(u8, Vec<u8>),
#[error("Invalid payload length")]

34
src/lib.rs

@ -1,4 +1,4 @@
use std::fmt;
use std::{fmt, str::FromStr};
pub mod commands;
pub mod device;
@ -39,6 +39,13 @@ impl WchLinkVariant {
_ => Err(Error::UnknownLinkVariant(value)),
}
}
pub fn can_switch_mode(&self) -> bool {
match self {
WchLinkVariant::Ch549 => false,
_ => true,
}
}
}
impl fmt::Display for WchLinkVariant {
@ -86,11 +93,14 @@ impl RiscvChip {
RiscvChip::CH32V103 | RiscvChip::CH32V003 | RiscvChip::CH32V20X | RiscvChip::CH32V30X
)
}
fn can_disable_debug(&self) -> bool {
/// Very unsafe. This disables the debug interface of the chip.
/// Command sequence is 810e0101
pub fn can_disable_debug(&self) -> bool {
matches!(self, RiscvChip::CH57X | RiscvChip::CH56X | RiscvChip::CH58X)
}
fn reset_command(&self) -> crate::commands::Reset {
pub fn reset_command(&self) -> crate::commands::Reset {
match self {
RiscvChip::CH57X | RiscvChip::CH58X => crate::commands::Reset::Normal2,
_ => crate::commands::Reset::Normal,
@ -146,3 +156,21 @@ impl RiscvChip {
}
}
}
// for clap parser
impl FromStr for RiscvChip {
type Err = Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match &*s.to_ascii_uppercase() {
"CH32V103" => Ok(RiscvChip::CH32V103),
"CH32V20X" => Ok(RiscvChip::CH32V20X),
"CH32V30X" => Ok(RiscvChip::CH32V30X),
"CH32V003" => Ok(RiscvChip::CH32V003),
"CH56X" => Ok(RiscvChip::CH56X),
"CH57X" => Ok(RiscvChip::CH57X),
"CH58X" => Ok(RiscvChip::CH58X),
_ => Err(Error::UnknownChip(0)),
}
}
}

8
src/main.rs

@ -1,7 +1,7 @@
use std::{thread::sleep, time::Duration};
use anyhow::Result;
use wlink::{commands, device::WchLink, format::read_firmware_from_file, regs};
use wlink::{commands, device::WchLink, format::read_firmware_from_file, regs, RiscvChip};
use clap::{Parser, Subcommand};
@ -20,6 +20,10 @@ struct Cli {
#[arg(long, global = true)]
detach: bool,
/// Specify the chip type, e.g. CH32V30X
#[arg(long, global = true)]
chip: Option<RiscvChip>,
#[command(subcommand)]
command: Option<Commands>,
}
@ -137,7 +141,7 @@ fn main() -> Result<()> {
Some(command) => {
let mut probe = WchLink::open_nth(device_index)?;
probe.probe_info()?;
probe.attach_chip()?;
probe.attach_chip(cli.chip)?;
match command {
Dump { address, length } => {
log::info!(

23
src/operations.rs

@ -18,23 +18,36 @@ impl WchLink {
Ok(info)
}
/// Attach chip and get chip info
pub fn attach_chip(&mut self) -> Result<()> {
pub fn attach_chip(&mut self, expected_chip: Option<RiscvChip>) -> Result<()> {
if self.chip.is_some() {
log::warn!("Chip already attached");
}
let mut chip_info = None;
let probe_info = self.send_command(commands::control::GetProbeInfo)?;
let mut chip_info = None;
for _ in 0..3 {
// self.send_command(commands::control::DetachChip)?;
// unknown command
// 0x07 seems to be the expected richvchip id
self.send_command(commands::RawCommand::<0x0c>(vec![0x07, 0x01]))?;
self.send_command(commands::SetTwoLineMode {
riscvchip: expected_chip.unwrap_or(RiscvChip::CH32V30X) as u8,
speed: 1, // 1 high, 2, medium, 3 low
})?;
if let Ok(resp) = self.send_command(commands::control::AttachChip) {
log::info!("Attached chip: {}", resp);
chip_info = Some(resp);
if let Some(expected_chip) = expected_chip {
if resp.chip_family != expected_chip {
log::error!(
"Attached chip type ({:?}) does not match expected chip type ({:?})",
resp.chip_family,
expected_chip
);
return Err(Error::ChipMismatch(expected_chip, resp.chip_family));
}
}
break;
} else {
log::debug!("retrying...");

Loading…
Cancel
Save