cat-dev 0.0.13

A library for interacting with the CAT-DEV hardware units distributed by Nintendo (i.e. a type of Wii-U DevKits).
Documentation
//! SDIO Protocol implementations live here.
//!
//! NOTE: this is not a traditional SDIO protocol that you may be familiar with
//! this is very specific to the nintendo's CAT-DEV environment. It is also
//! split over two TCP ports.
//!
//! The only part that "has a protocol" too is the control port. The data port
//! is literally just transferring files around.

pub mod message;
pub mod read;
pub mod write;

use crate::fsemul::sdio::errors::SdioProtocolError;

/// The size of an SDIO Block we end up serving.
pub const SDIO_BLOCK_SIZE: usize = 0x200_usize;
/// The size of an SDIO Block we end up serving.
pub const SDIO_BLOCK_SIZE_AS_U32: u32 = 0x200_u32;

/// The types of packets that can be received by the SDIO Control Port.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum SdioControlPacketType {
	/// A message that comes through or gets sent out on a particular telnet
	/// channel.
	TelnetMessage,
	/// Instruction to read on the data stream.
	Read,
	/// Instruction to write on the data stream.
	Write,
	/// TODO(mythra): confirm this is what it does.
	///
	/// Seems to be used in older firmwares to tell the server to
	/// 'start' the SDIO block channel.
	StartBlockChannel,
	/// TODO(mythra): confirm this is what it does.
	///
	/// Seems to be used in older firmwares to tell the server to
	/// 'start' the CTRL Character channel.
	StartControlListeningChannel,
}

impl From<SdioControlPacketType> for u16 {
	fn from(value: SdioControlPacketType) -> Self {
		match value {
			SdioControlPacketType::TelnetMessage => 8,
			SdioControlPacketType::Read => 0,
			SdioControlPacketType::Write => 1,
			SdioControlPacketType::StartBlockChannel => 0xA,
			SdioControlPacketType::StartControlListeningChannel => 0xB,
		}
	}
}

impl TryFrom<u16> for SdioControlPacketType {
	type Error = SdioProtocolError;

	fn try_from(value: u16) -> Result<Self, Self::Error> {
		match value {
			0 => Ok(Self::Read),
			1 => Ok(Self::Write),
			8 => Ok(Self::TelnetMessage),
			0xA => Ok(Self::StartBlockChannel),
			0xB => Ok(Self::StartControlListeningChannel),
			_ => Err(SdioProtocolError::UnknownPrintfPacketType(value)),
		}
	}
}

#[cfg(test)]
mod unit_tests {
	use super::*;

	#[test]
	pub fn roundtrip_control_packet_type() {
		for packet_ty in vec![
			SdioControlPacketType::TelnetMessage,
			SdioControlPacketType::Read,
			SdioControlPacketType::Write,
		] {
			assert_eq!(
				Ok(packet_ty),
				SdioControlPacketType::try_from(u16::from(packet_ty)),
				"Round-tripped control packet type was not the same?"
			);
		}
	}
}