#![no_std]
#![no_main]
extern crate panic_semihosting;
use cortex_m::{asm::delay, peripheral::DWT};
use embedded_hal::digital::v2::{InputPin, OutputPin};
use rtic::cyccnt::{Instant, U32Ext as _};
use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType};
use stm32f1xx_hal::{adc, gpio, prelude::*, stm32::ADC1};
use usb_device::bus;
use usb_device::prelude::*;
pub struct PanelState {
throttle0: u16,
throttle1: u16,
sw: u8,
}
#[allow(unused)]
pub mod hid {
use usb_device::class_prelude::*;
use usb_device::Result;
const USB_CLASS_HID: u8 = 0x03;
const USB_SUBCLASS_NONE: u8 = 0x00;
const USB_SUBCLASS_BOOT: u8 = 0x01;
const USB_INTERFACE_NONE: u8 = 0x00;
const USB_INTERFACE_KEYBOARD: u8 = 0x01;
const USB_INTERFACE_MOUSE: u8 = 0x02;
const REQ_GET_REPORT: u8 = 0x01;
const REQ_GET_IDLE: u8 = 0x02;
const REQ_GET_PROTOCOL: u8 = 0x03;
const REQ_SET_REPORT: u8 = 0x09;
const REQ_SET_IDLE: u8 = 0x0a;
const REQ_SET_PROTOCOL: u8 = 0x0b;
const REPORT_DESCR: &[u8] = &[
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x02, // USAGE_PAGE (Simulation)
0x09, 0xbb, // USAGE (Throttle)
0x16, 0x00, 0x80, /* Logical Minimum (-32768) */
0x26, 0xff, 0x7f, /* Logical Maximum (32767) */
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x10, // REPORT_SIZE (16)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x32, // USAGE (Z)
0x16, 0x00, 0x80, /* Logical Minimum (-32768) */
0x26, 0xff, 0x7f, /* Logical Maximum (32767) */
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x10, // REPORT_SIZE (16)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM(Button 1)
0x29, 0x05, // USAGE_MAXIMUM(Button 5)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x03, // REPORT_COUNT (3)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x01, // INPUT (Cnst,Arr,Abs)
0xc0, // END_COLLECTION
];
pub fn report(s: super::PanelState) -> [u8; 5] {
[
s.throttle1 as u8, // throttle 0
(s.throttle1 >> 8) as u8,
s.throttle0 as u8, // throttle 1
(s.throttle0 >> 8) as u8,
s.sw,
]
}
pub struct HIDClass<'a, B: UsbBus> {
report_if: InterfaceNumber,
report_ep: EndpointIn<'a, B>,
}
impl<B: UsbBus> HIDClass<'_, B> {
/// Creates a new HIDClass with the provided UsbBus and max_packet_size in bytes. For
/// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
pub fn new(alloc: &UsbBusAllocator<B>) -> HIDClass<'_, B> {
HIDClass {
report_if: alloc.interface(),
report_ep: alloc.interrupt(8, 10),
}
}
pub fn write(&mut self, data: &[u8]) {
self.report_ep.write(data).ok();
}
}
impl<B: UsbBus> UsbClass<B> for HIDClass<'_, B> {
fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
writer.interface(
self.report_if,
USB_CLASS_HID,
USB_SUBCLASS_NONE,
USB_INTERFACE_MOUSE,
)?;
let descr_len: u16 = REPORT_DESCR.len() as u16;
writer.write(
0x21,
&[
0x01, // bcdHID
0x01, // bcdHID
0x00, // bContryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType
descr_len as u8, // wDescriptorLength
(descr_len >> 8) as u8, // wDescriptorLength
],
)?;
writer.endpoint(&self.report_ep)?;
Ok(())
}
fn control_in(&mut self, xfer: ControlIn<B>) {
let req = xfer.request();
if req.request_type == control::RequestType::Standard {
match (req.recipient, req.request) {
(control::Recipient::Interface, control::Request::GET_DESCRIPTOR) => {
let (dtype, _index) = req.descriptor_type_index();
if dtype == 0x21 {
// HID descriptor
cortex_m::asm::bkpt();
let descr_len: u16 = REPORT_DESCR.len() as u16;
// HID descriptor
let descr = &[
0x09, // length
0x21, // descriptor type
0x01, // bcdHID
0x01, // bcdHID
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType
descr_len as u8, // wDescriptorLength
(descr_len >> 8) as u8, // wDescriptorLength
];
xfer.accept_with(descr).ok();
return;
} else if dtype == 0x22 {
// Report descriptor
xfer.accept_with(REPORT_DESCR).ok();
return;
}
}
_ => {
return;
}
};
}
if !(req.request_type == control::RequestType::Class
&& req.recipient == control::Recipient::Interface
&& req.index == u8::from(self.report_if) as u16)
{
return;
}
match req.request {
REQ_GET_REPORT => {
// USB host requests for report
// I'm not sure what should we do here, so just send empty report
xfer.accept_with(&report(super::PanelState {
throttle0: 0,
throttle1: 0,
sw: 0,
}))
.ok();
}
_ => {
xfer.reject().ok();
}
}
}
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.report_if) as u16)
{
return;
}
xfer.reject().ok();
}
}
}
use hid::HIDClass;
const PERIOD: u32 = 80_000;
#[rtic::app(device = stm32f1xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
const APP: () = {
struct Resources {
usb_dev: UsbDevice<'static, UsbBusType>,
hid: HIDClass<'static, UsbBusType>,
adc1: adc::Adc<ADC1>,
th0: gpio::gpioa::PA1<gpio::Analog>,
th1: gpio::gpioa::PA2<gpio::Analog>,
sw0: gpio::gpioa::PA8<gpio::Input<gpio::PullUp>>,
sw1: gpio::gpioa::PA9<gpio::Input<gpio::PullUp>>,
sw2: gpio::gpioa::PA10<gpio::Input<gpio::PullUp>>,
sw3: gpio::gpiob::PB14<gpio::Input<gpio::PullUp>>,
sw4: gpio::gpiob::PB15<gpio::Input<gpio::PullUp>>,
}
#[init(schedule = [on_tick])]
fn init(mut cx: init::Context) -> init::LateResources {
static mut USB_BUS: Option<bus::UsbBusAllocator<UsbBusType>> = None;
cx.core.DCB.enable_trace();
DWT::unlock();
cx.core.DWT.enable_cycle_counter();
let mut flash = cx.device.FLASH.constrain();
let mut rcc = cx.device.RCC.constrain();
let clocks = rcc
.cfgr
.use_hse(8.mhz())
.sysclk(48.mhz())
.pclk1(24.mhz())
.adcclk(2.mhz())
.freeze(&mut flash.acr);
assert!(clocks.usbclk_valid());
let mut gpioa = cx.device.GPIOA.split