-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathusb.rs
More file actions
133 lines (116 loc) · 4.32 KB
/
usb.rs
File metadata and controls
133 lines (116 loc) · 4.32 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// SPDX-License-Identifier: GPL-3.0-only
/*
* Copyright (c) 2025 Code Construct
*/
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use core::fmt::Write;
use embassy_executor::Spawner;
use embassy_stm32::peripherals::USB_OTG_HS;
use embassy_stm32::usb::{DmPin, DpPin, Driver};
use embassy_stm32::{bind_interrupts, usb, Peri};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::signal::Signal;
#[allow(unused_imports)]
use embassy_usb::class::cdc_acm;
use embassy_usb::Builder;
use heapless::String;
use mctp_estack::router::{Port, PortId, Router};
use mctp_usb_embassy::{MctpUsbClass, MCTP_USB_MAX_PACKET};
use static_cell::StaticCell;
bind_interrupts!(struct Irqs {
OTG_HS => usb::InterruptHandler<USB_OTG_HS>;
});
#[cfg(feature = "log-usbserial")]
type Endpoints = (
MctpUsbClass<'static, Driver<'static, USB_OTG_HS>>,
cdc_acm::CdcAcmClass<'static, Driver<'static, USB_OTG_HS>>,
);
#[cfg(not(feature = "log-usbserial"))]
type Endpoints = (MctpUsbClass<'static, Driver<'static, USB_OTG_HS>>,);
pub(crate) fn setup(
spawner: Spawner,
usb: Peri<'static, USB_OTG_HS>,
dp: Peri<'static, impl DpPin<USB_OTG_HS>>,
dm: Peri<'static, impl DmPin<USB_OTG_HS>>,
state_notify: &'static Signal<CriticalSectionRawMutex, bool>,
) -> Endpoints {
let mut config = embassy_usb::Config::new(0x3834, 0x0000);
config.manufacturer = Some("Code Construct");
config.product = Some(crate::PRODUCT);
// USB serial number matches the first 12 digits of the mctp uuid
static SERIAL: StaticCell<String<{ uuid::fmt::Simple::LENGTH }>> =
StaticCell::new();
let serial = SERIAL.init(String::new());
write!(serial, "{}", crate::device_uuid().simple()).unwrap();
config.serial_number = Some(&serial[..12]);
let driver_config = embassy_stm32::usb::Config::default();
// TODO: is vbus detection needed? Seems not on the nucleo?
// driver_config.vbus_detection = true;
const CONTROL_SZ: usize = 64;
const USBSERIAL_SZ: usize = 64;
// TODO: +1 workaround can be removed once this merges:
// https://github.com/embassy-rs/embassy/pull/3892
const OUT_SZ: usize = MCTP_USB_MAX_PACKET + CONTROL_SZ + USBSERIAL_SZ + 1;
static EP_OUT_BUF: StaticCell<[u8; OUT_SZ]> = StaticCell::new();
let ep_out_buf = EP_OUT_BUF.init([0; OUT_SZ]);
let driver = Driver::new_hs(usb, Irqs, dp, dm, ep_out_buf, driver_config);
// UsbDevice will be static to pass to usb_task. That requires static buffers.
static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new();
static BOS_DESCRIPTOR: StaticCell<[u8; 32]> = StaticCell::new();
static CONTROL_BUF: StaticCell<[u8; CONTROL_SZ]> = StaticCell::new();
let config_descriptor = CONFIG_DESCRIPTOR.init([0; 256]);
let bos_descriptor = BOS_DESCRIPTOR.init([0; 32]);
let control_buf = CONTROL_BUF.init([0; CONTROL_SZ]);
let mut builder = Builder::new(
driver,
config,
config_descriptor,
bos_descriptor,
&mut [],
control_buf,
);
let mctp = MctpUsbClass::new(&mut builder);
#[cfg(feature = "log-usbserial")]
let ret = {
static STATE: StaticCell<cdc_acm::State> = StaticCell::new();
let state = STATE.init(Default::default());
let serial = cdc_acm::CdcAcmClass::new(&mut builder, state, 64);
(mctp, serial)
};
#[cfg(not(feature = "log-usbserial"))]
let ret = (mctp,);
let usb = builder.build();
spawner.must_spawn(usb_task(usb, state_notify));
ret
}
#[embassy_executor::task]
async fn usb_task(
mut usb: embassy_usb::UsbDevice<'static, Driver<'static, USB_OTG_HS>>,
state_notify: &'static Signal<CriticalSectionRawMutex, bool>,
) -> ! {
loop {
usb.wait_resume().await;
state_notify.signal(true);
usb.run_until_suspend().await;
state_notify.signal(false);
}
}
#[embassy_executor::task]
pub async fn usb_recv_task(
router: &'static Router<'static>,
usb_receiver: mctp_usb_embassy::Receiver<
'static,
Driver<'static, USB_OTG_HS>,
>,
port: PortId,
) -> ! {
usb_receiver.run(router, port).await;
}
#[embassy_executor::task]
pub async fn usb_send_task(
mctp_usb_bottom: Port<'static>,
usb_sender: mctp_usb_embassy::Sender<'static, Driver<'static, USB_OTG_HS>>,
) -> ! {
usb_sender.run(mctp_usb_bottom).await;
}