mirror of
https://github.com/PSenfft/mb85rc.git
synced 2025-08-22 04:44:17 +00:00
partially implemented embedded_io traits
This commit is contained in:
parent
a4e8cc5250
commit
478a037fb0
3
src/embedded_io.rs
Normal file
3
src/embedded_io.rs
Normal file
@ -0,0 +1,3 @@
|
||||
mod device;
|
||||
mod head;
|
||||
mod error;
|
60
src/embedded_io/device.rs
Normal file
60
src/embedded_io/device.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use embedded_hal::i2c::I2c;
|
||||
use embedded_io::{ErrorType, Read, Seek, Write};
|
||||
|
||||
use crate::{
|
||||
MB85RC,
|
||||
embedded_io::{error::MB85RCErrorType, head::Head},
|
||||
};
|
||||
|
||||
pub struct EmbedIODev<T: I2c> {
|
||||
dev: crate::MB85RC<T>,
|
||||
head: Head,
|
||||
}
|
||||
|
||||
impl<T: I2c> EmbedIODev<T> {
|
||||
pub fn new(mb85rc: MB85RC<T>) -> Self {
|
||||
Self {
|
||||
dev: mb85rc,
|
||||
head: Head::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: I2c> ErrorType for EmbedIODev<T> {
|
||||
type Error = MB85RCErrorType<T::Error>;
|
||||
}
|
||||
|
||||
impl<T: I2c> Read for EmbedIODev<T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
self.dev
|
||||
.sequential_read(self.head.memory_address().unwrap(), buf)
|
||||
.map_err(MB85RCErrorType::I2c)
|
||||
.inspect(|read_bytes| {
|
||||
self.head.advance(*read_bytes);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: I2c> Write for EmbedIODev<T> {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
// From trait doc: Implementations must not return Ok(0) unless buf is empty.
|
||||
if buf.is_empty() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: I2c> Seek for EmbedIODev<T> {
|
||||
fn seek(&mut self, pos: embedded_io::SeekFrom) -> Result<u64, Self::Error> {
|
||||
self.head
|
||||
.seek(pos)
|
||||
.map_err(|_| MB85RCErrorType::InvalidPosition)?;
|
||||
Ok(self.head.into())
|
||||
}
|
||||
}
|
17
src/embedded_io/error.rs
Normal file
17
src/embedded_io/error.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use embedded_hal::i2c;
|
||||
use embedded_io::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MB85RCErrorType<T: i2c::Error> {
|
||||
I2c(T),
|
||||
InvalidPosition,
|
||||
}
|
||||
|
||||
impl<T: i2c::Error> Error for MB85RCErrorType<T> {
|
||||
fn kind(&self) -> embedded_io::ErrorKind {
|
||||
match self {
|
||||
MB85RCErrorType::I2c(_) => embedded_io::ErrorKind::Other,
|
||||
MB85RCErrorType::InvalidPosition => embedded_io::ErrorKind::Other,
|
||||
}
|
||||
}
|
||||
}
|
194
src/embedded_io/head.rs
Normal file
194
src/embedded_io/head.rs
Normal file
@ -0,0 +1,194 @@
|
||||
use embedded_io::SeekFrom;
|
||||
|
||||
/// moveable Read/Write head
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct Head(u64);
|
||||
|
||||
impl Head {
|
||||
pub fn new() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
|
||||
pub fn seek(&mut self, pos: SeekFrom) -> Result<u64, ()> {
|
||||
match pos {
|
||||
SeekFrom::Start(offset) => {
|
||||
self.0 = offset;
|
||||
Ok(self.0)
|
||||
}
|
||||
SeekFrom::End(offset) => {
|
||||
if offset > 0 {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
self.0 = u64::MAX - offset.unsigned_abs();
|
||||
|
||||
Ok(self.0)
|
||||
}
|
||||
SeekFrom::Current(offset) => {
|
||||
let new_pos = if offset > 0 {
|
||||
self.0.checked_add(offset.unsigned_abs())
|
||||
} else {
|
||||
self.0.checked_sub(offset.unsigned_abs())
|
||||
};
|
||||
|
||||
match new_pos {
|
||||
Some(pos) => {
|
||||
self.0 = pos;
|
||||
Ok(self.0)
|
||||
}
|
||||
None => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Move the head forward when reading files.
|
||||
/// Expected to not overflow. If it does it is capped at `u64::MAX`.
|
||||
pub fn advance(&mut self, bytes: usize) {
|
||||
match u64::try_from(bytes) {
|
||||
Ok(offset) => self.0 += offset,
|
||||
Err(_) => self.0 = u64::MAX,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert to a 2 byte memory address used by the i2c interface.
|
||||
pub fn memory_address(&self) -> Option<[u8; 2]> {
|
||||
if self.0 > u16::MAX as u64 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let addr16 = self.0 as u16;
|
||||
let high = (addr16 >> 8) as u8;
|
||||
let low = (addr16 & 0xFF) as u8;
|
||||
|
||||
Some([high, low])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Head> for u64 {
|
||||
fn from(head: Head) -> Self {
|
||||
head.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create() {
|
||||
let head = Head::new();
|
||||
let inner: u64 = head.into();
|
||||
assert_eq!(inner, 0u64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seek_start() {
|
||||
let mut head = Head::new();
|
||||
let res = head.seek(SeekFrom::Start(1337));
|
||||
|
||||
let inner: u64 = head.into();
|
||||
assert_eq!(inner, 1337u64);
|
||||
assert_eq!(res, Ok(inner));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seek_current_forward() {
|
||||
let mut head = Head::new();
|
||||
let _ = head.seek(SeekFrom::Start(1337));
|
||||
|
||||
let res = head.seek(SeekFrom::Current(3));
|
||||
|
||||
let inner: u64 = head.into();
|
||||
assert_eq!(inner, 1340u64);
|
||||
assert_eq!(res, Ok(inner));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seek_current_back() {
|
||||
let mut head = Head::new();
|
||||
let _ = head.seek(SeekFrom::Start(1337));
|
||||
|
||||
let res = head.seek(SeekFrom::Current(-337));
|
||||
|
||||
let inner: u64 = head.into();
|
||||
assert_eq!(inner, 1000u64);
|
||||
assert_eq!(res, Ok(inner));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seek_current_zero() {
|
||||
let mut head = Head::new();
|
||||
let _ = head.seek(SeekFrom::Start(1337));
|
||||
|
||||
let res = head.seek(SeekFrom::Current(0));
|
||||
|
||||
let inner: u64 = head.into();
|
||||
assert_eq!(inner, 1337u64);
|
||||
assert_eq!(res, Ok(inner));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seek_end() {
|
||||
let mut head = Head::new();
|
||||
let res = head.seek(SeekFrom::End(-10));
|
||||
|
||||
let inner: u64 = head.into();
|
||||
assert_eq!(inner, u64::MAX - 10);
|
||||
assert_eq!(res, Ok(inner));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seek_invalid_overflow() {
|
||||
let mut head = Head::new();
|
||||
let _ = head.seek(SeekFrom::Start(u64::MAX - 5));
|
||||
|
||||
let res = head.seek(SeekFrom::Current(10));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seek_invalid_underflow() {
|
||||
let mut head = Head::new();
|
||||
|
||||
let res = head.seek(SeekFrom::Current(-1));
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_zero() {
|
||||
let head = Head::new();
|
||||
let addr = head.memory_address();
|
||||
|
||||
assert_eq!(addr, Some([0, 0]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_1_byte() {
|
||||
let mut head = Head::new();
|
||||
let _ = head.seek(SeekFrom::Start(50));
|
||||
|
||||
let addr = head.memory_address();
|
||||
|
||||
assert_eq!(addr, Some([0, 50]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_2_bytes() {
|
||||
let mut head = Head::new();
|
||||
let _ = head.seek(SeekFrom::Start(260));
|
||||
|
||||
let addr = head.memory_address();
|
||||
|
||||
assert_eq!(addr, Some([1, 4]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_invalid() {
|
||||
let mut head = Head::new();
|
||||
let _ = head.seek(SeekFrom::Start(u16::MAX as u64 + 1));
|
||||
|
||||
let addr = head.memory_address();
|
||||
assert!(addr.is_none());
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
use core::result::Result;
|
||||
use embedded_hal::i2c::{I2c, SevenBitAddress};
|
||||
|
||||
mod embedded_io;
|
||||
|
||||
const DEVICE_ADDRESS: u8 = 0b10100000;
|
||||
const DEVICE_ADDRESS_CODE: u8 = 0b00000000;
|
||||
const DEVICE_W: u8 = 0b00000000;
|
||||
|
Loading…
x
Reference in New Issue
Block a user