Keyboard matrix implementation for PedestalBox

Signed-off-by: fly <merspieler@alwaysdata.net>
This commit is contained in:
fly 2024-09-25 00:56:30 +02:00
parent 4a301af6ae
commit af5db5d657
3 changed files with 171 additions and 92 deletions

View file

@ -54,6 +54,10 @@ logicalValueRange = [0, 65535]
usageRange = ['Button', 'Button 1', 'Button 32'] usageRange = ['Button', 'Button 1', 'Button 32']
logicalValueRange = [0, 1] logicalValueRange = [0, 1]
[[applicationCollection.inputReport.variableItem]]
usageRange = ['Button', 'Button 1', 'Button 32']
logicalValueRange = [0, 1]
[[applicationCollection.outputReport]] [[applicationCollection.outputReport]]
[[applicationCollection.outputReport.variableItem]] [[applicationCollection.outputReport.variableItem]]

View file

@ -43,11 +43,15 @@ pub const CUSTOM_DESCRIPTOR: &[u8] = &[
0x19, 0x01, // UsageIdMin(Button 1[0x0001]) 0x19, 0x01, // UsageIdMin(Button 1[0x0001])
0x29, 0x20, // UsageIdMax(Button 32[0x0020]) 0x29, 0x20, // UsageIdMax(Button 32[0x0020])
0x25, 0x01, // LogicalMaximum(1) 0x25, 0x01, // LogicalMaximum(1)
0x95, 0x10, // ReportCount(16) 0x95, 0x20, // ReportCount(32)
0x75, 0x01, // ReportSize(1) 0x75, 0x01, // ReportSize(1)
0x81, 0x02, // Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField) 0x81, 0x02, // Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField)
0x19, 0x01, // UsageIdMin(Button 1[0x0001])
0x29, 0x20, // UsageIdMax(Button 32[0x0020])
0x81, 0x02, // Input(Data, Variable, Absolute, NoWrap, Linear, PreferredState, NoNullPosition, BitField)
0x05, 0x0E, // UsagePage(Haptics[0x000E]) 0x05, 0x0E, // UsagePage(Haptics[0x000E])
0x09, 0x21, // UsageId(Manual Trigger[0x0021]) 0x09, 0x21, // UsageId(Manual Trigger[0x0021])
0x09, 0x21, // UsageId(Manual Trigger[0x0021])
0x27, 0x80, 0xBB, 0x00, 0x00, // LogicalMaximum(48,000) 0x27, 0x80, 0xBB, 0x00, 0x00, // LogicalMaximum(48,000)
0x95, 0x02, // ReportCount(2) 0x95, 0x02, // ReportCount(2)
0x75, 0x10, // ReportSize(16) 0x75, 0x10, // ReportSize(16)
@ -62,7 +66,7 @@ pub const CUSTOM_DESCRIPTOR: &[u8] = &[
]; ];
#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)]
#[packed_struct(endian = "lsb", size_bytes = "27")] // MUST be <= 64 else we get problem cause InBytes64 or OutBytes64 #[packed_struct(endian = "lsb", size_bytes = "31")] // MUST be <= 64 else we get problem cause InBytes64 or OutBytes64
pub struct CustomInputReport { pub struct CustomInputReport {
#[packed_field] #[packed_field]
pub report_id: u8, pub report_id: u8,
@ -70,6 +74,8 @@ pub struct CustomInputReport {
pub axis: [u16; 11], pub axis: [u16; 11],
#[packed_field] #[packed_field]
pub buttons: u32, pub buttons: u32,
#[packed_field]
pub ecam_buttons: u32,
} }
#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Default, PackedStruct)]

View file

@ -49,23 +49,23 @@ macro_rules! define_output_states {
macro_rules! define_ecam_output_states_row { macro_rules! define_ecam_output_states_row {
($index:literal, $pin:ident, $ecam_row:ident, $io_pins:ident) => { ($index:literal, $pin:ident, $ecam_row:ident, $io_pins:ident) => {
if $ecam_row[$index] == 1 { if $ecam_row[$index] == 1 {
$io_pins.$pin.set_high(); $io_pins.$pin.set_high();
} }
else { else {
$io_pins.$pin.set_low(); $io_pins.$pin.set_low();
} }
}; };
} }
macro_rules! define_ecam_output_states_col { macro_rules! define_ecam_output_states_col {
($index:literal, $pin:ident, $ecam_col:ident, $io_pins:ident) => { ($index:literal, $pin:ident, $ecam_col:ident, $io_pins:ident) => {
if $ecam_col[$index] == 1 { if $ecam_col[$index] == 1 {
$io_pins.$pin.set_high(); $io_pins.$pin.set_high();
} }
else { else {
$io_pins.$pin.set_low(); $io_pins.$pin.set_low();
} }
}; };
} }
@ -131,7 +131,20 @@ struct MyPins {
pe9: Pin<'E', 9, Output<PushPull>>, // ECAM LEDs Row 3 pe9: Pin<'E', 9, Output<PushPull>>, // ECAM LEDs Row 3
pe13: Pin<'E', 13, Output<PushPull>>, // ECAM LEDs Row 2 pe13: Pin<'E', 13, Output<PushPull>>, // ECAM LEDs Row 2
// TODO ECAM matrix pins // ECAM matrix read row
pe12: Pin<'E', 12, Input<PullDown>>, // ECAM Keys Row 1
pe15: Pin<'E', 15, Input<PullDown>>, // ECAM Keys Row 2
pe11: Pin<'E', 11, Input<PullDown>>, // ECAM Keys Row 3
pe7: Pin<'E', 7, Input<PullDown>>, // ECAM Keys Row 4
// ECAM matrix column select
pd11: Pin<'D', 11, Output<PushPull>>, // ECAM Keys Column 1
pd12: Pin<'D', 12, Output<PushPull>>, // ECAM Keys Column 2
pe8: Pin<'E', 8, Output<PushPull>>, // ECAM Keys Column 3
pb2: Pin<'B', 2, Output<PushPull>>, // ECAM Keys Column 4
pe10: Pin<'E', 10, Output<PushPull>>, // ECAM Keys Column 5
pe14: Pin<'E', 14, Output<PushPull>>, // ECAM Keys Column 6
} }
#[derive(Pod)] #[derive(Pod)]
@ -295,6 +308,21 @@ fn main() -> ! {
pe4: gpioe.pe4.into_push_pull_output(&mut gpioe.crl), pe4: gpioe.pe4.into_push_pull_output(&mut gpioe.crl),
pe9: gpioe.pe9.into_push_pull_output(&mut gpioe.crh), pe9: gpioe.pe9.into_push_pull_output(&mut gpioe.crh),
pe13: gpioe.pe13.into_push_pull_output(&mut gpioe.crh), pe13: gpioe.pe13.into_push_pull_output(&mut gpioe.crh),
// ECAM matrix read row
pe12: gpioe.pe12.into_pull_down_input(&mut gpioe.crh),
pe15: gpioe.pe15.into_pull_down_input(&mut gpioe.crh),
pe11: gpioe.pe11.into_pull_down_input(&mut gpioe.crh),
pe7: gpioe.pe7.into_pull_down_input(&mut gpioe.crl),
// ECAM matrix column select
pd11: gpiod.pd11.into_push_pull_output(&mut gpiod.crh),
pd12: gpiod.pd12.into_push_pull_output(&mut gpiod.crh),
pe8: gpioe.pe8.into_push_pull_output(&mut gpioe.crh),
pb2: gpiob.pb2.into_push_pull_output(&mut gpiob.crl),
pe10: gpioe.pe10.into_push_pull_output(&mut gpioe.crh),
pe14: gpioe.pe14.into_push_pull_output(&mut gpioe.crh),
}; };
// ====================== PWM setup ================= // ====================== PWM setup =================
@ -311,10 +339,127 @@ fn main() -> ! {
let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz(); let mut timer = Timer::syst(cp.SYST, &clocks).counter_hz();
timer.start(1.kHz()).unwrap(); timer.start(1.kHz()).unwrap();
// ====================== Setup other vars ==========
let mut ecam_col_select: u8 = 0;
let mut ecam_buttons: u32 = 0; // stores the values of the keyboard matrix we can not read out right now
// ====================== Main loop ================= // ====================== Main loop =================
loop { loop {
block!(timer.wait()).unwrap(); block!(timer.wait()).unwrap();
let report = get_report(&mut io_pins, &mut adc1, &cal); // Generate report
// Read axis
let mut values: [u16; 11] = [0; 11];
values[0] = adc1.read(&mut io_pins.pa2).unwrap();
values[1] = adc1.read(&mut io_pins.pa3).unwrap();
values[2] = adc1.read(&mut io_pins.pa5).unwrap();
values[3] = adc1.read(&mut io_pins.pa6).unwrap();
values[4] = adc1.read(&mut io_pins.pa7).unwrap();
values[5] = adc1.read(&mut io_pins.pb0).unwrap();
values[6] = adc1.read(&mut io_pins.pb1).unwrap();
values[7] = adc1.read(&mut io_pins.pc0).unwrap();
values[8] = adc1.read(&mut io_pins.pc1).unwrap();
values[9] = adc1.read(&mut io_pins.pc2).unwrap();
values[10] = adc1.read(&mut io_pins.pc3).unwrap();
// Apply calibration to axis data
let mut values_norm: [u16; 11] = [0; 11];
let mut i = 0;
loop {
if values[i] < cal.data[i].min {
values_norm[i] = 0;
}
else if values[i] > cal.data[i].max {
values_norm[i] = CalibrationData::ADC_MAX;
}
else {
values_norm[i] = ((values[i] - cal.data[i].min) as f32 * cal.data[i].factor) as u16;
}
i += 1;
if i == values_norm.len() {
break;
}
}
// Buttons
let mut buttons: u32 = 0;
if io_pins.pa0.is_high() { buttons += 0x1; }
if io_pins.pa1.is_high() { buttons += 0x2; }
if io_pins.pa4.is_high() { buttons += 0x4; }
if io_pins.pa8.is_high() { buttons += 0x8; }
if io_pins.pa9.is_high() { buttons += 0x10; }
if io_pins.pa10.is_high() { buttons += 0x20; }
if io_pins.pb4.is_high() { buttons += 0x40; }
if io_pins.pb5.is_high() { buttons += 0x80; }
if io_pins.pb8.is_high() { buttons += 0x100; }
if io_pins.pb9.is_high() { buttons += 0x200; }
if io_pins.pc4.is_high() { buttons += 0x400; }
if io_pins.pc5.is_high() { buttons += 0x800; }
if io_pins.pc6.is_high() { buttons += 0x1000; }
if io_pins.pc9.is_high() { buttons += 0x0200; }
if io_pins.pc13.is_high() { buttons += 0x4000; }
if io_pins.pc14.is_high() { buttons += 0x8000; }
if io_pins.pc15.is_high() { buttons += 0x10000; }
if io_pins.pd1.is_high() { buttons += 0x20000; }
if io_pins.pd3.is_high() { buttons += 0x40000; }
if io_pins.pd4.is_high() { buttons += 0x80000; }
if io_pins.pd5.is_high() { buttons += 0x100000; }
if io_pins.pd6.is_high() { buttons += 0x200000; }
if io_pins.pd7.is_high() { buttons += 0x400000; }
if io_pins.pd13.is_high() { buttons += 0x800000; }
if io_pins.pd14.is_high() { buttons += 0x1000000; }
if io_pins.pd15.is_high() { buttons += 0x2000000; }
if io_pins.pe0.is_high() { buttons += 0x4000000; }
if io_pins.pe5.is_high() { buttons += 0x8000000; }
if io_pins.pe6.is_high() { buttons += 0x10000000; }
// ECAM Keyboard matrix
let mut ecam_buttons_read: u32 = 0;
if io_pins.pe12.is_high() { ecam_buttons_read += 0x1; }
if io_pins.pe15.is_high() { ecam_buttons_read += 0x2; }
if io_pins.pe11.is_high() { ecam_buttons_read += 0x4; }
if io_pins.pe7.is_high() { ecam_buttons_read += 0x8; }
ecam_buttons = ecam_buttons & (0xFFFFFFFF - (0xF << (ecam_col_select * 4)));
ecam_buttons += ecam_buttons_read << (ecam_col_select * 4);
// Pull the next column high for next time coming through in the main loop ~1ms
if ecam_col_select == 0 {
io_pins.pd11.set_high();
io_pins.pe14.set_low();
}
else if ecam_col_select == 1 {
io_pins.pd12.set_high();
io_pins.pd11.set_low();
}
else if ecam_col_select == 2 {
io_pins.pe8.set_high();
io_pins.pd12.set_low();
}
else if ecam_col_select == 3 {
io_pins.pb2.set_high();
io_pins.pe8.set_low();
}
else if ecam_col_select == 4 {
io_pins.pe10.set_high();
io_pins.pb2.set_low();
}
else if ecam_col_select == 5 {
io_pins.pe14.set_high();
io_pins.pe10.set_low();
}
ecam_col_select += 1;
if ecam_col_select >= 6 {
ecam_col_select = 0
}
let report = CustomInputReport {
report_id: 1,
axis: values_norm,
buttons,
ecam_buttons,
};
match consumer.device().write_report(&report) { match consumer.device().write_report(&report) {
Err(UsbHidError::WouldBlock) => {} Err(UsbHidError::WouldBlock) => {}
Err(UsbHidError::UsbError(usb_device::UsbError::BufferOverflow)) => { Err(UsbHidError::UsbError(usb_device::UsbError::BufferOverflow)) => {
@ -446,82 +591,6 @@ fn calculate_factor(min: u16, max: u16) -> f32 {
return CalibrationData::ADC_MAX as f32 / (CalibrationData::ADC_MAX - min - (CalibrationData::ADC_MAX - max)) as f32; return CalibrationData::ADC_MAX as f32 / (CalibrationData::ADC_MAX - min - (CalibrationData::ADC_MAX - max)) as f32;
} }
// Returns a CustomInputReport from the inputs given
fn get_report(pins: &mut MyPins, adc1: &mut adc::Adc<pac::ADC1>, cal: &Calibration) -> CustomInputReport {
// Read axis
let mut values: [u16; 11] = [0; 11];
values[0] = adc1.read(&mut pins.pa2).unwrap();
values[1] = adc1.read(&mut pins.pa3).unwrap();
values[2] = adc1.read(&mut pins.pa5).unwrap();
values[3] = adc1.read(&mut pins.pa6).unwrap();
values[4] = adc1.read(&mut pins.pa7).unwrap();
values[5] = adc1.read(&mut pins.pb0).unwrap();
values[6] = adc1.read(&mut pins.pb1).unwrap();
values[7] = adc1.read(&mut pins.pc0).unwrap();
values[8] = adc1.read(&mut pins.pc1).unwrap();
values[9] = adc1.read(&mut pins.pc2).unwrap();
values[10] = adc1.read(&mut pins.pc3).unwrap();
// Apply calibration to axis data
let mut values_norm: [u16; 11] = [0; 11];
let mut i = 0;
loop {
if values[i] < cal.data[i].min {
values_norm[i] = 0;
}
else if values[i] > cal.data[i].max {
values_norm[i] = CalibrationData::ADC_MAX;
}
else {
values_norm[i] = ((values[i] - cal.data[i].min) as f32 * cal.data[i].factor) as u16;
}
i += 1;
if i == values_norm.len() {
break;
}
}
// Buttons
let mut buttons: u32 = 0;
if pins.pa0.is_high() { buttons += 0x1; }
if pins.pa1.is_high() { buttons += 0x2; }
if pins.pa4.is_high() { buttons += 0x4; }
if pins.pa8.is_high() { buttons += 0x8; }
if pins.pa9.is_high() { buttons += 0x10; }
if pins.pa10.is_high() { buttons += 0x20; }
if pins.pb4.is_high() { buttons += 0x40; }
if pins.pb5.is_high() { buttons += 0x80; }
if pins.pb8.is_high() { buttons += 0x100; }
if pins.pb9.is_high() { buttons += 0x200; }
if pins.pc4.is_high() { buttons += 0x400; }
if pins.pc5.is_high() { buttons += 0x800; }
if pins.pc6.is_high() { buttons += 0x1000; }
if pins.pc9.is_high() { buttons += 0x0200; }
if pins.pc13.is_high() { buttons += 0x4000; }
if pins.pc14.is_high() { buttons += 0x8000; }
if pins.pc15.is_high() { buttons += 0x10000; }
if pins.pd1.is_high() { buttons += 0x20000; }
if pins.pd3.is_high() { buttons += 0x40000; }
if pins.pd4.is_high() { buttons += 0x80000; }
if pins.pd5.is_high() { buttons += 0x100000; }
if pins.pd6.is_high() { buttons += 0x200000; }
if pins.pd7.is_high() { buttons += 0x400000; }
if pins.pd13.is_high() { buttons += 0x800000; }
if pins.pd14.is_high() { buttons += 0x1000000; }
if pins.pd15.is_high() { buttons += 0x2000000; }
if pins.pe0.is_high() { buttons += 0x4000000; }
if pins.pe5.is_high() { buttons += 0x8000000; }
if pins.pe6.is_high() { buttons += 0x10000000; }
// ECAM Keyboard matrix
CustomInputReport {
report_id: 1,
axis: values_norm,
buttons,
}
}
// Save calibration to flash // Save calibration to flash
fn save_calibration(flash: &mut FlashWriter, cal: &Calibration) -> bool { fn save_calibration(flash: &mut FlashWriter, cal: &Calibration) -> bool {
let mut data: [u8; 1024] = [0; 1024]; let mut data: [u8; 1024] = [0; 1024];