Mirror of espurna firmware for wireless switches and more
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
3.0 KiB

  1. /*
  2. RTMEM MODULE
  3. Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
  4. */
  5. #include "espurna.h"
  6. #include "rtcmem.h"
  7. static constexpr uint32_t RtcmemMagic { RTCMEM_MAGIC };
  8. static constexpr uintptr_t RtcmemBlocks { RTCMEM_BLOCKS };
  9. static constexpr uintptr_t RtcmemBegin { RTCMEM_ADDR };
  10. static constexpr uintptr_t RtcmemEnd { RtcmemBegin + (4 * RtcmemBlocks) };
  11. volatile RtcmemData* Rtcmem = reinterpret_cast<volatile RtcmemData*>(RtcmemBegin);
  12. namespace espurna {
  13. namespace peripherals {
  14. namespace {
  15. namespace rtc {
  16. namespace internal {
  17. bool status = false;
  18. } // namespace internal
  19. void erase() {
  20. DEBUG_MSG_P(PSTR("[RTCMEM] Erasing start=0x%08x end=0x%08x\n"),
  21. RtcmemBegin, RtcmemEnd);
  22. auto begin = reinterpret_cast<volatile uint32_t*>(RtcmemBegin);
  23. auto end = reinterpret_cast<volatile uint32_t*>(RtcmemEnd);
  24. for (auto it = begin; it != end; ++it) {
  25. *it = 0;
  26. }
  27. }
  28. void init() {
  29. erase();
  30. Rtcmem->magic = RtcmemMagic;
  31. }
  32. // Treat memory as dirty on cold boot, hardware wdt reset and rst pin
  33. bool status() {
  34. bool readable;
  35. switch (systemResetReason()) {
  36. case REASON_EXT_SYS_RST:
  37. case REASON_DEFAULT_RST:
  38. readable = false;
  39. break;
  40. default:
  41. readable = true;
  42. }
  43. readable = readable
  44. && (RtcmemMagic == Rtcmem->magic);
  45. return readable;
  46. }
  47. #if TERMINAL_SUPPORT
  48. namespace terminal {
  49. PROGMEM_STRING(Init, "RTCMEM.INIT");
  50. void init(::terminal::CommandContext&& ctx) {
  51. rtc::init();
  52. terminalOK(ctx);
  53. }
  54. PROGMEM_STRING(Dump, "RTCMEM.DUMP");
  55. void dump(::terminal::CommandContext&& ctx) {
  56. ctx.output.printf_P(PSTR("boot_status=%s status=%s\n"),
  57. internal::status ? "OK" : "INIT",
  58. status() ? "OK" : "INIT");
  59. constexpr size_t BytesPerBlock = sizeof(uint32_t);
  60. constexpr size_t BlocksPerLine = 8;
  61. alignas(4) uint8_t buffer[BytesPerBlock * BlocksPerLine];
  62. String line;
  63. for (auto addr = RtcmemBegin; addr < RtcmemEnd; addr += std::size(buffer)) {
  64. std::memcpy(&buffer[0], reinterpret_cast<uint32_t*>(addr), std::size(buffer));
  65. line += PSTR("0x");
  66. line += String(addr, 16);
  67. line += ':';
  68. for (auto it = std::begin(buffer); it != std::end(buffer); it += BytesPerBlock) {
  69. line += PSTR(" ");
  70. line += hexEncode(it, it + BytesPerBlock);
  71. }
  72. line += '\n';
  73. ctx.output.print(line);
  74. line = "";
  75. }
  76. }
  77. static constexpr ::terminal::Command Commands[] PROGMEM {
  78. {Init, init},
  79. {Dump, dump},
  80. };
  81. void setup() {
  82. espurna::terminal::add(Commands);
  83. }
  84. } // namespace terminal
  85. #endif
  86. bool current_status() {
  87. return internal::status;
  88. }
  89. void setup() {
  90. #if TERMINAL_SUPPORT
  91. terminal::setup();
  92. #endif
  93. internal::status = status();
  94. if (!internal::status) {
  95. init();
  96. }
  97. }
  98. } // namespace rtc
  99. } // namespace
  100. } // namespace peripherals
  101. } // namespace espurna
  102. bool rtcmemStatus() {
  103. return espurna::peripherals::rtc::current_status();
  104. }
  105. void rtcmemSetup() {
  106. espurna::peripherals::rtc::setup();
  107. }