use crate::types::{DeviceClassId, SubClassId, ProgInterfaceId};
use alloc::string::ToString;
#[derive(Debug, Clone)]
pub struct ProgInterface {
pub id: ProgInterfaceId,
pub name: &'static str,
}
impl ProgInterface {
#[inline]
pub const fn new(id: ProgInterfaceId, name: &'static str) -> Self {
Self { id, name }
}
#[inline]
pub const fn id(&self) -> ProgInterfaceId {
self.id
}
#[inline]
pub const fn name(&self) -> &'static str {
self.name
}
}
impl PartialEq for ProgInterface {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for ProgInterface {}
impl PartialOrd for ProgInterface {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ProgInterface {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.id.cmp(&other.id)
}
}
#[derive(Debug, Clone)]
pub struct SubClass {
pub id: SubClassId,
pub name: &'static str,
pub prog_interfaces: &'static [ProgInterface],
}
impl SubClass {
#[inline]
pub const fn new(id: SubClassId, name: &'static str, prog_interfaces: &'static [ProgInterface]) -> Self {
Self {
id,
name,
prog_interfaces,
}
}
#[inline]
pub const fn id(&self) -> SubClassId {
self.id
}
#[inline]
pub const fn name(&self) -> &'static str {
self.name
}
#[inline]
pub const fn prog_interfaces(&self) -> &'static [ProgInterface] {
self.prog_interfaces
}
pub fn find_prog_interface(&self, prog_interface_id: ProgInterfaceId) -> Option<&ProgInterface> {
self.prog_interfaces
.iter()
.find(|prog_if| prog_if.id == prog_interface_id)
}
#[inline]
pub const fn prog_interface_count(&self) -> usize {
self.prog_interfaces.len()
}
pub fn has_prog_interface(&self, prog_interface_id: ProgInterfaceId) -> bool {
self.find_prog_interface(prog_interface_id).is_some()
}
pub fn iter_prog_interfaces(&self) -> core::slice::Iter<'_, ProgInterface> {
self.prog_interfaces.iter()
}
}
impl PartialEq for SubClass {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for SubClass {}
impl PartialOrd for SubClass {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for SubClass {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.id.cmp(&other.id)
}
}
#[derive(Debug, Clone)]
pub struct DeviceClass {
pub id: DeviceClassId,
pub name: &'static str,
pub subclasses: &'static [SubClass],
}
impl DeviceClass {
#[inline]
pub const fn new(id: DeviceClassId, name: &'static str, subclasses: &'static [SubClass]) -> Self {
Self {
id,
name,
subclasses,
}
}
#[inline]
pub const fn id(&self) -> DeviceClassId {
self.id
}
#[inline]
pub const fn name(&self) -> &'static str {
self.name
}
#[inline]
pub const fn subclasses(&self) -> &'static [SubClass] {
self.subclasses
}
pub fn find_subclass(&self, subclass_id: SubClassId) -> Option<&SubClass> {
self.subclasses.iter().find(|subclass| subclass.id == subclass_id)
}
pub fn find_prog_interface(&self, subclass_id: SubClassId, prog_interface_id: ProgInterfaceId) -> Option<&ProgInterface> {
self.find_subclass(subclass_id)?
.find_prog_interface(prog_interface_id)
}
#[inline]
pub const fn subclass_count(&self) -> usize {
self.subclasses.len()
}
pub fn has_subclass(&self, subclass_id: SubClassId) -> bool {
self.find_subclass(subclass_id).is_some()
}
pub fn iter_subclasses(&self) -> core::slice::Iter<'_, SubClass> {
self.subclasses.iter()
}
pub fn describe_device(&self, subclass_id: Option<SubClassId>, prog_interface_id: Option<ProgInterfaceId>) -> alloc::string::String {
use alloc::format;
match (subclass_id, prog_interface_id) {
(Some(sc_id), Some(pi_id)) => {
if let Some(subclass) = self.find_subclass(sc_id) {
if let Some(prog_if) = subclass.find_prog_interface(pi_id) {
format!("{} - {} - {}", self.name, subclass.name, prog_if.name)
} else {
format!("{} - {} - Unknown Programming Interface ({:02x})", self.name, subclass.name, pi_id.value())
}
} else {
format!("{} - Unknown Subclass ({:02x})", self.name, sc_id.value())
}
}
(Some(sc_id), None) => {
if let Some(subclass) = self.find_subclass(sc_id) {
format!("{} - {}", self.name, subclass.name)
} else {
format!("{} - Unknown Subclass ({:02x})", self.name, sc_id.value())
}
}
(None, _) => self.name.to_string(),
}
}
}
impl PartialEq for DeviceClass {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for DeviceClass {}
impl PartialOrd for DeviceClass {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for DeviceClass {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.id.cmp(&other.id)
}
}
pub mod well_known {
use super::DeviceClassId;
pub const UNCLASSIFIED: DeviceClassId = DeviceClassId::new(0x00);
pub const MASS_STORAGE: DeviceClassId = DeviceClassId::new(0x01);
pub const NETWORK: DeviceClassId = DeviceClassId::new(0x02);
pub const DISPLAY: DeviceClassId = DeviceClassId::new(0x03);
pub const MULTIMEDIA: DeviceClassId = DeviceClassId::new(0x04);
pub const MEMORY: DeviceClassId = DeviceClassId::new(0x05);
pub const BRIDGE: DeviceClassId = DeviceClassId::new(0x06);
pub const COMMUNICATION: DeviceClassId = DeviceClassId::new(0x07);
pub const SYSTEM_PERIPHERAL: DeviceClassId = DeviceClassId::new(0x08);
pub const INPUT_DEVICE: DeviceClassId = DeviceClassId::new(0x09);
pub const DOCKING_STATION: DeviceClassId = DeviceClassId::new(0x0a);
pub const PROCESSOR: DeviceClassId = DeviceClassId::new(0x0b);
pub const SERIAL_BUS: DeviceClassId = DeviceClassId::new(0x0c);
pub const WIRELESS: DeviceClassId = DeviceClassId::new(0x0d);
pub const INTELLIGENT: DeviceClassId = DeviceClassId::new(0x0e);
pub const SATELLITE: DeviceClassId = DeviceClassId::new(0x0f);
pub const ENCRYPTION: DeviceClassId = DeviceClassId::new(0x10);
pub const SIGNAL_PROCESSING: DeviceClassId = DeviceClassId::new(0x11);
pub const PROCESSING_ACCELERATOR: DeviceClassId = DeviceClassId::new(0x12);
pub const NON_ESSENTIAL_INSTRUMENTATION: DeviceClassId = DeviceClassId::new(0x13);
pub const COPROCESSOR: DeviceClassId = DeviceClassId::new(0x40);
pub const UNASSIGNED: DeviceClassId = DeviceClassId::new(0xff);
}