From ab37d32b6ddeda6b7ce48b63bed1ad35f2c89d76 Mon Sep 17 00:00:00 2001 From: John Poole Date: Fri, 3 Apr 2026 15:54:08 -0700 Subject: [PATCH] Shows available RAM --- exercises/15_RAM/README.md | 16 ++++ exercises/15_RAM/platformio.ini | 55 ++++++++++++ exercises/15_RAM/scripts/set_build_epoch.py | 12 +++ exercises/15_RAM/src/main.cpp | 93 +++++++++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 exercises/15_RAM/README.md create mode 100644 exercises/15_RAM/platformio.ini create mode 100644 exercises/15_RAM/scripts/set_build_epoch.py create mode 100644 exercises/15_RAM/src/main.cpp diff --git a/exercises/15_RAM/README.md b/exercises/15_RAM/README.md new file mode 100644 index 0000000..7f35cf7 --- /dev/null +++ b/exercises/15_RAM/README.md @@ -0,0 +1,16 @@ +# Exercise 15: RAM + +This exercise shows available RAM on the console and on the OLED display on a T-Beam Supreme. + +Behavior: +- Reports heap statistics every second over serial. +- Shows live heap status on the OLED display. +- Designed as the first step toward volatile /tmp RAM-backed storage. + +Build and upload: + +```bash +cd /usr/local/src/microreticulum/microReticulumTbeam/exercises/15_RAM +pio run -e amy -t upload +pio device monitor -b 115200 +``` diff --git a/exercises/15_RAM/platformio.ini b/exercises/15_RAM/platformio.ini new file mode 100644 index 0000000..f8e943d --- /dev/null +++ b/exercises/15_RAM/platformio.ini @@ -0,0 +1,55 @@ +; 20260403 ChatGPT +; Exercise 15_RAM + +[platformio] +default_envs = amy + +[env] +platform = espressif32 +framework = arduino +board = esp32-s3-devkitc-1 +monitor_speed = 115200 +extra_scripts = pre:scripts/set_build_epoch.py +lib_deps = + Wire + olikraus/U8g2@^2.36.4 + +build_flags = + -I ../../shared/boards + -I ../../external/microReticulum_Firmware + -D BOARD_MODEL=BOARD_TBEAM_S_V1 + -D OLED_SDA=17 + -D OLED_SCL=18 + -D OLED_ADDR=0x3C + -D ARDUINO_USB_MODE=1 + -D ARDUINO_USB_CDC_ON_BOOT=1 + +[env:amy] +extends = env +build_flags = + ${env.build_flags} + -D NODE_LABEL=\"AMY\" + +[env:bob] +extends = env +build_flags = + ${env.build_flags} + -D NODE_LABEL=\"BOB\" + +[env:cy] +extends = env +build_flags = + ${env.build_flags} + -D NODE_LABEL=\"CY\" + +[env:dan] +extends = env +build_flags = + ${env.build_flags} + -D NODE_LABEL=\"DAN\" + +[env:ed] +extends = env +build_flags = + ${env.build_flags} + -D NODE_LABEL=\"ED\" diff --git a/exercises/15_RAM/scripts/set_build_epoch.py b/exercises/15_RAM/scripts/set_build_epoch.py new file mode 100644 index 0000000..3011129 --- /dev/null +++ b/exercises/15_RAM/scripts/set_build_epoch.py @@ -0,0 +1,12 @@ +import time +Import("env") + +epoch = int(time.time()) +utc_tag = time.strftime("%Y%m%d_%H%M%S_z", time.gmtime(epoch)) + +env.Append( + CPPDEFINES=[ + ("FW_BUILD_EPOCH", str(epoch)), + ("FW_BUILD_UTC", '\\"%s\\"' % utc_tag), + ] +) diff --git a/exercises/15_RAM/src/main.cpp b/exercises/15_RAM/src/main.cpp new file mode 100644 index 0000000..5f3c5a6 --- /dev/null +++ b/exercises/15_RAM/src/main.cpp @@ -0,0 +1,93 @@ +// 20260403 ChatGPT +// Exercise 15_RAM + +#include +#include +#include + +#ifndef NODE_LABEL +#define NODE_LABEL "RAM" +#endif + +#ifndef OLED_SDA +#define OLED_SDA 17 +#endif +#ifndef OLED_SCL +#define OLED_SCL 18 +#endif +#ifndef OLED_ADDR +#define OLED_ADDR 0x3C +#endif + +static U8G2_SH1106_128X64_NONAME_F_HW_I2C g_oled(U8G2_R0, U8X8_PIN_NONE); + +static void oledShowLines(const char *l1, + const char *l2 = nullptr, + const char *l3 = nullptr, + const char *l4 = nullptr, + const char *l5 = nullptr) +{ + g_oled.clearBuffer(); + g_oled.setFont(u8g2_font_5x8_tf); + if (l1) g_oled.drawUTF8(0, 12, l1); + if (l2) g_oled.drawUTF8(0, 24, l2); + if (l3) g_oled.drawUTF8(0, 36, l3); + if (l4) g_oled.drawUTF8(0, 48, l4); + if (l5) g_oled.drawUTF8(0, 60, l5); + g_oled.sendBuffer(); +} + +static size_t getAvailableRamBytes() +{ + return ESP.getFreeHeap(); +} + +static void printRamStatus() +{ + const size_t freeBytes = getAvailableRamBytes(); + const size_t totalBytes = ESP.getHeapSize(); + const size_t maxAlloc = ESP.getMaxAllocHeap(); + + Serial.printf("RAM total=%u free=%u maxAlloc=%u\r\n", (unsigned)totalBytes, (unsigned)freeBytes, (unsigned)maxAlloc); + + char line1[32]; + char line2[32]; + char line3[32]; + + snprintf(line1, sizeof(line1), "Exercise 15 RAM"); + snprintf(line2, sizeof(line2), "Node: %s", NODE_LABEL); + snprintf(line3, sizeof(line3), "Free: %u KB", (unsigned)(freeBytes / 1024U)); + char line4[32]; + snprintf(line4, sizeof(line4), "Total: %u KB", (unsigned)(totalBytes / 1024U)); + char line5[32]; + snprintf(line5, sizeof(line5), "Max alloc: %u KB", (unsigned)(maxAlloc / 1024U)); + + oledShowLines(line1, line2, line3, line4, line5); +} + +void setup() +{ + Serial.begin(115200); + delay(800); + Serial.println("Exercise 15_RAM boot"); + + Wire.begin(OLED_SDA, OLED_SCL); + g_oled.setI2CAddress(OLED_ADDR << 1); + g_oled.begin(); + oledShowLines("Exercise 15_RAM", "Node: " NODE_LABEL, "Booting..."); + + delay(1000); +} + +void loop() +{ + static uint32_t lastMs = 0; + const uint32_t now = millis(); + if (now - lastMs < 1000) { + delay(10); + return; + } + lastMs = now; + + printRamStatus(); +}