#[cfg(target_arch="avr")]
use avr_oxide::io::{Read, Write};
#[cfg(not(target_arch="avr"))]
use std::io::{Read, Write};
pub trait EepromSpace<'e> {
const SIZE : usize;
type W: Write;
type R: Read;
fn read_at_into(&self, offset: usize, dest: &mut [u8]) -> usize;
fn write_at_from(&mut self, offset: usize, src: &[u8]) -> usize;
fn writer(&'e mut self) -> Self::W;
fn writer_at(&'e mut self, offset: usize) -> Self::W;
fn reader(&'e self) -> Self::R;
fn reader_at(&'e self, offset: usize) -> Self::R;
}
#[cfg(target_arch="avr")]
pub mod base {
pub mod nvmctrl {
use avr_oxide::hal::generic::eeprom::EepromSpace;
use avr_oxide::cpu;
use avr_oxide::hal::generic::cpu::{ConfigurationChange, Cpu};
use avr_oxide::io::{Read, Write};
use avr_oxide::sync::Mutex;
use avr_oxide::util::datatypes::Volatile;
use avr_oxide::OxideResult::{Err,Ok};
#[repr(C)]
pub struct AtmelNvmCtrl {
pub(crate) ctrla: u8,
pub(crate) ctrlb: u8,
pub(crate) status: u8,
pub(crate) intctrl: u8,
pub(crate) intflags: u8,
pub(crate) reserved: u8,
pub(crate) datah: u8,
pub(crate) datal: u8,
pub(crate) addrh: u8,
pub(crate) addrl: u8
}
pub struct EepromNvmCtrlImpl<const SIZE: usize, const PAGESIZE: usize, const PAGES: usize> {
pub(crate) control: &'static mut AtmelNvmCtrl,
pub(crate) buffer: &'static mut [Volatile<u8>; SIZE],
pub(crate) mutex: Mutex<()>
}
pub struct EepromNvmCtrlReader<'r,const SIZE: usize, const PAGESIZE: usize, const PAGES: usize> {
eeprom: &'r EepromNvmCtrlImpl<SIZE,PAGESIZE,PAGES>,
cursor: usize
}
pub struct EepromNvmCtrlWriter<'w,const SIZE: usize, const PAGESIZE: usize, const PAGES: usize> {
eeprom: &'w mut EepromNvmCtrlImpl<SIZE,PAGESIZE,PAGES>,
cursor: usize
}
impl<'e,const SIZE: usize, const PAGESIZE: usize, const PAGES: usize> EepromSpace<'e> for EepromNvmCtrlImpl<SIZE,PAGESIZE,PAGES> {
const SIZE: usize = SIZE;
type W = EepromNvmCtrlWriter<'e,SIZE,PAGESIZE,PAGES>;
type R = EepromNvmCtrlReader<'e,SIZE,PAGESIZE,PAGES>;
fn read_at_into(&self, offset: usize, dest: &mut [u8]) -> usize {
let lock = self.mutex.lock();
let mut bytes_read : usize = 0;
for idx in 0..dest.len() {
let loc = offset+idx;
if loc >= SIZE {
break;
} else {
dest[idx] = self.buffer[loc].read();
bytes_read += 1;
}
}
drop(lock);
bytes_read
}
fn write_at_from(&mut self, offset: usize, src: &[u8]) -> usize {
let lock = self.mutex.lock();
let mut bytes_consumed : usize = 0;
let mut page_dirty = false;
for idx in (0..src.len()).rev() {
let loc = offset+idx;
if loc >= SIZE { avr_oxide::oserror::halt(avr_oxide::oserror::OsError::BadParams);
}
let current_val = self.buffer[loc].read();
if current_val != src[idx] {
self.buffer[loc].write(src[idx]);
page_dirty = true;
}
bytes_consumed += 1;
if ((loc % PAGESIZE) == 0) || (idx==0) { if page_dirty {
unsafe {
cpu!().write_protected(ConfigurationChange::SelfProgramming,
&mut self.control.ctrla, 0x03); }
}
page_dirty = false; }
}
drop(lock);
bytes_consumed
}
fn writer(&'e mut self) -> Self::W {
self.writer_at(0)
}
fn writer_at(&'e mut self, offset: usize) -> Self::W {
EepromNvmCtrlWriter {
eeprom: self,
cursor: offset
}
}
fn reader(&'e self) -> Self::R {
self.reader_at(0)
}
fn reader_at(&'e self, offset: usize) -> Self::R {
EepromNvmCtrlReader {
eeprom: self,
cursor: offset
}
}
}
impl<const SIZE: usize, const PAGESIZE: usize, const PAGES: usize> Read for EepromNvmCtrlReader<'_,SIZE,PAGESIZE,PAGES> {
fn read(&mut self, buf: &mut [u8]) -> avr_oxide::io::Result<usize> {
let bytes = self.eeprom.read_at_into(self.cursor, buf);
self.cursor += bytes;
match bytes {
0 => Err(avr_oxide::io::IoError::EndOfFile),
v => Ok(v)
}
}
}
impl<const SIZE: usize, const PAGESIZE: usize, const PAGES: usize> Write for EepromNvmCtrlWriter<'_,SIZE,PAGESIZE,PAGES> {
fn write_buffered(&mut self, buf: &[u8]) -> avr_oxide::io::Result<usize> {
let bytes = self.eeprom.write_at_from(self.cursor, buf);
self.cursor += bytes;
match bytes {
0 => Err(avr_oxide::io::IoError::EndOfFile),
v => Ok(v)
}
}
fn flush(&mut self) -> avr_oxide::io::Result<()> {
Ok(())
}
}
unsafe impl<const SIZE: usize, const PAGESIZE: usize, const PAGES: usize> Send for EepromNvmCtrlWriter<'_,SIZE,PAGESIZE,PAGES> {}
unsafe impl<const SIZE: usize, const PAGESIZE: usize, const PAGES: usize> Sync for EepromNvmCtrlWriter<'_,SIZE,PAGESIZE,PAGES> {}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_nvmctrl_eeprom_tpl {
($nvmctrlref:expr, $pagebufferref:expr, $pagesize:expr, $pages:expr, $cpu:expr) => {
use avr_oxide::hal::generic::eeprom::base::nvmctrl::EepromNvmCtrlImpl;
use avr_oxide::mut_singleton_explicit_init;
use avr_oxide::sync::Mutex;
pub type EepromImpl = EepromNvmCtrlImpl<{$pagesize*$pages},{$pagesize},{$pages}>;
mut_singleton_explicit_init!(
EepromImpl,
__INSTANCE,
initialise, instance, instance_isolated,
EepromNvmCtrlImpl {
control: core::mem::transmute($nvmctrlref),
buffer: core::mem::transmute($pagebufferref),
mutex: Mutex::new(())
}
);
}
}
}
}
#[cfg(not(target_arch="avr"))]
pub mod base {
use avr_oxide::hal::generic::eeprom::EepromSpace;
pub struct DummyEepromImpl<const SIZE: usize> {
pub(crate) buffer: [u8; SIZE]
}
impl<'e,const SIZE: usize> EepromSpace<'e> for DummyEepromImpl<SIZE> {
const SIZE: usize = SIZE;
type W = std::io::Stderr;
type R = std::io::Stdin;
fn read_at_into(&self, offset: usize, dest: &mut [u8]) -> usize {
todo!()
}
fn write_at_from(&mut self, offset: usize, src: &[u8]) -> usize {
todo!()
}
fn writer(&'e mut self) -> Self::W {
todo!()
}
fn writer_at(&'e mut self, offset: usize) -> Self::W {
todo!()
}
fn reader(&'e self) -> Self::R {
todo!()
}
fn reader_at(&'e self, offset: usize) -> Self::R {
todo!()
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_nvmctrl_eeprom_tpl {
($nvmctrlref:expr, $pagebufferref:expr, $pagesize:expr, $pages:expr, $cpu:expr) => {
use avr_oxide::hal::generic::eeprom::base::DummyEepromImpl;
use avr_oxide::mut_singleton_explicit_init;
pub type EepromImpl = DummyEepromImpl<{$pagesize*$pages}>;
mut_singleton_explicit_init!(
EepromImpl,
__INSTANCE,
initialise, instance, instance_isolated,
DummyEepromImpl {
buffer: [ 0xff; {$pagesize*$pages} ]
}
);
}
}
}