2020-04-07 05:02:38 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <avr/eeprom.h>
|
|
|
|
|
|
|
|
#include "../type/type.hpp"
|
|
|
|
|
|
|
|
#define EEVAR(type, name) \
|
|
|
|
type EEMEM __##name; \
|
|
|
|
constexpr auto name = &__##name
|
|
|
|
|
2020-04-08 02:15:56 +02:00
|
|
|
#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 <typename T>
|
|
|
|
constexpr T readEepromValue(const T *addr)
|
|
|
|
{
|
|
|
|
if constexpr (type::is_integral_v<T>) {
|
|
|
|
if constexpr (sizeof(T) == 1) {
|
|
|
|
return eeprom_read_byte(reinterpret_cast<const uint8_t *>(addr));
|
|
|
|
} else if constexpr (sizeof(T) == 2) {
|
|
|
|
return eeprom_read_word(reinterpret_cast<const uint16_t *>(addr));
|
|
|
|
} else if constexpr (sizeof(T) == 4) {
|
|
|
|
return eeprom_read_dword(reinterpret_cast<const uint32_t *>(addr));
|
|
|
|
} else if constexpr (sizeof(T) == 8) {
|
|
|
|
T number;
|
|
|
|
eeprom_read_block(&number, addr, sizeof(T));
|
|
|
|
return number;
|
2020-04-07 05:02:38 +02:00
|
|
|
}
|
2020-04-08 02:15:56 +02:00
|
|
|
} else if constexpr (type::is_floating_point_v<T>) {
|
|
|
|
static_assert(sizeof(T) == 4, "Only floats of size 4 are supported");
|
|
|
|
return eeprom_read_float(reinterpret_cast<const float *>(addr));
|
2020-04-07 05:02:38 +02:00
|
|
|
}
|
2020-04-08 02:15:56 +02:00
|
|
|
}
|
2020-04-07 05:02:38 +02:00
|
|
|
|
2020-04-08 02:15:56 +02:00
|
|
|
template <typename T, size_t Size>
|
|
|
|
constexpr void readEepromArray(const T *addr, T *array)
|
|
|
|
{
|
|
|
|
eeprom_read_block(array, addr, Size * sizeof(T));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, bool Update>
|
|
|
|
constexpr void writeEepromValue(T *addr, const T &value)
|
|
|
|
{
|
|
|
|
if constexpr (type::is_integral_v<T>) {
|
|
|
|
if constexpr (sizeof(T) == 1) {
|
|
|
|
if constexpr (Update) {
|
|
|
|
eeprom_update_byte(reinterpret_cast<uint8_t *>(addr), value);
|
|
|
|
} else {
|
|
|
|
eeprom_write_byte(reinterpret_cast<uint8_t *>(addr), value);
|
|
|
|
}
|
|
|
|
} else if constexpr (sizeof(T) == 2) {
|
|
|
|
if constexpr (Update) {
|
|
|
|
eeprom_update_word(reinterpret_cast<uint16_t *>(addr), value);
|
|
|
|
} else {
|
|
|
|
eeprom_write_word(reinterpret_cast<uint16_t *>(addr), value);
|
|
|
|
}
|
|
|
|
} else if constexpr (sizeof(T) == 4) {
|
|
|
|
if constexpr (Update) {
|
|
|
|
eeprom_update_dword(reinterpret_cast<uint32_t *>(addr), value);
|
|
|
|
} else {
|
|
|
|
eeprom_write_dword(reinterpret_cast<uint32_t *>(addr), value);
|
2020-04-07 05:02:38 +02:00
|
|
|
}
|
2020-04-08 02:15:56 +02:00
|
|
|
} else if constexpr (sizeof(T) == 8) {
|
2020-04-07 05:02:38 +02:00
|
|
|
if constexpr (Update) {
|
2020-04-08 02:15:56 +02:00
|
|
|
eeprom_update_block(&value, addr, sizeof(T));
|
2020-04-07 05:02:38 +02:00
|
|
|
} else {
|
2020-04-08 02:15:56 +02:00
|
|
|
eeprom_write_block(&value, addr, sizeof(T));
|
2020-04-07 05:02:38 +02:00
|
|
|
}
|
|
|
|
}
|
2020-04-08 02:15:56 +02:00
|
|
|
} else if constexpr (type::is_floating_point_v<T>) {
|
|
|
|
static_assert(sizeof(T) == 4, "Only floats of size 4 are supported");
|
|
|
|
if constexpr (Update) {
|
|
|
|
eeprom_update_float(reinterpret_cast<float *>(addr), value);
|
|
|
|
} else {
|
|
|
|
eeprom_write_float(reinterpret_cast<float *>(addr), value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, size_t Size, bool Update>
|
|
|
|
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
|
2020-04-07 05:02:38 +02:00
|
|
|
|
2020-04-08 02:15:56 +02:00
|
|
|
template <auto Address, bool Update = false, typename T = type::decay_t<decltype(*Address)>>
|
|
|
|
class Eeprom {
|
|
|
|
public:
|
|
|
|
operator T() const
|
|
|
|
{
|
|
|
|
return detail::readEepromValue<T>(Address);
|
|
|
|
}
|
|
|
|
|
|
|
|
Eeprom &operator=(const T &other)
|
|
|
|
{
|
|
|
|
detail::writeEepromValue<T, Update>(Address, other);
|
2020-04-07 05:02:38 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static_assert(type::is_integral_v<T> || type::is_floating_point_v<T>,
|
|
|
|
"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");
|
|
|
|
};
|
2020-04-08 02:15:56 +02:00
|
|
|
|
|
|
|
template <auto Address, size_t Size, bool Update = false, typename T = type::decay_t<decltype(*Address)>>
|
|
|
|
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<T, Update>(Address + m_idx, other);
|
|
|
|
}
|
|
|
|
constexpr operator T() const
|
|
|
|
{
|
|
|
|
return detail::readEepromValue<T>(Address + m_idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const size_t m_idx;
|
|
|
|
};
|
|
|
|
};
|