2024-04-14 23:15:09 +00:00
|
|
|
#![deny(unsafe_code)]
|
|
|
|
#![no_main]
|
|
|
|
#![no_std]
|
|
|
|
|
2024-05-02 17:52:05 +00:00
|
|
|
// Silence certain clippy warnings
|
|
|
|
#![allow(non_upper_case_globals)]
|
|
|
|
#![allow(clippy::needless_late_init)]
|
|
|
|
|
2024-04-14 23:15:09 +00:00
|
|
|
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},
|
2024-05-03 19:45:25 +00:00
|
|
|
flash::{FlashWriter, FLASH_START, FlashSize, SectorSize},
|
2024-05-02 17:52:05 +00:00
|
|
|
usb::{Peripheral, UsbBus},
|
2024-04-14 23:15:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
use usb_device::prelude::*;
|
|
|
|
use usbd_human_interface_device::prelude::*;
|
|
|
|
|
2024-05-02 17:52:05 +00:00
|
|
|
use crate::device::{CustomConfig, CustomInputReport};
|
|
|
|
use bytemuck::{bytes_of, try_from_bytes, Pod, Zeroable};
|
|
|
|
|
|
|
|
// Set layout version
|
|
|
|
const FLASH_LAYOUT_VERSION: u16 = 0;
|
2024-04-14 23:15:09 +00:00
|
|
|
|
|
|
|
struct MyPins {
|
|
|
|
pa1: Pin<'A', 1, Analog>,
|
|
|
|
pa2: Pin<'A', 2, Analog>,
|
|
|
|
}
|
|
|
|
|
2024-05-02 17:52:05 +00:00
|
|
|
#[derive(Pod)]
|
|
|
|
#[repr(C)]
|
|
|
|
#[derive(Copy)]
|
|
|
|
#[derive(Clone)]
|
|
|
|
#[derive(Zeroable)]
|
2024-04-30 20:06:07 +00:00
|
|
|
struct CalibrationData {
|
|
|
|
min: u16,
|
|
|
|
max: u16,
|
2024-05-02 17:52:05 +00:00
|
|
|
factor: f32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CalibrationData {
|
|
|
|
const ADC_MAX: u16 = 4095;
|
|
|
|
const _dummy: () = {
|
|
|
|
let size = core::mem::size_of::<CalibrationData>();
|
|
|
|
assert!(size <= 1021, "CalibrationData too big for flash size!");
|
|
|
|
};
|
|
|
|
fn new (min: u16, max: u16) -> CalibrationData {
|
|
|
|
return CalibrationData {min, max, factor: calculate_factor(min, max)};
|
|
|
|
}
|
2024-04-30 20:06:07 +00:00
|
|
|
}
|
|
|
|
|
2024-05-02 17:52:05 +00:00
|
|
|
#[derive(Pod)]
|
|
|
|
#[repr(C)]
|
|
|
|
#[derive(Copy)]
|
|
|
|
#[derive(Clone)]
|
|
|
|
#[derive(Zeroable)]
|
2024-04-30 20:06:07 +00:00
|
|
|
struct Calibration {
|
|
|
|
integ_lt: CalibrationData,
|
2024-05-02 17:52:05 +00:00
|
|
|
// flood_lt: CalibrationData,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Calibration {
|
|
|
|
fn new () -> Calibration {
|
|
|
|
return Calibration {
|
|
|
|
integ_lt: CalibrationData::new(0, CalibrationData::ADC_MAX),
|
|
|
|
// flood_lt: CalibrationData::new(0, CalibrationData::ADC_MAX),
|
|
|
|
};
|
|
|
|
}
|
2024-04-30 20:06:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-14 23:15:09 +00:00
|
|
|
#[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 =================
|
|
|
|
let mut adc1 = adc::Adc::adc1(p.ADC1, clocks);
|
|
|
|
|
2024-04-30 20:06:07 +00:00
|
|
|
// ====================== Calibration ===============
|
2024-05-02 17:52:05 +00:00
|
|
|
let mut cal = load_calibration();
|
2024-04-30 20:06:07 +00:00
|
|
|
|
2024-04-14 23:15:09 +00:00
|
|
|
// ====================== Pin setup =================
|
|
|
|
let mut input_pins = MyPins {
|
|
|
|
pa1: gpioa.pa1.into_analog(&mut gpioa.crl),
|
|
|
|
pa2: gpioa.pa2.into_analog(&mut gpioa.crl),
|
|
|
|
};
|
|
|
|
|
2024-04-30 20:06:07 +00:00
|
|
|
let mut last = get_report(&mut input_pins, &mut adc1, &cal);
|
2024-04-14 23:15:09 +00:00
|
|
|
|
|
|
|
// ====================== 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::<Tim2NoRemap, _, _>(c1, &mut afio.mapr, 1.kHz(), &clocks);
|
|
|
|
pwm.enable(Channel::C1);
|
2024-05-02 17:52:05 +00:00
|
|
|
let pwm_max = pwm.get_max_duty(); //48000 in our case
|
|
|
|
|
|
|
|
// ====================== Calibration things ========
|
|
|
|
let mut calibration_active = false;
|
|
|
|
let mut calibration_min_done = false;
|
2024-04-14 23:15:09 +00:00
|
|
|
|
2024-05-03 19:45:25 +00:00
|
|
|
// ====================== Calibration things ========
|
|
|
|
let mut flash_writer = flash.writer(SectorSize::Sz1K, FlashSize::Sz64K);
|
|
|
|
|
2024-04-14 23:15:09 +00:00
|
|
|
// ====================== Main loop =================
|
|
|
|
loop {
|
2024-04-30 20:06:07 +00:00
|
|
|
let report = get_report(&mut input_pins, &mut adc1, &cal);
|
2024-04-14 23:15:09 +00:00
|
|
|
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) => {
|
2024-05-02 17:52:05 +00:00
|
|
|
// Set backlight brightness
|
2024-04-14 23:15:09 +00:00
|
|
|
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);
|
2024-05-02 17:52:05 +00:00
|
|
|
|
|
|
|
// Check generic input field
|
|
|
|
// Calibration bit
|
|
|
|
if output.generic & 0x1 == 0x1 {
|
|
|
|
calibration_active = true;
|
|
|
|
if !calibration_min_done && output.generic & 0x2 == 0x2 {
|
|
|
|
cal.integ_lt.min = adc1.read(&mut input_pins.pa1).unwrap();
|
|
|
|
calibration_min_done = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if calibration_active {
|
|
|
|
let max = adc1.read(&mut input_pins.pa1).unwrap();
|
|
|
|
if max > cal.integ_lt.min {
|
|
|
|
cal.integ_lt.max = max;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cal.integ_lt.max = CalibrationData::ADC_MAX;
|
|
|
|
}
|
|
|
|
cal.integ_lt.factor = calculate_factor(cal.integ_lt.min, cal.integ_lt.max);
|
2024-05-03 19:45:25 +00:00
|
|
|
save_calibration(&mut flash_writer, &cal);
|
|
|
|
pwm.set_duty(Channel::C1, pwm_max);
|
2024-05-02 17:52:05 +00:00
|
|
|
}
|
|
|
|
calibration_active = false;
|
|
|
|
calibration_min_done = false;
|
|
|
|
}
|
2024-04-14 23:15:09 +00:00
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
core::panic!("Failed to write consumer report: {:?}", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-02 17:52:05 +00:00
|
|
|
// Calculate factor from min and max
|
|
|
|
fn calculate_factor(min: u16, max: u16) -> f32 {
|
2024-05-03 19:45:25 +00:00
|
|
|
return CalibrationData::ADC_MAX as f32 / (CalibrationData::ADC_MAX - min - (CalibrationData::ADC_MAX - max)) as f32;
|
2024-05-02 17:52:05 +00:00
|
|
|
}
|
|
|
|
|
2024-04-14 23:15:09 +00:00
|
|
|
// Returns a CustomInputReport from the inputs given
|
2024-04-30 20:06:07 +00:00
|
|
|
fn get_report(pins: &mut MyPins, adc1: &mut adc::Adc<pac::ADC1>, cal: &Calibration) -> CustomInputReport {
|
2024-04-14 23:15:09 +00:00
|
|
|
let integ_lt: u16 = adc1.read(&mut pins.pa1).unwrap();
|
|
|
|
let flood_lt: u16 = adc1.read(&mut pins.pa2).unwrap();
|
|
|
|
let buttons: u16 = 0;
|
|
|
|
|
2024-04-30 20:06:07 +00:00
|
|
|
let integ_lt_norm: u16;
|
|
|
|
if integ_lt < cal.integ_lt.min {
|
|
|
|
integ_lt_norm = 0;
|
|
|
|
}
|
|
|
|
else if integ_lt > cal.integ_lt.max {
|
2024-05-02 17:52:05 +00:00
|
|
|
integ_lt_norm = CalibrationData::ADC_MAX;
|
2024-04-30 20:06:07 +00:00
|
|
|
}
|
|
|
|
else {
|
2024-05-02 17:52:05 +00:00
|
|
|
integ_lt_norm = ((integ_lt - cal.integ_lt.min) as f32 * cal.integ_lt.factor) as u16;
|
2024-04-30 20:06:07 +00:00
|
|
|
}
|
|
|
|
|
2024-04-14 23:15:09 +00:00
|
|
|
CustomInputReport {
|
2024-05-02 17:52:05 +00:00
|
|
|
x: integ_lt_norm,
|
|
|
|
y: flood_lt,
|
2024-04-14 23:15:09 +00:00
|
|
|
buttons,
|
|
|
|
}
|
|
|
|
}
|
2024-04-30 20:06:07 +00:00
|
|
|
|
2024-05-02 17:52:05 +00:00
|
|
|
// Save calibration to flash
|
|
|
|
fn save_calibration(flash: &mut FlashWriter, cal: &Calibration) -> bool {
|
|
|
|
let mut data: [u8; 1024] = [0; 1024];
|
|
|
|
|
|
|
|
let encoded_layout_version = bytes_of(&FLASH_LAYOUT_VERSION);
|
|
|
|
data[0..2].copy_from_slice(encoded_layout_version);
|
|
|
|
|
|
|
|
data[2] = 1; // Calibration available bit
|
|
|
|
|
|
|
|
let encoded_calibration_data = bytes_of(cal);
|
|
|
|
data[3..][..encoded_calibration_data.len()].copy_from_slice(encoded_calibration_data);
|
|
|
|
|
2024-05-03 19:45:25 +00:00
|
|
|
let test = flash.erase(FLASH_START + 64512, 1024);
|
2024-05-02 17:52:05 +00:00
|
|
|
match flash.write(FLASH_START + 64512, &data) {
|
|
|
|
Ok(_ret) => return true,
|
|
|
|
Err(_e) => return false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load calibration to flash
|
|
|
|
fn load_calibration() -> Calibration {
|
2024-05-03 19:45:25 +00:00
|
|
|
let cal = Calibration::new();
|
2024-05-02 17:52:05 +00:00
|
|
|
// TODO reject loading if version is off or no calibration data found
|
|
|
|
// TODO return calibration data
|
|
|
|
return cal;
|
2024-04-30 20:06:07 +00:00
|
|
|
}
|