#[cfg(target_arch="avr")]
use crate::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::devices::internal::StaticShareable;
use crate::hal::generic::eeprom::EepromSpace;
use crate::{v_read, v_write};
use crate::hal::generic::cpu::base::AvrCpuControlBlock;
use crate::hal::generic::cpu::{ConfigurationChange, Cpu};
use crate::io::{Read, Write};
#[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 [u8; SIZE],
pub(crate) cpu: &'static mut AvrCpuControlBlock,
}
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> StaticShareable for EepromNvmCtrlImpl<SIZE,PAGESIZE,PAGES> {}
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 mut bytes_read : usize = 0;
for idx in 0..dest.len() {
let loc = offset+idx;
if loc >= SIZE {
break;
} else {
dest[idx] = unsafe { v_read!(u8, self.buffer[loc]) };
bytes_read += 1;
}
}
bytes_read
}
fn write_at_from(&mut self, offset: usize, src: &[u8]) -> usize {
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 { panic!()
}
let current_val = unsafe { v_read!(u8, self.buffer[loc]) };
if current_val != src[idx] {
unsafe { v_write!(u8, self.buffer[loc], src[idx]) };
page_dirty = true;
}
bytes_consumed += 1;
if ((loc % PAGESIZE) == 0) || (idx==0) { if page_dirty {
unsafe {
self.cpu.write_protected(ConfigurationChange::SelfProgramming,
&mut self.control.ctrla, 0x03); }
}
page_dirty = false; }
}
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]) -> crate::io::Result<usize> {
let bytes = self.eeprom.read_at_into(self.cursor, buf);
self.cursor += bytes;
match bytes {
0 => Err(crate::io::IoError::EndOfFile),
v => Ok(v)
}
}
}
impl<const SIZE: usize, const PAGESIZE: usize, const PAGES: usize> Write for EepromNvmCtrlWriter<'_,SIZE,PAGESIZE,PAGES> {
fn write(&mut self, buf: &[u8]) -> crate::io::Result<usize> {
let bytes = self.eeprom.write_at_from(self.cursor, buf);
self.cursor += bytes;
match bytes {
0 => Err(crate::io::IoError::EndOfFile),
v => Ok(v)
}
}
fn flush(&mut self) -> crate::io::Result<()> {
Ok(())
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! atmel_nvmctrl_eeprom_tpl {
($nvmctrlref:expr, $pagebufferref:expr, $pagesize:expr, $pages:expr, $cpu:expr) => {
use crate::hal::generic::eeprom::base::nvmctrl::EepromNvmCtrlImpl;
use crate::mut_singleton;
pub type EepromImpl = EepromNvmCtrlImpl<{$pagesize*$pages},{$pagesize},{$pages}>;
mut_singleton!(
EepromImpl,
INSTANCE,
instance,
EepromNvmCtrlImpl {
control: core::mem::transmute($nvmctrlref),
buffer: core::mem::transmute($pagebufferref),
cpu: $cpu
}
);
}
}
}
}
#[cfg(not(target_arch="avr"))]
pub mod base {
use crate::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 crate::hal::generic::eeprom::base::DummyEepromImpl;
use crate::mut_singleton;
pub type EepromImpl = DummyEepromImpl<{$pagesize*$pages}>;
mut_singleton!(
EepromImpl,
INSTANCE,
instance,
DummyEepromImpl {
buffer: [ 0xff; {$pagesize*$pages} ]
}
);
}
}
}