1
0
Fork 0

Compare commits

...

8 commits

Author SHA1 Message Date
fly
d7bdcb1a3f Make LEDs work with full resolution
Signed-off-by: fly <merspieler@alwaysdata.com>
2024-04-12 01:02:59 +02:00
fly
43bccaf380 Working LED control!
Signed-off-by: fly <merspieler@alwaysdata.com>
2024-04-11 03:45:24 +02:00
fly
0bdb9ab4ec Works with returning 12 bit as expected
Signed-off-by: fly <merspieler@alwaysdata.com>
2024-04-11 03:20:55 +02:00
fly
7bdc627898 Works at least when making it to be 16 bit
Signed-off-by: fly <merspieler@alwaysdata.com>
2024-04-11 02:55:35 +02:00
fly
4a0cdccdb5 Make the hidtools scrip print out the thing in the way we want it
Signed-off-by: fly <merspieler@alwaysdata.com>
2024-04-11 02:33:09 +02:00
fly
e8774ca450 Meow
Signed-off-by: fly <merspieler@alwaysdata.com>
2024-04-11 02:31:40 +02:00
fly
e0449c9ac8 Meow
Signed-off-by: fly <merspieler@alwaysdata.com>
2024-04-06 00:10:13 +02:00
fly
2c7db2f6de On device LED controls reactivated
Signed-off-by: fly <merspieler@alwaysdata.com>
2024-03-29 15:46:09 +01:00
6 changed files with 221 additions and 36 deletions

12
firmware/Cargo.lock generated
View file

