use crate::crc;
use crate::error::Error;
use crate::registers::Address;
pub const SYNC: u8 = 0x05;
pub const MASTER_ADDR: u8 = 0xFF;
pub const WRITE_BIT: u8 = 0x80;
pub const ADDRESS_MASK: u8 = 0x7F;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ReadRequest {
bytes: [u8; Self::LEN],
}
impl ReadRequest {
pub const LEN: usize = 4;
pub fn new(slave_addr: u8, reg_addr: Address) -> Self {
let mut bytes = [SYNC, slave_addr, reg_addr as u8, 0];
bytes[3] = crc::compute(&bytes[..3]);
Self { bytes }
}
pub fn from_raw_addr(slave_addr: u8, reg_addr: u8) -> Self {
let mut bytes = [SYNC, slave_addr, reg_addr & ADDRESS_MASK, 0];
bytes[3] = crc::compute(&bytes[..3]);
Self { bytes }
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
#[inline]
pub fn slave_addr(&self) -> u8 {
self.bytes[1]
}
#[inline]
pub fn reg_addr(&self) -> u8 {
self.bytes[2]
}
}
impl AsRef<[u8]> for ReadRequest {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct WriteRequest {
bytes: [u8; Self::LEN],
}
impl WriteRequest {
pub const LEN: usize = 8;
pub fn new(slave_addr: u8, reg_addr: Address, data: u32) -> Self {
Self::from_raw(slave_addr, reg_addr as u8, data)
}
pub fn from_raw(slave_addr: u8, reg_addr: u8, data: u32) -> Self {
let data_bytes = data.to_be_bytes();
let mut bytes = [
SYNC,
slave_addr,
(reg_addr & ADDRESS_MASK) | WRITE_BIT,
data_bytes[0],
data_bytes[1],
data_bytes[2],
data_bytes[3],
0,
];
bytes[7] = crc::compute(&bytes[..7]);
Self { bytes }
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
#[inline]
pub fn slave_addr(&self) -> u8 {
self.bytes[1]
}
#[inline]
pub fn reg_addr(&self) -> u8 {
self.bytes[2] & ADDRESS_MASK
}
#[inline]
pub fn data(&self) -> u32 {
u32::from_be_bytes([self.bytes[3], self.bytes[4], self.bytes[5], self.bytes[6]])
}
}
impl AsRef<[u8]> for WriteRequest {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ReadResponse {
bytes: [u8; Self::LEN],
}
impl ReadResponse {
pub const LEN: usize = 8;
pub const SYNC_IDX: usize = 0;
pub const MASTER_ADDR_IDX: usize = 1;
pub const REG_ADDR_IDX: usize = 2;
pub const DATA_START_IDX: usize = 3;
pub const DATA_END_IDX: usize = 7;
pub const CRC_IDX: usize = 7;
pub fn from_bytes<E>(bytes: [u8; Self::LEN]) -> Result<Self, Error<E>> {
let response = Self { bytes };
response.validate()?;
Ok(response)
}
pub fn from_slice<E>(slice: &[u8]) -> Result<Self, Error<E>> {
if slice.len() < Self::LEN {
return Err(Error::BufferTooSmall);
}
let mut bytes = [0u8; Self::LEN];
bytes.copy_from_slice(&slice[..Self::LEN]);
Self::from_bytes(bytes)
}
fn validate<E>(&self) -> Result<(), Error<E>> {
if self.bytes[Self::SYNC_IDX] != SYNC {
return Err(Error::InvalidSync);
}
if self.bytes[Self::MASTER_ADDR_IDX] != MASTER_ADDR {
return Err(Error::InvalidMasterAddress);
}
if !crc::verify(&self.bytes) {
return Err(Error::CrcMismatch);
}
Ok(())
}
#[inline]
pub fn reg_addr(&self) -> u8 {
self.bytes[Self::REG_ADDR_IDX]
}
pub fn address(&self) -> Option<Address> {
Address::from_u8(self.reg_addr())
}
#[inline]
pub fn data(&self) -> u32 {
u32::from_be_bytes([self.bytes[3], self.bytes[4], self.bytes[5], self.bytes[6]])
}
#[inline]
pub fn as_bytes(&self) -> &[u8; Self::LEN] {
&self.bytes
}
#[inline]
pub fn crc_valid(&self) -> bool {
crc::verify(&self.bytes)
}
}
impl AsRef<[u8]> for ReadResponse {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
#[derive(Debug, Default)]
pub struct ResponseReader {
index: usize,
buffer: [u8; ReadResponse::LEN],
}
impl ResponseReader {
pub fn new() -> Self {
Self::default()
}
pub fn reset(&mut self) {
self.index = 0;
}
pub fn feed<E>(&mut self, bytes: &[u8]) -> (usize, Option<Result<ReadResponse, Error<E>>>) {
let mut consumed = 0;
let mut remaining = bytes;
loop {
while self.index == 0 {
match remaining.first() {
Some(&SYNC) => {
self.buffer[0] = SYNC;
self.index = 1;
remaining = &remaining[1..];
consumed += 1;
}
Some(_) => {
remaining = &remaining[1..];
consumed += 1;
}
None => {
return (consumed, None);
}
}
}
if self.index == 1 {
match remaining.first() {
Some(&MASTER_ADDR) => {
self.buffer[1] = MASTER_ADDR;
self.index = 2;
remaining = &remaining[1..];
consumed += 1;
}
Some(_) => {
self.index = 0;
continue;
}
None => {
return (consumed, None);
}
}
}
let needed = ReadResponse::LEN - self.index;
let available = remaining.len().min(needed);
self.buffer[self.index..self.index + available]
.copy_from_slice(&remaining[..available]);
self.index += available;
consumed += available;
if self.index == ReadResponse::LEN {
self.index = 0;
let result = ReadResponse::from_bytes(self.buffer);
return (consumed, Some(result));
}
return (consumed, None);
}
}
pub fn buffered(&self) -> usize {
self.index
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_read_request() {
let req = ReadRequest::new(0, Address::Gconf);
assert_eq!(req.slave_addr(), 0);
assert_eq!(req.reg_addr(), 0x00);
assert_eq!(req.as_bytes().len(), 4);
}
#[test]
fn test_write_request() {
let req = WriteRequest::new(0, Address::Gconf, 0x00000040);
assert_eq!(req.slave_addr(), 0);
assert_eq!(req.reg_addr(), 0x00);
assert_eq!(req.data(), 0x00000040);
assert_eq!(req.as_bytes().len(), 8);
}
#[test]
fn test_response_reader() {
let mut response_bytes = [SYNC, MASTER_ADDR, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00];
response_bytes[7] = crc::compute(&response_bytes[..7]);
let mut reader = ResponseReader::new();
let (consumed, result) = reader.feed::<()>(&response_bytes);
assert_eq!(consumed, 8);
assert!(result.is_some());
let response = result.unwrap().unwrap();
assert_eq!(response.data(), 0x00000040);
}
}