pybadge_high/
usb.rs

1use cortex_m::peripheral::NVIC;
2use edgebadge::{hal, pac, pins::USB as UsbPins};
3use hal::{clock::GenericClockController, usb::UsbBus};
4use pac::{interrupt, MCLK, USB as UsbPeripherals};
5pub use usb_device::UsbError;
6use usb_device::{bus::UsbBusAllocator, prelude::*};
7use usbd_serial::{SerialPort, USB_CLASS_CDC};
8
9static mut USB_ALLOCATOR: Option<UsbBusAllocator<UsbBus>> = None;
10static mut USB_DEV: Option<UsbDevice<UsbBus>> = None;
11static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None;
12static mut INTERRUPT_HANDLER: Option<fn()> = None;
13
14/// USB connection for serial communication.
15#[non_exhaustive] // prevent the user from creating this struct manual, without calling init.
16				  // to make sure static varibale are Some.
17pub struct Usb {}
18
19impl Usb {
20	/// Polls the UsbBus for new events.
21	/// Return true if serial may have data available for reading, false otherwise.
22	/// This should be called periodically as often as possible for the best data
23	/// rate, or preferably from an interrupt handler. Must be called at least once every 10
24	/// milliseconds while connected to the USB host to be USB compliant.
25	pub fn poll(&self) -> bool {
26		unsafe {
27			USB_DEV
28				.as_mut()
29				.unwrap()
30				.poll(&mut [USB_SERIAL.as_mut().unwrap()])
31		}
32	}
33
34	/// Reads bytes from the port into `data` and returns the number of bytes read.
35	///
36	/// # Errors
37	///
38	/// * [`WouldBlock`](UsbError::WouldBlock) - No bytes available for reading.
39	///
40	/// Other errors from `usb-device` may also be propagated.
41	pub fn read(&mut self, data: &mut [u8]) -> Result<usize, UsbError> {
42		unsafe { USB_SERIAL.as_mut().unwrap().read(data) }
43	}
44
45	/// Writes bytes from `data` into the port and returns the number of bytes written.
46	///
47	/// # Errors
48	///
49	/// * [`WouldBlock`](UsbError::WouldBlock) - No bytes could be written because the
50	///   buffers are full.
51	///
52	/// Other errors from `usb-device` may also be propagated.
53	pub fn write(&mut self, data: &[u8]) -> Result<usize, UsbError> {
54		unsafe { USB_SERIAL.as_mut().unwrap().write(data) }
55	}
56	//TODO: wrap more function from https://docs.rs/usbd-serial/0.1.1/usbd_serial/struct.SerialPort.html
57	//TODO: wrap more function from https://docs.rs/usb-device/0.2.9/usb_device/device/struct.UsbDevice.html
58
59	///use the given function as interrupt handler.
60	///
61	///Interupt must still be enable by calling [`enable_interrupt()`](Usb::enable_interrupt).
62	///It is guaranteed that the interupt is not called again, while it is still running.
63	pub fn set_interrupt(&mut self, handler: fn()) {
64		unsafe { INTERRUPT_HANDLER = Some(handler) }
65	}
66
67	/// [`poll()`](Usb::poll()) will be called automatically.
68	/// You can register an interrupt handler with [`set_interrupt()`](Usb::set_interrupt()).
69	pub fn enable_interrupt(&mut self) {
70		unsafe {
71			NVIC::unmask(interrupt::USB_OTHER);
72			NVIC::unmask(interrupt::USB_TRCPT0);
73			NVIC::unmask(interrupt::USB_TRCPT1);
74		}
75	}
76
77	pub fn disable_interrupt(&mut self) {
78		NVIC::mask(interrupt::USB_OTHER);
79		NVIC::mask(interrupt::USB_TRCPT0);
80		NVIC::mask(interrupt::USB_TRCPT1);
81	}
82}
83
84pub struct UsbBuilder {
85	pub usb_vid: u16,
86	pub usb_pid: u16,
87	pub manufacturer: &'static str,
88	pub product: &'static str,
89	pub serial_number: &'static str,
90	// The Peripherals are not needed for something else,
91	// after Pybadge::take() was called.
92	// So simple move it to this Builder, where it is still needed.
93	pub(crate) pins: UsbPins,
94	pub(crate) clocks: GenericClockController,
95	pub(crate) mclk: MCLK,
96	pub(crate) peripherals: UsbPeripherals
97}
98
99impl UsbBuilder {
100	/// Build the USB serial interface.
101	///
102	/// After building [`Usb::poll()`] must be called at least once every 10
103	/// milliseconds while connected to the USB host to be USB compliant.
104	pub fn build(mut self) -> Usb {
105		let usb_allocator =
106			self.pins
107				.init(self.peripherals, &mut self.clocks, &mut self.mclk);
108		unsafe {
109			USB_ALLOCATOR = Some(usb_allocator);
110		}
111		unsafe {
112			USB_SERIAL = Some(SerialPort::new(USB_ALLOCATOR.as_ref().unwrap()));
113		}
114		unsafe {
115			USB_DEV = Some(
116				UsbDeviceBuilder::new(
117					USB_ALLOCATOR.as_ref().unwrap(),
118					UsbVidPid(self.usb_vid, self.usb_pid)
119				)
120				.manufacturer(self.manufacturer)
121				.product(self.product)
122				.serial_number(self.serial_number)
123				.device_class(USB_CLASS_CDC)
124				.build()
125			);
126		}
127		Usb {}
128	}
129
130	//exist no dervie macro for this (usb_vid, get_usb_vid, set_usb_vid)?
131
132	pub fn usb_vid(mut self, usb_vid: u16) -> Self {
133		self.usb_vid = usb_vid;
134		self
135	}
136
137	pub fn usb_pid(mut self, usb_pid: u16) -> Self {
138		self.usb_pid = usb_pid;
139		self
140	}
141
142	pub fn manufacturer(mut self, manufacturer: &'static str) -> Self {
143		self.manufacturer = manufacturer;
144		self
145	}
146
147	pub fn product(mut self, product: &'static str) -> Self {
148		self.product = product;
149		self
150	}
151
152	pub fn serial_number(mut self, serial_number: &'static str) -> Self {
153		self.serial_number = serial_number;
154		self
155	}
156}
157
158fn handle_interrupt() {
159	// Disable interrupts while accessing USB_SERIAL and USB_BUS to prevent possible
160	// race conditions
161	cortex_m::interrupt::free(|_cs| {
162		Usb {}.poll(); //unsave see poll function
163			   //should I prefer panic instead? So the user get a respons
164		if let Some(handler) = unsafe { INTERRUPT_HANDLER } {
165			handler();
166		}
167	})
168}
169
170#[interrupt]
171fn USB_OTHER() {
172	handle_interrupt()
173}
174
175#[interrupt]
176fn USB_TRCPT0() {
177	handle_interrupt()
178}
179
180#[interrupt]
181fn USB_TRCPT1() {
182	handle_interrupt()
183}