Skip to content

Commit

Permalink
direct pin matrix support
Browse files Browse the repository at this point in the history
  • Loading branch information
Univa committed Mar 19, 2024
1 parent f617722 commit 7128881
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 85 deletions.
66 changes: 55 additions & 11 deletions docs/src/content/docs/getting-started/matrix-and-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl Keyboard for MyKeyboard {

In the [templates](https://github.com/Univa/rumcake-templates), you will see that
to implement a keyboard matrix, you need to implement the `KeyboardMatrix` trait
using the `build_matrix!` macro:
using one of the `build_<matrix_type>_matrix!` macros:

```rust ins={13-20}
use rumcake::keyboard;
Expand All @@ -56,18 +56,15 @@ impl Keyboard for MyKeyboard {
const SERIAL_NUMBER: &'static str = "1";
}

use rumcake::keyboard::{build_matrix, KeyboardMatrix};
use rumcake::keyboard::{build_standard_matrix, KeyboardMatrix};
impl KeyboardMatrix for MyKeyboard {
build_matrix! {
build_standard_matrix! {
{ PB2 PB10 PB11 PA3 } // Rows
{ PB12 PB1 PB0 PA7 PA6 PA5 PA4 PA2 PB3 PB4 PA15 PB5 } // Columns
}
}
```

Rows are defined first, followed by the columns. Row and columns are enumerated left-to-right, starting
from 0. In this example, `PB2` is row 0 and `PA3` is row 3.

The identifiers used for the matrix pins must match the identifiers used by the respective
HAL (hardware abstraction library) for your MCU. The linked sites below have a dropdown menu at
the top to allow you to select a chip. Choose your chip to see what pins are available:
Expand All @@ -78,6 +75,14 @@ the top to allow you to select a chip. Choose your chip to see what pins are ava
After defining your matrix, you can set up your [keyboard layout](#keyboard-layout). If you have
a duplex matrix, consider [checking that section](#duplex-matrix) before setting up your keyboard layout.

:::note
The example above assumes a matrix a standard matrix (switches wired in rows and columns, with diodes).
Rows are defined first, followed by the columns. Row and columns are enumerated left-to-right, starting
from 0. In this example, `PB2` is row 0 and `PA3` is row 3.

For other matrix types, see the [Other Matrix Types](#other-matrix-types) section.
:::

# Keyboard Layout

To implement a keyboard layout, you must implement the `KeyboardLayout` trait.
Expand All @@ -100,9 +105,9 @@ impl Keyboard for MyKeyboard {
const SERIAL_NUMBER: &'static str = "1";
}

use rumcake::keyboard::{build_matrix, KeyboardMatrix};
use rumcake::keyboard::{build_standard_matrix, KeyboardMatrix};
impl KeyboardMatrix for MyKeyboard {
build_matrix! {
build_standard_matrix! {
{ PB2 PB10 PB11 PA3 } // Rows
{ PB12 PB1 PB0 PA7 PA6 PA5 PA4 PA2 PB3 PB4 PA15 PB5 } // Columns
}
Expand Down Expand Up @@ -137,6 +142,45 @@ impl KeyboardLayout for MyKeyboard {
Congratulations! You have implemented a basic keyboard. You can now move onto building
and flashing your firmware, or try implementing additional features in the "Features" sidebar.

# Other matrix types

## Direct pin matrix (diodeless matrix)

If your MCU pins are connected directly to a switch (as opposed to pins being connected to a row / column of switches),
then you can use the `build_direct_pin_matrix!` macro instead.

```rust ins={3-9}
// rest of your config...

use rumcake::keyboard::{build_direct_pin_matrix, KeyboardMatrix};
impl KeyboardMatrix for MyKeyboard {
build_direct_pin_matrix! {
[ PB2 PB10 PB11 PA3 ]
[ PB12 PB1 PB0 No ]
}
}

use rumcake::keyboard::{build_layout, KeyboardLayout};
impl KeyboardLayout for MyKeyboard {
build_layout! {
{
[ Tab Q W E ]
[ LCtrl A S D ]
}
{
[ LGui F1 F2 F3 ]
[ t t t t ]
}
}
}
```

Each pin will map directly to a (row, column) position, which determines the key in the layout it corresponds to.
Each row must have the same number of columns. If there are matrix positions that are unused, you can use `No` to ignore them.

In this example, the switch connected to `PB10` maps to row 0, column 1. Based on the implementation of `KeyboardLayout`, this
switch will correspond to the `Q`/`F1` key.

# Revisualizing a matrix (e.g. duplex matrix)

Sometimes, your keyboard might have a complicated matrix scheme that could make it
Expand All @@ -161,7 +205,7 @@ This can be useful for your keyboard layout config, or your backlight matrix con
```rust del={50-63} ins={1-26,64-75}
// This creates a `remap!` macro that you can use in other parts of your config.
remap_matrix! {
// This has the same number of rows and columns that you specified in `build_matrix!`
// This has the same number of rows and columns that you specified in your matrix.
// Note that `No` is used to denote an unused matrix position.
{
[ K00 K01 K02 K03 K04 K05 K06 K07 ]
Expand Down Expand Up @@ -198,9 +242,9 @@ impl Keyboard for MyKeyboard {
const SERIAL_NUMBER: &'static str = "1";
}

use rumcake::keyboard::{build_matrix, KeyboardMatrix};
use rumcake::keyboard::{build_standard_matrix, KeyboardMatrix};
impl KeyboardMatrix for MyKeyboard {
build_matrix! {
build_standard_matrix! {
{ PB3 PB4 PA15 PB5 PA0 PA1 PB2 PB10 PB11 PA3 } // Rows
{ PB12 PB1 PB0 PA7 PA6 PA5 PA4 PA2 } // Columns
}
Expand Down
2 changes: 2 additions & 0 deletions rumcake-macros/src/hw/nrf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use quote::quote;
use syn::punctuated::Punctuated;
use syn::Token;

pub const HAL_CRATE: &'static str = "embassy_nrf";

pub fn input_pin(ident: Ident) -> TokenStream {
quote! {
unsafe {
Expand Down
2 changes: 2 additions & 0 deletions rumcake-macros/src/hw/rp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use quote::quote;
use syn::punctuated::Punctuated;
use syn::Token;

pub const HAL_CRATE: &'static str = "embassy_rp";

pub fn input_pin(ident: Ident) -> TokenStream {
quote! {
unsafe {
Expand Down
2 changes: 2 additions & 0 deletions rumcake-macros/src/hw/stm32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use quote::quote;
use syn::punctuated::Punctuated;
use syn::Token;

pub const HAL_CRATE: &'static str = "embassy_stm32";

pub fn input_pin(ident: Ident) -> TokenStream {
quote! {
unsafe {
Expand Down
108 changes: 86 additions & 22 deletions rumcake-macros/src/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use proc_macro_error::OptionExt;
use quote::{quote, quote_spanned, ToTokens};
use syn::parse::{Parse, Parser};
use syn::spanned::Spanned;
use syn::{braced, bracketed, ItemStruct};
use syn::{braced, bracketed, ItemStruct, PathSegment};

#[derive(Debug, FromMeta, Default)]
#[darling(default)]
Expand Down Expand Up @@ -364,12 +364,9 @@ pub(crate) fn keyboard_main(

// Keyboard setup, and matrix polling task
if !keyboard.no_matrix {
initialization.extend(quote! {
let (matrix, debouncer) = ::rumcake::keyboard::setup_keyboard_matrix(#kb_name);
});
spawning.extend(quote! {
spawner
.spawn(::rumcake::matrix_poll!(#kb_name, matrix, debouncer))
.spawn(::rumcake::matrix_poll!(#kb_name))
.unwrap();
});
}
Expand Down Expand Up @@ -727,14 +724,14 @@ impl<T: ToTokens> ToTokens for OptionalItem<T> {
}

#[derive(Debug)]
pub struct MatrixDefinition<T> {
pub struct StandardMatrixDefinition {
pub row_brace: syn::token::Brace,
pub rows: Vec<T>,
pub rows: Vec<Ident>,
pub col_brace: syn::token::Brace,
pub cols: Vec<T>,
pub cols: Vec<Ident>,
}

impl<T: Parse> syn::parse::Parse for MatrixDefinition<T> {
impl syn::parse::Parse for StandardMatrixDefinition {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let row_content;
let row_brace = braced!(row_content in input);
Expand Down Expand Up @@ -771,26 +768,93 @@ impl<T: Parse> syn::parse::Parse for MatrixDefinition<T> {
}
}

pub fn build_matrix(input: MatrixDefinition<Ident>) -> TokenStream {
let MatrixDefinition { rows, cols, .. } = input;
pub fn build_standard_matrix(input: StandardMatrixDefinition) -> TokenStream {
let StandardMatrixDefinition { rows, cols, .. } = input;
let row_count = rows.len();
let col_count = cols.len();

let hal_name: PathSegment = syn::parse_str(crate::hw::HAL_CRATE).unwrap();

quote! {
const MATRIX_ROWS: usize = #row_count;
const MATRIX_COLS: usize = #col_count;

fn build_matrix(
) -> Result<::rumcake::keyberon::matrix::Matrix<impl ::rumcake::embedded_hal::digital::v2::InputPin<Error = core::convert::Infallible>, impl ::rumcake::embedded_hal::digital::v2::OutputPin<Error = core::convert::Infallible>, { Self::MATRIX_COLS }, { Self::MATRIX_ROWS }>, core::convert::Infallible> {
::rumcake::keyberon::matrix::Matrix::new([
#(
::rumcake::hw::mcu::input_pin!(#cols)
),*
], [
#(
::rumcake::hw::mcu::output_pin!(#rows)
),*
])
fn get_matrix() -> &'static ::rumcake::keyboard::PollableMatrix<impl ::rumcake::keyboard::Pollable> {
static MATRIX: ::rumcake::once_cell::sync::OnceCell<
::rumcake::keyboard::PollableMatrix<
::rumcake::keyboard::PollableStandardMatrix<
::rumcake::hw::mcu::#hal_name::gpio::Input<'static>,
::rumcake::hw::mcu::#hal_name::gpio::Output<'static>,
#col_count,
#row_count
>
>
> = ::rumcake::once_cell::sync::OnceCell::new();
MATRIX.get_or_init(|| {
::rumcake::keyboard::PollableMatrix::new(
::rumcake::keyboard::setup_standard_keyboard_matrix(
[
#(
::rumcake::hw::mcu::input_pin!(#cols)
),*
],
[
#(
::rumcake::hw::mcu::output_pin!(#rows)
),*
],
Self::DEBOUNCE_MS
).unwrap()
)
})
}
}
}

pub fn build_direct_pin_matrix(input: MatrixLike<OptionalItem<Ident>>) -> TokenStream {
let values = input.rows.iter().map(|row| {
let items = row.cols.iter().map(|item| match item {
OptionalItem::None => quote! { None },
OptionalItem::Some(pin_ident) => {
quote! { Some(::rumcake::hw::mcu::input_pin!(#pin_ident)) }
}
});
quote! { #(#items),* }
});

let row_count = input.rows.len();
let col_count = input
.rows
.first()
.expect_or_abort("At least one row is required.")
.cols
.len();

let hal_name: PathSegment = syn::parse_str(crate::hw::HAL_CRATE).unwrap();

quote! {
const MATRIX_ROWS: usize = #row_count;
const MATRIX_COLS: usize = #col_count;
fn get_matrix() -> &'static ::rumcake::keyboard::PollableMatrix<impl ::rumcake::keyboard::Pollable> {
static MATRIX: ::rumcake::once_cell::sync::OnceCell<
::rumcake::keyboard::PollableMatrix<
::rumcake::keyboard::PollableDirectPinMatrix<
::rumcake::hw::mcu::#hal_name::gpio::Input<'static>,
#col_count,
#row_count
>
>
> = ::rumcake::once_cell::sync::OnceCell::new();
MATRIX.get_or_init(|| {
::rumcake::keyboard::PollableMatrix::new(
::rumcake::keyboard::setup_direct_pin_keyboard_matrix(
[
#([ #values ]),*
],
Self::DEBOUNCE_MS
).unwrap()
)
})
}
}
}
Expand Down
12 changes: 9 additions & 3 deletions rumcake-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,15 @@ pub fn keyboard_main(
}

#[proc_macro]
pub fn build_matrix(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let matrix = parse_macro_input!(input as keyboard::MatrixDefinition<Ident>);
keyboard::build_matrix(matrix).into()
pub fn build_standard_matrix(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let matrix = parse_macro_input!(input as keyboard::StandardMatrixDefinition);
keyboard::build_standard_matrix(matrix).into()
}

#[proc_macro]
pub fn build_direct_pin_matrix(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let matrix = parse_macro_input!(input as keyboard::MatrixLike<keyboard::OptionalItem<Ident>>);
keyboard::build_direct_pin_matrix(matrix).into()
}

#[proc_macro]
Expand Down
Loading

0 comments on commit 7128881

Please sign in to comment.