1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use usb_device::class_prelude::*;
use usb_device::Result;
const USB_CLASS_APPLICATION_SPECIFIC: u8 = 0xfe;
const DFU_SUBCLASS_FIRMWARE_UPGRADE: u8 = 0x01;
const DFU_PROTOCOL_RUNTIME: u8 = 0x01;
const DFU_TYPE_FUNCTIONAL: u8 = 0x21;
const DFU_WILL_DETACH: u8 = 1 << 3;
const DFU_MANIFESTATION_TOLERANT: u8 = 1 << 2;
const DFU_CAN_UPLOAD: u8 = 1 << 1;
const DFU_CAN_DNLOAD: u8 = 1 << 0;
const DFU_REQ_DETACH: u8 = 0;
pub struct DfuRuntimeClass<T: DfuRuntimeOps> {
dfu_ops: T,
iface: InterfaceNumber,
timeout: Option<u16>,
}
pub trait DfuRuntimeOps {
fn enter(&mut self);
}
impl<T: DfuRuntimeOps> DfuRuntimeClass<T> {
pub fn new<B: UsbBus>(alloc: &UsbBusAllocator<B>, dfu_ops: T) -> Self {
Self {
dfu_ops,
iface: alloc.interface(),
timeout: None,
}
}
}
impl<T: DfuRuntimeOps, B: UsbBus> UsbClass<B> for DfuRuntimeClass<T> {
fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
writer.iad(
self.iface,
1,
USB_CLASS_APPLICATION_SPECIFIC,
DFU_SUBCLASS_FIRMWARE_UPGRADE,
DFU_PROTOCOL_RUNTIME)?;
writer.interface(
self.iface,
USB_CLASS_APPLICATION_SPECIFIC,
DFU_SUBCLASS_FIRMWARE_UPGRADE,
DFU_PROTOCOL_RUNTIME)?;
let detach_timeout: u16 = 255;
let transfer_size: u16 = 2048;
let dfu_version: u16 = 0x011a;
writer.write(
DFU_TYPE_FUNCTIONAL,
&[
(DFU_WILL_DETACH | DFU_CAN_UPLOAD | DFU_CAN_DNLOAD) & !DFU_MANIFESTATION_TOLERANT,
detach_timeout.to_le_bytes()[0], detach_timeout.to_le_bytes()[1],
transfer_size.to_le_bytes()[0], transfer_size.to_le_bytes()[1],
dfu_version.to_le_bytes()[0], dfu_version.to_le_bytes()[1],
])
}
fn poll(&mut self) {
if let Some(_timeout) = self.timeout.take() {
self.dfu_ops.enter();
}
}
fn control_out(&mut self, xfer: ControlOut<B>) {
let req = xfer.request();
if !(req.request_type == control::RequestType::Class
&& req.recipient == control::Recipient::Interface
&& req.index == u8::from(self.iface) as u16)
{
return;
}
match req.request {
DFU_REQ_DETACH => {
self.timeout = Some(req.value);
xfer.accept().ok();
},
_ => { xfer.reject().ok(); },
}
}
}