Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Input device #192

Draft
wants to merge 23 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3c9b5df
wip: input device
HaoboGu Dec 16, 2024
f9615e5
Merge branch 'main' into feat/input_device
HaoboGu Dec 16, 2024
730b79f
Merge branch 'main' into feat/input_device
HaoboGu Dec 16, 2024
dbc5516
Merge branch 'main' into feat/input_device
HaoboGu Dec 16, 2024
022ab54
Merge branch 'main' into feat/input_device
HaoboGu Dec 16, 2024
e74a277
Merge branch 'main' into feat/input_device
HaoboGu Dec 16, 2024
a8767f6
Merge branch 'main' into feat/input_device
HaoboGu Dec 16, 2024
7a5e255
Merge branch 'main' into feat/input_device
HaoboGu Dec 16, 2024
3af5dfa
Merge branch 'main' into feat/input_device
HaoboGu Dec 16, 2024
6eee9ce
Merge branch 'main' into feat/input_device
HaoboGu Dec 16, 2024
35b3714
Merge branch 'main' into feat/input_device
HaoboGu Dec 21, 2024
0328876
Merge branch 'main' into feat/input_device
HaoboGu Dec 23, 2024
4e90351
Merge branch 'main' into feat/input_device
HaoboGu Dec 24, 2024
663b2bd
Merge branch 'feat/input_device' of github.com:HaoboGu/rmk into feat/…
HaoboGu Dec 24, 2024
29a8972
wip(input_device): POC impl for input device trait
HaoboGu Dec 24, 2024
4c7a48f
feat(input_device): add first POC impl of input device, add rotary en…
HaoboGu Dec 24, 2024
dc6eb25
Merge branch 'main' into feat/input_device
HaoboGu Dec 25, 2024
32236ee
chore: update input device example
HaoboGu Dec 25, 2024
ae465ff
feat(input_device): send event from the rotary encoder
HaoboGu Dec 26, 2024
2a186c7
feat(input_device): expose key event channel
HaoboGu Dec 26, 2024
5a91d3a
feat(macro): add input device toml config
HaoboGu Dec 26, 2024
4a3597c
feat(core): add mouse event
HaoboGu Dec 26, 2024
ff8aa3a
feat(input_device): add event definition
HaoboGu Dec 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/po/zh_CN.po
Original file line number Diff line number Diff line change
Expand Up @@ -2538,15 +2538,15 @@ msgstr ""

#: src\how_to_contribute.md:41
msgid ""
"`key_event_channel`: a multi-sender, single-receiver channel. The sender can "
"`KEY_EVENT_CHANNEL`: a multi-sender, single-receiver channel. The sender can "
"be a matrix task which scans the key matrix or a split peripheral monitor "
"which receives key event from split peripheral. The receiver, i.e. keyboard "
"task, receives the key event and processes the key"
msgstr ""

#: src\how_to_contribute.md:42
msgid ""
"`keyboard_report_channel`: a single-sender, single-receiver channel, "
"`KEYBOARD_REPORT_CHANNEL`: a single-sender, single-receiver channel, "
"keyboard task sends keyboard report to channel after the key event is "
"processed, and USB/BLE task receives the keyboard report and sends the key "
"to the host."
Expand Down
4 changes: 2 additions & 2 deletions docs/src/how_to_contribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ So, if you want to contribute new features of RMK, just look into `rmk` core cra
Generally, there are 4-5 running tasks in the meanwhile, according to the user's config. Communication between tasks is done by channels.There are several built-in channels:

