217 lines
5.6 KiB
Rust
217 lines
5.6 KiB
Rust
#![no_std]
|
|
#![no_main]
|
|
|
|
use panic_halt as _;
|
|
|
|
use common::{handle_input, Handshake, UnsafeSync};
|
|
use core::cell::RefCell;
|
|
use cortex_m::{asm::delay as cycle_delay, interrupt::Mutex, peripheral::NVIC};
|
|
use once_cell::unsync::OnceCell;
|
|
use rp2040_hal::{
|
|
pac::{interrupt, Interrupt, Peripherals},
|
|
usb::UsbBus,
|
|
Sio, Watchdog,
|
|
};
|
|
use usb_device::{class_prelude::*, prelude::*};
|
|
use usbd_serial::{SerialPort, USB_CLASS_CDC};
|
|
|
|
mod bsp;
|
|
mod buttons;
|
|
mod device_signature;
|
|
|
|
use bsp::{entry, Pins};
|
|
use buttons::Buttons;
|
|
|
|
static USB_ALLOCATOR: UnsafeSync<OnceCell<UsbBusAllocator<UsbBus>>> =
|
|
UnsafeSync::new(OnceCell::new());
|
|
// static RTC_COUNT: Mutex<RefCell<Option<Rtc<Count32Mode>>>> = Mutex::new(RefCell::new(None));
|
|
|
|
static USB_BUS: Mutex<RefCell<Option<UsbDevice<UsbBus>>>> = Mutex::new(RefCell::new(None));
|
|
static USB_SERIAL: Mutex<RefCell<Option<SerialPort<UsbBus>>>> = Mutex::new(RefCell::new(None));
|
|
|
|
static HANDSHAKE: Mutex<RefCell<Handshake>> = Mutex::new(RefCell::new(Handshake::new()));
|
|
|
|
fn get_current_time() -> u32 {
|
|
unimplemented!()
|
|
}
|
|
|
|
fn is_handshake_complete() -> bool {
|
|
cortex_m::interrupt::free(|cs| HANDSHAKE.borrow(cs).borrow().is_complete())
|
|
}
|
|
|
|
#[entry]
|
|
fn main() -> ! {
|
|
let mut peripherals = Peripherals::take().unwrap();
|
|
|
|
let mut watchdog = Watchdog::new(peripherals.WATCHDOG);
|
|
|
|
let clocks = rp2040_hal::clocks::init_clocks_and_plls(
|
|
bsp::XOSC_CRYSTAL_FREQ,
|
|
peripherals.XOSC,
|
|
peripherals.CLOCKS,
|
|
peripherals.PLL_SYS,
|
|
peripherals.PLL_USB,
|
|
&mut peripherals.RESETS,
|
|
&mut watchdog,
|
|
)
|
|
.ok()
|
|
.unwrap();
|
|
|
|
let sio = Sio::new(peripherals.SIO);
|
|
|
|
let pins = Pins::new(
|
|
peripherals.IO_BANK0,
|
|
peripherals.PADS_BANK0,
|
|
sio.gpio_bank0,
|
|
&mut peripherals.RESETS,
|
|
);
|
|
|
|
let usb_allocator = UsbBusAllocator::new(UsbBus::new(
|
|
peripherals.USBCTRL_REGS,
|
|
peripherals.USBCTRL_DPRAM,
|
|
clocks.usb_clock,
|
|
true,
|
|
&mut peripherals.RESETS,
|
|
));
|
|
|
|
// SAFETY: No interrupt will access USB_ALLOCATOR before this point, since it is only
|
|
// referenced from inside the USB_SERIAL mutex and the USB_BUS mutex, which have not been set
|
|
// yet.
|
|
//
|
|
// SAFETY: This is the only line of the program that modifies USB_ALLOCATOR
|
|
let allocator = unsafe {
|
|
USB_ALLOCATOR.get().set(usb_allocator).ok().unwrap();
|
|
USB_ALLOCATOR.get().get().unwrap()
|
|
};
|
|
|
|
cortex_m::interrupt::free(|cs| {
|
|
let serial = USB_SERIAL.borrow(cs);
|
|
let mut serial = serial.borrow_mut();
|
|
*serial = Some(SerialPort::new(allocator));
|
|
});
|
|
|
|
cortex_m::interrupt::free(|cs| {
|
|
let bus = USB_BUS.borrow(cs);
|
|
let mut bus = bus.borrow_mut();
|
|
*bus = Some(
|
|
UsbDeviceBuilder::new(allocator, UsbVidPid(0x16c0, 0x27dd))
|
|
.manufacturer("Aode Lion")
|
|
.product("Pico Streamdeck")
|
|
.serial_number("AAAB")
|
|
.device_class(USB_CLASS_CDC)
|
|
.build(),
|
|
);
|
|
});
|
|
|
|
unsafe {
|
|
NVIC::unmask(Interrupt::USBCTRL_IRQ);
|
|
}
|
|
|
|
let mut buttons = Buttons {
|
|
d0: pins.gpio0,
|
|
d1: pins.gpio1,
|
|
d2: pins.gpio2,
|
|
d3: pins.gpio3,
|
|
d4: pins.gpio4,
|
|
}
|
|
.init();
|
|
|
|
loop {
|
|
let current_time = get_current_time();
|
|
|
|
if !is_handshake_complete() {
|
|
cycle_delay(1024 * 15);
|
|
continue;
|
|
}
|
|
|
|
if let Some(byte) = buttons.tick(current_time) {
|
|
let _ = cortex_m::interrupt::free(|cs| {
|
|
let mut serial = USB_SERIAL.borrow(cs).borrow_mut();
|
|
let serial = serial.as_mut().unwrap();
|
|
let _ = serial.write(&[byte])?;
|
|
serial.flush()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
#[interrupt]
|
|
fn USBCTRL_IRQ() {
|
|
poll_usb();
|
|
}
|
|
|
|
fn poll_usb() -> Option<()> {
|
|
let ready = cortex_m::interrupt::free(|cs1| {
|
|
cortex_m::interrupt::free(|cs2| {
|
|
let mut usb_dev = USB_BUS.borrow(cs1).borrow_mut();
|
|
let usb_dev = usb_dev.as_mut()?;
|
|
let mut serial = USB_SERIAL.borrow(cs2).borrow_mut();
|
|
let serial = serial.as_mut()?;
|
|
|
|
Some(usb_dev.poll(&mut [&mut *serial]))
|
|
})
|
|
})?;
|
|
|
|
if !ready {
|
|
return Some(());
|
|
}
|
|
|
|
let mut input = [0u8; 32];
|
|
|
|
let count = cortex_m::interrupt::free(|cs| {
|
|
USB_SERIAL
|
|
.borrow(cs)
|
|
.borrow_mut()
|
|
.as_mut()?
|
|
.read(&mut input)
|
|
.ok()
|
|
})?;
|
|
|
|
let current_time = get_current_time();
|
|
|
|
cortex_m::interrupt::free(|cs| {
|
|
let mut handshake = HANDSHAKE.borrow(cs).borrow_mut();
|
|
|
|
if count == 32 && handshake.perform(&input, current_time, &mut Device)? {
|
|
return None;
|
|
}
|
|
|
|
let is_complete = handshake.is_complete();
|
|
if !is_complete {
|
|
return None;
|
|
}
|
|
|
|
Some(())
|
|
})?;
|
|
|
|
handle_input(&mut Device, &input, count)?;
|
|
Some(())
|
|
}
|
|
|
|
struct Device;
|
|
|
|
impl common::Device<8, 1> for Device {
|
|
fn serial_number(&mut self) -> [u8; 8] {
|
|
device_signature::read_uid()
|
|
}
|
|
|
|
fn write(&mut self, bytes: &[u8]) -> Option<()> {
|
|
cortex_m::interrupt::free(|cs| {
|
|
let mut serial = USB_SERIAL.borrow(cs).borrow_mut();
|
|
let serial = serial.as_mut()?;
|
|
serial.write(bytes).ok()?;
|
|
serial.flush().ok()
|
|
})
|
|
}
|
|
|
|
fn extras() -> [(&'static str, &'static str); 1] {
|
|
[("version", env!("FIRMWARE_VERSION"))]
|
|
}
|
|
|
|
fn reset(&mut self) {
|
|
cortex_m::interrupt::disable();
|
|
rp2040_hal::rom_data::reset_to_usb_boot(0, 0);
|
|
}
|
|
}
|