24#include "boards/board_traits.h"
25#include <avr/interrupt.h>
26#include <avr/eeprom.h>
36#define REGISTER_EEPROM_ISR() \
39 eeprom::isr_handler::eeprom_ready(); \
53#define REGISTER_EEPROM_ISR_METHOD(HANDLER, CALLBACK) \
56 eeprom::isr_handler::eeprom_ready_method<HANDLER, CALLBACK>(); \
69#define REGISTER_EEPROM_ISR_FUNCTION(CALLBACK) \
72 eeprom::isr_handler::eeprom_ready_function<CALLBACK>(); \
81#define DECL_EEPROM_ISR_HANDLERS_FRIEND \
82 friend struct eeprom::isr_handler; \
83 friend void ::EE_READY_vect();
149 template<
typename T>
static bool read(
const T* address, T& value)
151 return read((uint16_t) address, value);
169 template<
typename T>
static bool read(uint16_t address, T& value)
171 if (!check(address,
sizeof(T)))
return false;
172 uint8_t* pvalue = (uint8_t*) &value;
173 for (uint16_t i = 0; i <
sizeof(T); ++i) blocked_read(address++, *pvalue++);
194 template<
typename T>
static bool read(
const T* address, T* value, uint16_t count)
196 return read((uint16_t) address, value, count);
215 template<
typename T>
static bool read(uint16_t address, T* value, uint16_t count)
217 if (!check(address, count *
sizeof(T)))
return false;
218 uint8_t* pvalue = (uint8_t*) value;
219 for (uint16_t i = 0; i < (count *
sizeof(T)); ++i) blocked_read(address++, *pvalue++);
235 static bool read(
const uint8_t* address, uint8_t& value)
237 return read((uint16_t) address, value);
251 static bool read(uint16_t address, uint8_t& value)
253 if (!check(address, 1))
258 blocked_read(address, value);
278 template<
typename T>
static bool write(
const T* address,
const T& value)
280 return write((uint16_t) address, value);
298 template<
typename T>
static bool write(uint16_t address,
const T& value)
300 if (!check(address,
sizeof(T)))
return false;
301 uint8_t* pvalue = (uint8_t*) &value;
302 for (uint8_t i = 0; i <
sizeof(T); ++i) blocked_write(address++, *pvalue++);
323 template<
typename T>
static bool write(
const T* address,
const T* value, uint16_t count)
325 return write((uint16_t) address, value, count);
344 template<
typename T>
static bool write(uint16_t address,
const T* value, uint16_t count)
346 if (!check(address, count *
sizeof(T)))
return false;
347 uint8_t* pvalue = (uint8_t*) value;
348 for (uint8_t i = 0; i < (count *
sizeof(T)); ++i) blocked_write(address++, *pvalue++);
363 static bool write(
const uint8_t* address, uint8_t value)
365 return write((uint16_t) address, value);
378 static bool write(uint16_t address, uint8_t value)
380 if (!check(address, 1))
return false;
381 blocked_write(address, value);
392 for (uint16_t address = 0; address <
size(); ++address)
395 erase_address(address);
402 static constexpr uint16_t
size()
415 EECR_.loop_until_bit_clear(EEPE);
420 static bool constexpr check(uint16_t address, uint16_t
size)
422 return (
size != 0) && (address <= E2END) && (
size <= (E2END + 1)) && ((address +
size) <= (E2END + 1));
425 static void blocked_read(uint16_t address, uint8_t& value)
428 read_byte(address, value);
431 static void read_byte(uint16_t address, uint8_t& value)
438 static void blocked_write(uint16_t address, uint8_t value)
441 write_byte(address, value);
448 static void write_byte(uint16_t address, uint8_t value)
452 uint8_t old_value = EEDR_;
453 uint8_t diff = old_value ^ value;
457 if (value == UINT8_MAX)
482 static bool erase_address(uint16_t address)
486 uint8_t value = EEDR;
488 if (value == UINT8_MAX)
return false;
501 using REG8 = board_traits::REG8;
502 using REG16 = board_traits::REG16;
503 static constexpr const REG16 EEAR_{EEAR};
504 static constexpr const REG8 EECR_{EECR};
505 static constexpr const REG8 EEDR_{EEDR};
540 template<u
int16_t SIZE>
563 template<
typename T>
bool write(
const T* address,
const T& value)
565 return write((uint16_t) address, value);
584 template<
typename T>
bool write(uint16_t address,
const T& value)
586 if (!check(address,
sizeof(T)))
return false;
587 synchronized return write_data(address, (uint8_t*) &value,
sizeof(T));
608 template<
typename T>
bool write(
const T* address,
const T* value, uint16_t count)
610 return write((uint16_t) address, value, count);
630 template<
typename T>
bool write(uint16_t address,
const T* value, uint16_t count)
632 if (!check(address, count *
sizeof(T)))
return false;
633 synchronized return write_data(address, (uint8_t*) value, count *
sizeof(T));
648 bool write(
const uint8_t* address, uint8_t value)
650 return write((uint16_t) address, value);
664 bool write(uint16_t address, uint8_t value)
666 if (!check(address, 1))
return false;
667 synchronized return write_data(address, &value, 1);
692 current_.address = 0;
693 current_.size =
size();
721 static const uint16_t ITEM_SIZE = 3;
741 else if (current_.size)
744 else if (!buffer_.
empty_())
748 current_ = next_item();
763 buffer_.
pull_(value);
764 EEPROM::write_byte(current_.address++, value);
771 EEPROM::erase_address(current_.address++);
776 bool write_data(uint16_t address, uint8_t* value, uint16_t
size)
779 if ((buffer_.
free_() < (
size + ITEM_SIZE)) || (
size == 0))
return false;
782 buffer_.
push_(WriteItem::value1(address,
size));
783 buffer_.
push_(WriteItem::value2(address,
size));
784 buffer_.
push_(WriteItem::value3(address,
size));
785 for (uint16_t i = 0; i <
size; ++i) buffer_.
push_(*value++);
794 WriteItem() =
default;
795 WriteItem(uint8_t value1, uint8_t value2, uint8_t value3)
796 : address{uint16_t(uint16_t(value1 << 4) | uint8_t(value2 >> 4))},
797 size{uint16_t(
utils::
is_zero(((value2 & 0x0F) << 8) | value3, E2END + 1))} {}
799 static uint8_t value1(uint16_t address, uint16_t size
UNUSED)
803 static uint8_t value2(uint16_t address, uint16_t size)
805 return (address << 4) | (size >> 8);
807 static uint8_t value3(uint16_t address
UNUSED, uint16_t size)
812 uint16_t address = 0;
816 WriteItem next_item()
819 buffer_.
pull_(value1);
821 buffer_.
pull_(value2);
823 buffer_.
pull_(value3);
824 return WriteItem{value1, value2, value3};
827 using REG8 = board_traits::REG8;
828 using REG16 = board_traits::REG16;
829 static constexpr const REG16 EEAR_{EEAR};
830 static constexpr const REG8 EECR_{EECR};
831 static constexpr const REG8 EEDR_{EEDR};
835 volatile bool erase_ =
false;
836 volatile bool done_ =
true;
838 friend struct isr_handler;
844 static void eeprom_ready()
846 interrupt::HandlerHolder<eeprom::QueuedWriter>::handler()->on_ready();
849 template<
void (*CALLBACK)()>
static void eeprom_ready_function()
851 if (interrupt::HandlerHolder<eeprom::QueuedWriter>::handler()->on_ready())
852 interrupt::CallbackHandler<void (*)(), CALLBACK>::call();
855 template<
typename HANDLER,
void (HANDLER::*CALLBACK)()>
static void eeprom_ready_method()
857 if (interrupt::HandlerHolder<eeprom::QueuedWriter>::handler()->on_ready())
858 interrupt::CallbackHandler<void (HANDLER::*)(), CALLBACK>::call();
void clear_()
Completely clear this queue.
bool empty_() const
Tell if this queue is currently empty.
bool pull_(T &item)
Pull an item from the beginning of this queue, if not empty, and copy it into item.
uint8_t free_() const
Tell the current number of available locations for items to be pushed to this queue.
bool push_(TREF item)
Push item to the end of this queue, provided there is still available space in its ring buffer.
Collection of static methods to read or write the AVR EEPROM.
static constexpr uint16_t size()
Return the size (in bytes) of the embedded EEPROM.
static bool read(const T *address, T &value)
Read value of type T stored in EEPROM at address.
static bool read(const uint8_t *address, uint8_t &value)
Read one byte stored in EEPROM at address.
static bool write(uint16_t address, const T &value)
Write the content of value of type T to the EEPROM at address.
static bool read(uint16_t address, T &value)
Read value of type T stored in EEPROM at address.
static void wait_until_ready()
Block until the current EEPROM operation, whetever it is (e.g.
static bool write(uint16_t address, uint8_t value)
Write one byte to the EEPROM at address.
static bool write(const T *address, const T &value)
Write the content of value of type T to the EEPROM at address.
static bool write(const uint8_t *address, uint8_t value)
Write one byte to the EEPROM at address.
static bool write(const T *address, const T *value, uint16_t count)
Write value, an array of count values of type T to the EEPROM at address.
static bool write(uint16_t address, const T *value, uint16_t count)
Write value, an array of count values of type T to the EEPROM at address.
static bool read(uint16_t address, T *value, uint16_t count)
Read an array of count values of type T stored in EEPROM at address.
static void erase()
Erase the full EEPROM content.
static bool read(const T *address, T *value, uint16_t count)
Read an array of count values of type T stored in EEPROM at address.
static bool read(uint16_t address, uint8_t &value)
Read one byte stored in EEPROM at address.
API that allows asynchronous writing to EEPROM; this can be useful when you have large amount of data...
QueuedWriter(uint8_t(&buffer)[SIZE])
Construct a QueuedWriter from a given buffer array.
bool is_done() const
Tell if there is no queued, nor on-going write operation.
bool write(const T *address, const T &value)
Write the content of value of type T to the EEPROM at address.
bool write(const T *address, const T *value, uint16_t count)
Write value, an array of count values of type T to the EEPROM at address.
bool write(uint16_t address, const T *value, uint16_t count)
Write value, an array of count values of type T to the EEPROM at address.
bool write(uint16_t address, uint8_t value)
Write one byte to the EEPROM at address.
bool write(uint16_t address, const T &value)
Write the content of value of type T to the EEPROM at address.
void wait_until_done() const
Block until all pending operations (queued in the ring buffer) are complete.
void erase()
Erase the full EEPROM content.
bool write(const uint8_t *address, uint8_t value)
Write one byte to the EEPROM at address.
#define UNUSED
Specific GCC attribute to declare an argument or variable unused, so that the compiler does not emit ...
General API for handling AVR interrupt vectors.
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
Defines the API for accessing the EEPROM embedded in each AVR MCU.
void register_handler(Handler &handler)
Register a class instance containing methods that shall be called back by an ISR.
Contains all generic utility methods.
constexpr T is_zero(T value, T default_value)
Replace value by default_value if not "true" (also known as "Elvis operator").
Utility API to handle ring-buffer queue containers.
General utilities API that have broad application in programs.