- /*
-
- Show extended heap stats when EspClass::getHeapStats() is available
-
- */
-
- #pragma once
-
- #include <type_traits>
-
- struct heap_stats_t {
- uint32_t available;
- uint16_t usable;
- uint8_t frag_pct;
- };
-
- namespace EspClass_has_getHeapStats {
- struct _detector {
- template<typename T, typename = decltype(
- std::declval<T>().getHeapStats(0,0,0))>
- static std::true_type detect(int);
-
- template<typename>
- static std::false_type detect(...);
- };
-
- template <typename T>
- struct detector : public _detector {
- using result = decltype(
- std::declval<detector>().detect<T>(0));
- };
-
- template <typename T>
- struct typed_check : public detector<T>::result {
- };
-
- typed_check<EspClass> check{};
- };
-
- template <typename T>
- void _getHeapStats(std::true_type&, T& instance, heap_stats_t& stats) {
- instance.getHeapStats(&stats.available, &stats.usable, &stats.frag_pct);
- }
-
- template <typename T>
- 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);
- }
- }
|