embedded_devices/devices/belling/
mod.rs1use core::num::Wrapping;
2
3use embedded_interfaces::TransportError;
4use embedded_interfaces::registers::{ReadableRegister, Register, RegisterCodec, WritableRegister};
5
6#[cfg(feature = "belling-bl0942")]
7pub mod bl0942;
8
9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
11#[derive(Debug, thiserror::Error)]
12pub enum ChecksumError {
13 #[error("the calculated checksum {calculated:#02x} did not match the expected value {expected:#02x}")]
14 Mismatch { calculated: u8, expected: u8 },
15}
16
17pub struct BellingSpiCodec<const CMD_READ: u8, const CMD_WRITE: u8> {}
29
30impl<const CMD_READ: u8, const CMD_WRITE: u8> RegisterCodec for BellingSpiCodec<CMD_READ, CMD_WRITE> {
31 type Error = ChecksumError;
32}
33
34#[maybe_async_cfg::maybe(
35 idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), Codec),
36 sync(feature = "sync"),
37 async(feature = "async"),
38 keep_self
39)]
40impl<const CMD_READ: u8, const CMD_WRITE: u8> embedded_interfaces::registers::spi::Codec
41 for BellingSpiCodec<CMD_READ, CMD_WRITE>
42{
43 #[inline]
44 async fn read_register<R, I>(interface: &mut I) -> Result<R, TransportError<Self::Error, I::Error>>
45 where
46 R: Register<CodecError = Self::Error> + ReadableRegister,
47 I: hal::spi::r#SpiDevice,
48 {
49 assert_eq!(R::REGISTER_SIZE, 3);
50 let mut buffer = [CMD_READ, R::ADDRESS as u8, 0, 0, 0, 0];
51 interface.transfer_in_place(&mut buffer).await?;
52
53 buffer[0] = CMD_READ;
54 buffer[1] = R::ADDRESS as u8;
55 let data = &buffer[2..5];
56 let calculated = !(buffer[0..5].iter().map(|&x| Wrapping(x)).sum::<Wrapping<u8>>().0);
57 let expected = buffer[5];
58 if expected != calculated {
59 return Err(TransportError::r#Codec(ChecksumError::Mismatch {
60 calculated,
61 expected,
62 }));
63 }
64
65 let mut register = R::zeroed();
67 bytemuck::bytes_of_mut(&mut register).copy_from_slice(data);
68
69 #[cfg(feature = "trace-communication")]
70 log::trace!(
71 "SPI [32mread[m register_addr={:08x}:\n{}",
72 R::ADDRESS,
73 register.bitdump()
74 );
75
76 Ok(register)
77 }
78
79 #[inline]
80 async fn write_register<R, I>(
81 interface: &mut I,
82 register: impl AsRef<R>,
83 ) -> Result<(), TransportError<Self::Error, I::Error>>
84 where
85 R: Register<CodecError = Self::Error> + WritableRegister,
86 I: hal::spi::r#SpiDevice,
87 {
88 assert_eq!(R::REGISTER_SIZE, 3);
89
90 #[cfg(feature = "trace-communication")]
91 log::trace!(
92 "SPI [32mwrite[m register_addr={:08x}:\n{}",
93 R::ADDRESS,
94 register.as_ref().bitdump()
95 );
96
97 let mut buffer = [CMD_WRITE, R::ADDRESS as u8, 0, 0, 0, 0];
98 buffer[2..5].copy_from_slice(bytemuck::bytes_of(register.as_ref()));
99
100 let checksum = !(buffer[0..5].iter().map(|&x| Wrapping(x)).sum::<Wrapping<u8>>().0);
102 buffer[5] = checksum;
103
104 Ok(interface.write(&buffer).await?)
105 }
106}