From 295f0158ce94dcde5254c656db38825bb4542bd0 Mon Sep 17 00:00:00 2001 From: Thomas Preindl Date: Fri, 31 Jul 2026 16:38:08 +0200 Subject: [PATCH] fix(ble): send exact payload size for split message --- rmk/src/split/ble/central.rs | 42 +++++++++++++++------------------ rmk/src/split/ble/mod.rs | 42 +++++++++++++++++++++++++++++++++ rmk/src/split/ble/peripheral.rs | 24 ++++++++----------- 3 files changed, 71 insertions(+), 37 deletions(-) diff --git a/rmk/src/split/ble/central.rs b/rmk/src/split/ble/central.rs index d43fe2deb..487e6c710 100644 --- a/rmk/src/split/ble/central.rs +++ b/rmk/src/split/ble/central.rs @@ -9,6 +9,7 @@ use embassy_time::{Duration, Timer, with_timeout}; use heapless::VecView; use trouble_host::prelude::*; +use super::GattSplitMessage; use crate::ble::sleep::report_activity; use crate::ble::{update_ble_phy, update_conn_params}; use crate::channel::FLASH_CHANNEL; @@ -364,7 +365,7 @@ async fn run_peripheral_manager< info!("Services found"); if let Some(service) = services.first() { let message_to_central = client - .characteristic_by_uuid::<[u8; SPLIT_MESSAGE_MAX_SIZE]>( + .characteristic_by_uuid::( service, // uuid: 0e6313e3-bd0b-45c2-8d2e-37a2e8128bc3 &Uuid::Uuid128([ @@ -375,7 +376,7 @@ async fn run_peripheral_manager< .await?; info!("Message to central found"); let message_to_peripheral = client - .characteristic_by_uuid::<[u8; SPLIT_MESSAGE_MAX_SIZE]>( + .characteristic_by_uuid::( service, // uuid: 4b3514fb-cae4-4d38-a097-3a2a3d1c3b9c &Uuid::Uuid128([ @@ -404,7 +405,7 @@ pub(crate) struct BleSplitCentralDriver<'a, 'b, 'c, C: Controller + ControllerCm // Listener for split message from peripheral listener: NotificationListener<'b, 512>, // Characteristic to send split message to peripheral - message_to_peripheral: Characteristic<[u8; SPLIT_MESSAGE_MAX_SIZE]>, + message_to_peripheral: Characteristic, // Client client: &'c GattClient<'a, C, P, 10>, } @@ -412,7 +413,7 @@ pub(crate) struct BleSplitCentralDriver<'a, 'b, 'c, C: Controller + ControllerCm impl<'a, 'b, 'c, C: Controller + ControllerCmdAsync, P: PacketPool> BleSplitCentralDriver<'a, 'b, 'c, C, P> { pub(crate) fn new( listener: NotificationListener<'b, 512>, - message_to_peripheral: Characteristic<[u8; SPLIT_MESSAGE_MAX_SIZE]>, + message_to_peripheral: Characteristic, client: &'c GattClient<'a, C, P, 10>, ) -> Self { Self { @@ -445,27 +446,22 @@ impl<'a, 'b, 'c, C: Controller + ControllerCmdAsync, P: PacketPool> Sp for BleSplitCentralDriver<'a, 'b, 'c, C, P> { async fn write(&mut self, message: &SplitMessage) -> Result { - let mut buf = [0_u8; SPLIT_MESSAGE_MAX_SIZE]; - match postcard::to_slice(&message, &mut buf) { - Ok(_bytes) => { - if let Err(e) = self - .client - .write_characteristic_without_response(&self.message_to_peripheral, &buf) - .await - { - if let BleHostError::BleHost(Error::NotFound) = e { - error!("Peripheral disconnected"); - return Err(SplitDriverError::Disconnected); - } - #[cfg(feature = "defmt")] - let e = defmt::Debug2Format(&e); - error!("BLE message_to_peripheral_write error: {:?}", e); - } + let gatt_msg = GattSplitMessage::try_from(message)?; + if let Err(e) = self + .client + .write_characteristic_without_response(&self.message_to_peripheral, gatt_msg.as_gatt()) + .await + { + if let BleHostError::BleHost(Error::NotFound) = e { + error!("Peripheral disconnected"); + return Err(SplitDriverError::Disconnected); } - Err(e) => error!("Postcard serialize split message error: {}", e), - }; + #[cfg(feature = "defmt")] + let e = defmt::Debug2Format(&e); + error!("BLE message_to_peripheral_write error: {:?}", e); + } - Ok(SPLIT_MESSAGE_MAX_SIZE) + Ok(gatt_msg.len) } } diff --git a/rmk/src/split/ble/mod.rs b/rmk/src/split/ble/mod.rs index b9bdc08de..2713b789c 100644 --- a/rmk/src/split/ble/mod.rs +++ b/rmk/src/split/ble/mod.rs @@ -3,6 +3,10 @@ pub mod peripheral; use postcard::experimental::max_size::MaxSize; use serde::{Deserialize, Serialize}; +use trouble_host::types::gatt_traits::AsGatt; + +use super::SplitMessage; +use super::driver::SplitDriverError; #[derive(Clone, Debug, Serialize, Deserialize, MaxSize)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -21,3 +25,41 @@ impl PeerAddress { } } } + +#[derive(Default, Clone)] +pub(crate) struct GattSplitMessage { + buf: [u8; SplitMessage::POSTCARD_MAX_SIZE], + len: usize, +} + +impl TryFrom<&SplitMessage> for GattSplitMessage { + type Error = SplitDriverError; + + fn try_from(value: &SplitMessage) -> Result { + let mut buf = [0; SplitMessage::POSTCARD_MAX_SIZE]; + let encoded = postcard::to_slice(value, &mut buf).map_err(|e| { + error!("Postcard serialize split message error: {}", e); + SplitDriverError::SerializeError + })?; + + let len = encoded.len(); + + // Check if slice starts at the beginning of buffer + if encoded.as_ptr() != buf.as_ptr() { + error!("Postcard serialize split message did not use the buffer correctly!"); + return Err(SplitDriverError::SerializeError); + } + + Ok(Self { buf, len }) + } +} + +impl AsGatt for GattSplitMessage { + const MIN_SIZE: usize = 0; + + const MAX_SIZE: usize = SplitMessage::POSTCARD_MAX_SIZE; + + fn as_gatt(&self) -> &[u8] { + &self.buf[..self.len] + } +} diff --git a/rmk/src/split/ble/peripheral.rs b/rmk/src/split/ble/peripheral.rs index 7064a557e..edc097466 100644 --- a/rmk/src/split/ble/peripheral.rs +++ b/rmk/src/split/ble/peripheral.rs @@ -7,20 +7,20 @@ use trouble_host::prelude::*; #[cfg(feature = "storage")] use super::PeerAddress; +use super::{GattSplitMessage, SplitMessage}; use crate::event::{CentralConnectedEvent, KeyboardEvent, SubscribableEvent, publish_event}; use crate::split::driver::{SplitDriverError, SplitReader, SplitWriter}; use crate::split::peripheral::SplitPeripheral; -use crate::split::{SPLIT_MESSAGE_MAX_SIZE, SplitMessage}; use crate::state::update_status; /// Gatt service used in split peripheral to send split message to central #[gatt_service(uuid = "4dd5fbaa-18e5-4b07-bf0a-353698659946")] pub(crate) struct SplitBleService { #[characteristic(uuid = "0e6313e3-bd0b-45c2-8d2e-37a2e8128bc3", read, notify, indicate)] - pub(crate) message_to_central: [u8; SPLIT_MESSAGE_MAX_SIZE], + pub(crate) message_to_central: GattSplitMessage, #[characteristic(uuid = "4b3514fb-cae4-4d38-a097-3a2a3d1c3b9c", write_without_response, read, notify)] - pub(crate) message_to_peripheral: [u8; SPLIT_MESSAGE_MAX_SIZE], + pub(crate) message_to_peripheral: GattSplitMessage, } /// Gatt server in split peripheral @@ -31,16 +31,16 @@ pub(crate) struct BleSplitPeripheralServer { /// BLE driver for split peripheral pub(crate) struct BleSplitPeripheralDriver<'stack, 'server, 'c, P: PacketPool> { - message_to_peripheral: Characteristic<[u8; SPLIT_MESSAGE_MAX_SIZE]>, - message_to_central: Characteristic<[u8; SPLIT_MESSAGE_MAX_SIZE]>, + message_to_peripheral: Characteristic, + message_to_central: Characteristic, conn: &'c GattConnection<'stack, 'server, P>, } impl<'stack, 'server, 'c, P: PacketPool> BleSplitPeripheralDriver<'stack, 'server, 'c, P> { pub(crate) fn new(server: &'server BleSplitPeripheralServer, conn: &'c GattConnection<'stack, 'server, P>) -> Self { Self { - message_to_central: server.service.message_to_central, - message_to_peripheral: server.service.message_to_peripheral, + message_to_central: server.service.message_to_central.clone(), + message_to_peripheral: server.service.message_to_peripheral.clone(), conn, } } @@ -109,20 +109,16 @@ impl<'stack, 'server, 'c, P: PacketPool> SplitReader for BleSplitPeripheralDrive impl<'stack, 'server, 'c, P: PacketPool> SplitWriter for BleSplitPeripheralDriver<'stack, 'server, 'c, P> { async fn write(&mut self, message: &SplitMessage) -> Result { - let mut buf = [0_u8; SPLIT_MESSAGE_MAX_SIZE]; - postcard::to_slice(message, &mut buf).map_err(|e| { - error!("Postcard serialize split message error: {}", e); - SplitDriverError::SerializeError - })?; + let gatt_msg = GattSplitMessage::try_from(message)?; info!("Writing split message to central: {:?}", message); self.message_to_central - .notify(self.conn, &buf, true) + .notify(self.conn, &gatt_msg, true) .await .map_err(|e| { error!("BLE notify error: {:?}", e); SplitDriverError::BleError(1) })?; - Ok(buf.len()) + Ok(gatt_msg.len) } }