@ -126,7 +126,9 @@ dependencies = [
"cortex-m",
"cortex-m-rt",
"embedded-hal",
"fugit",
"nb 1.1.0",
"packed_struct",
"panic-halt",
"panic-semihosting",
"ryu",
@ -160,7 +162,7 @@ checksum = "b0fa992f1656e1707946bbba340ad244f0814009ef8c0118eb7b658395f19a2e"
dependencies = [
"frunk_proc_macro_helpers",
"quote",
"syn 2.0.53",
"syn 2.0.55",
]
[[package]]
@ -172,7 +174,7 @@ dependencies = [
"frunk_core",
"proc-macro2",
"quote",
"syn 2.0.53",
"syn 2.0.55",
]
[[package]]
@ -257,7 +259,7 @@ checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
"syn 2.0.55",
]
[[package]]
@ -419,9 +421,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.53"
version = "2.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0"
dependencies = [
"proc-macro2",
"quote",

View file

@ -18,6 +18,8 @@ usbd-serial = "0.1.1"
ryu = "1.0.16"
panic-semihosting = "0.6.0"
usbd-human-interface-device = "0.4.5"
packed_struct = { version = "0.10.1", default-features = false }
fugit = "0.3.7"
[dependencies.stm32f1xx-hal]
version = "0.10.0"

17
firmware/descriptor.wara Normal file
View file

@ -0,0 +1,17 @@
[[applicationCollection]]
usage = ['Generic Desktop', 'Joystick']
[[applicationCollection.inputReport]]
[[applicationCollection.inputReport.physicalCollection]]
usage = ['Generic Desktop', 'Pointer']
[[applicationCollection.inputReport.physicalCollection.variableItem]]
usage = ['Generic Desktop', 'X']
logicalValueRange = [0, 65535]
[[applicationCollection.outputReport]]
[[applicationCollection.outputReport.variableItem]]
usage = ['Haptics', 'Manual Trigger']
logicalValueRange = [0, 255]

3
firmware/hidtools.sh Executable file
View file

@ -0,0 +1,3 @@
#! /usr/bin/env bash
nix run github:feathecutie/hidtools -- -s descriptor.wara
cat descriptor.h |grep " 0x"|grep -v "ReportId"

138
firmware/src/device.rs Normal file
View file

@ -0,0 +1,138 @@
use core::default::Default;
use fugit::ExtU32;
use packed_struct::prelude::*;
use usb_device::bus::UsbBus;
use usb_device::class_prelude::UsbBusAllocator;
use usbd_human_interface_device::{
descriptor::InterfaceProtocol,
device::DeviceClass,
interface::{
InBytes8, Interface, InterfaceBuilder, InterfaceConfig, OutBytes8, ReportSingle,
UsbAllocatable,
},
UsbHidError,
};
// Generated using Waratah
#[rustfmt::skip]
pub const CUSTOM_DESCRIPTOR: &[u8] = &[
0x05, 0x01, // UsagePage(Generic Desktop[0x0001])
0x09, 0x04, // UsageId(Joystick[0x0004])
0xA1, 0x01, // Collection(Application)
0x09, 0x01, // UsageId(Pointer[0x0001])
0xA1, 0x00, // Collection(Physical)
0x09, 0x30, // UsageId(X[0x0030])
0x09, 0x32, // UsageId(Z[0x0032])
0x15, 0x00, // LogicalMinimum(0)
0x26, 0xFF, 0x0F, // LogicalMaximum(4,095)
0x95, 0x02, // ReportCount(2)
0x75, 0x10, // ReportSize(16)
0x81, 0x02, // Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField)
0xC0, // EndCollection()
0x05, 0x09, // UsagePage(Button[0x0009])
0x19, 0x01, // UsageIdMin(Button 1[0x0001])
0x29, 0x10, // UsageIdMax(Button 16[0x0010])
0x25, 0x01, // LogicalMaximum(1)
0x95, 0x10, // ReportCount(16)
0x75, 0x01, // ReportSize(1)
0x81, 0x02, // Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField)
0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x21, // UsageId(Manual Trigger[0x0021])
0x27, 0x80, 0xBB, 0x00, 0x00, // LogicalMaximum(48,000)
0x95, 0x01, // ReportCount(1)
0x75, 0x10, // ReportSize(16)
0x91, 0x02, // Output(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, NonVolatile, BitField)
0xC0, // EndCollection()
];
#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)]
#[packed_struct(endian = "lsb", size_bytes = "6")]
pub struct CustomInputReport {
#[packed_field]
pub x: u16,
#[packed_field]
pub y: u16,
#[packed_field]
pub buttons: u16,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)]
#[packed_struct(endian = "lsb", size_bytes = "2")]
pub struct CustomOutputReport {
#[packed_field]
pub int: u16,
}
pub struct CustomDevice<'a, B: UsbBus> {
interface: Interface<'a, B, InBytes8, OutBytes8, ReportSingle>,
}
impl<'a, B: UsbBus> CustomDevice<'a, B> {
pub fn write_report(&mut self, report: &CustomInputReport) -> Result<(), UsbHidError> {
let data = report.pack().map_err(|_| UsbHidError::SerializationError)?;
self.interface
.write_report(&data)
.map(|_| ())
.map_err(UsbHidError::from)
}
pub fn read_report(&mut self) -> Result<CustomOutputReport, UsbHidError> {
let mut data = [0, 0];
self.interface
.read_report(&mut data[..])
.map(|_| CustomOutputReport::unpack(&data).unwrap())
.map_err(UsbHidError::from)
}
}
impl<'a, B: UsbBus> DeviceClass<'a> for CustomDevice<'a, B> {
type I = Interface<'a, B, InBytes8, OutBytes8, ReportSingle>;
fn interface(&mut self) -> &mut Self::I {
&mut self.interface
}
fn reset(&mut self) {}
fn tick(&mut self) -> Result<(), UsbHidError> {
Ok(())
}
}
pub struct CustomConfig<'a> {
interface: InterfaceConfig<'a, InBytes8, OutBytes8, ReportSingle>,
}
impl<'a> Default for CustomConfig<'a> {
#[must_use]
fn default() -> Self {
Self::new(
InterfaceBuilder::new(CUSTOM_DESCRIPTOR)
.unwrap()
.boot_device(InterfaceProtocol::None)
.description(" CustomDevice")
.in_endpoint(10.millis())
.unwrap()
.with_out_endpoint(10.millis())
.unwrap()
.build(),
)
}
}
impl<'a> CustomConfig<'a> {
#[must_use]
pub fn new(interface: InterfaceConfig<'a, InBytes8, OutBytes8, ReportSingle>) -> Self {
Self { interface }
}
}
impl<'a, B: UsbBus + 'a> UsbAllocatable<'a, B> for CustomConfig<'a> {
type Allocated = CustomDevice<'a, B>;
fn allocate(self, usb_alloc: &'a UsbBusAllocator<B>) -> Self::Allocated {
Self::Allocated {
interface: Interface::new(usb_alloc, self.interface),
}
}
}

