From 4b65eefa7b98574e0f40e4998329993ecf2a8695 Mon Sep 17 00:00:00 2001 From: Univa <41708691+Univa@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:47:36 -0500 Subject: [PATCH] remove "drivers" feature flag and give drivers their own feature flags this moves the serial driver from the "split" module to the "drivers" module. this also updates the docs to include lists of available drivers for each feature. --- .../docs/features/feature-backlight.md | 16 +++- .../content/docs/features/feature-display.md | 15 +++- .../content/docs/features/feature-split.md | 24 +++++- .../docs/features/feature-underglow.md | 15 +++- rumcake-macros/src/keyboard.rs | 4 +- rumcake/Cargo.toml | 22 ++++-- rumcake/src/drivers/mod.rs | 76 +++++++++++++++++++ rumcake/src/lib.rs | 5 +- rumcake/src/split/drivers.rs | 63 +-------------- 9 files changed, 157 insertions(+), 83 deletions(-) diff --git a/docs/src/content/docs/features/feature-backlight.md b/docs/src/content/docs/features/feature-backlight.md index 30a7efe..819cac1 100644 --- a/docs/src/content/docs/features/feature-backlight.md +++ b/docs/src/content/docs/features/feature-backlight.md @@ -22,7 +22,7 @@ You must enable the following `rumcake` features: - `simple-backlight` (single color backlighting, all LEDs have the same brightness) - `simple-backlight-matrix` (single color backlighting, each LED in the matrix is individually addressable) - `rgb-backlight-matrix` (RGB backlighting, each LED in the matrix is individually addressable) -- `drivers` (optional built-in drivers to power backlighting) +- Feature flag for one of the [available backlight drivers](#available-drivers) that you would like to use - `storage` (optional, if you want to save your backlight settings) Some drivers may not be able to support all backlight types. @@ -123,7 +123,10 @@ Note that for reactive effects, matrix positions will map directly to LED positi a key at switch matrix position row 0, column 0, will correspond to the LED at row 0, column 0 on your LED matrix. ::: -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`: +Lastly, you must also implement the appropriate trait that corresponds to your chosen driver in the `#[keyboard]` macro. +Check the [list of available backlight drivers](#available-drivers) for this information. + +For example, with `is31fl3731`, you must implement `IS31FL3731DriverSettings` and `IS31FL3731BacklightDriver`: ```rust ins={3-30} // later in your file... @@ -219,3 +222,12 @@ use rumcake::keyboard::{build_layout, Keyboard, Keycode::*}; - [ ] RGB Backlight animations - [ ] Allow different backlighting systems to be used at the same time + +# Available Drivers + +| Name | Feature Flag | `keyboard` Macro Driver String | Required Traits | +| -------------- | ---------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| IS31FL3731 | `is31fl3731` | `"is31fl3731"` | `IS31FL3731DriverSettings`[^1], [`IS31FL3731BacklightDriver`](/rumcake/api/nrf52840/rumcake/drivers/is31fl3731/backlight/trait.IS31FL3731BacklightDriver.html) | +| WS2812 Bitbang | `ws2812_bitbang` | `"ws2812_bitbang"` | `WS2812BitbangDriverSettings`[^1], [`WS2812BitbangBacklightDriver`](/rumcake/api/nrf52840/rumcake/drivers/ws2812_bitbang/backlight/trait.WS2812BitbangBacklightDriver.html) | + +[^1]: This trait is generated by the `keyboard` macro, and not included in the `rumcake` API. diff --git a/docs/src/content/docs/features/feature-display.md b/docs/src/content/docs/features/feature-display.md index de59d6f..424e5ac 100644 --- a/docs/src/content/docs/features/feature-display.md +++ b/docs/src/content/docs/features/feature-display.md @@ -14,7 +14,7 @@ etc. You must enable the following `rumcake` features: - `display` -- `drivers` (optional built-in drivers to power displays) +- Feature flag for one of the [available display drivers](#available-drivers) that you would like to use ## Required code @@ -42,7 +42,9 @@ 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`: +Check the [list of available display drivers](#available-drivers) for this information. + +For example, with `ssd1306`, you must implement `Ssd1306I2cDriverSettings` and `Ssd1306I2cDisplayDriver`: ```rust ins={3-23} // later in your file... @@ -123,3 +125,12 @@ impl Ssd1306I2cDisplayDriver for MyKeyboard { .unwrap(); } ``` + +# Available Drivers + +| Name | Feature Flag | `keyboard` Macro Driver String | Required Traits | +| ----------- | ------------ | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| SSD1306[^1] | `ssd1306` | `"ssd1306"` | `Ssd1306I2cDriverSettings`[^2], [`Ssd1306I2cDisplayDriver`](/rumcake/api/nrf52840/rumcake/drivers/ssd1306/display/trait.Ssd1306I2cDisplayDriver.html) | + +[^1]: I2C only +[^2]: This trait is generated by the `keyboard` macro, and not included in the `rumcake` API. diff --git a/docs/src/content/docs/features/feature-split.md b/docs/src/content/docs/features/feature-split.md index f95b6f6..c27f6f5 100644 --- a/docs/src/content/docs/features/feature-split.md +++ b/docs/src/content/docs/features/feature-split.md @@ -40,13 +40,16 @@ Typically, the central device could be a dongle (good for saving battery life), You must compile a binary with the following `rumcake` features: - `split-central` -- `drivers` (optional built-in drivers to connect your central device to peripheral devices) +- Feature flag for one of the [available split drivers](#available-drivers) that you would like to use ## Required code for central device To set up the central device, you must add `split_central(driver = "")` to your `#[keyboard]` macro invocation, -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`: +and your keyboard must implement the appropriate trait for the driver you're using. Check the [list of available split +keyboard drivers](#available-drivers) for this information. + +For example, with the `ble` and an nRF5x chip selected, you must implement `NRFBLECentralDriverSettings`, +and `BluetoothDevice`: ```rust ins={6-8,20-36} // left.rs @@ -118,7 +121,7 @@ You must compile a binary with the following `rumcake` features: To set up the peripheral device, you must add `split_peripheral(driver = "")` to your `#[keyboard]` macro invocation, 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 `NRFBLEPeripheralDevice`, and `BluetoothDevice`: +selected, you must implement `NRFBLEPeripheralDriverSettings`, and `BluetoothDevice`: ```rust ins={6-8,12-24} // right.rs @@ -187,3 +190,16 @@ struct MyKeyboardDongle; - [ ] Single device that can act as both a peripheral and central device - [ ] Serial (half duplex) driver - [ ] I2C driver + +# Available Drivers + +| Name | Feature Flag | `keyboard` Macro Driver String | Required Traits | +| ---------------- | -------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Serial[^1] | N/A (available by default) | `"serial"` | `SerialDriverSettings`[^2] | +| nRF Bluetooth LE | `nrf-ble` | `"ble"` | [`BluetoothDevice`](rumcake/hw/mcu/trait.BluetoothDevice.html), `NRFBLECentralDriverSettings`[^2] (central device only), `NRFBLEPeripheralDriverSettings`[^2] (peripheral device only) | + +[^1]: + Compatible with any type that implements both `embedded_io_async::Read` and `embedded_io_async::Write`. + This includes `embassy_nrf::buffered_uarte::BufferedUarte` (nRF UARTE) and `embassy_stm32::usart::BufferedUart` (STM32 UART). + +[^2]: This trait is generated by the `keyboard` macro, and not included in the `rumcake` API. diff --git a/docs/src/content/docs/features/feature-underglow.md b/docs/src/content/docs/features/feature-underglow.md index 8720383..add873e 100644 --- a/docs/src/content/docs/features/feature-underglow.md +++ b/docs/src/content/docs/features/feature-underglow.md @@ -14,7 +14,7 @@ addressable. You must enable the following `rumcake` features: - `underglow` -- `drivers` (optional built-in drivers to power underglow) +- Feature flag for one of the [available underglow drivers](#available-drivers) that you would like to use - `storage` (optional, if you want to save your backlight settings) ## Required code @@ -73,7 +73,10 @@ You will need to do additional setup for your selected storage driver as well. 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`: +Lastly, you must also implement the appropriate trait that corresponds to your chosen driver in the `#[keyboard]` macro. +Check the [list of available underglow drivers](#available-drivers) for this information. + +For example, with `ws2812_bitbang`, you must implement `WS2812BitbangDriverSettings`: ```rust ins={3-7} // later in your file... @@ -127,3 +130,11 @@ use rumcake::keyboard::{build_layout, Keyboard, Keycode::*}; } } ``` + +# Available Drivers + +| Name | Feature Flag | `keyboard` Macro Driver String | Required Traits | +| -------------- | ---------------- | ------------------------------ | --------------------------------- | +| WS2812 Bitbang | `ws2812-bitbang` | `"ws2812_bitbang"` | `WS2812BitbangDriverSettings`[^1] | + +[^1]: This trait is generated by the `keyboard` macro, and not included in the `rumcake` API. diff --git a/rumcake-macros/src/keyboard.rs b/rumcake-macros/src/keyboard.rs index f186df4..645bafc 100644 --- a/rumcake-macros/src/keyboard.rs +++ b/rumcake-macros/src/keyboard.rs @@ -103,10 +103,10 @@ fn setup_split_driver( traits.insert(driver, crate::drivers::serial_driver_trait()); match role { SplitRole::Central => initialization.extend(quote! { - let split_central_driver = ::rumcake::split::drivers::SerialSplitDriver { serial: <#kb_name as SerialDriverSettings>::setup_serial() }; + let split_central_driver = ::rumcake::drivers::SerialSplitDriver { serial: <#kb_name as SerialDriverSettings>::setup_serial() }; }), SplitRole::Peripheral => initialization.extend(quote! { - let split_peripheral_driver = ::rumcake::split::drivers::SerialSplitDriver { serial: <#kb_name as SerialDriverSettings>::setup_serial() }; + let split_peripheral_driver = ::rumcake::drivers::SerialSplitDriver { serial: <#kb_name as SerialDriverSettings>::setup_serial() }; }), } }; diff --git a/rumcake/Cargo.toml b/rumcake/Cargo.toml index 4aae5d6..5857d7e 100644 --- a/rumcake/Cargo.toml +++ b/rumcake/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" # Metadata for generating docs using ../docs/scripts/gen_api_docs.js # API doc generation is inspired by they way embassy-rs generates their docs: https://github.com/embassy-rs/docserver features = [ - "drivers", "storage", "simple-backlight", "simple-backlight-matrix", @@ -18,7 +17,10 @@ features = [ "display", "split-peripheral", "split-central", - "media-keycodes" + "media-keycodes", + "ws2812-bitbang", + "is31fl3731", + "ssd1306" ] flavours = [ @@ -69,11 +71,9 @@ postcard = { version = "1.0.7", features = ["experimental-derive"] } # third party utilities for dealing with rgb values smart-leds = "0.3.0" -# third party drivers for backlight -is31fl3731 = { git = "https://github.com/Univa/is31fl3731", features = ["async"] } - -# third party drivers for display -ssd1306 = "0.8.2" +# third party drivers +is31fl3731 = { git = "https://github.com/Univa/is31fl3731", features = ["async"], optional = true } +ssd1306 = { version = "0.8.2", optional = true } rumcake-macros = { path = "../rumcake-macros" } @@ -125,3 +125,11 @@ display = [] split-peripheral = ["nrf-softdevice?/ble-peripheral", "nrf-softdevice?/ble-gatt-server"] split-central = ["nrf-softdevice?/ble-central", "nrf-softdevice?/ble-gatt-client"] +# +# Drivers +# + +ws2812-bitbang = [] +is31fl3731 = ["dep:is31fl3731"] +ssd1306 = ["dep:ssd1306"] + diff --git a/rumcake/src/drivers/mod.rs b/rumcake/src/drivers/mod.rs index 2d3f20d..e3f1178 100644 --- a/rumcake/src/drivers/mod.rs +++ b/rumcake/src/drivers/mod.rs @@ -1,7 +1,83 @@ //! An optional set of built-in drivers which implement rumcake's driver traits, so they can be used with rumcake tasks. +use embedded_io_async::{Read, Write}; + +#[cfg(feature = "is31fl3731")] pub mod is31fl3731; + #[cfg(feature = "nrf-ble")] pub mod nrf_ble; + +#[cfg(feature = "ssd1306")] pub mod ssd1306; + +#[cfg(feature = "ws2812-bitbang")] pub mod ws2812_bitbang; + +/// Struct that allows you to use a serial driver (implementor of both [`embedded_io_async::Read`] +/// and [`embedded_io_async::Write`]) with rumcake. This can be used for split keyboards. +pub struct SerialSplitDriver { + /// A serial driver that implements the [`embedded_io_async::Read`] and + /// [`embedded_io_async::Write`] traits. + pub serial: D, +} + +#[cfg(feature = "split-central")] +impl crate::split::drivers::CentralDeviceDriver for SerialSplitDriver { + type DriverError = D::Error; + + async fn receive_message_from_peripherals( + &mut self, + ) -> Result< + crate::split::MessageToCentral, + crate::split::drivers::CentralDeviceError, + > { + let mut buffer = [0; crate::split::MESSAGE_TO_CENTRAL_BUFFER_SIZE]; + self.serial.read_exact(&mut buffer).await?; + postcard::from_bytes_cobs(&mut buffer) + .map_err(crate::split::drivers::CentralDeviceError::DeserializationError) + } + + async fn broadcast_message_to_peripherals( + &mut self, + message: crate::split::MessageToPeripheral, + ) -> Result<(), crate::split::drivers::CentralDeviceError> { + let mut buffer = [0; crate::split::MESSAGE_TO_PERIPHERAL_BUFFER_SIZE]; + postcard::to_slice_cobs(&message, &mut buffer) + .map_err(crate::split::drivers::CentralDeviceError::SerializationError)?; + self.serial + .write_all(&buffer) + .await + .map_err(crate::split::drivers::CentralDeviceError::DriverError) + } +} + +#[cfg(feature = "split-peripheral")] +impl crate::split::drivers::PeripheralDeviceDriver for SerialSplitDriver { + type DriverError = D::Error; + + async fn send_message_to_central( + &mut self, + event: crate::split::MessageToCentral, + ) -> Result<(), crate::split::drivers::PeripheralDeviceError> { + let mut buffer = [0; crate::split::MESSAGE_TO_CENTRAL_BUFFER_SIZE]; + postcard::to_slice_cobs(&event, &mut buffer) + .map_err(crate::split::drivers::PeripheralDeviceError::SerializationError)?; + self.serial + .write_all(&buffer) + .await + .map_err(crate::split::drivers::PeripheralDeviceError::DriverError) + } + + async fn receive_message_from_central( + &mut self, + ) -> Result< + crate::split::MessageToPeripheral, + crate::split::drivers::PeripheralDeviceError, + > { + let mut buffer = [0; crate::split::MESSAGE_TO_PERIPHERAL_BUFFER_SIZE]; + self.serial.read_exact(&mut buffer).await?; + postcard::from_bytes_cobs(&mut buffer) + .map_err(crate::split::drivers::PeripheralDeviceError::DeserializationError) + } +} diff --git a/rumcake/src/lib.rs b/rumcake/src/lib.rs index 6c4dc6a..e7f1295 100644 --- a/rumcake/src/lib.rs +++ b/rumcake/src/lib.rs @@ -150,7 +150,6 @@ pub mod display; pub mod hw; -#[cfg(feature = "drivers")] pub mod drivers; pub mod tasks { @@ -212,8 +211,8 @@ pub mod tasks { #[cfg(all(feature = "nrf", feature = "bluetooth"))] pub use crate::bluetooth::nrf_ble::__nrf_ble_task; - #[cfg(all(feature = "drivers", feature = "nrf-ble", feature = "split-central"))] + #[cfg(all(feature = "nrf-ble", feature = "split-central"))] pub use crate::drivers::nrf_ble::central::__nrf_ble_central_task; - #[cfg(all(feature = "drivers", feature = "nrf-ble", feature = "split-peripheral"))] + #[cfg(all(feature = "nrf-ble", feature = "split-peripheral"))] pub use crate::drivers::nrf_ble::peripheral::__nrf_ble_peripheral_task; } diff --git a/rumcake/src/split/drivers.rs b/rumcake/src/split/drivers.rs index 8359afa..669c0b4 100644 --- a/rumcake/src/split/drivers.rs +++ b/rumcake/src/split/drivers.rs @@ -4,11 +4,10 @@ use core::fmt::Debug; use embedded_io_async::ReadExactError; -use embedded_io_async::{Read, Write}; use postcard::Error; -use super::{MessageToCentral, MESSAGE_TO_CENTRAL_BUFFER_SIZE}; -use super::{MessageToPeripheral, MESSAGE_TO_PERIPHERAL_BUFFER_SIZE}; +use super::MessageToCentral; +use super::MessageToPeripheral; /// A trait that a driver must implement to allow a central device to send and receive messages from peripherals. pub trait CentralDeviceDriver { @@ -27,39 +26,6 @@ pub trait CentralDeviceDriver { ) -> Result<(), CentralDeviceError>; } -/// Struct that allows you to use a serial driver (implementor of both [`embedded_io_async::Read`] -/// and [`embedded_io_async::Write`]) with rumcake's split keyboard tasks. -pub struct SerialSplitDriver { - /// A serial driver that implements the [`embedded_io_async::Read`] and - /// [`embedded_io_async::Write`] traits. - pub serial: D, -} - -impl CentralDeviceDriver for SerialSplitDriver { - type DriverError = D::Error; - - async fn receive_message_from_peripherals( - &mut self, - ) -> Result> { - let mut buffer = [0; MESSAGE_TO_CENTRAL_BUFFER_SIZE]; - self.serial.read_exact(&mut buffer).await?; - postcard::from_bytes_cobs(&mut buffer).map_err(CentralDeviceError::DeserializationError) - } - - async fn broadcast_message_to_peripherals( - &mut self, - message: MessageToPeripheral, - ) -> Result<(), CentralDeviceError> { - let mut buffer = [0; MESSAGE_TO_PERIPHERAL_BUFFER_SIZE]; - postcard::to_slice_cobs(&message, &mut buffer) - .map_err(CentralDeviceError::SerializationError)?; - self.serial - .write_all(&buffer) - .await - .map_err(CentralDeviceError::DriverError) - } -} - #[derive(Debug)] /// Types of errors that can occur when a central device sends and receives messages from peripherals pub enum CentralDeviceError { @@ -102,31 +68,6 @@ pub trait PeripheralDeviceDriver { ) -> Result>; } -impl PeripheralDeviceDriver for SerialSplitDriver { - type DriverError = D::Error; - - async fn send_message_to_central( - &mut self, - event: MessageToCentral, - ) -> Result<(), PeripheralDeviceError> { - let mut buffer = [0; MESSAGE_TO_CENTRAL_BUFFER_SIZE]; - postcard::to_slice_cobs(&event, &mut buffer) - .map_err(PeripheralDeviceError::SerializationError)?; - self.serial - .write_all(&buffer) - .await - .map_err(PeripheralDeviceError::DriverError) - } - - async fn receive_message_from_central( - &mut self, - ) -> Result> { - let mut buffer = [0; MESSAGE_TO_PERIPHERAL_BUFFER_SIZE]; - self.serial.read_exact(&mut buffer).await?; - postcard::from_bytes_cobs(&mut buffer).map_err(PeripheralDeviceError::DeserializationError) - } -} - #[derive(Debug)] /// Types of errors that can occur when a peripheral device sends and receives messages from a central device pub enum PeripheralDeviceError {