/* Show extended heap stats when EspClass::getHeapStats() is available */ #pragma once #include struct heap_stats_t { uint32_t available; uint16_t usable; uint8_t frag_pct; }; namespace EspClass_has_getHeapStats { struct _detector { template().getHeapStats(0,0,0))> static std::true_type detect(int); template static std::false_type detect(...); }; template struct detector : public _detector { using result = decltype( std::declval().detect(0)); }; template struct typed_check : public detector::result { }; typed_check check{}; }; template void _getHeapStats(std::true_type&, T& instance, heap_stats_t& stats) { instance.getHeapStats(&stats.available, &stats.usable, &stats.frag_pct); } template void _getHeapStats(std::false_type&, T& instance, heap_stats_t& stats) { stats.available = instance.getFreeHeap(); stats.usable = 0; stats.frag_pct = 0; } void getHeapStats(heap_stats_t& stats) { _getHeapStats(EspClass_has_getHeapStats::check, ESP, stats); } // WTF // Calling ESP.getFreeHeap() is making the system crash on a specific // AiLight bulb, but anywhere else it should work as expected static bool _heap_value_wtf = false; heap_stats_t getHeapStats() { heap_stats_t stats; if (_heap_value_wtf) { stats.available = 9999; stats.usable = 9999; stats.frag_pct = 0; return stats; } getHeapStats(stats); return stats; } void wtfHeap(bool value) { _heap_value_wtf = value; } unsigned int getFreeHeap() { return getHeapStats().available; } static unsigned int _initial_heap_value = 0; void setInitialFreeHeap() { _initial_heap_value = getFreeHeap(); } unsigned int getInitialFreeHeap() { if (0 == _initial_heap_value) { setInitialFreeHeap(); } return _initial_heap_value; } void infoMemory(const char* name, const heap_stats_t& stats) { infoMemory(name, getInitialFreeHeap(), stats.available); } void infoHeapStats(const char* name, const heap_stats_t& stats) { DEBUG_MSG_P( PSTR("[MAIN] %-6s: %5u bytes available | %5u bytes lost (%2u%%) | %5u bytes free (%2u%%)\n"), name, stats.available, (stats.available - stats.usable), stats.frag_pct, stats.usable, (100 - stats.frag_pct) ); } void infoHeapStats(bool show_frag_stats = true) { const auto stats = getHeapStats(); infoMemory("Heap", stats); if (show_frag_stats && EspClass_has_getHeapStats::check) { infoHeapStats("Heap", stats); } }