- `FLASH_CHANNEL`: a multi-sender, single-receiver channel. There are many tasks send the `FlashOperationMessage`, such as BLE task(which saves bond info), vial task(which saves key), etc.
- `key_event_channel`: a multi-sender, single-receiver channel. The sender can be a matrix task which scans the key matrix or a split peripheral monitor which receives key event from split peripheral. The receiver, i.e. keyboard task, receives the key event and processes the key
- `keyboard_report_channel`: a single-sender, single-receiver channel, keyboard task sends keyboard report to channel after the key event is processed, and USB/BLE task receives the keyboard report and sends the key to the host.
- `KEY_EVENT_CHANNEL`: a multi-sender, single-receiver channel. The sender can be a matrix task which scans the key matrix or a split peripheral monitor which receives key event from split peripheral. The receiver, i.e. keyboard task, receives the key event and processes the key
- `KEYBOARD_REPORT_CHANNEL`: a single-sender, single-receiver channel, keyboard task sends keyboard report to channel after the key event is processed, and USB/BLE task receives the keyboard report and sends the key to the host.

### Matrix scanning & key processing

Expand Down
2 changes: 2 additions & 0 deletions examples/use_rust/nrf52840_ble/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ embassy-executor = { version = "0.6", features = [
"executor-thread",
"integrated-timers",
] }
embassy-futures = { version = "0.1", features = ["defmt"] }

defmt = "0.3"
defmt-rtt = "0.4"
panic-probe = { version = "0.3", features = ["print-defmt"] }
Expand Down
35 changes: 27 additions & 8 deletions examples/use_rust/nrf52840_ble/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ use panic_probe as _;
use rmk::{
ble::SOFTWARE_VBUS,
config::{BleBatteryConfig, KeyboardUsbConfig, RmkConfig, StorageConfig, VialConfig},
run_rmk,
input_device::{rotary_encoder::RotaryEncoder, InputDevice},
run_devices, run_rmk,
};

use vial::{VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID};
Expand Down Expand Up @@ -106,13 +107,31 @@ async fn main(spawner: Spawner) {
..Default::default()
};

run_rmk(
input_pins,
output_pins,
driver,
&mut keymap::get_default_keymap(),
keyboard_config,
spawner,
let mut my_device = MyDevice {};
let pin_a = Input::new(AnyPin::from(p.P0_06), embassy_nrf::gpio::Pull::Up);
let pin_b = Input::new(AnyPin::from(p.P0_11), embassy_nrf::gpio::Pull::Up);
let mut encoder = RotaryEncoder::new(pin_a, pin_b, (0, 0), (0, 1));

embassy_futures::join::join(
run_rmk(
input_pins,
output_pins,
driver,
&mut keymap::get_default_keymap(),
keyboard_config,
spawner,
),
run_devices!(my_device, encoder),
)
.await;
}

struct MyDevice {}
impl InputDevice for MyDevice {
async fn run(&mut self) {
loop {
info!("Hi my device");
embassy_time::Timer::after_secs(1).await;
}
}
}
23 changes: 23 additions & 0 deletions rmk-macro/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub struct KeyboardTomlConfig {
pub dependency: Option<DependencyConfig>,
/// Split config
pub split: Option<SplitConfig>,
/// Input device config
pub input_device: Option<InputDeviceConfig>,
}

/// Configurations for keyboard info
Expand Down Expand Up @@ -185,7 +187,10 @@ pub struct SplitBoardConfig {
pub ble_addr: Option<[u8; 6]>,
/// Serial config, the vector length should be 1 for peripheral
pub serial: Option<Vec<SerialConfig>>,
/// Matrix config for the split
pub matrix: MatrixConfig,
/// Input device config for the split
pub input_device: InputDeviceConfig,
}

/// Serial port config
Expand Down Expand Up @@ -220,3 +225,21 @@ fn parse_duration_millis<'de, D: de::Deserializer<'de>>(deserializer: D) -> Resu
other => Err(de::Error::custom(format!("Invalid unit \"{other}\" in [one_shot.timeout]: unit part must be either \"s\" or \"ms\""))),
}
}

/// Configurations for input devices
///
#[derive(Clone, Debug, Default, Deserialize)]
pub struct InputDeviceConfig {
pub encoder: Option<Vec<EncoderConfig>>,
}

