embedded_interfaces/registers/spi/codecs/
standard_codec.rs1use crate::TransportError;
2use crate::registers::{ReadableRegister, Register, RegisterCodec, WritableRegister};
3
4use bytemuck::Zeroable;
5
6pub struct StandardCodec<
33 const HEADER_SIZE: usize,
34 const ADDR_MSB: u8,
35 const ADDR_LSB: u8,
36 const RW_BIT: u8,
37 const RW_1_IS_READ: bool,
38 const READ_DELAY: usize,
39> {}
40
41impl<
42 const HEADER_SIZE: usize,
43 const ADDR_MSB: u8,
44 const ADDR_LSB: u8,
45 const RW_BIT: u8,
46 const RW_1_IS_READ: bool,
47 const READ_DELAY: usize,
48> StandardCodec<HEADER_SIZE, ADDR_MSB, ADDR_LSB, RW_BIT, RW_1_IS_READ, READ_DELAY>
49{
50 #[inline]
51 pub fn fill_addr_header<R>(header: &mut [u8])
52 where
53 R: Register,
54 {
55 let addr_mask = u64::checked_shl(1, ADDR_MSB as u32 + 1).unwrap_or(0).wrapping_sub(1);
59 let addr_shifted = (R::ADDRESS << ADDR_LSB) & addr_mask;
61 let addr_bytes = addr_shifted.to_le_bytes();
63 let affected_bytes = ((ADDR_MSB - ADDR_LSB) / 8) as usize;
64 for i in 0..=affected_bytes {
65 header[HEADER_SIZE - 1 - i] |= addr_bytes[i];
66 }
67 }
68}
69
70impl<
71 const HEADER_SIZE: usize,
72 const ADDR_MSB: u8,
73 const ADDR_LSB: u8,
74 const RW_BIT: u8,
75 const RW_1_IS_READ: bool,
76 const READ_DELAY: usize,
77> RegisterCodec for StandardCodec<HEADER_SIZE, ADDR_MSB, ADDR_LSB, RW_BIT, RW_1_IS_READ, READ_DELAY>
78{
79 type Error = ();
80}
81
82#[maybe_async_cfg::maybe(
83 idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), Codec),
84 sync(feature = "sync"),
85 async(feature = "async"),
86 keep_self
87)]
88impl<
89 const HEADER_SIZE: usize,
90 const ADDR_MSB: u8,
91 const ADDR_LSB: u8,
92 const RW_BIT: u8,
93 const RW_1_IS_READ: bool,
94 const READ_DELAY: usize,
95> crate::registers::spi::Codec for StandardCodec<HEADER_SIZE, ADDR_MSB, ADDR_LSB, RW_BIT, RW_1_IS_READ, READ_DELAY>
96{
97 #[inline]
98 async fn read_register<R, I>(interface: &mut I) -> Result<R, TransportError<Self::Error, I::Error>>
99 where
100 R: Register<CodecError = Self::Error> + ReadableRegister,
101 I: hal::spi::r#SpiDevice,
102 {
103 #[repr(C, packed(1))]
104 #[derive(Copy, Clone, bytemuck::Pod, Zeroable)]
105 struct Buffer<const HEADER_SIZE: usize, const READ_DELAY: usize, R> {
106 header: [u8; HEADER_SIZE],
107 delay: [u8; READ_DELAY],
108 register: R,
109 }
110
111 let mut buffer = Buffer::<{ HEADER_SIZE }, { READ_DELAY }, R>::zeroed();
112 let data = bytemuck::bytes_of_mut(&mut buffer);
113 data[HEADER_SIZE - 1 - (RW_BIT as usize) / 8] |= (RW_1_IS_READ as u8) << (RW_BIT % 8);
115 Self::fill_addr_header::<R>(data);
116 interface.transfer_in_place(data).await?;
117
118 let register = buffer.register;
120
121 #[cfg(feature = "trace-communication")]
122 log::trace!(
123 "SPI [32mread[m register_addr={:08x}:\n{}",
124 R::ADDRESS,
125 register.bitdump()
126 );
127
128 Ok(register)
129 }
130
131 #[inline]
132 async fn write_register<R, I>(
133 interface: &mut I,
134 register: impl AsRef<R>,
135 ) -> Result<(), TransportError<Self::Error, I::Error>>
136 where
137 R: Register<CodecError = Self::Error> + WritableRegister,
138 I: hal::spi::r#SpiDevice,
139 {
140 #[cfg(feature = "trace-communication")]
141 log::trace!(
142 "SPI [32mwrite[m register_addr={:08x}:\n{}",
143 R::ADDRESS,
144 register.as_ref().bitdump()
145 );
146
147 #[repr(C, packed(1))]
148 #[derive(Copy, Clone, bytemuck::Pod, Zeroable)]
149 struct Buffer<const HEADER_SIZE: usize, R> {
150 header: [u8; HEADER_SIZE],
151 register: R,
152 }
153
154 let mut buffer = Buffer::<{ HEADER_SIZE }, R> {
155 header: [0u8; HEADER_SIZE],
156 register: *register.as_ref(),
157 };
158
159 let data = bytemuck::bytes_of_mut(&mut buffer);
160 data[HEADER_SIZE - 1 - (RW_BIT as usize) / 8] |= ((!RW_1_IS_READ) as u8) << (RW_BIT % 8);
162 Self::fill_addr_header::<R>(data);
163 Ok(interface.write(data).await?)
164 }
165}