/*
|
|
|
|
RTMEM MODULE
|
|
|
|
Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
|
|
|
|
*/
|
|
|
|
#include "espurna.h"
|
|
#include "rtcmem.h"
|
|
|
|
static constexpr uint32_t RtcmemMagic { RTCMEM_MAGIC };
|
|
|
|
static constexpr uintptr_t RtcmemBlocks { RTCMEM_BLOCKS };
|
|
static constexpr uintptr_t RtcmemBegin { RTCMEM_ADDR };
|
|
static constexpr uintptr_t RtcmemEnd { RtcmemBegin + (4 * RtcmemBlocks) };
|
|
|
|
volatile RtcmemData* Rtcmem = reinterpret_cast<volatile RtcmemData*>(RtcmemBegin);
|
|
|
|
namespace espurna {
|
|
namespace peripherals {
|
|
namespace {
|
|
|
|
namespace rtc {
|
|
namespace internal {
|
|
|
|
bool status = false;
|
|
|
|
} // namespace internal
|
|
|
|
void erase() {
|
|
DEBUG_MSG_P(PSTR("[RTCMEM] Erasing start=0x%08x end=0x%08x\n"),
|
|
RtcmemBegin, RtcmemEnd);
|
|
|
|
auto begin = reinterpret_cast<volatile uint32_t*>(RtcmemBegin);
|
|
auto end = reinterpret_cast<volatile uint32_t*>(RtcmemEnd);
|
|
for (auto it = begin; it != end; ++it) {
|
|
*it = 0;
|
|
}
|
|
}
|
|
|
|
void init() {
|
|
erase();
|
|
Rtcmem->magic = RtcmemMagic;
|
|
}
|
|
|
|
// Treat memory as dirty on cold boot, hardware wdt reset and rst pin
|
|
bool status() {
|
|
bool readable;
|
|
|
|
switch (systemResetReason()) {
|
|
case REASON_EXT_SYS_RST:
|
|
case REASON_DEFAULT_RST:
|
|
readable = false;
|
|
break;
|
|
default:
|
|
readable = true;
|
|
}
|
|
|
|
readable = readable
|
|
&& (RtcmemMagic == Rtcmem->magic);
|
|
|
|
return readable;
|
|
}
|
|
|
|
#if TERMINAL_SUPPORT
|
|
namespace terminal {
|
|
|
|
PROGMEM_STRING(Init, "RTCMEM.INIT");
|
|
|
|
void init(::terminal::CommandContext&& ctx) {
|
|
rtc::init();
|
|
terminalOK(ctx);
|
|
}
|
|
|
|
PROGMEM_STRING(Dump, "RTCMEM.DUMP");
|
|
|
|
void dump(::terminal::CommandContext&& ctx) {
|
|
ctx.output.printf_P(PSTR("boot_status=%s status=%s\n"),
|
|
internal::status ? "OK" : "INIT",
|
|
status() ? "OK" : "INIT");
|
|
|
|
constexpr size_t BytesPerBlock = sizeof(uint32_t);
|
|
constexpr size_t BlocksPerLine = 8;
|
|
|
|
alignas(4) uint8_t buffer[BytesPerBlock * BlocksPerLine];
|
|
String line;
|
|
|
|
for (auto addr = RtcmemBegin; addr < RtcmemEnd; addr += std::size(buffer)) {
|
|
std::memcpy(&buffer[0], reinterpret_cast<uint32_t*>(addr), std::size(buffer));
|
|
|
|
line += PSTR("0x");
|
|
line += String(addr, 16);
|
|
line += ':';
|
|
|
|
for (auto it = std::begin(buffer); it != std::end(buffer); it += BytesPerBlock) {
|
|
line += PSTR(" ");
|
|
line += hexEncode(it, it + BytesPerBlock);
|
|
}
|
|
|
|
line += '\n';
|
|
|
|
ctx.output.print(line);
|
|
line = "";
|
|
}
|
|
}
|
|
|
|
static constexpr ::terminal::Command Commands[] PROGMEM {
|
|
{Init, init},
|
|
{Dump, dump},
|
|
};
|
|
|
|
void setup() {
|
|
espurna::terminal::add(Commands);
|
|
}
|
|
|
|
} // namespace terminal
|
|
#endif
|
|
|
|
bool current_status() {
|
|
return internal::status;
|
|
}
|
|
|
|
void setup() {
|
|
#if TERMINAL_SUPPORT
|
|
terminal::setup();
|
|
#endif
|
|
|
|
internal::status = status();
|
|
if (!internal::status) {
|
|
init();
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace rtc
|
|
|
|
} // namespace
|
|
} // namespace peripherals
|
|
} // namespace espurna
|
|
|
|
bool rtcmemStatus() {
|
|
return espurna::peripherals::rtc::current_status();
|
|
}
|
|
|
|
void rtcmemSetup() {
|
|
espurna::peripherals::rtc::setup();
|
|
}
|