#![deny(unsafe_code)] #![no_main] #![no_std] mod device; use panic_halt as _; use cortex_m::asm::delay; use cortex_m_rt::entry; use stm32f1xx_hal::{ adc, gpio::{Analog, Pin}, pac, prelude::*, timer::{Channel, Tim2NoRemap}, }; use stm32f1xx_hal::usb::{Peripheral, UsbBus}; use usb_device::prelude::*; use usbd_human_interface_device::prelude::*; use crate::device::{CustomConfig, CustomInputReport, CustomOutputReport}; use core::cell::OnceCell; struct MyPins { pa1: Pin<'A', 1, Analog>, pa2: Pin<'A', 2, Analog>, } struct CalibrationData { min: u16, max: u16, factor: OnceCell, } struct Calibration { integ_lt: CalibrationData, flood_lt: CalibrationData, } #[entry] fn main() -> ! { // ====================== general setup ================= // Acquire peripherals // let cp = cortex_m::Peripherals::take().unwrap(); let p = pac::Peripherals::take().unwrap(); let mut flash = p.FLASH.constrain(); let rcc = p.RCC.constrain(); // Setup GPIOA let mut gpioa = p.GPIOA.split(); // configure clock let clocks = rcc .cfgr .use_hse(16.MHz()) .sysclk(48.MHz()) .pclk1(24.MHz()) .freeze(&mut flash.acr); // ====================== USB setup ================= assert!(clocks.usbclk_valid()); let mut usb_dp = gpioa.pa12.into_push_pull_output(&mut gpioa.crh); usb_dp.set_low(); delay(clocks.sysclk().raw() / 100); let usb = Peripheral { usb: p.USB, pin_dm: gpioa.pa11, pin_dp: usb_dp.into_floating_input(&mut gpioa.crh), }; let usb_bus = UsbBus::new(usb); let mut consumer = UsbHidClassBuilder::new() .add_device(CustomConfig::default()) .build(&usb_bus); let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd)) .manufacturer("FLC Meow") .product("Pedestal box") .serial_number("01189998819991197253") .build(); // ====================== ADC setup ================= // Setup ADC let mut adc1 = adc::Adc::adc1(p.ADC1, clocks); // ====================== Calibration =============== let cal = Calibration { integ_lt: CalibrationData {min: 100, max: 4000, factor: OnceCell::new()}, flood_lt: CalibrationData {min: 0, max: 0, factor: OnceCell::new()}, }; // ====================== Pin setup ================= let mut input_pins = MyPins { pa1: gpioa.pa1.into_analog(&mut gpioa.crl), pa2: gpioa.pa2.into_analog(&mut gpioa.crl), }; let mut last = get_report(&mut input_pins, &mut adc1, &cal); // ====================== PWM setup ================= let mut afio = p.AFIO.constrain(); let c1 = gpioa.pa0.into_alternate_push_pull(&mut gpioa.crl); let mut pwm = p .TIM2 .pwm_hz::(c1, &mut afio.mapr, 1.kHz(), &clocks); pwm.enable(Channel::C1); let pwm_max = pwm.get_max_duty() as u16; //48000 in our case // ====================== Main loop ================= loop { let report = get_report(&mut input_pins, &mut adc1, &cal); if report != last { match consumer.device().write_report(&report) { Err(UsbHidError::WouldBlock) => {} Ok(_) => { last = report; } Err(e) => { core::panic!("Failed to write consumer report: {:?}", e) } } } if usb_dev.poll(&mut [&mut consumer]) { match consumer.device().read_report() { Err(UsbHidError::WouldBlock) => {} Ok(output) => { let pwm_val: u16; if output.integ_lt > pwm_max { pwm_val = pwm_max; } else { pwm_val = output.integ_lt; } pwm.set_duty(Channel::C1, pwm_val); } Err(e) => { core::panic!("Failed to write consumer report: {:?}", e) } } } } } // Returns a CustomInputReport from the inputs given fn get_report(pins: &mut MyPins, adc1: &mut adc::Adc, cal: &Calibration) -> CustomInputReport { let integ_lt: u16 = adc1.read(&mut pins.pa1).unwrap(); let flood_lt: u16 = adc1.read(&mut pins.pa2).unwrap(); let buttons: u16 = 0; let integ_lt_norm: u16; if integ_lt < cal.integ_lt.min { integ_lt_norm = 0; } else if integ_lt > cal.integ_lt.max { integ_lt_norm = 4095; } else { let factor: f32 = *cal.integ_lt.factor.get_or_init(|| cal.integ_lt.get_scale_factor()); integ_lt_norm = ((integ_lt - cal.integ_lt.min) as f32 * factor) as u16; } CustomInputReport { x: integ_lt_norm.into(), y: flood_lt.into(), buttons, } } impl CalibrationData { const ADC_MAX: u16 = 4095; fn get_scale_factor (&self) -> f32 { return (Self::ADC_MAX / (Self::ADC_MAX - self.min - (Self::ADC_MAX - self.max))) as f32; } }