2024-10-14 11:52:15 +08:00
|
|
|
use core::{
|
|
|
|
fmt::{self, Write},
|
|
|
|
mem::MaybeUninit,
|
|
|
|
};
|
2020-09-11 05:17:31 +08:00
|
|
|
use cortex_m::interrupt::free;
|
2024-10-14 11:52:15 +08:00
|
|
|
use log::{Log, Metadata, Record};
|
2020-09-11 05:17:31 +08:00
|
|
|
use stm32f4xx_hal::{
|
2024-10-14 11:52:15 +08:00
|
|
|
otg_fs::{UsbBus as Bus, USB},
|
2020-09-11 05:17:31 +08:00
|
|
|
stm32::{interrupt, Interrupt, NVIC},
|
|
|
|
};
|
|
|
|
use usb_device::{
|
2024-10-14 11:52:15 +08:00
|
|
|
class_prelude::UsbBusAllocator,
|
2020-09-18 06:55:53 +08:00
|
|
|
prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid},
|
2020-09-11 05:17:31 +08:00
|
|
|
};
|
|
|
|
use usbd_serial::SerialPort;
|
|
|
|
|
|
|
|
static mut EP_MEMORY: [u32; 1024] = [0; 1024];
|
|
|
|
|
|
|
|
static mut BUS: MaybeUninit<UsbBusAllocator<Bus<USB>>> = MaybeUninit::uninit();
|
|
|
|
// static mut SERIAL_DEV: Option<(SerialPort<'static, Bus<USB>>, UsbDevice<'static, Bus<USB>>)> = None;
|
|
|
|
static mut STATE: Option<State> = None;
|
|
|
|
|
|
|
|
pub struct State {
|
|
|
|
serial: SerialPort<'static, Bus<USB>>,
|
|
|
|
dev: UsbDevice<'static, Bus<USB>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl State {
|
|
|
|
pub fn setup(usb: USB) {
|
|
|
|
unsafe { BUS.write(Bus::new(usb, &mut EP_MEMORY)) };
|
|
|
|
|
|
|
|
let bus = unsafe { BUS.assume_init_ref() };
|
|
|
|
let serial = SerialPort::new(bus);
|
|
|
|
let dev = UsbDeviceBuilder::new(bus, UsbVidPid(0x16c0, 0x27dd))
|
|
|
|
.manufacturer("M-Labs")
|
2020-10-11 02:45:44 +08:00
|
|
|
.product("thermostat")
|
2020-09-11 05:17:31 +08:00
|
|
|
.device_release(0x20)
|
|
|
|
.self_powered(true)
|
|
|
|
.device_class(usbd_serial::USB_CLASS_CDC)
|
|
|
|
.build();
|
|
|
|
|
2024-10-14 11:52:15 +08:00
|
|
|
free(|_| unsafe {
|
|
|
|
STATE = Some(State { serial, dev });
|
2020-09-11 05:17:31 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
NVIC::unmask(Interrupt::OTG_FS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get() -> Option<&'static mut Self> {
|
|
|
|
unsafe { STATE.as_mut() }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn poll() {
|
|
|
|
if let Some(ref mut s) = Self::get() {
|
|
|
|
if s.dev.poll(&mut [&mut s.serial]) {
|
|
|
|
// discard any input
|
|
|
|
let mut buf = [0u8; 64];
|
|
|
|
let _ = s.serial.read(&mut buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[interrupt]
|
|
|
|
fn OTG_FS() {
|
|
|
|
free(|_| {
|
|
|
|
State::poll();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Logger;
|
|
|
|
|
|
|
|
impl Log for Logger {
|
|
|
|
fn enabled(&self, _: &Metadata) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
fn log(&self, record: &Record) {
|
|
|
|
if self.enabled(record.metadata()) {
|
|
|
|
let mut output = SerialOutput;
|
|
|
|
let _ = writeln!(&mut output, "{} - {}", record.level(), record.args());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn flush(&self) {
|
|
|
|
if let Some(ref mut state) = State::get() {
|
|
|
|
let _ = free(|_| state.serial.flush());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SerialOutput;
|
|
|
|
|
|
|
|
impl Write for SerialOutput {
|
|
|
|
fn write_str(&mut self, s: &str) -> core::result::Result<(), core::fmt::Error> {
|
|
|
|
if let Some(ref mut state) = State::get() {
|
|
|
|
for chunk in s.as_bytes().chunks(16) {
|
2024-10-14 11:52:15 +08:00
|
|
|
free(|_| state.serial.write(chunk)).map_err(|_| fmt::Error)?;
|
2020-09-11 05:17:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|