use crate::mion::proto::cgis::MionCGIErrors;
#[cfg(feature = "clients")]
use mac_address::MacAddress;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::net::Ipv4Addr;
#[allow(
// Clippy this is not a state machine, >:(
clippy::struct_excessive_bools,
)]
#[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
#[cfg(feature = "clients")]
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct SetupParameters {
static_ip_address: Ipv4Addr,
subnet_mask: Ipv4Addr,
default_gateway: Ipv4Addr,
dhcp: bool,
dns: bool,
primary_dns_server: Ipv4Addr,
secondary_dns_server: Ipv4Addr,
jumbo_frame: bool,
host_pc_ip: Ipv4Addr,
bank_size: CatDevBankSize,
hdd_bank_no: u8,
atapi_emulator_port: u16,
sdio_printf_port: u16,
sdio_block_port: u16,
exi_port: u16,
parameter_space_port: u16,
drive_timing_emulation: bool,
operational_mode_is_reader: bool,
drive_product_revision: String,
drive_vendor_code: String,
drive_device_code: String,
drive_release_date: String,
device_name: String,
mac_address: MacAddress,
}
#[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
#[cfg(feature = "clients")]
impl SetupParameters {
#[allow(
// This is how many fields we have clippy.
clippy::too_many_arguments,
// This isn't a state machine, or anything.
clippy::fn_params_excessive_bools,
)]
#[must_use]
pub const fn new(
static_ip_address: Ipv4Addr,
subnet_mask: Ipv4Addr,
default_gateway: Ipv4Addr,
dhcp: bool,
dns: bool,
primary_dns_server: Ipv4Addr,
secondary_dns_server: Ipv4Addr,
jumbo_frame: bool,
host_pc_ip: Ipv4Addr,
bank_size: CatDevBankSize,
hdd_bank_no: u8,
atapi_emulator_port: u16,
sdio_printf_port: u16,
sdio_block_port: u16,
exi_port: u16,
parameter_space_port: u16,
drive_timing_emulation: bool,
operational_mode_is_reader: bool,
drive_product_revision: String,
drive_vendor_code: String,
drive_device_code: String,
drive_release_date: String,
device_name: String,
mac_address: MacAddress,
) -> Self {
Self {
static_ip_address,
subnet_mask,
default_gateway,
dhcp,
dns,
primary_dns_server,
secondary_dns_server,
jumbo_frame,
host_pc_ip,
bank_size,
hdd_bank_no,
atapi_emulator_port,
sdio_printf_port,
sdio_block_port,
exi_port,
parameter_space_port,
drive_timing_emulation,
operational_mode_is_reader,
drive_product_revision,
drive_vendor_code,
drive_device_code,
drive_release_date,
device_name,
mac_address,
}
}
#[must_use]
pub fn default_settings(device_name: String, mac_address: MacAddress) -> Self {
Self {
static_ip_address: Ipv4Addr::new(192, 168, 0, 1),
subnet_mask: Ipv4Addr::new(255, 255, 255, 0),
default_gateway: Ipv4Addr::UNSPECIFIED,
dhcp: true,
dns: false,
primary_dns_server: Ipv4Addr::UNSPECIFIED,
secondary_dns_server: Ipv4Addr::UNSPECIFIED,
jumbo_frame: true,
host_pc_ip: Ipv4Addr::UNSPECIFIED,
bank_size: CatDevBankSize::Blank,
hdd_bank_no: 0,
atapi_emulator_port: 7974,
sdio_printf_port: 7975,
sdio_block_port: 7976,
exi_port: 7977,
parameter_space_port: 7978,
drive_timing_emulation: false,
operational_mode_is_reader: false,
drive_product_revision: String::with_capacity(0),
drive_vendor_code: String::with_capacity(0),
drive_device_code: String::with_capacity(0),
drive_release_date: String::with_capacity(0),
device_name,
mac_address,
}
}
#[must_use]
pub const fn static_ip_address(&self) -> Option<Ipv4Addr> {
if self.dhcp {
None
} else {
Some(self.static_ip_address)
}
}
#[must_use]
pub const fn raw_static_ip_address(&self) -> Ipv4Addr {
self.static_ip_address
}
#[must_use]
pub const fn subnet_mask(&self) -> Ipv4Addr {
self.subnet_mask
}
#[must_use]
pub const fn default_gateway(&self) -> Ipv4Addr {
self.default_gateway
}
#[must_use]
pub const fn using_dhcp(&self) -> bool {
self.dhcp
}
#[must_use]
pub const fn using_self_managed_dns(&self) -> bool {
self.dns
}
#[must_use]
pub const fn primary_dns(&self) -> Option<Ipv4Addr> {
if self.dns {
Some(self.primary_dns_server)
} else {
None
}
}
#[must_use]
pub const fn raw_primary_dns(&self) -> Ipv4Addr {
self.primary_dns_server
}
#[must_use]
pub const fn secondary_dns(&self) -> Option<Ipv4Addr> {
if self.dns {
Some(self.secondary_dns_server)
} else {
None
}
}
#[must_use]
pub const fn raw_secondary_dns(&self) -> Ipv4Addr {
self.secondary_dns_server
}
#[must_use]
pub const fn jumbo_frame(&self) -> bool {
self.jumbo_frame
}
#[must_use]
pub const fn host_pc_ip_address(&self) -> Ipv4Addr {
self.host_pc_ip
}
#[must_use]
pub const fn hdd_bank_size(&self) -> CatDevBankSize {
self.bank_size
}
#[must_use]
pub const fn hdd_bank_no(&self) -> u8 {
self.hdd_bank_no
}
#[must_use]
pub const fn atapi_emulator_port(&self) -> u16 {
self.atapi_emulator_port
}
#[must_use]
pub const fn sdio_printf_port(&self) -> u16 {
self.sdio_printf_port
}
#[must_use]
pub const fn sdio_block_port(&self) -> u16 {
self.sdio_block_port
}
#[must_use]
pub const fn exi_port(&self) -> u16 {
self.exi_port
}
#[must_use]
pub const fn parameter_space_port(&self) -> u16 {
self.parameter_space_port
}
#[must_use]
pub const fn drive_timing_emulation_enabled(&self) -> bool {
self.drive_timing_emulation
}
#[must_use]
pub const fn is_cat_dev_mode(&self) -> bool {
!self.operational_mode_is_reader
}
#[must_use]
pub const fn is_h_reader_mode(&self) -> bool {
self.operational_mode_is_reader
}
#[must_use]
pub const fn drive_product_revision(&self) -> &String {
&self.drive_product_revision
}
#[must_use]
pub const fn drive_vendor_code(&self) -> &String {
&self.drive_vendor_code
}
#[must_use]
pub const fn drive_device_code(&self) -> &String {
&self.drive_device_code
}
#[must_use]
pub const fn drive_release_date(&self) -> &String {
&self.drive_release_date
}
#[must_use]
pub const fn device_name(&self) -> &String {
&self.device_name
}
#[must_use]
pub const fn mac_address(&self) -> MacAddress {
self.mac_address
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum CatDevBankSize {
Blank,
TwentyFiveGbs,
FiveGbs,
NineGbs,
TwelveGbs,
FourteenGbs,
SixteenGbs,
EighteenGbs,
TwentyOneGbs,
}
impl From<&CatDevBankSize> for u32 {
fn from(size: &CatDevBankSize) -> u32 {
match *size {
CatDevBankSize::Blank => 4_294_967_295,
CatDevBankSize::TwentyFiveGbs => 0,
CatDevBankSize::FiveGbs => 1,
CatDevBankSize::NineGbs => 2,
CatDevBankSize::TwelveGbs => 3,
CatDevBankSize::FourteenGbs => 4,
CatDevBankSize::SixteenGbs => 5,
CatDevBankSize::EighteenGbs => 6,
CatDevBankSize::TwentyOneGbs => 7,
}
}
}
impl From<CatDevBankSize> for u32 {
fn from(value: CatDevBankSize) -> Self {
Self::from(&value)
}
}
impl TryFrom<u32> for CatDevBankSize {
type Error = MionCGIErrors;
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
u32::MAX => Ok(Self::Blank),
0 => Ok(Self::TwentyFiveGbs),
1 => Ok(Self::FiveGbs),
2 => Ok(Self::NineGbs),
3 => Ok(Self::TwelveGbs),
4 => Ok(Self::FourteenGbs),
5 => Ok(Self::SixteenGbs),
6 => Ok(Self::EighteenGbs),
7 => Ok(Self::TwentyOneGbs),
_ => Err(MionCGIErrors::UnknownCatDevBankSizeId(value)),
}
}
}
impl Display for CatDevBankSize {
fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
write!(
fmt,
"{}",
match *self {
Self::Blank => " ",
Self::TwentyFiveGbs => "25GB",
Self::FiveGbs => "5GB",
Self::NineGbs => "9GB",
Self::TwelveGbs => "12GB",
Self::FourteenGbs => "14GB",
Self::SixteenGbs => "16GB",
Self::EighteenGbs => "18GB",
Self::TwentyOneGbs => "21GB",
}
)
}
}
#[cfg(test)]
mod unit_tests {
use super::*;
#[test]
pub fn convert_bank_size() {
for bank_size in vec![
CatDevBankSize::Blank,
CatDevBankSize::TwentyFiveGbs,
CatDevBankSize::FiveGbs,
CatDevBankSize::NineGbs,
CatDevBankSize::TwelveGbs,
CatDevBankSize::FourteenGbs,
CatDevBankSize::SixteenGbs,
CatDevBankSize::EighteenGbs,
CatDevBankSize::TwentyOneGbs,
] {
assert_eq!(
Ok(bank_size),
CatDevBankSize::try_from(u32::from(bank_size)),
"bank size: {} was not the same after converting it back & forth",
bank_size,
);
}
}
}