inital structure for bms communication protocol implemented

This commit is contained in:
2026-01-04 14:02:49 +01:00
parent df6d9bf03d
commit 95c5045a00
3 changed files with 173 additions and 8 deletions
Generated
+3
View File
@@ -535,6 +535,9 @@ dependencies = [
[[package]]
name = "lib-bms-protocol"
version = "0.1.0"
dependencies = [
"embedded-hal 1.0.0",
]
[[package]]
name = "litrs"
+1
View File
@@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
embedded-hal = "1.0.0"
[profile.dev]
+169 -8
View File
@@ -1,29 +1,190 @@
#![no_std]
use embedded_hal::i2c::{I2c, Operation, SevenBitAddress};
pub const BMS_I2C_ADDRESS: u8 = 0x55;
pub trait BmsReadable {
fn read_from_i2c<I>(i2c_dev: &mut I) -> Result<Self, BmsProtocolError>
where
Self: Sized,
I: I2c<SevenBitAddress>;
}
pub trait BmsWriteable {
fn write_to_device<I>(&self, i2c_dev: &mut I) -> Result<(), BmsProtocolError>
where
I: I2c<SevenBitAddress>;
}
pub enum BmsProtocolError {
I2cCommunicationError,
}
impl<E> From<E> for BmsProtocolError
where
E: embedded_hal::i2c::Error,
{
fn from(_value: E) -> Self {
Self::I2cCommunicationError
}
}
#[derive(Debug)]
pub struct BmsSoftwareReset;
impl BmsWriteable for BmsSoftwareReset {
fn write_to_device<I>(&self, i2c_dev: &mut I) -> Result<(), BmsProtocolError>
where
I: I2c<SevenBitAddress>,
{
i2c_dev.write(
BMS_I2C_ADDRESS,
&(BmsRegisterMap::Reset as u32).to_be_bytes(),
)?;
Ok(())
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct Version(u32);
pub struct ProtocolVersion(u32);
impl BmsReadable for ProtocolVersion {
fn read_from_i2c<I>(i2c_dev: &mut I) -> Result<Self, BmsProtocolError>
where
Self: Sized,
I: I2c<SevenBitAddress>,
{
let cmd = BmsRegisterMap::ProtocolVersion;
let mut version: [u8; 4] = [0x00; 4];
i2c_dev.transaction(
BMS_I2C_ADDRESS,
&mut [
Operation::Write(&(cmd as u32).to_be_bytes()),
Operation::Read(&mut version),
],
)?;
Ok(ProtocolVersion(u32::from_be_bytes(version)))
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct FirmwareVersion(u32);
impl BmsReadable for FirmwareVersion {
fn read_from_i2c<I>(i2c_dev: &mut I) -> Result<Self, BmsProtocolError>
where
Self: Sized,
I: I2c<SevenBitAddress>,
{
let cmd = BmsRegisterMap::FirmwareVersion;
let mut version: [u8; 4] = [0x00; 4];
i2c_dev.transaction(
BMS_I2C_ADDRESS,
&mut [
Operation::Write(&(cmd as u32).to_be_bytes()),
Operation::Read(&mut version),
],
)?;
Ok(FirmwareVersion(u32::from_be_bytes(version)))
}
}
#[derive(Debug)]
pub struct Config {
pub capacity_mah: u32,
pub v_full_mv: u32,
pub v_full_mv: u32,
pub v_empty_mv: u32,
}
impl BmsReadable for Config {
fn read_from_i2c<I>(i2c_dev: &mut I) -> Result<Self, BmsProtocolError>
where
Self: Sized,
I: I2c<SevenBitAddress>,
{
let cmd = BmsRegisterMap::ConfigCapacityMilliAmpereHours;
let mut capacity_mah: [u8; 4] = [0x00; 4];
let mut v_full_mv: [u8; 4] = [0x00; 4];
let mut v_empty_mv: [u8; 4] = [0x00; 4];
i2c_dev.transaction(
BMS_I2C_ADDRESS,
&mut [
Operation::Write(&(cmd as u32).to_be_bytes()),
Operation::Read(&mut capacity_mah),
Operation::Read(&mut v_full_mv),
Operation::Read(&mut v_empty_mv),
],
)?;
Ok(Config {
capacity_mah: u32::from_be_bytes(capacity_mah),
v_full_mv: u32::from_be_bytes(v_full_mv),
v_empty_mv: u32::from_be_bytes(v_empty_mv),
})
}
}
#[derive(Debug, Clone, Copy)]
pub struct BatteryState {
pub lifetime_capacity_mah: u32,
pub remaining_capacity_mah: u32,
pub current_mv: u16,
pub current_mv: u32,
pub temperature_celcius: i32,
pub health_percent: u8
pub health_percent: u32,
}
pub enum BmsCommand {
GetVersion,
GetConfig,
GetBatteryState,
impl BmsReadable for BatteryState {
fn read_from_i2c<I>(i2c_dev: &mut I) -> Result<Self, BmsProtocolError>
where
Self: Sized,
I: I2c<SevenBitAddress>,
{
let cmd = BmsRegisterMap::BatteryLifetimeCapacityMilliAmpereHours;
let mut lifetime_capacity_mah: [u8; 4] = [0x00; 4];
let mut remaining_capacity_mah: [u8; 4] = [0x00; 4];
let mut current_mv: [u8; 4] = [0x00; 4];
let mut temperature_celcius: [u8; 4] = [0x00; 4];
let mut health_percent: [u8; 4] = [0x00; 4];
i2c_dev.transaction(
BMS_I2C_ADDRESS,
&mut [
Operation::Write(&(cmd as u32).to_be_bytes()),
Operation::Read(&mut lifetime_capacity_mah),
Operation::Read(&mut remaining_capacity_mah),
Operation::Read(&mut current_mv),
Operation::Read(&mut temperature_celcius),
Operation::Read(&mut health_percent),
],
)?;
Ok(BatteryState {
lifetime_capacity_mah: u32::from_be_bytes(lifetime_capacity_mah),
remaining_capacity_mah: u32::from_be_bytes(remaining_capacity_mah),
current_mv: u32::from_be_bytes(current_mv),
temperature_celcius: i32::from_be_bytes(temperature_celcius),
health_percent: u32::from_be_bytes(health_percent),
})
}
}
#[repr(u32)]
#[non_exhaustive]
pub enum BmsRegisterMap {
// software reset register
Reset = 0x00000000,
// bms protocol revesion as u32 value
ProtocolVersion = 0x00000001,
// bms firmware revesion as u32 value
FirmwareVersion = 0x00000002,
// Configuration Values Start Here
ConfigCapacityMilliAmpereHours = 0x00010000,
ConfigFullMilliVolt = 0x00010004,
ConfigEmptyMilliVolt = 0x00010008,
// Battery State Values Start Here
BatteryLifetimeCapacityMilliAmpereHours = 0x00020000,
BatteryRemainingCapacityMilliAmpereHours = 0x00020004,
BatteryCurrentVoltageMilliVolt = 0x00020008,
BatteryTemperatureCelcius = 0x0002000c,
BatteryHealthPercent = 0x00020010,
}