#[derive(Clone, Debug, Default, Deserialize)]
pub struct EncoderConfig {
pub pin_a: String,
pub pin_b: String,
pub pin_btn: Option<String>,
pub resolution: Option<u8>,
pub clockwise_pos: (u8, u8),
pub counter_clockwise_pos: (u8, u8),
pub press_pos: Option<(u8, u8)>,
}
6 changes: 3 additions & 3 deletions rmk/src/ble/esp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub(crate) mod server;

use self::server::{BleServer, VialReaderWriter};
use crate::config::StorageConfig;
use crate::keyboard::keyboard_report_channel;
use crate::keyboard::KEYBOARD_REPORT_CHANNEL;
use crate::matrix::MatrixTrait;
use crate::storage::nor_flash::esp_partition::{Partition, PartitionType};
use crate::storage::Storage;
Expand Down Expand Up @@ -61,8 +61,8 @@ pub(crate) async fn initialize_esp_ble_keyboard_with_config_and_run<

let keymap = RefCell::new(KeyMap::new_from_storage(default_keymap, Some(&mut storage)).await);

let keyboard_report_sender = keyboard_report_channel.sender();
let keyboard_report_receiver = keyboard_report_channel.receiver();
let keyboard_report_sender = KEYBOARD_REPORT_CHANNEL.sender();
let keyboard_report_receiver = KEYBOARD_REPORT_CHANNEL.receiver();

