use byteorder::{LE, ReadBytesExt};
use num_enum::{FromPrimitive, IntoPrimitive};
use std::{
fmt,
io::{self, Read},
};
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct FirmwareInfo {
pub major: u8,
pub minor: u8,
pub is_main_firmware: bool,
pub max_cmd: u8,
pub sample_freq: u32,
pub hw_model: HwModel,
pub usb_speed: UsbSpeed,
pub mcu_id: Option<McuId>,
pub mcu_mhz: u16,
pub mcu_sram_kb: u16,
pub usb_buf_kb: u16,
}
impl FirmwareInfo {
pub(crate) fn read_from(mut read: impl Read) -> Result<Self, io::Error> {
Ok(Self {
major: read.read_u8()?,
minor: read.read_u8()?,
is_main_firmware: read.read_u8()? != 0,
max_cmd: read.read_u8()?,
sample_freq: read.read_u32::<LE>()?,
hw_model: {
let hw_model = read.read_u8()?;
let hw_submodel = read.read_u8()?;
match hw_model {
1 => HwModel::F1(hw_submodel.into()),
4 => HwModel::V4(hw_submodel.into()),
7 => HwModel::F7(hw_submodel.into()),
8 => HwModel::AdafruitFloppy(hw_submodel.into()),
_ => HwModel::Unknown(hw_model, hw_submodel),
}
},
usb_speed: read.read_u8()?.into(),
mcu_id: Some(read.read_u8()?).filter(|&id| id != 0).map(Into::into),
mcu_mhz: read.read_u16::<LE>()?,
mcu_sram_kb: read.read_u16::<LE>()?,
usb_buf_kb: read.read_u16::<LE>()?,
})
}
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
#[repr(u8)]
pub enum HwModel {
F1(HwSubmodelF1) = 1,
V4(HwSubmodelV4) = 4,
F7(HwSubmodelF7) = 7,
AdafruitFloppy(HwSubmodelAdafruitFloppy) = 8,
Unknown(u8, u8) = 0xFF,
}
impl fmt::Display for HwModel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::F1(submodel) => submodel.fmt(f),
Self::V4(submodel) => submodel.fmt(f),
Self::F7(submodel) => submodel.fmt(f),
Self::AdafruitFloppy(submodel) => submodel.fmt(f),
Self::Unknown(m, s) => write!(f, "unknown model {m}, submodel {s}"),
}
}
}
#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub enum HwSubmodelF1 {
F1 = 0,
F1Plus = 1,
F1PlusUnbuffered = 2,
#[num_enum(catch_all)]
Unknown(u8) = 0xFF,
}
impl fmt::Display for HwSubmodelF1 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::F1 => write!(f, "F1"),
Self::F1Plus => write!(f, "F1 Plus"),
Self::F1PlusUnbuffered => write!(f, "F1 Plus (unbuffered)"),
Self::Unknown(id) => write!(f, "F1, unknown submodel {id}"),
}
}
}
#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub enum HwSubmodelV4 {
V4 = 0,
V4Slim = 1,
V4_1 = 2,
#[num_enum(catch_all)]
Unknown(u8) = 0xFF,
}
impl fmt::Display for HwSubmodelV4 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::V4 => write!(f, "V4"),
Self::V4Slim => write!(f, "V4 Slim"),
Self::V4_1 => write!(f, "V4.1"),
Self::Unknown(id) => write!(f, "V4, unknown submodel {id}"),
}
}
}
#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub enum HwSubmodelF7 {
F7V1 = 0,
F7PlusV1 = 1,
F7Lightning = 2,
F7V2 = 3,
F7PlusV2 = 4,
F7LightningPlus = 5,
F7Slim = 6,
F7V3Thunderbolt = 7,
#[num_enum(catch_all)]
Unknown(u8) = 0xFF,
}
impl fmt::Display for HwSubmodelF7 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::F7V1 => write!(f, "F7 v1"),
Self::F7PlusV1 => write!(f, "F7 Plus (Ant Goffart, v1)"),
Self::F7Lightning => write!(f, "F7 Lightning"),
Self::F7V2 => write!(f, "F7 v2"),
Self::F7PlusV2 => write!(f, "F7 Plus (Ant Goffart, v2)"),
Self::F7LightningPlus => write!(f, "F7 Lightning Plus"),
Self::F7Slim => write!(f, "F7 Slim"),
Self::F7V3Thunderbolt => write!(f, "F7 v3 Thunderbolt"),
Self::Unknown(id) => write!(f, "F7, unknown submodel {id}"),
}
}
}
#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub enum HwSubmodelAdafruitFloppy {
Generic = 0,
#[num_enum(catch_all)]
Unknown(u8) = 0xFF,
}
impl fmt::Display for HwSubmodelAdafruitFloppy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::Generic => write!(f, "Adafruit Floppy Generic"),
Self::Unknown(id) => write!(f, "Adafruit Floppy, unknown submodel {id}"),
}
}
}
#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub enum UsbSpeed {
FullSpeed = 0,
HighSpeed = 1,
#[num_enum(catch_all)]
Unknown(u8) = 0xFF,
}
impl fmt::Display for UsbSpeed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::FullSpeed => write!(f, "full speed (12 Mbit/s)"),
Self::HighSpeed => write!(f, "high speed (480 Mbit/s)"),
Self::Unknown(id) => write!(f, "unknown speed {id}"),
}
}
}
#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub enum McuId {
AT32F403 = 2,
AT32F415 = 5,
AT32F403A = 7,
#[num_enum(catch_all)]
Unknown(u8) = 0xFF,
}
impl fmt::Display for McuId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Self::AT32F403 => write!(f, "AT32F403"),
Self::AT32F415 => write!(f, "AT32F415"),
Self::AT32F403A => write!(f, "AT32F403A"),
Self::Unknown(id) => write!(f, "unknown MCU {id}"),
}
}
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct DriveInfo {
pub is_motor_on: bool,
pub is_flippy: bool,
pub cylinder: Option<i32>,
}
impl DriveInfo {
pub(crate) fn read_from(mut read: impl Read) -> Result<Self, io::Error> {
const FLAG_CYL_VALID: u32 = 0x1;
const FLAG_MOTOR_ON: u32 = 0x2;
const FLAG_FLIPPY: u32 = 0x4;
let flags = read.read_u32::<LE>()?;
Ok(Self {
is_motor_on: flags & FLAG_MOTOR_ON != 0,
is_flippy: flags & FLAG_FLIPPY != 0,
cylinder: Some(read.read_i32::<LE>()?).filter(|_| flags & FLAG_CYL_VALID != 0),
})
}
}
#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub enum BusType {
None = 0,
IbmPc = 1,
Shugart = 2,
#[num_enum(catch_all)]
Other(u8),
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct Delays {
pub select_us: u16,
pub step_us: u16,
pub seek_settle_ms: u16,
pub motor_ms: u16,
pub watchdog_ms: u16,
pub pre_write_us: Option<u16>,
pub post_write_us: Option<u16>,
pub index_mask_us: Option<u16>,
}
#[derive(Debug, IntoPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub(crate) enum GetInfo {
Firmware = 0,
BandwidthStats = 1,
CurrentDrive = 7,
Drive = 8,
}
#[derive(Debug, IntoPrimitive)]
#[non_exhaustive]
#[repr(u8)]
pub(crate) enum Param {
Delays = 0,
}