use std::time::Duration;
use bytemuck::from_bytes;
use crate::raw::{self, Command, device::Error};
use super::Proxmark;
pub const FIRMWARE_VERSION: u8 = 6;
mod features {
#![allow(missing_docs)]
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Features: u32 {
const ViaFpc = 1 << 0;
const ViaUsb = 1 << 1;
const CompiledWithFlash = 1 << 2;
const CompiledWithSmartcard = 1 << 3;
const CompiledWithFpcUsart = 1 << 4;
const CompiledWithFpcUsartDev = 1 << 5;
const CompiledWithFpcUsartHost = 1 << 6;
const CompiledWithLf = 1 << 7;
const CompiledWithHitag = 1 << 8;
const CompiledWithEm4x50 = 1 << 9;
const CompiledWithEm4x70 = 1 << 10;
const CompiledWithZx8211 = 1 << 11;
const CompiledWithHfSniff = 1 << 12;
const CompiledWithHfPlot = 1 << 13;
const CompiledWithIso14443a = 1 << 14;
const CompiledWithIso14443b = 1 << 15;
const CompiledWithIso15693 = 1 << 16;
const CompiledWithFelica = 1 << 17;
const CompiledWithLegicRf = 1 << 18;
const CompiledWithIClass = 1 << 19;
const CompiledWithNfcBarcode = 1 << 20;
const CompiledWithLcd = 1 << 21;
const HwAvailableFlash = 1 << 22;
const HwAvailableSmartcard = 1 << 23;
const IsRdv4 = 1 << 24;
}
}
}
pub use features::Features;
#[derive(Debug, Copy, Clone)]
pub struct Capabilities {
pub version: u8,
pub baudrate: u32,
pub bigbuf_size: u32,
pub features: Features,
}
#[derive(Debug, thiserror::Error)]
pub enum CapabilitiesError {
#[error(
"device sent capabilities with unexpected length (expected: {expected}, got: {got}, device version: {version:?})"
)]
LengthMismatch {
expected: usize,
got: usize,
version: Option<u8>,
},
#[error(
"device reported an unexpected firmware version (expected: {FIRMWARE_VERSION}, got {})", .0.version
)]
VersionMismatch(Capabilities),
#[error(transparent)]
Proxmark(#[from] Error),
}
impl Proxmark {
#[tracing::instrument(skip(self), level = tracing::Level::TRACE)]
pub fn capabilities(&mut self) -> Result<Capabilities, CapabilitiesError> {
self.0
.request(raw::request::ng(Command::CAPABILITIES, []))
.map_err(Error::from)?;
let resp = self
.0
.response_of(Command::CAPABILITIES, Duration::from_secs(1))
.map_err(Error::from)?;
#[repr(C, packed)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct PackedCapabilities {
version: u8,
baudrate: u32,
bigbuf_size: u32,
features: Features,
}
if resp.payload().len() != size_of::<PackedCapabilities>() {
return Err(CapabilitiesError::LengthMismatch {
expected: size_of::<PackedCapabilities>(),
got: resp.payload().len(),
version: resp.payload().first().copied(),
});
}
let packed = from_bytes::<PackedCapabilities>(resp.payload());
let unpacked = Capabilities {
version: packed.version,
baudrate: packed.baudrate,
bigbuf_size: packed.bigbuf_size,
features: packed.features,
};
if unpacked.version != FIRMWARE_VERSION {
return Err(CapabilitiesError::VersionMismatch(unpacked));
}
Ok(unpacked)
}
}