Skip to content

Commit

Permalink
remove "drivers" feature flag and give drivers their own feature flags
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Univa committed Mar 6, 2024
1 parent 4a21aeb commit 4b65eef
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 83 deletions.
16 changes: 14 additions & 2 deletions docs/src/content/docs/features/feature-backlight.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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...
Expand Down Expand Up @@ -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.
15 changes: 13 additions & 2 deletions docs/src/content/docs/features/feature-display.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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...
Expand Down Expand Up @@ -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.
24 changes: 20 additions & 4 deletions docs/src/content/docs/features/feature-split.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "<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
Expand Down Expand Up @@ -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 = "<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
Expand Down Expand Up @@ -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.
15 changes: 13 additions & 2 deletions docs/src/content/docs/features/feature-underglow.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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...
Expand Down Expand Up @@ -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.
4 changes: 2 additions & 2 deletions rumcake-macros/src/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() };
}),
}
};
Expand Down
22 changes: 15 additions & 7 deletions rumcake/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -18,7 +17,10 @@ features = [
"display",
"split-peripheral",
"split-central",
"media-keycodes"
"media-keycodes",
"ws2812-bitbang",
"is31fl3731",
"ssd1306"
]

flavours = [
Expand Down Expand Up @@ -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" }

Expand Down Expand Up @@ -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"]

76 changes: 76 additions & 0 deletions rumcake/src/drivers/mod.rs
Original file line number Diff line number Diff line change
@@ -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<D: Write + Read> {
/// A serial driver that implements the [`embedded_io_async::Read`] and
/// [`embedded_io_async::Write`] traits.
pub serial: D,
}

#[cfg(feature = "split-central")]
impl<D: Write + Read> crate::split::drivers::CentralDeviceDriver for SerialSplitDriver<D> {
type DriverError = D::Error;

async fn receive_message_from_peripherals(
&mut self,
) -> Result<
crate::split::MessageToCentral,
crate::split::drivers::CentralDeviceError<Self::DriverError>,
> {
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<Self::DriverError>> {
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<D: Write + Read> crate::split::drivers::PeripheralDeviceDriver for SerialSplitDriver<D> {
type DriverError = D::Error;

async fn send_message_to_central(
&mut self,
event: crate::split::MessageToCentral,
) -> Result<(), crate::split::drivers::PeripheralDeviceError<Self::DriverError>> {
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<Self::DriverError>,
> {
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)
}
}
5 changes: 2 additions & 3 deletions rumcake/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ pub mod display;

pub mod hw;

#[cfg(feature = "drivers")]
pub mod drivers;

pub mod tasks {
Expand Down Expand Up @@ -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;
}
63 changes: 2 additions & 61 deletions rumcake/src/split/drivers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -27,39 +26,6 @@ pub trait CentralDeviceDriver {
) -> Result<(), CentralDeviceError<Self::DriverError>>;
}

/// 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<D: Write + Read> {
/// A serial driver that implements the [`embedded_io_async::Read`] and
/// [`embedded_io_async::Write`] traits.
pub serial: D,
}

impl<D: Write + Read> CentralDeviceDriver for SerialSplitDriver<D> {
type DriverError = D::Error;

async fn receive_message_from_peripherals(
&mut self,
) -> Result<MessageToCentral, CentralDeviceError<Self::DriverError>> {
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<Self::DriverError>> {
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<E> {
Expand Down Expand Up @@ -102,31 +68,6 @@ pub trait PeripheralDeviceDriver {
) -> Result<MessageToPeripheral, PeripheralDeviceError<Self::DriverError>>;
}

impl<D: Write + Read> PeripheralDeviceDriver for SerialSplitDriver<D> {
type DriverError = D::Error;

async fn send_message_to_central(
&mut self,
event: MessageToCentral,
) -> Result<(), PeripheralDeviceError<Self::DriverError>> {
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<MessageToPeripheral, PeripheralDeviceError<Self::DriverError>> {
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<T> {
Expand Down

0 comments on commit 4b65eef

Please sign in to comment.