pub mod capabilities;
pub mod iclass;
pub mod iso14443a;
pub mod version;
use std::time::{Duration, Instant};
use tracing::{Level, error, instrument};
use crate::raw::{
self, Command,
common::SZ_DATA,
device::{self, DirtyError},
request,
};
#[cfg(target_os = "linux")]
use crate::raw::device::FindError;
pub use crate::raw::find_path;
pub fn new<'a>(path: impl Into<std::borrow::Cow<'a, str>>) -> Result<Proxmark, DirtyError> {
raw::new(path).map(Proxmark)
}
#[cfg(target_os = "linux")]
pub fn find() -> Result<Proxmark, FindError> {
let ret = new(find_path()?)?;
Ok(ret)
}
#[must_use]
#[derive(Debug)]
pub struct Proxmark(raw::Proxmark);
#[must_use]
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("response was malformed: {0:?}")]
MalformedResponse(Box<raw::Response>),
#[error(transparent)]
Raw(#[from] raw::device::Error),
}
impl Proxmark {
pub unsafe fn from_raw(proxmark: raw::Proxmark) -> Self {
Self(proxmark)
}
pub fn into_raw(self) -> raw::Proxmark {
self.0
}
#[instrument(skip(self), level = Level::TRACE)]
pub fn ping(&mut self) -> Result<Duration, Error> {
#[allow(clippy::cast_possible_truncation)]
let payload: [u8; SZ_DATA] = core::array::from_fn(|i| ((i * 113) % 256) as u8);
let start = Instant::now();
let resp = self
.0
.request_response(request::ng(Command::PING, payload), Duration::from_secs(1))?;
let end = Instant::now();
if resp.payload() == payload {
Ok(end - start)
} else {
Err(Error::MalformedResponse(Box::new(resp)))
}
}
#[instrument(skip(self), level = Level::TRACE)]
pub fn status(&mut self) -> Result<String, Error> {
self.0
.request(request::ng(Command::STATUS, []))
.map_err(Error::from)?;
let ret = self.0.debug_disable(|p| {
let mut acc = String::new();
loop {
let resp = p.response(Duration::from_secs(2)).map_err(Error::from)?;
match resp.cmd() {
Command::STATUS => break Ok(acc),
Command::DEBUG_PRINT_STRINGS => {
let text = String::from_utf8_lossy(&resp.payload()[2..]);
acc.push_str(&text);
acc.push('\n');
}
Command::DOWNLOADED_BIGBUF => {} cmd => {
error!(?cmd, "invalid command for status report");
break Err(Error::MalformedResponse(Box::new(resp)));
}
}
}
})?;
Ok(ret)
}
}
impl From<device::RequestError> for Error {
fn from(value: device::RequestError) -> Self {
Error::Raw(value.into())
}
}
impl From<device::ResponseError> for Error {
fn from(value: device::ResponseError) -> Self {
Error::Raw(value.into())
}
}