initial commit: beginnings of descriptor definition
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+219
@@ -0,0 +1,219 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder-embedded-io"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed6bb9472871706c9b1f648ca527031e33d647a95706d6ab5659f22ca28d419"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"embedded-io",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"defmt-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt-macros"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e"
|
||||||
|
dependencies = [
|
||||||
|
"defmt-parser",
|
||||||
|
"proc-macro-error2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "defmt-parser"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-io"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9eb1aa714776b75c7e67e1da744b81a129b3ff919c8712b5e1b32252c1f07cc7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hash32"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heapless"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||||
|
dependencies = [
|
||||||
|
"hash32",
|
||||||
|
"stable_deref_trait",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "modular-bitfield"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2956e537fc68236d2aa048f55704f231cc93f1c4de42fe1ecb5bd7938061fc4a"
|
||||||
|
dependencies = [
|
||||||
|
"modular-bitfield-impl",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "modular-bitfield-impl"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59b43b4fd69e3437618106f7754f34021b831a514f9e1a98ae863cabcd8d8dad"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "1.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr2"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error2"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stable_deref_trait"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.117"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "usb-device"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6"
|
||||||
|
dependencies = [
|
||||||
|
"heapless",
|
||||||
|
"portable-atomic",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "usbd-uac2"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder-embedded-io",
|
||||||
|
"defmt",
|
||||||
|
"embedded-io",
|
||||||
|
"modular-bitfield",
|
||||||
|
"usb-device",
|
||||||
|
]
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "usbd-uac2"
|
||||||
|
description = "USB Audio Class 2.0 for usb-device"
|
||||||
|
authors = ["Keenan Tims <ktims@gotroot.ca>"]
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
keywords = ["no-std", "usb-device"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
defmt = ["dep:defmt"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
byteorder-embedded-io = { version = "0.1.1", features = ["embedded-io"] }
|
||||||
|
defmt = { version = "1.0.1", optional = true }
|
||||||
|
embedded-io = "0.7.1"
|
||||||
|
modular-bitfield = "0.13.1"
|
||||||
|
usb-device = "0.3"
|
||||||
@@ -0,0 +1,490 @@
|
|||||||
|
pub const AUDIO: u8 = 0x1;
|
||||||
|
pub const HEADER: u8 = 0x1;
|
||||||
|
|
||||||
|
/// A.2 Audio Function Subclass Codes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum FunctionSubclass {
|
||||||
|
Undefined = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.3 Audio Function Protocol Codes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum FunctionProtocol {
|
||||||
|
Undefined = 0,
|
||||||
|
Version2 = 0x20,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.5 Audio Interface Subclass Codes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum InterfaceSubclass {
|
||||||
|
Undefined = 0,
|
||||||
|
AudioControl = 1,
|
||||||
|
AudioStreaming = 2,
|
||||||
|
MidiStreaming = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.6 Audio Interface Protocol Codes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum InterfaceProtocol {
|
||||||
|
Undefined = 0,
|
||||||
|
Version2 = 0x20,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.7 Audio Function Category Codes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum FunctionCode {
|
||||||
|
Undefined = 0,
|
||||||
|
DesktopSpeaker = 1,
|
||||||
|
HomeTheater = 2,
|
||||||
|
Microphone = 3,
|
||||||
|
Headset = 4,
|
||||||
|
Telephone = 5,
|
||||||
|
Converter = 6,
|
||||||
|
SoundRecorder = 7,
|
||||||
|
IoBox = 8,
|
||||||
|
MusicalInstrument = 9,
|
||||||
|
ProAudio = 0xa,
|
||||||
|
AudioVideo = 0xb,
|
||||||
|
ControlPanel = 0xc,
|
||||||
|
Other = 0xff,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.8 Audio Class-Specific Descriptor Types
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ClassSpecificDescriptorType {
|
||||||
|
Undefined = 0x20,
|
||||||
|
Device = 0x21,
|
||||||
|
Configuration = 0x22,
|
||||||
|
String = 0x23,
|
||||||
|
Interface = 0x24,
|
||||||
|
Endpoint = 0x25,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.9 Audio Class-Specific AC Interface Descriptor Subtypes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ClassSpecificACInterfaceDescriptorSubtype {
|
||||||
|
Undefined = 0,
|
||||||
|
Header = 0x01,
|
||||||
|
InputTerminal = 0x02,
|
||||||
|
OutputTerminal = 0x03,
|
||||||
|
MixerUnit = 0x04,
|
||||||
|
SelectorUnit = 0x05,
|
||||||
|
FeatureUnit = 0x06,
|
||||||
|
EffectUnit = 0x07,
|
||||||
|
ProcessingUnit = 0x08,
|
||||||
|
ExtensionUnit = 0x09,
|
||||||
|
ClockSource = 0x0A,
|
||||||
|
ClockSelector = 0x0B,
|
||||||
|
ClockMultiplier = 0x0C,
|
||||||
|
SampleRateConverter = 0x0D,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.10 Audio Class-Specific AS Interface Descriptor Subtypes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ClassSpecificASInterfaceDescriptorSubtype {
|
||||||
|
Undefined = 0,
|
||||||
|
General = 1,
|
||||||
|
FormatType = 2,
|
||||||
|
Encoder = 3,
|
||||||
|
Decoder = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.11 Effect Unit Effect Types
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum EffectUnitEffectType {
|
||||||
|
Undefined = 0,
|
||||||
|
ParamEqSection = 1,
|
||||||
|
Reverb = 2,
|
||||||
|
ModDelay = 3,
|
||||||
|
DynRangeComp = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.12 Processing Unit Process Types
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ProcessingUnitProcessType {
|
||||||
|
Undefined = 0,
|
||||||
|
UpDownMix = 1,
|
||||||
|
DolbyPrologic = 2,
|
||||||
|
StereoExtender = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.13 Audio Class-Specific Endpoint Descriptor Subtypes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ClassSpecificEndpointDescriptorSubtype {
|
||||||
|
Undefined = 0,
|
||||||
|
General = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.14 Audio Class-Specific Request Codes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ClassSpecificRequest {
|
||||||
|
Undefined = 0,
|
||||||
|
Cur = 1,
|
||||||
|
Range = 2,
|
||||||
|
Mem = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.15 Encoder Type Codes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum EncoderType {
|
||||||
|
Undefined = 0,
|
||||||
|
Other = 1,
|
||||||
|
Mpeg = 2,
|
||||||
|
Ac3 = 3,
|
||||||
|
Wma = 4,
|
||||||
|
Dts = 5,
|
||||||
|
}
|
||||||
|
/// A.16 Decoder Type Codes
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum DecoderType {
|
||||||
|
Undefined = 0,
|
||||||
|
Other = 1,
|
||||||
|
Mpeg = 2,
|
||||||
|
Ac3 = 3,
|
||||||
|
Wma = 4,
|
||||||
|
Dts = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.1 Clock Source Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ClockSourceControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
SamFreqControl = 1,
|
||||||
|
ClockValidControl = 2,
|
||||||
|
}
|
||||||
|
/// A.17.2 Clock Selector Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ClockSelectorControlSelector {
|
||||||
|
ControlUndefined = 0,
|
||||||
|
ClockSelectorControl = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.3 Clock Multiplier Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ClockMultiplierControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
NumeratorControl = 1,
|
||||||
|
DenominatorControl = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.4 Terminal Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TerminalControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
CopyProtect = 1,
|
||||||
|
Connector = 2,
|
||||||
|
Overload = 3,
|
||||||
|
Cluster = 4,
|
||||||
|
Underflow = 5,
|
||||||
|
Overflow = 6,
|
||||||
|
Latency = 7,
|
||||||
|
PhantomPower = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.5 Mixer Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum MixerControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Mixer = 1,
|
||||||
|
Cluster = 2,
|
||||||
|
Underflow = 3,
|
||||||
|
Overflow = 4,
|
||||||
|
Latency = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.6 Selector Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum SelectorControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Selector = 1,
|
||||||
|
Latency = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.7 Feature Unit Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum FeatureUnitControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Mute = 0x01,
|
||||||
|
Volume = 0x02,
|
||||||
|
Bass = 0x03,
|
||||||
|
Mid = 0x04,
|
||||||
|
Treble = 0x05,
|
||||||
|
GraphicEqualizer = 0x06,
|
||||||
|
AutomaticGain = 0x07,
|
||||||
|
Delay = 0x08,
|
||||||
|
BassBoost = 0x09,
|
||||||
|
Loudness = 0x0A,
|
||||||
|
InputGain = 0x0B,
|
||||||
|
InputGainPad = 0x0C,
|
||||||
|
PhaseInverter = 0x0D,
|
||||||
|
Underflow = 0x0E,
|
||||||
|
Overflow = 0x0F,
|
||||||
|
Latency = 0x10,
|
||||||
|
HighpassFilter = 0x11,
|
||||||
|
}
|
||||||
|
/// A.17.8.1 Parametric Equalizer Section Effect Unit Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ParametricEqSectionEffectUnitControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Enable = 1,
|
||||||
|
CenterFreq = 2,
|
||||||
|
QFactor = 3,
|
||||||
|
Gain = 4,
|
||||||
|
Underflow = 5,
|
||||||
|
Overflow = 6,
|
||||||
|
Latency = 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.8.2 Reverberation Effect Unit Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ReverbEffectUnitControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Enable = 1,
|
||||||
|
Type = 2,
|
||||||
|
Level = 3,
|
||||||
|
Time = 4,
|
||||||
|
Feedback = 5,
|
||||||
|
PreDelay = 6,
|
||||||
|
Density = 7,
|
||||||
|
HiFreqRolloff = 8,
|
||||||
|
Underflow = 9,
|
||||||
|
Overflow = 0xa,
|
||||||
|
Latency = 0xb,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.8.3 Modulation Delay Effect Unit Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ModDelayEffectUnitControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Enable = 1,
|
||||||
|
Balance = 2,
|
||||||
|
Rate = 3,
|
||||||
|
Depth = 4,
|
||||||
|
Time = 5,
|
||||||
|
Feedback = 6,
|
||||||
|
Underflow = 7,
|
||||||
|
Overflow = 8,
|
||||||
|
Latency = 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.8.4 Dynamic Range Compressor Effect Unit Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum DynamicRangeCompressorEffectUnitControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Enable = 1,
|
||||||
|
CompressionRate = 2,
|
||||||
|
MaxAmplitude = 3,
|
||||||
|
Threshold = 4,
|
||||||
|
AttackTime = 5,
|
||||||
|
ReleaseTime = 6,
|
||||||
|
Underflow = 7,
|
||||||
|
Overflow = 8,
|
||||||
|
Latency = 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.9.1 Up/Down-mix Processing Unit Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum UpDownMixProcessingUnitControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Enable = 1,
|
||||||
|
ModeSelect = 2,
|
||||||
|
Cluster = 3,
|
||||||
|
Underflow = 4,
|
||||||
|
Overflow = 5,
|
||||||
|
Latency = 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.9.2 Dolby Prologic Processing Unit Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum DolbyProcessingUnitControlSelectors {
|
||||||
|
Undefined = 0,
|
||||||
|
Enable = 1,
|
||||||
|
ModeSelect = 2,
|
||||||
|
Cluster = 3,
|
||||||
|
Underflow = 4,
|
||||||
|
Overflow = 5,
|
||||||
|
Latency = 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.9.3 Stereo Extender Processing Unit Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum StereoExtenderProcessingUnitControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Enable = 1,
|
||||||
|
Width = 2,
|
||||||
|
Underflow = 3,
|
||||||
|
Overflow = 4,
|
||||||
|
Latency = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.10 Extension Unit Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ExtensionUnitControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Enable = 1,
|
||||||
|
Cluster = 2,
|
||||||
|
Underflow = 3,
|
||||||
|
Overflow = 4,
|
||||||
|
Latency = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.11 AudioStreaming Interface Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum AudioStreamingInterfaceControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
ActAltSetting = 1,
|
||||||
|
ValAltSetting = 2,
|
||||||
|
AudioDataFormat = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.12 Encoder Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum EncoderControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
BitRate = 0x01,
|
||||||
|
Quality = 0x02,
|
||||||
|
Vbr = 0x03,
|
||||||
|
Type = 0x04,
|
||||||
|
Underflow = 0x05,
|
||||||
|
Overflow = 0x06,
|
||||||
|
EncoderError = 0x07,
|
||||||
|
Param1 = 0x08,
|
||||||
|
Param2 = 0x09,
|
||||||
|
Param3 = 0x0A,
|
||||||
|
Param4 = 0x0B,
|
||||||
|
Param5 = 0x0C,
|
||||||
|
Param6 = 0x0D,
|
||||||
|
Param7 = 0x0E,
|
||||||
|
Param8 = 0x0F,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.13.1 MPEG Decoder Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum MpegDecoderControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
DualChannel = 1,
|
||||||
|
SecondStereo = 2,
|
||||||
|
Multilingual = 3,
|
||||||
|
DynRange = 4,
|
||||||
|
Scaling = 5,
|
||||||
|
HiloScaling = 6,
|
||||||
|
Underflow = 7,
|
||||||
|
Overflow = 8,
|
||||||
|
DecoderError = 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.13.2 AC-3 Decoder Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Ac3DecoderControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Mode = 1,
|
||||||
|
DynRange = 2,
|
||||||
|
Scaling = 3,
|
||||||
|
HiloScaling = 4,
|
||||||
|
Underflow = 5,
|
||||||
|
Overflow = 6,
|
||||||
|
DecoderError = 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.13.3 WMA Decoder Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum WmaDecoderControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Underflow = 1,
|
||||||
|
Overflow = 2,
|
||||||
|
DecoderError = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.13.4 DTS Decoder Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum DtsDecoderControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Underflow = 1,
|
||||||
|
Overflow = 2,
|
||||||
|
DecoderError = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A.17.14 Endpoint Control Selectors
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum EndpointControlSelector {
|
||||||
|
Undefined = 0,
|
||||||
|
Pitch = 1,
|
||||||
|
DataOverrun = 2,
|
||||||
|
DataUnderrun = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Universal Serial Bus Device Class Definition for Terminal Types
|
||||||
|
#[repr(u16)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TerminalType {
|
||||||
|
// USB Terminal Types
|
||||||
|
UsbUndefined = 0x0100,
|
||||||
|
UsbStreaming = 0x0101,
|
||||||
|
UsbVendor = 0x01ff,
|
||||||
|
|
||||||
|
// Input Terminal Types
|
||||||
|
InUndefined = 0x0200,
|
||||||
|
InMicrophone = 0x0201,
|
||||||
|
InDesktopMicrophone = 0x0202,
|
||||||
|
InPersonalMicrophone = 0x0203,
|
||||||
|
InOmniDirectionalMicrophone = 0x0204,
|
||||||
|
InMicrophoneArray = 0x0205,
|
||||||
|
InProcessingMicrophoneArray = 0x0206,
|
||||||
|
|
||||||
|
// Output Terminal Types
|
||||||
|
OutUndefined = 0x0300,
|
||||||
|
OutSpeaker = 0x0301,
|
||||||
|
OutHeadphones = 0x0302,
|
||||||
|
OutHeadMountedDisplayAudio = 0x0303,
|
||||||
|
OutDesktopSpeaker = 0x0304,
|
||||||
|
OutRoomSpeaker = 0x0305,
|
||||||
|
OutCommunicationSpeaker = 0x0306,
|
||||||
|
OutLowFrequencyEffectsSpeaker = 0x0307,
|
||||||
|
|
||||||
|
// External Terminal Types
|
||||||
|
ExtUndefined = 0x0600,
|
||||||
|
ExtAnalogConnector = 0x0601,
|
||||||
|
ExtDigitalAudioInterface = 0x0602,
|
||||||
|
ExtLineConnector = 0x0603,
|
||||||
|
ExtLegacyAudioConnector = 0x0604,
|
||||||
|
ExtSpdifConnector = 0x0605,
|
||||||
|
Ext1394DaStream = 0x0606,
|
||||||
|
Ext1394DvStreamSoundtrack = 0x0607,
|
||||||
|
}
|
||||||
+169
@@ -0,0 +1,169 @@
|
|||||||
|
// Copy most of embedded_io_cursor here to avoid multiple embedded-io versions in dep tree
|
||||||
|
|
||||||
|
use core::cmp;
|
||||||
|
use embedded_io::{BufRead, Error, ErrorKind, ErrorType, Read, Seek, SeekFrom, Write};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Eq, PartialEq)]
|
||||||
|
pub struct Cursor<T> {
|
||||||
|
inner: T,
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Cursor<T> {
|
||||||
|
/// Creates a new cursor wrapping the provided underlying in-memory buffer.
|
||||||
|
///
|
||||||
|
/// Cursor initial position is `0` even if underlying buffer (e.g., `Vec`)
|
||||||
|
/// is not empty. So writing to cursor starts with overwriting `Vec`
|
||||||
|
/// content, not with appending to it.
|
||||||
|
pub const fn new(inner: T) -> Cursor<T> {
|
||||||
|
Cursor { pos: 0, inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes this cursor, returning the underlying value.
|
||||||
|
pub fn into_inner(self) -> T {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a reference to the underlying value in this cursor.
|
||||||
|
pub const fn get_ref(&self) -> &T {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a mutable reference to the underlying value in this cursor.
|
||||||
|
///
|
||||||
|
/// Care should be taken to avoid modifying the internal I/O state of the
|
||||||
|
/// underlying value as it may corrupt this cursor's position.
|
||||||
|
pub fn get_mut(&mut self) -> &mut T {
|
||||||
|
&mut self.inner
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current position of this cursor.
|
||||||
|
pub const fn position(&self) -> usize {
|
||||||
|
self.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the position of this cursor.
|
||||||
|
pub fn set_position(&mut self, pos: usize) {
|
||||||
|
self.pos = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Cursor<T>
|
||||||
|
where
|
||||||
|
T: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
/// Returns the remaining slice from the current position.
|
||||||
|
///
|
||||||
|
/// This method returns the portion of the underlying buffer that
|
||||||
|
/// can still be read from the current cursor position.
|
||||||
|
pub fn remaining_slice(&self) -> &[u8] {
|
||||||
|
let pos = cmp::min(self.pos, self.inner.as_ref().len());
|
||||||
|
&self.inner.as_ref()[pos..]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if there are no more bytes to read from the cursor.
|
||||||
|
///
|
||||||
|
/// This is equivalent to checking if `remaining_slice().is_empty()`.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.pos >= self.inner.as_ref().len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for Cursor<T>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Cursor {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
pos: self.pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clone_from(&mut self, other: &Self) {
|
||||||
|
self.inner.clone_from(&other.inner);
|
||||||
|
self.pos = other.pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ErrorType for Cursor<T> {
|
||||||
|
type Error = ErrorKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read implementation for AsRef<[u8]> types
|
||||||
|
impl<T> Read for Cursor<T>
|
||||||
|
where
|
||||||
|
T: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
let remaining = self.remaining_slice();
|
||||||
|
let n = cmp::min(buf.len(), remaining.len());
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
buf[..n].copy_from_slice(&remaining[..n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.pos += n;
|
||||||
|
Ok(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BufRead implementation for AsRef<[u8]> types
|
||||||
|
impl<T> BufRead for Cursor<T>
|
||||||
|
where
|
||||||
|
T: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
||||||
|
Ok(self.remaining_slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consume(&mut self, amt: usize) {
|
||||||
|
self.pos += amt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek implementation for AsRef<[u8]> types
|
||||||
|
impl<T> Seek for Cursor<T>
|
||||||
|
where
|
||||||
|
T: AsRef<[u8]>,
|
||||||
|
{
|
||||||
|
fn seek(&mut self, style: SeekFrom) -> Result<u64, Self::Error> {
|
||||||
|
let (base_pos, offset) = match style {
|
||||||
|
SeekFrom::Start(n) => {
|
||||||
|
self.pos = n as usize;
|
||||||
|
return Ok(n);
|
||||||
|
}
|
||||||
|
SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
|
||||||
|
SeekFrom::Current(n) => (self.pos as u64, n),
|
||||||
|
};
|
||||||
|
|
||||||
|
match base_pos.checked_add_signed(offset) {
|
||||||
|
Some(n) => {
|
||||||
|
self.pos = n as usize;
|
||||||
|
Ok(self.pos as u64)
|
||||||
|
}
|
||||||
|
None => Err(ErrorKind::InvalidInput),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function for writing to fixed-size slices
|
||||||
|
fn slice_write(pos_mut: &mut usize, slice: &mut [u8], buf: &[u8]) -> Result<usize, ErrorKind> {
|
||||||
|
let pos = cmp::min(*pos_mut, slice.len()) as usize;
|
||||||
|
let amt = (&mut slice[pos..]).write(buf).map_err(|err| err.kind())?;
|
||||||
|
*pos_mut += amt;
|
||||||
|
Ok(amt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write implementation for &mut [u8]
|
||||||
|
impl Write for Cursor<&mut [u8]> {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
|
slice_write(&mut self.pos, self.inner, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
+1422
File diff suppressed because it is too large
Load Diff
+285
@@ -0,0 +1,285 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
mod constants;
|
||||||
|
mod cursor;
|
||||||
|
mod descriptors;
|
||||||
|
|
||||||
|
use constants::*;
|
||||||
|
use descriptors::*;
|
||||||
|
|
||||||
|
use usb_device::control::{Recipient, Request, RequestType};
|
||||||
|
use usb_device::device::DEFAULT_ALTERNATE_SETTING;
|
||||||
|
use usb_device::endpoint::{self, Endpoint, EndpointDirection, In, Out};
|
||||||
|
use usb_device::{UsbDirection, class_prelude::*};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Format {
|
||||||
|
/// Signed, 16 bits per subframe, little endian
|
||||||
|
S16le,
|
||||||
|
/// Signed, 24 bits per subframe, little endian
|
||||||
|
S24le,
|
||||||
|
/// Signed, 32 bits per subframe, little endian
|
||||||
|
S32le,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sampling rates that shall be supported by an steaming endpoint
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Rates<'a> {
|
||||||
|
/// A continuous range of sampling rates in samples/second defined by a
|
||||||
|
/// tuple including a minimum value and a maximum value. The maximum value
|
||||||
|
/// must be greater than the minimum value.
|
||||||
|
Continuous(u32, u32),
|
||||||
|
/// A set of discrete sampling rates in samples/second
|
||||||
|
Discrete(&'a [u32]),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct StreamConfig<'a> {
|
||||||
|
format: Format,
|
||||||
|
channels: u8,
|
||||||
|
rates: Rates<'a>,
|
||||||
|
terminal_type: TerminalType,
|
||||||
|
/// ISO endpoint size calculated from format, channels and rates (may be
|
||||||
|
/// removed in future)
|
||||||
|
ep_size: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StreamConfig<'_> {
|
||||||
|
/// Create a stream configuration with one or more discrete sampling rates
|
||||||
|
/// indicated in samples/second. An input stream or an output stream will
|
||||||
|
/// have an Input Terminal or Output Terminal of Terminal Type
|
||||||
|
/// `terminal_type`, respectively.
|
||||||
|
pub fn new_discrete(
|
||||||
|
format: Format,
|
||||||
|
channels: u8,
|
||||||
|
rates: &'_ [u32],
|
||||||
|
terminal_type: TerminalType,
|
||||||
|
) -> Result<StreamConfig<'_>> {
|
||||||
|
let max_rate = rates.iter().max().unwrap();
|
||||||
|
let ep_size = Self::ep_size(format, channels, *max_rate)?;
|
||||||
|
let rates = Rates::Discrete(rates);
|
||||||
|
Ok(StreamConfig {
|
||||||
|
format,
|
||||||
|
channels,
|
||||||
|
rates,
|
||||||
|
terminal_type,
|
||||||
|
ep_size,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a stream configuration with a continuous range of supported
|
||||||
|
/// sampling rates indicated in samples/second. An input stream or an output
|
||||||
|
/// stream will have an Input Terminal or Output Terminal of Terminal Type
|
||||||
|
/// `terminal_type`, respectively.
|
||||||
|
pub fn new_continuous(
|
||||||
|
format: Format,
|
||||||
|
channels: u8,
|
||||||
|
min_rate: u32,
|
||||||
|
max_rate: u32,
|
||||||
|
terminal_type: TerminalType,
|
||||||
|
) -> Result<StreamConfig<'static>> {
|
||||||
|
if min_rate >= max_rate {
|
||||||
|
return Err(Error::InvalidValue);
|
||||||
|
}
|
||||||
|
let ep_size = Self::ep_size(format, channels, max_rate)?;
|
||||||
|
let rates = Rates::Continuous(min_rate, max_rate);
|
||||||
|
Ok(StreamConfig {
|
||||||
|
format,
|
||||||
|
channels,
|
||||||
|
rates,
|
||||||
|
terminal_type,
|
||||||
|
ep_size,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// calculate ISO endpoint size from format, channels and rates
|
||||||
|
fn ep_size(format: Format, channels: u8, max_rate: u32) -> Result<u16> {
|
||||||
|
let octets_per_frame = channels as u32
|
||||||
|
* match format {
|
||||||
|
Format::S16le => 2,
|
||||||
|
Format::S24le => 3,
|
||||||
|
Format::S32le => 4,
|
||||||
|
};
|
||||||
|
let ep_size = octets_per_frame * max_rate / 1000;
|
||||||
|
// if ep_size > MAX_ISO_EP_SIZE {
|
||||||
|
// return Err(Error::BandwidthExceeded);
|
||||||
|
// }
|
||||||
|
Ok(ep_size as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// USB audio errors, including possible USB Stack errors
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
InvalidValue,
|
||||||
|
BandwidthExceeded,
|
||||||
|
StreamNotInitialized,
|
||||||
|
UsbError(usb_device::UsbError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<UsbError> for Error {
|
||||||
|
fn from(err: UsbError) -> Self {
|
||||||
|
Error::UsbError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
|
struct AudioStream<'a, B: UsbBus, D: EndpointDirection> {
|
||||||
|
stream_config: StreamConfig<'a>,
|
||||||
|
interface: InterfaceNumber,
|
||||||
|
endpoint: Endpoint<'a, B, D>,
|
||||||
|
alt_setting: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: UsbBus> AudioStream<'_, B, endpoint::In> {
|
||||||
|
fn input_terminal_desc(&self, id: u8, clock_source: u8) -> InputTerminal {
|
||||||
|
let channel_config = ChannelConfig::default_chans(self.stream_config.channels);
|
||||||
|
InputTerminal {
|
||||||
|
id,
|
||||||
|
terminal_type: TerminalType::UsbStreaming,
|
||||||
|
assoc_terminal: 0,
|
||||||
|
clock_source,
|
||||||
|
num_channels: self.stream_config.channels,
|
||||||
|
channel_config,
|
||||||
|
channel_names: 0,
|
||||||
|
copy_protect_control: AccessControl::NotPresent,
|
||||||
|
connector_control: AccessControl::NotPresent,
|
||||||
|
overload_control: AccessControl::NotPresent,
|
||||||
|
cluster_control: AccessControl::NotPresent,
|
||||||
|
underflow_control: AccessControl::NotPresent,
|
||||||
|
overflow_control: AccessControl::NotPresent,
|
||||||
|
phantom_power_control: AccessControl::NotPresent,
|
||||||
|
string: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: UsbBus> AudioStream<'_, B, endpoint::Out> {
|
||||||
|
fn output_terminal_desc(&self, id: u8, source_id: u8, clock_source: u8) -> OutputTerminal {
|
||||||
|
OutputTerminal {
|
||||||
|
id,
|
||||||
|
terminal_type: TerminalType::UsbStreaming,
|
||||||
|
assoc_terminal: 0,
|
||||||
|
source_id,
|
||||||
|
clock_source,
|
||||||
|
copy_protect_control: AccessControl::NotPresent,
|
||||||
|
connector_control: AccessControl::NotPresent,
|
||||||
|
overload_control: AccessControl::NotPresent,
|
||||||
|
underflow_control: AccessControl::NotPresent,
|
||||||
|
overflow_control: AccessControl::NotPresent,
|
||||||
|
string: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AudioClass<'a, B: UsbBus> {
|
||||||
|
control_iface: InterfaceNumber,
|
||||||
|
input: Option<AudioStream<'a, B, In>>,
|
||||||
|
output: Option<AudioStream<'a, B, Out>>,
|
||||||
|
function: FunctionCode,
|
||||||
|
clock_type: ClockType,
|
||||||
|
input_type: Option<TerminalType>,
|
||||||
|
output_type: Option<TerminalType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: UsbBus> AudioClass<'_, B> {}
|
||||||
|
|
||||||
|
impl<B: UsbBus> UsbClass<B> for AudioClass<'_, B> {
|
||||||
|
fn get_configuration_descriptors(
|
||||||
|
&self,
|
||||||
|
writer: &mut DescriptorWriter,
|
||||||
|
) -> usb_device::Result<()> {
|
||||||
|
// Build the necessary descriptors
|
||||||
|
// Clock Source - id 1
|
||||||
|
// USB Input Terminal - id 2
|
||||||
|
// Audio Output Terminal - id 3
|
||||||
|
// USB Output Terminal - id 4
|
||||||
|
// Audio Input Terminal - id 5
|
||||||
|
let clock_source = ClockSource {
|
||||||
|
id: 1,
|
||||||
|
clock_type: self.clock_type,
|
||||||
|
sof_sync: false,
|
||||||
|
frequency_access: if self.clock_type == ClockType::InternalProgrammable {
|
||||||
|
AccessControl::Programmable
|
||||||
|
} else {
|
||||||
|
AccessControl::NotPresent
|
||||||
|
},
|
||||||
|
validity_access: AccessControl::ReadOnly,
|
||||||
|
assoc_terminal: 0,
|
||||||
|
string: 0,
|
||||||
|
};
|
||||||
|
let in_terminals = match &self.input {
|
||||||
|
Some(i) => Some((
|
||||||
|
i.input_terminal_desc(2, 1),
|
||||||
|
OutputTerminal {
|
||||||
|
id: 3,
|
||||||
|
terminal_type: self.output_type.unwrap_or(TerminalType::OutUndefined),
|
||||||
|
assoc_terminal: 0,
|
||||||
|
source_id: 2,
|
||||||
|
clock_source: 1,
|
||||||
|
copy_protect_control: AccessControl::NotPresent,
|
||||||
|
connector_control: AccessControl::NotPresent,
|
||||||
|
overload_control: AccessControl::NotPresent,
|
||||||
|
underflow_control: AccessControl::NotPresent,
|
||||||
|
overflow_control: AccessControl::NotPresent,
|
||||||
|
string: 0,
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let out_terminals = match &self.output {
|
||||||
|
Some(i) => Some((
|
||||||
|
i.output_terminal_desc(4, 5, 1),
|
||||||
|
InputTerminal {
|
||||||
|
id: 5,
|
||||||
|
terminal_type: self.input_type.unwrap_or(TerminalType::InUndefined),
|
||||||
|
assoc_terminal: 0,
|
||||||
|
clock_source: 1,
|
||||||
|
num_channels: i.stream_config.channels,
|
||||||
|
channel_config: ChannelConfig::default_chans(i.stream_config.channels),
|
||||||
|
channel_names: 0,
|
||||||
|
copy_protect_control: AccessControl::NotPresent,
|
||||||
|
connector_control: AccessControl::NotPresent,
|
||||||
|
overload_control: AccessControl::NotPresent,
|
||||||
|
cluster_control: AccessControl::NotPresent,
|
||||||
|
underflow_control: AccessControl::NotPresent,
|
||||||
|
overflow_control: AccessControl::NotPresent,
|
||||||
|
phantom_power_control: AccessControl::NotPresent,
|
||||||
|
string: 0,
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let n_interfaces = match (&self.input, &self.output) {
|
||||||
|
(Some(_), Some(_)) => 3, // two audio, one control
|
||||||
|
(Some(_), None) | (None, Some(_)) => 2, // one audio, one control
|
||||||
|
(None, None) => 1, // no audio (?!), one control
|
||||||
|
};
|
||||||
|
writer.iad(
|
||||||
|
self.control_iface,
|
||||||
|
n_interfaces,
|
||||||
|
AUDIO,
|
||||||
|
FunctionSubclass::Undefined as u8,
|
||||||
|
FunctionProtocol::Version2 as u8,
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
writer.interface(
|
||||||
|
self.control_iface,
|
||||||
|
AUDIO,
|
||||||
|
InterfaceSubclass::AudioControl as u8,
|
||||||
|
InterfaceProtocol::Version2 as u8,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if let Some(terminals) = in_terminals {
|
||||||
|
terminals.0.write_descriptor(writer)?;
|
||||||
|
terminals.1.write_descriptor(writer)?;
|
||||||
|
}
|
||||||
|
if let Some(terminals) = out_terminals {
|
||||||
|
terminals.0.write_descriptor(writer)?;
|
||||||
|
terminals.1.write_descriptor(writer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user