use std::fmt::Display;
use std::sync::{Arc, Mutex};
use bitmask_enum::bitmask;
use color_eyre::eyre::Result;
use crate::serial::bmd_rsp::BmdRspInterface;
use crate::serial::remote::adi::{AdiV5AccessPort, AdiV5DebugPort};
use crate::serial::remote::protocol_v0::{RemoteV0, RemoteV0Plus};
use crate::serial::remote::protocol_v1::RemoteV1;
use crate::serial::remote::protocol_v2::RemoteV2;
use crate::serial::remote::protocol_v3::RemoteV3;
use crate::serial::remote::protocol_v4::RemoteV4;
use crate::serial::remote::riscv_debug::RiscvDmi;
pub mod adi;
mod protocol_v0;
mod protocol_v1;
mod protocol_v2;
mod protocol_v3;
mod protocol_v4;
pub mod riscv_debug;
pub const REMOTE_MAX_MSG_SIZE: usize = 1024;
pub const REMOTE_SOM: u8 = b'!';
pub const REMOTE_EOM: u8 = b'#';
pub const REMOTE_RESP: u8 = b'&';
pub const REMOTE_RESP_OK: u8 = b'K';
pub const REMOTE_RESP_PARERR: u8 = b'P';
pub const REMOTE_RESP_ERR: u8 = b'E';
pub const REMOTE_RESP_NOTSUP: u8 = b'N';
pub type TargetAddr32 = u32;
pub type TargetAddr64 = u64;
#[repr(u8)]
pub enum Align
{
As8Bit,
As16Bit,
As32Bit,
As64Bit,
}
#[bitmask(u64)]
pub enum TargetArchitecture
{
CortexM,
CortexAR,
RiscV32,
RiscV64,
}
#[bitmask(u64)]
pub enum TargetFamily
{
AT32,
Apollo3,
CH32,
CH579,
EFM,
GD32,
HC32,
LPC,
MM32,
NRF,
NXPKinetis,
Puya,
RenesasRZ,
RenesasRA,
RP,
SAM,
STM,
TI,
Xilinx,
NXPiMXRT,
}
pub trait BmdRemoteProtocol
{
fn swd_init(&self) -> Result<Box<dyn BmdSwdProtocol>>;
fn jtag_init(&self) -> Result<Box<dyn BmdJtagProtocol>>;
fn adiv5_init(&self) -> Option<Arc<dyn BmdAdiV5Protocol>>;
fn adiv6_init(&self) -> Option<Arc<dyn BmdAdiV5Protocol>>;
fn riscv_jtag_init(&self) -> Option<Arc<dyn BmdRiscvProtocol>>;
fn add_jtag_dev(&self, dev_index: u32, jtag_dev: &JtagDev);
fn get_comms_frequency(&self) -> u32;
fn set_comms_frequency(&self, freq: u32) -> bool;
fn target_clk_output_enable(&self, enable: bool);
fn supported_architectures(&self) -> Result<Option<TargetArchitecture>>;
fn supported_families(&self) -> Result<Option<TargetFamily>>;
}
pub trait BmdSwdProtocol
{
fn seq_in(&self, clock_cycles: usize) -> u32;
fn seq_in_parity(&self, clock_cycles: usize) -> Option<u32>;
fn seq_out(&self, value: u32, clock_cycles: usize);
fn seq_out_parity(&self, value: u32, clock_cycles: usize);
}
pub trait BmdJtagProtocol
{
fn tap_reset(&self);
fn tap_next(&self, tms: bool, tdi: bool) -> bool;
fn tap_tms_seq(&self, tms_states: u32, clock_cycles: usize);
fn tap_tdi_tdo_seq(
&self,
data_out: Option<&mut [u8]>,
final_tms: bool,
data_in: Option<&[u8]>,
clock_cycles: usize,
);
fn tap_tdi_seq(&self, final_tms: bool, data_in: &[u8], clock_cycles: usize);
fn tap_cycle(&self, tms: bool, tdi: bool, clock_cycles: usize);
}
pub trait BmdAdiV5Protocol
{
fn raw_access(&self, dp: AdiV5DebugPort, rnw: u8, addr: u16, value: u32) -> u32;
fn dp_read(&self, dp: AdiV5DebugPort, addr: u16) -> u32;
fn ap_read(&self, ap: AdiV5AccessPort, addr: u16) -> u32;
fn ap_write(&self, ap: AdiV5AccessPort, addr: u16, value: u32);
fn mem_read(&self, ap: AdiV5AccessPort, dest: &mut [u8], src: TargetAddr64);
fn mem_write(&self, ap: AdiV5AccessPort, dest: TargetAddr64, src: &[u8], align: Align);
}
pub trait BmdRiscvProtocol
{
fn dmi_read(&self, dmi: RiscvDmi, address: u32) -> Option<u32>;
fn dmi_write(&self, dmi: RiscvDmi, address: u32, value: u32) -> bool;
}
#[allow(unused)]
pub struct JtagDev
{
idcode: u32,
current_ir: u32,
dr_prescan: u8,
dr_postscan: u8,
ir_len: u8,
ir_prescan: u8,
ir_postscan: u8,
}
#[derive(Copy, Clone)]
pub(crate) enum ProtocolVersion
{
Unknown,
V0,
V0Plus,
V1,
V2,
V3,
V4,
}
pub fn decode_response(response: &str, digits: usize) -> u64
{
let digits = if digits > response.len() {
response.len()
} else {
digits
};
let mut value = 0;
for byte in response[..digits].chars() {
value <<= 4;
value |= byte.to_digit(16).unwrap() as u64;
}
value
}
impl ProtocolVersion
{
pub fn protocol_impl(&self, interface: Arc<Mutex<BmdRspInterface>>) -> Result<Box<dyn BmdRemoteProtocol>>
{
match self {
Self::V0 => Ok(Box::new(RemoteV0::from(interface))),
Self::V0Plus => Ok(Box::new(RemoteV0Plus::from(interface))),
Self::V1 => Ok(Box::new(RemoteV1::from(interface))),
Self::V2 => Ok(Box::new(RemoteV2::from(interface))),
Self::V3 => Ok(Box::new(RemoteV3::from(interface))),
Self::V4 => Ok(Box::new(RemoteV4::try_from(interface)?)),
_ => todo!(),
}
}
}
impl Display for ProtocolVersion
{
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
match self {
Self::Unknown => write!(fmt, "<unknown>"),
Self::V0 => write!(fmt, "v0"),
Self::V0Plus => write!(fmt, "v0+"),
Self::V1 => write!(fmt, "v1"),
Self::V2 => write!(fmt, "v2"),
Self::V3 => write!(fmt, "v3"),
Self::V4 => write!(fmt, "v4"),
}
}
}
impl Display for TargetArchitecture
{
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
let mut architectures = Vec::with_capacity(4);
if self.contains(Self::CortexM) {
architectures.push("ARM Cortex-M");
}
if self.contains(Self::CortexAR) {
architectures.push("ARM Cortex-A/R");
}
if self.contains(Self::RiscV32) {
architectures.push("RISC-V 32-bit");
}
if self.contains(Self::RiscV64) {
architectures.push("RISC-V 64-bit");
}
write!(fmt, "{}", architectures.join(", "))
}
}
impl Display for TargetFamily
{
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
let mut families = Vec::with_capacity(64);
if self.contains(Self::AT32) {
families.push("AteryTek AT32");
}
if self.contains(Self::Apollo3) {
families.push("Ambiq Apollo3");
}
if self.contains(Self::CH32) {
families.push("WinChipHead CH32");
}
if self.contains(Self::CH579) {
families.push("WinChipHead CH579");
}
if self.contains(Self::EFM) {
families.push("Energy Micro EFM32/EFR32/EZR32");
}
if self.contains(Self::GD32) {
families.push("GigaDevice GD32");
}
if self.contains(Self::HC32) {
families.push("HDSC HC32");
}
if self.contains(Self::LPC) {
families.push("NXP LPC");
}
if self.contains(Self::MM32) {
families.push("MindMotion MM32");
}
if self.contains(Self::NRF) {
families.push("Nordi Semi nRF");
}
if self.contains(Self::NXPKinetis) {
families.push("NXP/Freescale Kinetis");
}
if self.contains(Self::NXPiMXRT) {
families.push("NXP i.MXRT");
}
if self.contains(Self::Puya) {
families.push("Puya PY32");
}
if self.contains(Self::RenesasRA) {
families.push("Renesas RA");
}
if self.contains(Self::RenesasRZ) {
families.push("Renesas RZ");
}
if self.contains(Self::RP) {
families.push("RPi Foundation RP2040/RP2350");
}
if self.contains(Self::SAM) {
families.push("Atmel/Microchip ATSAM");
}
if self.contains(Self::STM) {
families.push("ST Micro STM32");
}
if self.contains(Self::TI) {
families.push("TI MSP432 and LM3S/TM4C");
}
if self.contains(Self::Xilinx) {
families.push("Xilinx Zynq");
}
write!(fmt, "{}", families.join(", "))
}
}