Skip to content

Commit

Permalink
remove traits used to set up some drivers, add macros to set up seria…
Browse files Browse the repository at this point in the history
…l drivers

this makes the `setup_driver` functions (previously `setup_backlight_driver`, `setup_underglow_driver`, etc.) less restrictive, since you just pass arguments instead of implementing a trait.
the traits that were removed from the main `rumcake` library are instead generated by the `keyboard` macro so that you can still configure your drivers using an impl block

this also adds a setup_buffered_uarte macro for nrf chips, which can be used for split keyboards.
  • Loading branch information
Univa committed Mar 1, 2024
1 parent 25d21c7 commit 87fbf6c
Show file tree
Hide file tree
Showing 18 changed files with 514 additions and 336 deletions.
17 changes: 11 additions & 6 deletions docs/src/content/docs/features/feature-backlight.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,17 @@ a key at switch matrix position row 0, column 0, will correspond to the LED at r

Lastly, you must also implement the appropriate trait that corresponds to your chosen driver in the `#[keyboard]` macro. For example, with `is31fl3731`, you must implement `IS31FL3731BacklightDriver`:

```rust ins={3-25}
```rust ins={3-30}
// later in your file...

use rumcake::hw::mcu::setup_i2c;
use rumcake::drivers::is31fl3731::backlight::get_led_from_matrix_coordinates;
impl IS31FL3731BacklightDriver for MyKeyboard {
const LED_DRIVER_ADDR: u32 = 0b1110100; // see https://github.com/qmk/qmk_firmware/blob/d9fa80c0b0044bb951694aead215d72e4a51807c/docs/feature_rgb_matrix.md#is31fl3731-idis31fl3731
use rumcake::drivers::is31fl3731::backlight::{
get_led_from_matrix_coordinates, IS31FL3731BacklightDriver
};
// Note: The IS31FL3731DriverSettings trait does NOT come from the `rumcake` library. It is generated by the `keyboard` macro.
impl IS31FL3731DriverSettings for MyKeyboard {
const LED_DRIVER_ADDR: u8 = 0b1110100; // see https://github.com/qmk/qmk_firmware/blob/d9fa80c0b0044bb951694aead215d72e4a51807c/docs/feature_rgb_matrix.md#is31fl3731-idis31fl3731

setup_i2c! { // Note: The arguments of setup_i2c may change depending on platform. This assumes STM32.
I2C1_EV, // Event interrupt
I2C1_ER, // Error interrupt
Expand All @@ -141,7 +145,8 @@ impl IS31FL3731BacklightDriver for MyKeyboard {
DMA1_CH7, // RX DMA Channel
DMA1_CH6 // TX DMA Channel
}

}
impl IS31FL3731BacklightDriver for MyKeyboard {
// This must have the same number of rows and columns as specified in your `BacklightMatrixDevice` implementation.
get_led_from_matrix_coordinates! {
[ C1_1 C1_2 C1_3 C1_4 C1_5 C1_6 C1_7 C1_8 C1_9 C1_10 C1_11 C1_12 C1_13 C1_14 C1_15 C2_15 ]
Expand All @@ -155,7 +160,7 @@ impl IS31FL3731BacklightDriver for MyKeyboard {

:::note
The IS31FL3731 driver setup above assumes usage of a `simple-backlight-matrix`. If you want
an RGB matrix, there is a separate `is31fl3731_get_led_from_rgb_matrix_coordinates` macro.
an RGB matrix, there is a separate `rumcake::drivers::is31fl3731::backlight::get_led_from_rgb_matrix_coordinates` macro.
:::

# Keycodes
Expand Down
21 changes: 13 additions & 8 deletions docs/src/content/docs/features/feature-display.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,32 +44,37 @@ impl DisplayDevice for MyKeyboard {
Lastly, you must also implement the appropriate trait that corresponds to your chosen driver in the `#[keyboard]` macro.
For example, with `ssd1306`, you must implement `Ssd1306I2cDisplayDriver`:

```rust ins={3-18}
```rust ins={3-23}
// later in your file...

use rumcake::hw::mcu::setup_i2c_blocking;
use rumcake::drivers::ssd1306::driver::size::DisplaySize128x32;
use rumcake::drivers::ssd1306::display::Ssd1306I2cDisplayDriver;
impl Ssd1306I2cDisplayDriver for MyKeyboard {
const SIZE: DisplaySize128x32 = DisplaySize128x32;
// Note: The Ssd1306I2cDriverSettings trait does NOT come from the `rumcake` library. It is generated by the `keyboard` macro.
impl Ssd1306I2cDriverSettings for MyKeyboard {
// Set size of the display
type SIZE_TYPE = DisplaySize128x32;
const SIZE: Self::SIZE_TYPE = DisplaySize128x32;

// Optional: set rotation
const ROTATION: DisplayRotation = DisplayRotation::Rotate90;

// Set up the I2C peripheral to communicate with the SSD1306 screen
setup_i2c_blocking! {
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
TWISPI0,
P0_17,
P0_20
}
}
impl Ssd1306I2cDisplayDriver for MyKeyboard {}
```

# Custom graphics

By default, the display will show information about the keyboard depending on
what features are being used. If you're using any bluetooth features (e.g. `split-driver-ble`
or `bluetooth`), then the battery level will be displayed. If you are communicating
what features are being used. If you're using any bluetooth features (e.g. `bluetooth`),
then the battery level will be displayed. If you are communicating
with your host device over USB and Bluetooth (`usb` and `bluetooth` enabled),
then it will also show the operation mode.

Expand All @@ -89,7 +94,7 @@ use embedded_graphics::text::Text;
use embedded_graphics::Drawable;
use rumcake::drivers::ssd1306::driver::mode::BufferedGraphicsMode;
use rumcake::drivers::ssd1306::driver::prelude::I2CInterface;
use rumcake::drivers::ssd1306::driver::size::DisplaySize128x32;
use rumcake::drivers::ssd1306::driver::size::{DisplaySize, DisplaySize128x32};
use rumcake::drivers::ssd1306::driver::Ssd1306;
use rumcake::drivers::ssd1306::display::Ssd1306I2cDisplayDriver;

Expand All @@ -99,9 +104,9 @@ pub static DEFAULT_STYLE: MonoTextStyle<'_, BinaryColor> = MonoTextStyleBuilder:
.build();

impl Ssd1306I2cDisplayDriver for MyKeyboard {
/* ... your existing settings */
/* ... in your trait implementation */

fn on_update(
fn on_update<S: DisplaySize>(
display: &mut Ssd1306<
I2CInterface<impl Write<Error = impl Debug>>,
S,
Expand Down
10 changes: 5 additions & 5 deletions docs/src/content/docs/features/feature-split.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ To set up the central device, you must add `split_central(driver = "<driver>")`
and your keyboard must implement the appropriate trait for the driver you're using. For example, with `ble` and an nRF5x
chip selected, you must implement `NRFBLECentralDevice`, and `BluetoothDevice`:

```rust ins={6-8,20-37}
```rust ins={6-8,20-36}
// left.rs
use rumcake::keyboard;

Expand Down Expand Up @@ -77,8 +77,8 @@ impl BluetoothDevice for MyKeyboardLeftHalf {
}

// Split central setup
use rumcake::split::drivers::nrf_ble::central::NRFBLECentralDevice;
impl NRFBLECentralDevice for MyKeyboardLeftHalf {
// Note: The NRFBLECentralDriverSettings trait does NOT come from the `rumcake` library. It is generated by the `keyboard` macro.
impl NRFBLECentralDriverSettings for MyKeyboardLeftHalf {
// Must be valid "Random Static" bluetooth addresses.
// This central device can connect to one other peripheral. Feel free to add more addresses to connect more peripherals.
const PERIPHERAL_ADDRESSES: &'static [[u8; 6]] = [
Expand Down Expand Up @@ -140,8 +140,8 @@ impl BluetoothDevice for WingpairLeft {
}

// Split peripheral setup
use rumcake::split::drivers::nrf_ble::peripheral::NRFBLEPeripheralDevice;
impl NRFBLEPeripheralDevice for MyKeyboardRightHalf {
// Note: The NRFBLEPeripheralDriverSettings trait does NOT come from the `rumcake` library. It is generated by the `keyboard` macro.
impl NRFBLEPeripheralDriverSettings for MyKeyboardRightHalf {
// Must be valid "Random Static" bluetooth address.
const CENTRAL_ADDRESS: [u8; 6] = [0x41, 0x5A, 0xE3, 0x1E, 0x83, 0xE7]; // Must match the BLUETOOTH_ADDRESS specified in the left half
}
Expand Down
7 changes: 4 additions & 3 deletions docs/src/content/docs/features/feature-underglow.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,12 @@ For more information, see the docs for the [storage feature](../feature-storage/

Lastly, you must also implement the appropriate trait that corresponds to your chosen driver in the `#[keyboard]` macro. For example, with `ws2812_bitbang`, you must implement `WS2812BitbangUnderglowDriver`:

```rust ins={3-6}
```rust ins={3-7}
// later in your file...

use rumcake::drivers::ws2812_bitbang::{underglow::WS2812BitbangUnderglowDriver, ws2812_bitbang_pin};
impl WS2812BitbangUnderglowDriver for MyKeyboard {
use rumcake::drivers::ws2812_bitbang::ws2812_bitbang_pin;
// Note: The WS2812BitbangDriverSettings trait does NOT come from the `rumcake` library. It is generated by the `keyboard` macro.
impl WS2812BitbangDriverSettings for MyKeyboard {
ws2812_bitbang_pin! { PA10 }
}
```
Expand Down
15 changes: 15 additions & 0 deletions rumcake-macros/src/drivers/is31fl3731.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,18 @@ pub fn get_led_from_rgb_matrix_coordinates(input: LayoutLike<OptionalItem<Ident>
}
}
}

pub fn driver_trait() -> TokenStream {
quote! {
/// A trait that must be implemented to set up the IS31FL3731 driver.
pub(crate) trait IS31FL3731DriverSettings {
/// I2C Address for the IS31FL3731 driver. Consult the datasheet for more information.
const LED_DRIVER_ADDR: u8;

/// Setup the I2C peripheral to communicate with the IS31FL3731 chip.
///
/// It is recommended to use [`rumcake::hw::mcu::setup_i2c`] to implement this function.
fn setup_i2c() -> impl ::rumcake::embedded_hal_async::i2c::I2c<Error = impl core::fmt::Debug>;
}
}
}
16 changes: 16 additions & 0 deletions rumcake-macros/src/drivers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
use proc_macro2::TokenStream;
use quote::quote;

pub mod is31fl3731;
pub mod nrf_ble;
pub mod ssd1306;
pub mod ws2812;

pub fn serial_driver_trait() -> TokenStream {
quote! {
/// A trait that must be implemented to set up the IS31FL3731 driver.
pub(crate) trait SerialDriverSettings {
/// Setup a serial driver that is capable of both reading and writing.
///
/// It is recommended to use a macro to implement this function.
fn setup_serial() -> impl ::rumcake::embedded_io_async::Write + ::rumcake::embedded_io_async::Read;
}
}
}
22 changes: 22 additions & 0 deletions rumcake-macros/src/drivers/nrf_ble.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use proc_macro2::TokenStream;
use quote::quote;

pub fn peripheral_driver_trait() -> TokenStream {
quote! {
/// A trait that nRF-based keyboards must implement to use bluetooth to drive peripheral devices in a split keyboard setup.
pub(crate) trait NRFBLEPeripheralDriverSettings {
/// A "Random Static" bluetooth address of the central device that this peripheral will connect to.
const CENTRAL_ADDRESS: [u8; 6];
}
}
}

pub fn central_driver_trait() -> TokenStream {
quote! {
/// A trait that nRF-based keyboards must implement to use bluetooth to drive central devices in a split keyboard setup.
pub(crate) trait NRFBLECentralDriverSettings {
/// A list of "Random Static" bluetooth addresses that this central device can connect to.
const PERIPHERAL_ADDRESSES: &'static [[u8; 6]];
}
}
}
24 changes: 24 additions & 0 deletions rumcake-macros/src/drivers/ssd1306.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use proc_macro2::TokenStream;
use quote::quote;

pub fn driver_trait() -> TokenStream {
quote! {
/// A trait that keyboards must implement to set up the SSD1306 driver.
pub(crate) trait Ssd1306I2cDriverSettings {
/// Size of the display. Must be an implementor of [`DisplaySize`].
type SIZE_TYPE: ::rumcake::drivers::ssd1306::driver::size::DisplaySize;

/// Size of the display. Must be an implementor of [`DisplaySize`].
const SIZE: Self::SIZE_TYPE;

/// Rotation of the SSD1306 display. See [`DisplayRotation`].
const ROTATION: ::rumcake::drivers::ssd1306::driver::rotation::DisplayRotation =
::rumcake::drivers::ssd1306::driver::rotation::DisplayRotation::Rotate90;

/// Setup the I2C peripheral to communicate with the SSD1306 display.
///
/// It is recommended to use [`rumcake::hw::mcu::setup_i2c`] to implement this function.
fn setup_i2c() -> impl ::rumcake::embedded_hal::blocking::i2c::Write<Error = impl core::fmt::Debug>;
}
}
}
14 changes: 14 additions & 0 deletions rumcake-macros/src/drivers/ws2812.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ pub mod bitbang {
use proc_macro2::{Ident, TokenStream};
use quote::quote;

pub fn driver_trait() -> TokenStream {
quote! {
/// A trait that must be implemented to set up the WS2812 driver.
pub(crate) trait WS2812BitbangDriverSettings {
/// Setup the GPIO pin used to send data to the WS2812 LEDs.
///
/// It is recommended to use
/// [`rumcake::drivers::ws2812_bitbang::ws2812_bitbang_pin`] to implement this
/// function.
fn ws2812_pin() -> impl ::rumcake::embedded_hal::digital::v2::OutputPin;
}
}
}

pub fn pin(input: Ident) -> TokenStream {
quote! {
fn ws2812_pin() -> impl ::rumcake::embedded_hal::digital::v2::OutputPin {
Expand Down
66 changes: 66 additions & 0 deletions rumcake-macros/src/hw/nrf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,69 @@ pub fn setup_i2c_blocking(args: Punctuated<Ident, Token![,]>) -> TokenStream {
}
}
}

fn setup_buffered_uarte_inner(args: Punctuated<Ident, Token![,]>) -> TokenStream {
let mut args = args.iter();

let interrupt = args.next().expect_or_abort("Missing interrupt argument.");
let uarte = args
.next()
.expect_or_abort("Missing UARTE peripheral argument.");
let timer = args
.next()
.expect_or_abort("Missing timer peripheral argument.");
let ppi_ch1 = args
.next()
.expect_or_abort("Missing PPI CH1 peripheral argument.");
let ppi_ch2 = args
.next()
.expect_or_abort("Missing PPI CH2 peripheral argument.");
let ppi_group = args
.next()
.expect_or_abort("Missing PPI Group peripheral argument.");
let rx_pin = args.next().expect_or_abort("Missing RX pin argument.");
let tx_pin = args.next().expect_or_abort("Missing TX pin argument.");

quote! {
unsafe {
static mut RBUF: [u8; 4096] = [0; 4096];
static mut TBUF: [u8; 4096] = [0; 4096];
::rumcake::hw::mcu::embassy_nrf::bind_interrupts! {
struct Irqs {
#interrupt => ::rumcake::hw::mcu::embassy_nrf::buffered_uarte::InterruptHandler<::rumcake::hw::mcu::embassy_nrf::peripherals::#uarte>;
}
};
let uarte = ::rumcake::hw::mcu::embassy_nrf::peripherals::#uarte::steal();
let timer = ::rumcake::hw::mcu::embassy_nrf::peripherals::#timer::steal();
let ppi_ch1 = ::rumcake::hw::mcu::embassy_nrf::peripherals::#ppi_ch1::steal();
let ppi_ch2 = ::rumcake::hw::mcu::embassy_nrf::peripherals::#ppi_ch2::steal();
let ppi_group = ::rumcake::hw::mcu::embassy_nrf::peripherals::#ppi_group::steal();
let rx_pin = ::rumcake::hw::mcu::embassy_nrf::peripherals::#rx_pin::steal();
let tx_pin = ::rumcake::hw::mcu::embassy_nrf::peripherals::#tx_pin::steal();
::rumcake::hw::mcu::embassy_nrf::buffered_uarte::BufferedUarte::new(
uarte,
timer,
ppi_ch1,
ppi_ch2,
ppi_group,
Irqs,
rx_pin,
tx_pin,
Default::default(),
&mut RBUF,
&mut TBUF,
)
}
}
}

pub fn setup_buffered_uarte(args: Punctuated<Ident, Token![,]>) -> TokenStream {
let inner = setup_buffered_uarte_inner(args);

quote! {
fn setup_serial(
) -> impl ::rumcake::embedded_io_async::Write + ::rumcake::embedded_io_async::Read {
#inner
}
}
}
Loading

0 comments on commit 87fbf6c

Please sign in to comment.