Basic USB keyboard working!
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
[[package]]
-name = "bitvec"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
-dependencies = [
- "funty",
- "radium",
- "tap",
- "wyz",
-]
-
-[[package]]
name = "byteorder"
-version = "1.5.0"
+version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cortex-m"
[[package]]
name = "either"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "embedded-dma"
]
[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
+[[package]]
name = "frunk"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
]
[[package]]
-name = "funty"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
-
-[[package]]
name = "gcd"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
"embedded-hal",
"frunk_core",
"fugit",
- "heapless 0.7.17",
+ "heapless",
"r0",
+ "serde",
+ "ssmarshal",
"usb-device",
- "usbd-human-interface-device",
+ "usbd-hid",
"usbd-serial",
]
]
[[package]]
-name = "hash32"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
-dependencies = [
- "byteorder",
-]
-
-[[package]]
name = "heapless"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
dependencies = [
"atomic-polyfill",
- "hash32 0.2.1",
+ "hash32",
"rustc_version 0.4.0",
"spin",
"stable_deref_trait",
]
[[package]]
-name = "heapless"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
-dependencies = [
- "hash32 0.3.1",
- "stable_deref_trait",
-]
-
-[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
dependencies = [
- "num_enum_derive 0.5.11",
-]
-
-[[package]]
-name = "num_enum"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
-dependencies = [
- "num_enum_derive 0.7.2",
+ "num_enum_derive",
]
[[package]]
]
[[package]]
-name = "num_enum_derive"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.48",
-]
-
-[[package]]
-name = "option-block"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f2c5d345596a14d7c8b032a68f437955f0059f2eb9a5972371c84f7eef3227"
-
-[[package]]
-name = "packed_struct"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36b29691432cc9eff8b282278473b63df73bea49bc3ec5e67f31a3ae9c3ec190"
-dependencies = [
- "bitvec",
- "packed_struct_codegen",
-]
-
-[[package]]
-name = "packed_struct_codegen"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cd6706dfe50d53e0f6aa09e12c034c44faacd23e966ae5a209e8bdb8f179f98"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76e09694b50f89f302ed531c1f2a7569f0be5867aee4ab4f8f729bbeec0078e3"
dependencies = [
"arrayvec",
- "num_enum 0.5.11",
+ "num_enum",
"paste",
]
checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
[[package]]
-name = "radium"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
-
-[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
+name = "serde"
+version = "1.0.196"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.196"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.48",
+]
+
+[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
]
[[package]]
+name = "ssmarshal"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3e6ad23b128192ed337dfa4f1b8099ced0c2bf30d61e551b65fda5916dbb850"
+dependencies = [
+ "encode_unicode",
+ "serde",
+]
+
+[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
]
[[package]]
-name = "tap"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
-
-[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
[[package]]
-name = "usbd-human-interface-device"
-version = "0.4.5"
+name = "usbd-hid"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d69710303c06f23a1259d086bfb241212ae1ccfb5d582ebd596bb042d662ed73"
+checksum = "975bd411f4a939986751ea09992a24fa47c4d25c6ed108d04b4c2999a4fd0132"
dependencies = [
- "frunk",
- "fugit",
- "heapless 0.8.0",
- "num_enum 0.7.2",
- "option-block",
- "packed_struct",
+ "serde",
+ "ssmarshal",
"usb-device",
+ "usbd-hid-macros",
+]
+
+[[package]]
+name = "usbd-hid-descriptors"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcbee8c6735e90894fba04770bc41e11fd3c5256018856e15dc4dd1e6c8a3dd1"
+dependencies = [
+ "bitfield",
+]
+
+[[package]]
+name = "usbd-hid-macros"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "261079a9ada015fa1acac7cc73c98559f3a92585e15f508034beccf6a2ab75a2"
+dependencies = [
+ "byteorder",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "syn 1.0.109",
+ "usbd-hid-descriptors",
]
[[package]]
dependencies = [
"vcell",
]
-
-[[package]]
-name = "wyz"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
-dependencies = [
- "tap",
-]
r0 = "1.0"
doa-hallonbrod = { path = "../doa-hallonbrod" }
-usb-device = "0.2.9"
-usbd-serial = "0.1.1"
-usbd-human-interface-device = "0.4.5"
+serde = { version = "1.0", default-features = false }
+ssmarshal = { version = "1.0", default-features = false }
+usb-device = "0.2"
+usbd-serial = "0.1"
+usbd-hid = "0.6.0"
[target.thumbv6m-none-eabi]
runner = "elf2uf2-rs"
+pub mod keyboard;
pub mod shell;
\ No newline at end of file
+use core::fmt::{self, Arguments};
+
+use crate::stdlib;
+
+const KEYCODE_MAP: [u8; 81] = [
+ // Row 1
+ 53, //Grave
+ 30, //Keyboard1
+ 32, //Keyboard3
+ 34, //Keyboard5
+ 36, //Keyboard7
+ 38, //Keyboard9
+ 45, //Minus
+ 42, //DeleteBackspace
+ 120, //Stop (RUN/STOP)
+ // Row 2
+ 41, //Escape
+ 31, //Keyboard2
+ 33, //Keyboard4
+ 35, //Keyboard6
+ 37, //Keyboard8
+ 39, //Keyboard0
+ 46, //Equal
+ 73, //Insert
+ 75, //PageUp
+ // Row 3
+ 68, //F11, // Macro 1
+ 26, //W
+ 21, //R
+ 28, //Y
+ 12, //I
+ 19, //P
+ 48, //RightBrace
+ 74, //Home
+ 77, //End
+ // Row 4
+ 43, //Tab
+ 20, //Q
+ 8, //E
+ 23, //T
+ 24, //U
+ 18, //O
+ 47, //LeftBrace
+ 76, //DeleteForward
+ 78, //PageDown
+ // Row 5
+ 69, //F12 (Macro 2)
+ 4, //A
+ 7, //D
+ 9, //F
+ 13, //J
+ 15, //L
+ 52, //Apostrophe
+ 49, //Backslash
+ 106, //F15 (Cyan)
+ // Row 6
+ 224, //LeftControl
+ 225, //LeftShift
+ 22, //S
+ 10, //G
+ 14, //K
+ 51, //Semicolon
+ 56, //ForwardSlash
+ 40, //ReturnEnter
+ 107, //F16 (Magenta)
+ // Row 7
+ 104, //F13 (Macro 3)
+ 29, //Z
+ 27, //X
+ 11, //H
+ 16, //M
+ 55, //Dot
+ 229, //RightShift
+ 82, //UpArrow
+ 108, //F17 (Yellow)
+ // Row 8
+ 105, //F14 (Macro 4)
+ 224, //LeftControl (Meta Left)
+ 6, //C
+ 5, //B
+ 17, //N
+ 54, //Comma
+ 228, //RightControl (Meta Down)
+ 80, //LeftArrow
+ 79, //RightArrow
+ // Row 9
+ 0, //NoEventIndicated (Func; should never be sent)
+ 227, //LeftGUI (Meta)
+ 226, //LeftAlt (Meta Right)
+ 25, //V
+ 44, //Space
+ 230, //RightAlt (Meta Up)
+ 231, //RightGUI (Compose)
+ 81, //DownArrow
+ 109, //F18 (Black)
+];
+
+fn print(buf: &mut heapless::String<80>, args: Arguments<'_>) {
+ buf.clear();
+ if fmt::write(buf, args).is_ok() {
+ stdlib::print(buf);
+ } else {
+ stdlib::print("blonk");
+ }
+}
+
+pub fn main(_base: u32, _size: u32) -> ! {
+ let mut fmt_buffer: heapless::String<80> = heapless::String::new();
+ let mut key_state = [0u32; 3];
+ let mut new_key_state = [0u32; 3];
+ let mut pressed = [0u32; 3];
+ let mut released = [0u32; 3];
+ let mut modifier = 0u8;
+ let mut keycodes = [0u8; 6];
+
+ loop {
+ stdlib::kb_read_matrix(&mut new_key_state);
+ for i in 0..3 {
+ pressed[i] = new_key_state[i] & !key_state[i];
+ released[i] = !new_key_state[i] & key_state[i];
+ key_state[i] = new_key_state[i];
+ }
+ //print(&mut fmt_buffer, format_args!("{:08x?}\r\n", key_state));
+
+ if (pressed[0] | pressed[1] | pressed[2] | released[0] | released[1] | released[2]) == 0 {
+ stdlib::sleep(1);
+ continue;
+ }
+
+ modifier = 0;
+ for i in 0..6 {
+ keycodes[i] = 0;
+ }
+ let mut c = 0;
+ for i in 0..81 {
+ let b = (key_state[i / 32] >> (i % 32) & 1) != 0;
+ if b {
+ let keycode = KEYCODE_MAP[i];
+ if keycode >= 224 && keycode <= 231 {
+ modifier |= 1 << (keycode - 224);
+ } else {
+ if c == 6 {
+ keycodes[0] = 1;
+ } else {
+ keycodes[c] = keycode;
+ c += 1;
+ }
+ }
+ //print(&mut fmt_buffer, format_args!("{} ", KEYCODE_MAP[i] as u32));
+ }
+ }
+ /*
+ if keys.len() > 0 {
+ stdlib::print("\r\n");
+ }
+ */
+
+ let mut report_bytes = [0u8; 8];
+ report_bytes[0] = modifier;
+ for i in 0..6 {
+ report_bytes[i + 2] = keycodes[i];
+ }
+ if !stdlib::kb_write_hid(&report_bytes) {
+ stdlib::print("Failed to push report\r\n");
+ } else {
+ print(&mut fmt_buffer, format_args!("wrote {:?}\r\n", report_bytes));
+ }
+
+ stdlib::sleep(10);
+ }
+}
"k" => {
let mut keybits = [0u32; 3];
let mut db = [0u8; 1];
- stdlib::read_keys(&mut keybits);
+ stdlib::kb_read_matrix(&mut keybits);
stdlib::print(" c1 c2 c3 c4 c5 c6 c7 c8 c9\r\n");
for r in 0..9 {
stdlib::print("r");
kprintf!("Kernel started: {} ticks\r\n", ticks);
with_task_manager(|tm| {
- tm.add_task("shell", apps::shell::shell, &[CapType::ConsoleRead, CapType::ConsoleWrite], 0).expect("launch task one");
+ tm.add_task("shell", apps::shell::shell, &[CapType::ConsoleRead, CapType::ConsoleWrite], 1).expect("shell task");
+ tm.add_task("keyboard", apps::keyboard::main, &[CapType::Keyboard], 0).expect("keyboard task");
});
unsafe {
-use core::arch::asm;
-
use doa_hallonbrod::hal::gpio::{DynPinId, FunctionSioInput, FunctionSioOutput, Pin, PullNone, PullUp};
use embedded_hal::digital::v2::{InputPin, OutputPin};
use bsp::hal::usb::UsbBus;
use bsp::pac::{interrupt, RESETS, USBCTRL_DPRAM, USBCTRL_REGS};
use critical_section::Mutex;
-use frunk_core::hlist::{HCons, HNil};
+use serde::{ser::SerializeTuple, Serialize, Serializer};
use usb_device::{class_prelude::*, prelude::*};
-use usbd_human_interface_device::device::keyboard::NKROBootKeyboard;
-use usbd_human_interface_device::prelude::*;
+use usbd_hid::descriptor::{gen_hid_descriptor, AsInputReport, SerializedDescriptor};
+use usbd_hid::hid_class::{
+ HIDClass, HidClassSettings, HidCountryCode, HidProtocol, HidSubClass, ProtocolModeConfig,
+};
use usbd_serial::SerialPort;
+#[gen_hid_descriptor(
+ (collection = APPLICATION, usage_page = GENERIC_DESKTOP, usage = KEYBOARD) = {
+ (usage_page = KEYBOARD, usage_min = 0xE0, usage_max = 0xE7) = {
+ #[packed_bits 8]
+ #[item_settings data, variable, absolute]
+ modifier = input;
+ };
+ #[item_settings constant, array, absolute]
+ reserved = input;
+ (usage_page = LEDS, usage_min = 0x01, usage_max = 0x03) = {
+ #[packed_bits 3]
+ #[item_settings data, variable, absolute]
+ leds = output;
+ };
+ (usage_page = KEYBOARD, usage_min = 0x00, usage_max = 0xFF) = {
+ #[item_settings data, array, absolute]
+ keycodes = input;
+ };
+ }
+)]
+struct KeyboardReport {
+ pub modifier: u8,
+ pub reserved: u8,
+ pub leds: u8,
+ pub keycodes: [u8; 6],
+}
+
static mut USB_ALLOCATOR: Option<UsbBusAllocator<UsbBus>> = None;
static USB_MANAGER: Mutex<RefCell<Option<UsbManager>>> = Mutex::new(RefCell::new(None));
pub struct UsbManager<'a> {
- dev: usb_device::device::UsbDevice<'a, UsbBus>,
- keyboard: UsbHidClass<'a, UsbBus, HCons<NKROBootKeyboard<'a, UsbBus>, HNil>>,
+ dev: UsbDevice<'a, UsbBus>,
+ keyboard: HIDClass<'a, UsbBus>,
serial: SerialPort<'a, UsbBus>,
}
impl<'a> UsbManager<'a> {
pub fn update(&mut self) {
- match self.keyboard.tick() {
- Err(UsbHidError::WouldBlock) => {}
- Ok(_) => {}
- Err(e) => {
- core::panic!("Failed to process keyboard tick: {:?}", e)
- }
- }
-
if self.dev.poll(&mut [&mut self.keyboard, &mut self.serial]) {
- match self.keyboard.device().read_report() {
- Err(UsbError::WouldBlock) => {}
- Err(e) => {
- core::panic!("Failed to read keyboard report: {:?}", e)
- }
- Ok(_leds) => {}
- }
let mut buf = [0u8; 64];
match self.serial.read(&mut buf) {
Ok(n) => {
}
}
- pub fn keyboard(
- &mut self,
- ) -> &mut UsbHidClass<'a, UsbBus, HCons<NKROBootKeyboard<'a, UsbBus>, HNil>> {
+ pub fn keyboard(&mut self) -> &mut HIDClass<'a, UsbBus> {
&mut self.keyboard
}
USB_ALLOCATOR.as_ref().unwrap()
};
- let keyboard = UsbHidClassBuilder::new()
- .add_device(
- usbd_human_interface_device::device::keyboard::NKROBootKeyboardConfig::default(),
- )
- .build(usballoc);
+ let keyboard = HIDClass::new_ep_in_with_settings(
+ usballoc,
+ KeyboardReport::desc(),
+ 1,
+ HidClassSettings {
+ subclass: HidSubClass::NoSubClass,
+ protocol: HidProtocol::Keyboard,
+ config: ProtocolModeConfig::DefaultBehavior,
+ locale: HidCountryCode::NotSupported,
+ },
+ );
let serial = SerialPort::new(usballoc);
unsafe { _svc_call(200, 0, 0, 0); }
}
-pub fn read_keys(buf: &mut [u32; 3]) {
+pub fn kb_read_matrix(buf: &mut [u32; 3]) {
let ptr = buf.as_ptr() as u32;
unsafe { _svc_call(1000, ptr, 0, 0); }
+}
+
+pub fn kb_write_hid(buf: &[u8]) -> bool {
+ let ptr = buf.as_ptr() as u32;
+ let len = buf.len() as u32;
+ unsafe { _svc_call(1001, ptr, len, 0) == 1 }
}
\ No newline at end of file
use core::arch::global_asm;
use embedded_hal::digital::v2::OutputPin;
+use usbd_hid::descriptor::KeyboardReport;
use crate::bsp::pac::SCB;
use crate::capabilities::CapType;
use crate::console::{self, ConsoleError};
-use crate::peripherals::with_peripherals;
+use crate::kprintf;
+use crate::peripherals::{with_peripherals, with_usb};
use crate::task::{current_task_has_capability, with_task_manager, TaskRegisters};
use crate::timer::ticks;
regs.r0 = b as u32;
}
1000 => {
+ // kb_read_matrix(bits: *mut u32)
+ if !current_task_has_capability(CapType::Keyboard) {
+ return;
+ }
+
let keys = core::slice::from_raw_parts_mut(regs.r1 as *mut u32, 3);
let keybits = with_peripherals(|p| p.keyboard().scan());
keys.copy_from_slice(&keybits);
}
+ 1001 => {
+ // kb_write_hid(arr: *const u8, len: usize) -> bool
+ if !current_task_has_capability(CapType::Keyboard) {
+ return;
+ }
+
+ if regs.r2 > 8 {
+ return;
+ }
+
+ let raw_report = core::slice::from_raw_parts(regs.r1 as *const u8, regs.r2 as usize);
+ let report = KeyboardReport {
+ modifier: raw_report[0],
+ reserved: 0,
+ leds: 0,
+ keycodes: raw_report[2..].try_into().unwrap(),
+ };
+
+ let r = with_usb(|u| u.keyboard().push_input(&report));
+ regs.r0 = match r {
+ Ok(_) => 1,
+ Err(e) => {
+ kprintf!("{:?}\r\n", e);
+ 0
+ }
+ };
+ }
_ => panic!("Unknown SVCall"),
}
}
panic!("Scheduling with no tasks!");
}
- if self.tasks.len() == 1 && self.tasks[0].id == 1 {
+ if self.tasks.len() == 1 && self.tasks[0].name == "idle" {
kprint!("Only idle task remains - relaunching shell\r\n");
self.add_task(
"shell",