Prepare for orbital communication.

This commit is contained in:
4lDO2
2020-02-09 11:12:18 +01:00
parent 1013daf606
commit ae76f57162
4 changed files with 224 additions and 26 deletions
Generated
+1
View File
@@ -1328,6 +1328,7 @@ name = "usbhidd"
version = "0.1.0"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
"ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"xhcid 0.1.0",
]
+1
View File
@@ -9,5 +9,6 @@ license = "MIT"
[dependencies]
bitflags = "1.2"
orbclient = "0.3.27"
ux = "0.1"
xhcid = { path = "../xhcid" }
+190 -25
View File
@@ -1,18 +1,78 @@
use std::env;
use std::fs::File;
use bitflags::bitflags;
use orbclient::KeyEvent as OrbKeyEvent;
use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle};
mod report_desc;
mod reqs;
mod usage_tables;
use report_desc::{MainCollectionFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY};
use report_desc::{LocalItemsState, MainCollectionFlags, MainItem, MainItemFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY};
use reqs::ReportTy;
fn div_round_up(num: u32, denom: u32) -> u32 {
if num % denom == 0 { num / denom } else { num / denom + 1 }
}
bitflags! {
pub struct ModifierKeys: u8 {
const LEFT_CTRL = 1 << 0;
const LEFT_SHIFT = 1 << 1;
const LEFT_ALT = 1 << 2;
const LEFT_META = 1 << 3;
const RIGHT_CTRL = 1 << 4;
const RIGHT_SHIFT = 1 << 5;
const RIGHT_ALT = 1 << 6;
const RIGHT_META = 1 << 7;
}
}
struct BinaryView<'a> {
data: &'a [u8],
offset: usize,
len: usize,
}
impl<'a> BinaryView<'a> {
pub fn new(data: &'a [u8], offset: usize, len: usize) -> Self {
Self {
data,
offset,
len,
}
}
pub fn get(&self, bit_index: usize) -> Option<bool> {
let bit_index = self.offset + bit_index;
if bit_index >= self.offset + self.len { return None }
let byte_index = bit_index / 8;
let bits_from_first = bit_index % 8;
let byte = self.data.get(byte_index)?;
Some(byte & (1 << bits_from_first) != 0)
}
pub fn read_u8(&self, bit_index: usize) -> Option<u8> {
let bit_index = self.offset + bit_index;
if bit_index >= self.offset + self.len { return None }
let first = bit_index / 8;
let bits_from_first = bit_index % 8;
let first_byte = self.data.get(first)?;
let lo = first_byte >> bits_from_first;
let hi = if bits_from_first > 0 {
let hi = self.data.get(first + 1)? & ((1 << bits_from_first) - 1);
let bits_to_next = 8 - bits_from_first;
hi << bits_to_next
} else { 0 };
Some(lo | hi)
}
}
fn main() {
let mut args = env::args().skip(1);
@@ -62,56 +122,161 @@ fn main() {
handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0 }).expect("Failed to configure endpoints");
let (mut state, mut stack) = (GlobalItemsState::default(), Vec::new());
let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new());
let (_, application_collection) = report_desc.iter().inspect(|item: &&ReportIterItem| if let ReportIterItem::Item(ref item) = item {
report_desc::update_state(&mut state, &mut stack, item).unwrap()
}).filter_map(ReportIterItem::as_collection).find(|&(n, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection");
let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem|
match item {
&ReportIterItem::Item(ref item) => {
report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap();
report_desc::update_local_state(&mut local_state, item);
None
}
&ReportIterItem::Collection(n, ref collection) => {
let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default());
Some((n, collection, global_state, lc_state))
}
}
).find(|&(n, _, _, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection");
// Get all main items, and their global item options.
{
let items = application_collection.iter().filter_map(ReportIterItem::as_item).filter_map(|item| match item {
ReportItem::Global(_) => {
report_desc::update_state(&mut state, &mut stack, item).unwrap();
report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap();
None
}
ReportItem::Main(m) => Some((state, m)),
ReportItem::Local(_) => None,
ReportItem::Main(m) => {
let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default());
Some((global_state, lc_state, m))
}
ReportItem::Local(_) => {
report_desc::update_local_state(&mut local_state, item);
None
},
});
let total_length = items.filter_map(|(state, item)| {
let report_size = match state.report_size {
let mut bit_offset = 0;
let inputs = items.filter_map(|(global_state, local_state, item)| {
let report_size = match global_state.report_size {
Some(s) => s,
None => return None,
};
let report_count = match state.report_count {
let report_count = match global_state.report_count {
Some(c) => c,
None => return None,
};
let bit_length = report_size * report_count;
if item.report_ty() != Some(ReportTy::Input) {
if global_state.usage_page != Some(0x7) {
return None;
}
Some(bit_length)
}).sum();
let length = div_round_up(total_length, 8);
let bit_length = report_size * report_count;
let mut report_buffer = vec! [0u8; length as usize];
let offset = bit_offset;
bit_offset += bit_length;
if let &MainItem::Input(flags) = item {
Some((bit_length, offset, global_state, local_state, MainItemFlags::from_bits_truncate(flags)))
} else {
None
}
}).collect::<Vec<_>>();
let total_bit_length = inputs.iter().map(|(bit_length, _, _, _, _)| bit_length).sum();
let total_byte_length = div_round_up(total_bit_length, 8);
let mut report_buffer = vec! [0u8; total_byte_length as usize];
let mut last_buffer = report_buffer.clone();
let report_ty = ReportTy::Input;
let report_id = 0;
let orbital_socket = File::open("display:input").expect("Failed to open orbital input socket");
let mut pressed_keys = vec! [];
let mut last_pressed_keys = pressed_keys.clone();
let mut modifier_keys = ModifierKeys::empty();
let mut last_modifier_keys = modifier_keys;
loop {
std::thread::sleep(std::time::Duration::from_millis(10));
std::mem::swap(&mut report_buffer, &mut last_buffer);
reqs::get_report(&handle, report_ty, report_id, interface_num, &mut report_buffer).expect("Failed to get report");
if report_buffer != last_buffer {
for byte in &report_buffer {
print!("{:#0x} ", byte);
}
println!();
if report_buffer == last_buffer {
continue
}
std::thread::sleep(std::time::Duration::from_millis(10))
for &(bit_length, bit_offset, global_state, local_state, input) in &inputs {
let report_size = global_state.report_size.unwrap();
let report_count = global_state.report_count.unwrap();
if input.contains(MainItemFlags::VARIABLE) {
// variable
//assert_eq!(state.logical_max.unwrap() - state.logical_min.unwrap(), report_count, "modifiers don't map");
let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize);
// PRETTYFYME
if report_count == 8 && report_size == 1 && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) {
std::mem::swap(&mut modifier_keys, &mut last_modifier_keys);
modifier_keys = match ModifierKeys::from_bits(binary_view.read_u8(0).unwrap()) {
Some(f) => f,
None => unreachable!(),
};
} else {
println!("unknown report variable item");
}
} else {
std::mem::swap(&mut pressed_keys, &mut last_pressed_keys);
pressed_keys.clear();
println!("INPUT FLAGS: {:?}", input);
assert_eq!(report_size, 8);
// array
for report_index in 0..report_count as usize {
let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize);
let usage = binary_view.read_u8(0).expect("Failed to read array item");
if usage != 0 {
pressed_keys.push(usage);
}
println!("Report index array {}: {}", report_index, usage);
}
}
}
let changed_modifier_keys = modifier_keys ^ last_modifier_keys;
for (current, last) in pressed_keys.iter().copied().zip(last_pressed_keys.iter().copied()) {
if current == last { continue }
if current != 0 {
// Keycode current changed state to "pressed".
} else {
// Keycode current changed state to "released".
}
}
println!();
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn binary_view() {
// 0000 1000 1100 0111
// E S
let view = super::BinaryView::new(&[0xC7, 0x08], 3, 11);
assert_eq!(view.get(0), Some(false));
assert_eq!(view.get(2), Some(false));
assert_eq!(view.get(3), Some(true));
assert_eq!(view.get(7), Some(false));
assert_eq!(view.get(17), None);
assert_eq!(view.read_u8(0), Some(0b0001_1000));
assert_eq!(view.read_u8(1), Some(0b1000_1100));
assert_eq!(view.read_u8(2), Some(0b0100_0110));
assert_eq!(view.read_u8(3), Some(0b0010_0011));
assert_eq!(view.read_u8(7), None);
// 0000 1000 1100 0111
// E S
let view = super::BinaryView::new(&[0xC7, 0x08], 8, 8);
assert_eq!(view.read_u8(0), Some(0b0000_1000));
}
}
+32 -1
View File
@@ -85,7 +85,7 @@ pub struct GlobalItemsState {
#[derive(Debug)]
pub struct Invalid;
pub fn update_state(current_state: &mut GlobalItemsState, stack: &mut Vec<GlobalItemsState>, report_item: &ReportItem) -> Result<(), Invalid> {
pub fn update_global_state(current_state: &mut GlobalItemsState, stack: &mut Vec<GlobalItemsState>, report_item: &ReportItem) -> Result<(), Invalid> {
match report_item {
ReportItem::Global(global) => match global {
&GlobalItem::UsagePage(u) => current_state.usage_page = Some(u),
@@ -120,6 +120,37 @@ pub enum LocalItem {
StringMaximum(u32),
Delimeter(u32),
}
#[derive(Clone, Copy, Debug, Default)]
pub struct LocalItemsState {
pub usage: Option<u32>,
pub usage_min: Option<u32>,
pub usage_max: Option<u32>,
pub desig_idx: Option<u32>,
pub desig_min: Option<u32>,
pub desig_max: Option<u32>,
pub str_idx: Option<u32>,
pub str_min: Option<u32>,
pub str_max: Option<u32>,
}
pub fn update_local_state(current_state: &mut LocalItemsState, report_item: &ReportItem) {
match report_item {
ReportItem::Local(local) => match local {
&LocalItem::Usage(u) => current_state.usage = Some(u),
&LocalItem::UsageMinimum(m) => current_state.usage_min = Some(m),
&LocalItem::UsageMaximum(m) => current_state.usage_max = Some(m),
&LocalItem::DesignatorIndex(i) => current_state.desig_idx = Some(i),
&LocalItem::DesignatorMinimum(m) => current_state.desig_min = Some(m),
&LocalItem::DesignatorMaximum(m) => current_state.desig_max = Some(m),
&LocalItem::StringIndex(i) => current_state.str_idx = Some(i),
&LocalItem::StringMinimum(m) => current_state.str_min = Some(m),
&LocalItem::StringMaximum(m) => current_state.str_max = Some(m),
&LocalItem::Delimeter(_) => todo!(),
},
_ => todo!(),
}
}
#[derive(Debug)]
pub enum ReportItem {
Main(MainItem),