usbd_human_interface_device/device/
consumer.rs1use fugit::ExtU32;
4use packed_struct::prelude::*;
5#[allow(clippy::wildcard_imports)]
6use usb_device::class_prelude::*;
7
8use crate::page::Consumer;
9use crate::usb_class::prelude::*;
10
11#[rustfmt::skip]
13pub const MULTIPLE_CODE_REPORT_DESCRIPTOR: &[u8] = &[
14 0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x75, 0x10, 0x95, 0x04, 0x15, 0x00, 0x26, 0x9C, 0x02, 0x19, 0x00, 0x2A, 0x9C, 0x02, 0x81, 0x00, 0xC0, ];
26
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)]
29#[packed_struct(endian = "lsb", size_bytes = "8")]
30pub struct MultipleConsumerReport {
31 #[packed_field(ty = "enum", element_size_bytes = "2")]
32 pub codes: [Consumer; 4],
33}
34
35#[allow(clippy::doc_markdown)]
36#[rustfmt::skip]
50pub const FIXED_FUNCTION_REPORT_DESCRIPTOR: &[u8] = &[
51 0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x05, 0x0C, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x07, 0x09, 0xB5, 0x09, 0xB6, 0x09, 0xB7, 0x09, 0xCD, 0x09, 0xE2, 0x09, 0xE9, 0x09, 0xEA, 0x81, 0x02, 0x95, 0x01, 0x81, 0x01, 0xC0, ];
71
72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73#[derive(Clone, Copy, Debug, Eq, PartialEq, PackedStruct)]
74#[packed_struct(endian = "lsb", bit_numbering = "lsb0", size_bytes = "1")]
75pub struct FixedFunctionReport {
76 #[packed_field(bits = "0")]
77 pub next: bool,
78 #[packed_field(bits = "1")]
79 pub previous: bool,
80 #[packed_field(bits = "2")]
81 pub stop: bool,
82 #[packed_field(bits = "3")]
83 pub play_pause: bool,
84 #[packed_field(bits = "4")]
85 pub mute: bool,
86 #[packed_field(bits = "5")]
87 pub volume_increment: bool,
88 #[packed_field(bits = "6")]
89 pub volume_decrement: bool,
90}
91
92pub struct ConsumerControl<'a, B: UsbBus> {
93 interface: Interface<'a, B, InBytes8, OutNone, ReportSingle>,
94}
95
96impl<B: UsbBus> ConsumerControl<'_, B> {
97 pub fn write_report(&mut self, report: &MultipleConsumerReport) -> usb_device::Result<usize> {
98 let data = report.pack().map_err(|_| {
99 error!("Error packing MultipleConsumerReport");
100 UsbError::ParseError
101 })?;
102 self.interface.write_report(&data)
103 }
104}
105
106impl<'a, B: UsbBus> DeviceClass<'a> for ConsumerControl<'a, B> {
107 type I = Interface<'a, B, InBytes8, OutNone, ReportSingle>;
108
109 fn interface(&mut self) -> &mut Self::I {
110 &mut self.interface
111 }
112
113 fn reset(&mut self) {}
114
115 fn tick(&mut self) -> Result<(), crate::UsbHidError> {
116 Ok(())
117 }
118}
119
120pub struct ConsumerControlConfig<'a> {
121 interface: InterfaceConfig<'a, InBytes8, OutNone, ReportSingle>,
122}
123
124impl<'a> ConsumerControlConfig<'a> {
125 #[must_use]
126 pub fn new(interface: InterfaceConfig<'a, InBytes8, OutNone, ReportSingle>) -> Self {
127 Self { interface }
128 }
129}
130
131impl Default for ConsumerControlConfig<'_> {
132 fn default() -> Self {
133 Self::new(
134 unwrap!(
135 unwrap!(InterfaceBuilder::new(MULTIPLE_CODE_REPORT_DESCRIPTOR))
136 .description("Consumer Control")
137 .in_endpoint(50.millis())
138 )
139 .without_out_endpoint()
140 .build(),
141 )
142 }
143}
144
145impl<'a, B: UsbBus + 'a> UsbAllocatable<'a, B> for ConsumerControlConfig<'a> {
146 type Allocated = ConsumerControl<'a, B>;
147
148 fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
149 Self::Allocated {
150 interface: Interface::new(usb_alloc, self.interface),
151 }
152 }
153}
154
155pub struct ConsumerControlFixed<'a, B: UsbBus> {
156 interface: Interface<'a, B, InBytes8, OutNone, ReportSingle>,
157}
158
159impl<B: UsbBus> ConsumerControlFixed<'_, B> {
160 pub fn write_report(&mut self, report: &FixedFunctionReport) -> usb_device::Result<usize> {
161 let data = report.pack().map_err(|_| {
162 error!("Error packing MultipleConsumerReport");
163 UsbError::ParseError
164 })?;
165 self.interface.write_report(&data)
166 }
167}
168
169impl<'a, B: UsbBus> DeviceClass<'a> for ConsumerControlFixed<'a, B> {
170 type I = Interface<'a, B, InBytes8, OutNone, ReportSingle>;
171
172 fn interface(&mut self) -> &mut Self::I {
173 &mut self.interface
174 }
175
176 fn reset(&mut self) {}
177
178 fn tick(&mut self) -> Result<(), crate::UsbHidError> {
179 Ok(())
180 }
181}
182
183pub struct ConsumerControlFixedConfig<'a> {
184 interface: InterfaceConfig<'a, InBytes8, OutNone, ReportSingle>,
185}
186impl<'a> ConsumerControlFixedConfig<'a> {
187 #[must_use]
188 pub fn new(interface: InterfaceConfig<'a, InBytes8, OutNone, ReportSingle>) -> Self {
189 Self { interface }
190 }
191}
192
193impl Default for ConsumerControlFixedConfig<'_> {
194 fn default() -> Self {
195 Self::new(
196 unwrap!(
197 unwrap!(InterfaceBuilder::new(FIXED_FUNCTION_REPORT_DESCRIPTOR))
198 .description("Consumer Control")
199 .in_endpoint(50.millis())
200 )
201 .without_out_endpoint()
202 .build(),
203 )
204 }
205}
206
207impl<'a, B: UsbBus + 'a> UsbAllocatable<'a, B> for ConsumerControlFixedConfig<'a> {
208 type Allocated = ConsumerControlFixed<'a, B>;
209
210 fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
211 Self::Allocated {
212 interface: Interface::new(usb_alloc, self.interface),
213 }
214 }
215}