/* RTMEM MODULE Copyright (C) 2019 by Maxim Prokhorov */ #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(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(RtcmemBegin); auto end = reinterpret_cast(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(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(); }