let mut keyboard = Keyboard::new(
&keymap,
Expand Down
6 changes: 3 additions & 3 deletions rmk/src/ble/nrf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod vial_service;

use self::server::BleServer;
use crate::config::BleBatteryConfig;
use crate::keyboard::{keyboard_report_channel, REPORT_CHANNEL_SIZE};
use crate::keyboard::{KEYBOARD_REPORT_CHANNEL, REPORT_CHANNEL_SIZE};
use crate::matrix::MatrixTrait;
use crate::storage::StorageKeys;
use crate::{
Expand Down Expand Up @@ -295,8 +295,8 @@ pub(crate) async fn initialize_nrf_ble_keyboard_and_run<

let ble_server = unwrap!(BleServer::new(sd, keyboard_config.usb_config, bonder));

let keyboard_report_sender = keyboard_report_channel.sender();
let keyboard_report_receiver = keyboard_report_channel.receiver();
let keyboard_report_sender = KEYBOARD_REPORT_CHANNEL.sender();
let keyboard_report_receiver = KEYBOARD_REPORT_CHANNEL.receiver();

// Keyboard services
let mut keyboard = Keyboard::new(
Expand Down
6 changes: 3 additions & 3 deletions rmk/src/direct_pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::debounce::default_bouncer::DefaultDebouncer;
use crate::debounce::fast_debouncer::RapidDebouncer;
use crate::debounce::DebounceState;
use crate::debounce::DebouncerTrait;
use crate::keyboard::key_event_channel;
use crate::keyboard::KeyEvent;
use crate::keyboard::KEY_EVENT_CHANNEL;
use crate::event::KeyEvent;
use crate::matrix::KeyState;
use crate::MatrixTrait;
use crate::RmkConfig;
Expand Down Expand Up @@ -330,7 +330,7 @@ impl<
self.key_states[row_idx][col_idx].toggle_pressed();
let key_state = self.key_states[row_idx][col_idx];

key_event_channel
KEY_EVENT_CHANNEL
.send(KeyEvent {
row: row_idx as u8,
col: col_idx as u8,
Expand Down
64 changes: 64 additions & 0 deletions rmk/src/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use defmt::Format;
use postcard::experimental::max_size::MaxSize;
use serde::{Deserialize, Serialize};

/// Raw events from input devices and keyboards
///
/// This should be as close to the raw output of the devices as possible.
/// The input processors receives it, processes it,
/// and then converts it to the final keyboard/mouse report.
#[non_exhaustive]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum Event {
/// Keyboard event
Key(KeyEvent),
/// Multi-touch touchpad
Touchpad(TouchpadEvent),
/// Joystick, suppose we have x,y,z axes for this joystick
Joystick([AxisEvent; 3]),
}

/// Event for multi-touch touchpad
#[derive(Serialize, Deserialize, Clone, Debug, Format, MaxSize)]
pub struct TouchpadEvent {
/// Finger slot
pub finger: u8,
/// X, Y, Z axes for touchpad
pub axis: [AxisEvent; 3],
}

#[derive(Serialize, Deserialize, Clone, Debug, Copy, Format, MaxSize)]
pub struct AxisEvent {
/// The axis event value type, relative or absolute
pub typ: AxisValType,
/// The axis name
pub axis: Axis,
/// Value of the axis event
pub value: i8,
}

#[derive(Serialize, Deserialize, Clone, Debug, Copy, Format, MaxSize)]
pub enum AxisValType {
/// The axis value is relative
Rel,
/// The axis value is absolute
Abs,
}

#[derive(Serialize, Deserialize, Clone, Copy, Debug, Format, MaxSize)]
#[non_exhaustive]
pub enum Axis {
X,
Y,
Z,
H,
V,
// .. More is allowed
}

#[derive(Serialize, Deserialize, Clone, Copy, Debug, Format, MaxSize)]
pub struct KeyEvent {
pub row: u8,
pub col: u8,
pub pressed: bool,
}
77 changes: 77 additions & 0 deletions rmk/src/input_device/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//! Input device module for RMK
//!
//! This module defines the `InputDevice` trait and the `run_devices` macro, enabling the simultaneous execution of multiple input devices.
//! The `InputDevice` trait provides the interface for individual input devices, and the `run_devices` macro facilitates their concurrent execution.
//!
//! Note: The `InputDevice` trait must be used in conjunction with the `run_devices` macro to ensure correct execution of all input devices.

use core::future::Future;

pub mod rotary_encoder;

/// The trait for input devices.
///
/// This trait defines the interface for input devices in RMK.
/// The `run_devices` macro is required to run tasks associated with input devices concurrently.
///
/// # Example
/// ```rust
/// // Define an input device
/// struct MyInputDevice;
///
/// impl InputDevice for MyInputDevice {
/// async fn run(&mut self) {
/// // Input device implementation
/// }
/// }
///
/// // Use the input device
/// let d1 = MyInputDevice{};
/// let d2 = MyInputDevice{};
///
/// // Run all devices simultaneously with RMK
/// embassy_futures::join::join(
/// run_devices!(d1, d2),
/// run_rmk(
/// // .. arguments
/// ),
/// )
/// .await;
/// ```
pub trait InputDevice {
/// Starts the input device task.
///
/// This asynchronous method should contain the main logic for the input device.
/// It will be executed concurrently with other input devices using the `run_devices` macro.
fn run(&mut self) -> impl Future<Output = ()>;
}

/// Macro to run multiple input devices concurrently.
///
/// The `run_devices` macro is specifically designed to work with the `InputDevice` trait. It takes one or more instances of
/// input devices and combines their `run` methods into a single future. All futures are executed concurrently, enabling
/// efficient multitasking for multiple input devices.
///
/// # Note
/// This macro must be used with input devices that implement the `InputDevice` trait.
///
/// # Example
/// ```rust
/// // `MyInputDevice` should implement `InputDevice` trait
/// let d1 = MyInputDevice{};
/// let d2 = MyInputDevice{};
///
/// // Run all input devices concurrently
/// run_devices!(d1, d2).await;
/// ```
#[macro_export]
macro_rules! run_devices {
// Single device case
($single:expr) => {
$single.run()
};
// Multiple devices case
($first:expr, $second:expr $(, $rest:expr)*) => {
::embassy_futures::join::join($first.run(), run_devices!($second $(, $rest)*))
};
}
Loading
Loading