View file

@ -2,26 +2,36 @@
#![no_main]
#![no_std]
mod device;
use panic_halt as _;
//use nb::block;
use cortex_m_rt::entry;
use cortex_m::asm::delay;
use stm32f1xx_hal::{adc, pac, prelude::*, timer::{Channel, Tim2NoRemap}, gpio::{Analog, Pin}};
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::device::joystick::JoystickReport;
use usbd_human_interface_device::prelude::*;
struct MyPins { pa1: Pin<'A', 1, Analog>, pa2: Pin<'A', 2, Analog> }
use crate::device::{CustomConfig, CustomInputReport, CustomOutputReport};
struct MyPins {
pa1: Pin<'A', 1, Analog>,
pa2: Pin<'A', 2, Analog>,
}
#[entry]
fn main() -> ! {
// ====================== general setup =================
// Acquire peripherals
// let cp = cortex_m::Peripherals::take().unwrap();
// let cp = cortex_m::Peripherals::take().unwrap();
let p = pac::Peripherals::take().unwrap();
let mut flash = p.FLASH.constrain();
let rcc = p.RCC.constrain();
@ -36,7 +46,7 @@ fn main() -> ! {
.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);
@ -51,7 +61,7 @@ fn main() -> ! {
let usb_bus = UsbBus::new(usb);
let mut consumer = UsbHidClassBuilder::new()
.add_device(usbd_human_interface_device::device::joystick::JoystickConfig::default())
.add_device(CustomConfig::default())
.build(&usb_bus);
let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
@ -67,7 +77,7 @@ fn main() -> ! {
// ====================== Pin setup =================
let mut input_pins = MyPins {
pa1: gpioa.pa1.into_analog(&mut gpioa.crl),
pa2: gpioa.pa2.into_analog(&mut gpioa.crl)
pa2: gpioa.pa2.into_analog(&mut gpioa.crl),
};
let mut last = get_report(&mut input_pins, &mut adc1);
@ -75,10 +85,13 @@ fn main() -> ! {
// ====================== 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);
let mut pwm = p
.TIM2
.pwm_hz::<Tim2NoRemap, _, _>(c1, &mut afio.mapr, 1.kHz(), &clocks);
pwm.enable(Channel::C1);
// let pwm_max = pwm.get_max_duty() as u16; //48000 in our case
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);
if report != last {
@ -93,28 +106,38 @@ fn main() -> ! {
}
}
if usb_dev.poll(&mut [&mut consumer]) {}
if usb_dev.poll(&mut [&mut consumer]) {
match consumer.device().read_report() {
Err(UsbHidError::WouldBlock) => {}
Ok(output) => {
let pwm_val: u16;
if output.int > pwm_max {
pwm_val = pwm_max;
}
else {
pwm_val = output.int;
}
pwm.set_duty(Channel::C1, pwm_val);
}
Err(e) => {
core::panic!("Failed to write consumer report: {:?}", e)
}
}
}
// TODO get value and set PWM
//pwm.set_duty(Channel::C1, pwm_duty);
// // Get data from pots
// let data: u16 = adc1.read(&mut ch0).unwrap();
// let mut pwm_val = data as f32 / 0xfff as f32;
//
// let mut outBuf = ryu::Buffer::new();
// let mut ret = outBuf.format(pwm_val).as_bytes();
}
}
fn get_report(
pins: &mut MyPins,
adc1: &mut adc::Adc<pac::ADC1>,
) -> JoystickReport {
let integLT: u16 = adc1.read(&mut pins.pa1).unwrap();
let floodLT: u16 = adc1.read(&mut pins.pa2).unwrap();
let buttons: u8 = 0;
// Returns a CustomInputReport from the inputs given
fn get_report(pins: &mut MyPins, adc1: &mut adc::Adc<pac::ADC1>) -> 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 report = JoystickReport {x: (integLT / 16) as i8, y: (floodLT / 16) as i8, buttons};
report
CustomInputReport {
x: integ_lt.into(),
y: flood_lt.into(),
buttons,
}
}