#pragma once #include #include "../type/type.hpp" #define EEVAR(type, name) \ type EEMEM __##name; \ constexpr auto name = &__##name #define EEARRAY(type, name, size) \ type EEMEM __##name[size]; \ constexpr auto name = __##name #define EEARRAY_SIZE(name) (sizeof(__##name) / sizeof(__##name[0])) namespace detail { template constexpr T readEepromValue(const T *addr) { if constexpr (type::is_integral_v) { if constexpr (sizeof(T) == 1) { return eeprom_read_byte(reinterpret_cast(addr)); } else if constexpr (sizeof(T) == 2) { return eeprom_read_word(reinterpret_cast(addr)); } else if constexpr (sizeof(T) == 4) { return eeprom_read_dword(reinterpret_cast(addr)); } else if constexpr (sizeof(T) == 8) { T number; eeprom_read_block(&number, addr, sizeof(T)); return number; } } else if constexpr (type::is_floating_point_v) { static_assert(sizeof(T) == 4, "Only floats of size 4 are supported"); return eeprom_read_float(reinterpret_cast(addr)); } } template constexpr void readEepromArray(const T *addr, T *array) { eeprom_read_block(array, addr, Size * sizeof(T)); } template constexpr void writeEepromValue(T *addr, const T &value) { if constexpr (type::is_integral_v) { if constexpr (sizeof(T) == 1) { if constexpr (Update) { eeprom_update_byte(reinterpret_cast(addr), value); } else { eeprom_write_byte(reinterpret_cast(addr), value); } } else if constexpr (sizeof(T) == 2) { if constexpr (Update) { eeprom_update_word(reinterpret_cast(addr), value); } else { eeprom_write_word(reinterpret_cast(addr), value); } } else if constexpr (sizeof(T) == 4) { if constexpr (Update) { eeprom_update_dword(reinterpret_cast(addr), value); } else { eeprom_write_dword(reinterpret_cast(addr), value); } } else if constexpr (sizeof(T) == 8) { if constexpr (Update) { eeprom_update_block(&value, addr, sizeof(T)); } else { eeprom_write_block(&value, addr, sizeof(T)); } } } else if constexpr (type::is_floating_point_v) { static_assert(sizeof(T) == 4, "Only floats of size 4 are supported"); if constexpr (Update) { eeprom_update_float(reinterpret_cast(addr), value); } else { eeprom_write_float(reinterpret_cast(addr), value); } } } template constexpr void writeEepromArray(T *addr, const T *array) { if constexpr (Update) { eeprom_update_block(array, addr, Size * sizeof(T)); } else { eeprom_write_block(array, addr, Size * sizeof(T)); } } } // namespace detail template > class Eeprom { public: operator T() const { return detail::readEepromValue(Address); } Eeprom &operator=(const T &other) { detail::writeEepromValue(Address, other); return *this; } private: static_assert(type::is_integral_v || type::is_floating_point_v, "Only integral and floating point types are supported"); static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "Only sizes 1, 2, 4, and 8 are supported"); }; template > class EepromArray { private: class AccessHelper; public: constexpr size_t size() const { return Size; } constexpr AccessHelper operator[](const size_t &idx) { return AccessHelper(idx); } private: class AccessHelper { public: AccessHelper(const size_t &idx) : m_idx(idx) {} constexpr void operator=(const T &other) { detail::writeEepromValue(Address + m_idx, other); } constexpr operator T() const { return detail::readEepromValue(Address + m_idx); } private: const size_t m_idx; }; };