Skip to content

Commit

Permalink
Merge pull request #201 from HaoboGu/feat/sync_split_state
Browse files Browse the repository at this point in the history
  • Loading branch information
HaoboGu authored Dec 18, 2024
2 parents 1de30ac + aea4ed6 commit bb7e237
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 78 deletions.
1 change: 0 additions & 1 deletion rmk-macro/src/split/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ fn expand_split_peripheral_entry(
}
}
MatrixType::normal => {
let size = row + col;
quote! {
::rmk::split::peripheral::run_rmk_split_peripheral::<
::embassy_nrf::gpio::Input<'_>,
Expand Down
2 changes: 1 addition & 1 deletion rmk/src/ble/esp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::storage::nor_flash::esp_partition::{Partition, PartitionType};
use crate::storage::Storage;
use crate::via::process::VialService;
use crate::via::vial_task;
use crate::KEYBOARD_STATE;
use crate::CONNECTION_STATE;
use crate::KEYBOARD_STATE;
use crate::{
action::KeyAction, ble::ble_communication_task, config::RmkConfig, keyboard::Keyboard,
keymap::KeyMap,
Expand Down
2 changes: 1 addition & 1 deletion rmk/src/split/central.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::cell::RefCell;

use defmt::{error, info};
use defmt::info;
use embassy_executor::Spawner;
use embassy_time::{Instant, Timer};
use embassy_usb::driver::Driver;
Expand Down
76 changes: 53 additions & 23 deletions rmk/src/split/driver.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use core::sync::atomic::Ordering;

///! The abstracted driver layer of the split keyboard.
///!
use super::SplitMessage;
use crate::keyboard::{key_event_channel, KeyEvent};
use crate::CONNECTION_STATE;
use defmt::{debug, error, warn};
use embassy_futures::select::select;

#[derive(Debug, Clone, Copy, defmt::Format)]
pub(crate) enum SplitDriverError {
Expand Down Expand Up @@ -36,7 +39,7 @@ pub(crate) struct PeripheralMatrixMonitor<
const COL: usize,
const ROW_OFFSET: usize,
const COL_OFFSET: usize,
R: SplitReader,
R: SplitReader + SplitWriter,
> {
/// Receiver
receiver: R,
Expand All @@ -49,7 +52,7 @@ impl<
const COL: usize,
const ROW_OFFSET: usize,
const COL_OFFSET: usize,
R: SplitReader,
R: SplitReader + SplitWriter,
> PeripheralMatrixMonitor<ROW, COL, ROW_OFFSET, COL_OFFSET, R>
{
pub(crate) fn new(receiver: R, id: usize) -> Self {
Expand All @@ -60,32 +63,59 @@ impl<
///
/// The monitor receives from the peripheral and forward the message to key_event_channel.
pub(crate) async fn run(mut self) -> ! {
let mut conn_state = CONNECTION_STATE.load(Ordering::Acquire);
// Send once on start
if let Err(e) = self
.receiver
.write(&SplitMessage::ConnectionState(conn_state))
.await
{
error!("SplitDriver write error: {}", e);
}
loop {
match self.receiver.read().await {
Ok(received_message) => {
debug!("Received peripheral message: {}", received_message);
if let SplitMessage::Key(e) = received_message {
// Check row/col
if e.row as usize > ROW || e.col as usize > COL {
error!("Invalid peripheral row/col: {} {}", e.row, e.col);
continue;
}
match select(self.receiver.read(), embassy_time::Timer::after_millis(200)).await {
embassy_futures::select::Either::First(read_result) => match read_result {
Ok(received_message) => {
debug!("Received peripheral message: {}", received_message);
if let SplitMessage::Key(e) = received_message {
// Check row/col
if e.row as usize > ROW || e.col as usize > COL {
error!("Invalid peripheral row/col: {} {}", e.row, e.col);
continue;
}

if CONNECTION_STATE.load(core::sync::atomic::Ordering::Acquire) {
// Only when the connection is established, send the key event.
key_event_channel
.send(KeyEvent {
row: e.row + ROW_OFFSET as u8,
col: e.col + COL_OFFSET as u8,
pressed: e.pressed,
})
.await;
} else {
warn!("Key event from peripheral is ignored because the connection is not established.");
if CONNECTION_STATE.load(core::sync::atomic::Ordering::Acquire) {
// Only when the connection is established, send the key event.
key_event_channel
.send(KeyEvent {
row: e.row + ROW_OFFSET as u8,
col: e.col + COL_OFFSET as u8,
pressed: e.pressed,
})
.await;
} else {
warn!("Key event from peripheral is ignored because the connection is not established.");
}
}
}
Err(e) => error!("Peripheral message read error: {:?}", e),
},
embassy_futures::select::Either::Second(_) => {
// Check ConnectionState every 200ms
// Current, only ConnectionState will be notified to peripheral
let current_conn_state = CONNECTION_STATE.load(Ordering::Acquire);
if conn_state != current_conn_state {
// ConnectionState changed, notify peripheral
conn_state = current_conn_state;
if let Err(e) = self
.receiver
.write(&SplitMessage::ConnectionState(conn_state))
.await
{
error!("SplitDriver write error: {}", e);
};
}
}
Err(e) => error!("Peripheral message read error: {:?}", e),
}
}
}
Expand Down
92 changes: 45 additions & 47 deletions rmk/src/split/nrf/central.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@ use embassy_sync::{
};
use nrf_softdevice::ble::{central, gatt_client, Address, AddressType};

use crate::{
split::{
driver::{PeripheralMatrixMonitor, SplitDriverError, SplitReader},
SplitMessage, SPLIT_MESSAGE_MAX_SIZE,
},
CONNECTION_STATE,
use crate::split::{
driver::{PeripheralMatrixMonitor, SplitDriverError, SplitReader, SplitWriter},
SplitMessage, SPLIT_MESSAGE_MAX_SIZE,
};

/// Gatt client used in split central to receive split message from peripherals
Expand All @@ -35,13 +32,21 @@ pub(crate) async fn run_ble_peripheral_monitor<
id: usize,
addr: [u8; 6],
) {
let channel: Channel<CriticalSectionRawMutex, SplitMessage, 8> = Channel::new();

let sender = channel.sender();
let run_ble_client = run_ble_client(sender, addr);

let receiver = channel.receiver();
let split_ble_driver = BleSplitCentralDriver { receiver };
// Channel is used to receive messages from peripheral
let receive_channel: Channel<CriticalSectionRawMutex, SplitMessage, 8> = Channel::new();
// Channel is used to notify messages to peripheral
let notify_channel: Channel<CriticalSectionRawMutex, SplitMessage, 8> = Channel::new();

let receive_sender = receive_channel.sender();
let receive_receiver = receive_channel.receiver();
let notify_sender = notify_channel.sender();
let notify_receiver = notify_channel.receiver();
let run_ble_client = run_ble_client(receive_sender, notify_receiver, addr);

let split_ble_driver = BleSplitCentralDriver {
receiver: receive_receiver,
sender: notify_sender,
};

let peripheral =
PeripheralMatrixMonitor::<ROW, COL, ROW_OFFSET, COL_OFFSET, _>::new(split_ble_driver, id);
Expand All @@ -58,7 +63,8 @@ static CONNECTING_CLIENT: AtomicBool = AtomicBool::new(false);
/// All received messages are sent to the sender, those message are received in `SplitBleCentralDriver`.
/// Split driver will take `SplitBleCentralDriver` as the reader, process the message in matrix scanning.
pub(crate) async fn run_ble_client(
sender: Sender<'_, CriticalSectionRawMutex, SplitMessage, 8>,
receive_sender: Sender<'_, CriticalSectionRawMutex, SplitMessage, 8>,
notify_receiver: Receiver<'_, CriticalSectionRawMutex, SplitMessage, 8>,
addr: [u8; 6],
) -> ! {
// Wait 1s, ensure that the softdevice is ready
Expand Down Expand Up @@ -113,7 +119,7 @@ pub(crate) async fn run_ble_client(
BleSplitCentralClientEvent::MessageToCentralNotification(message) => {
match postcard::from_bytes(&message) {
Ok(split_message) => {
if let Err(e) = sender.try_send(split_message) {
if let Err(e) = receive_sender.try_send(split_message) {
error!("BLE_SYNC_CHANNEL send message error: {}", e);
}
}
Expand All @@ -126,35 +132,17 @@ pub(crate) async fn run_ble_client(

// Notify messages to peripheral
let notify_peripheral = async {
let mut conn_state = CONNECTION_STATE.load(Ordering::Acquire);
// Send once on start
let mut buf = [0_u8; SPLIT_MESSAGE_MAX_SIZE];
match postcard::to_slice(&SplitMessage::ConnectionState(conn_state), &mut buf) {
Ok(_bytes) => {
if let Err(e) = ble_client.message_to_peripheral_write(&buf).await {
error!("BLE message_to_peripheral_write error: {}", e);
}
}
Err(e) => error!("Postcard serialize split message error: {}", e),
};
loop {
// Check the central state every 200ms
embassy_time::Timer::after_millis(200).await;
// Current, only ConnectionState will be notified to peripheral
let current_conn_state = CONNECTION_STATE.load(Ordering::Acquire);
if conn_state != current_conn_state {
// ConnectionState changed, notify peripheral
conn_state = current_conn_state;
let mut buf = [0_u8; SPLIT_MESSAGE_MAX_SIZE];
match postcard::to_slice(&SplitMessage::ConnectionState(conn_state), &mut buf) {
Ok(_bytes) => {
if let Err(e) = ble_client.message_to_peripheral_write(&buf).await {
error!("BLE message_to_peripheral_write error: {}", e);
}
let mut buf = [0_u8; SPLIT_MESSAGE_MAX_SIZE];
let message = notify_receiver.receive().await;
match postcard::to_slice(&message, &mut buf) {
Ok(_bytes) => {
if let Err(e) = ble_client.message_to_peripheral_write(&buf).await {
error!("BLE message_to_peripheral_write error: {}", e);
}
Err(e) => error!("Postcard serialize split message error: {}", e),
};
}
}
Err(e) => error!("Postcard serialize split message error: {}", e),
};
}
};

Expand All @@ -170,18 +158,28 @@ pub(crate) async fn run_ble_client(
}
}

/// Ble central driver which reads the split message.
/// Ble central driver which reads and writes the split message.
///
/// Different from serial, BLE split message is received and processed in a separate service.
/// The BLE service should keep running, it sends out the split message to the channel in the callback.
/// It's impossible to implement `SplitReader` for BLE service,
/// so we need this thin wrapper that receives the message from the channel.
/// Different from serial, BLE split message is processed in a separate service.
/// The BLE service should keep running, it processes the split message in the callback, which is not async.
/// It's impossible to implement `SplitReader` or `SplitWriter` for BLE service,
/// so we need this wrapper to forward split message to channel.
pub(crate) struct BleSplitCentralDriver<'a> {
// Receiver that receives message from peripheral
pub(crate) receiver: Receiver<'a, CriticalSectionRawMutex, SplitMessage, 8>,
// Sender that send message to peripherals
pub(crate) sender: Sender<'a, CriticalSectionRawMutex, SplitMessage, 8>,
}

impl<'a> SplitReader for BleSplitCentralDriver<'a> {
async fn read(&mut self) -> Result<SplitMessage, SplitDriverError> {
Ok(self.receiver.receive().await)
}
}

impl SplitWriter for BleSplitCentralDriver<'_> {
async fn write(&mut self, message: &SplitMessage) -> Result<usize, SplitDriverError> {
self.sender.send(message.clone()).await;
Ok(SPLIT_MESSAGE_MAX_SIZE)
}
}
3 changes: 2 additions & 1 deletion rmk/src/split/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::direct_pin::DirectPinMatrix;
use crate::keyboard::key_event_channel;
use crate::matrix::Matrix;
use crate::CONNECTION_STATE;
use defmt::error;
use defmt::{error, info};
#[cfg(feature = "_nrf_ble")]
use embassy_executor::Spawner;
use embassy_futures::select::select;
Expand Down Expand Up @@ -161,6 +161,7 @@ impl<S: SplitWriter + SplitReader> SplitPeripheral<S> {
embassy_futures::select::Either::Second(e) => {
// Only send the key event if the connection is established
if CONNECTION_STATE.load(core::sync::atomic::Ordering::Acquire) {
info!("Writing split message to central");
self.split_driver.write(&SplitMessage::Key(e)).await.ok();
}
}
Expand Down
11 changes: 8 additions & 3 deletions rmk/src/split/serial/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use defmt::{error, info};
use embedded_io_async::{Read, Write};

use crate::{matrix::MatrixTrait, split::{
driver::{PeripheralMatrixMonitor, SplitReader, SplitWriter}, peripheral::SplitPeripheral, SplitMessage, SPLIT_MESSAGE_MAX_SIZE
}};
use crate::{
matrix::MatrixTrait,
split::{
driver::{PeripheralMatrixMonitor, SplitReader, SplitWriter},
peripheral::SplitPeripheral,
SplitMessage, SPLIT_MESSAGE_MAX_SIZE,
},
};

use super::driver::SplitDriverError;

Expand Down
3 changes: 2 additions & 1 deletion rmk/src/usb/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use usbd_hid::descriptor::SerializedDescriptor;
use crate::{
config::KeyboardUsbConfig,
hid::{UsbHidReader, UsbHidReaderWriter, UsbHidWriter},
usb::descriptor::{CompositeReport, ViaReport}, CONNECTION_STATE,
usb::descriptor::{CompositeReport, ViaReport},
CONNECTION_STATE,
};

pub(crate) static USB_STATE: AtomicU8 = AtomicU8::new(UsbState::Disabled as u8);
Expand Down

0 comments on commit bb7e237

Please sign in to comment.