/ firmware / src / programs / shell / microfetch.cpp
microfetch.cpp
  1  #include "microfetch.h"
  2  #include <config.h>
  3  #include "console/icons.h"
  4  #include <storage.h>
  5  #include <i2c.h>
  6  #include <networking/wifi.h>
  7  #include <manager.h>
  8  #include <identity.h>
  9  #include <services/system.h>
 10  
 11  #include <Arduino.h>
 12  #include <Console.h>
 13  
 14  static char fetch_buf[2048];
 15  
 16  static int fetch_pos;
 17  static int fetch_remaining;
 18  
 19  static void row(const char *color, const char *icon, const char *label, const char *fmt, ...) {
 20    int space = fetch_remaining;
 21    if (space <= 0) return;
 22  
 23    int n = snprintf(fetch_buf + fetch_pos, space,
 24      "  \x1b[1;%sm%s %-14s\x1b[0m ", color, icon, label);
 25    if (n > 0 && n < space) { fetch_pos += n; fetch_remaining -= n; }
 26  
 27    va_list args;
 28    va_start(args, fmt);
 29    n = vsnprintf(fetch_buf + fetch_pos, fetch_remaining, fmt, args);
 30    va_end(args);
 31    if (n > 0 && n < fetch_remaining) { fetch_pos += n; fetch_remaining -= n; }
 32  
 33    n = snprintf(fetch_buf + fetch_pos, fetch_remaining, "\r\n");
 34    if (n > 0 && n < fetch_remaining) { fetch_pos += n; fetch_remaining -= n; }
 35  }
 36  
 37  const char *programs::shell::microfetch::generate(const char *transport) {
 38    fetch_pos = 0;
 39    fetch_remaining = sizeof(fetch_buf) - 1;
 40  
 41    SystemQuery system_query = {
 42      .preferred_storage = StorageKind::LittleFS,
 43      .snapshot = {},
 44    };
 45    services::system::accessSnapshot(&system_query);
 46    const SystemSnapshot &snapshot = system_query.snapshot;
 47    SensorInventorySnapshot inventory = {};
 48    sensors::manager::accessInventory(&inventory);
 49    uint32_t heap_pct = snapshot.heap_total > 0
 50        ? ((snapshot.heap_total - snapshot.heap_free) * 100) / snapshot.heap_total
 51        : 0;
 52  
 53    int n;
 54  
 55    n = snprintf(fetch_buf + fetch_pos, fetch_remaining, "\r\n");
 56    fetch_pos += n; fetch_remaining -= n;
 57  
 58    const char *hostname = services::identity::access_hostname();
 59  
 60    n = snprintf(fetch_buf + fetch_pos, fetch_remaining,
 61      "  \x1b[1;32m%s\x1b[0m\x1b[2m@\x1b[0m\x1b[1;36m%s\x1b[0m\r\n",
 62      CONFIG_SSH_USER, hostname);
 63    fetch_pos += n; fetch_remaining -= n;
 64  
 65    n = snprintf(fetch_buf + fetch_pos, fetch_remaining, "  \x1b[2m");
 66    fetch_pos += n; fetch_remaining -= n;
 67    size_t sep_len = strlen(CONFIG_SSH_USER) + 1 + strlen(hostname);
 68    for (size_t i = 0; i < sep_len && fetch_remaining > 1; i++) {
 69      fetch_buf[fetch_pos++] = '-';
 70      fetch_remaining--;
 71    }
 72    n = snprintf(fetch_buf + fetch_pos, fetch_remaining, "\x1b[0m\r\n");
 73    fetch_pos += n; fetch_remaining -= n;
 74  
 75    row("33", NF_FA_MICROCHIP, "OS", "\x1b[1mceratina\x1b[0m (%s)", config::PLATFORM);
 76    row("35", NF_FA_DESKTOP, "Host", "\x1b[1m%s\x1b[0m (rev %d)", snapshot.chip_model, snapshot.chip_revision);
 77    row("36", NF_FA_COG, "Kernel", "\x1b[1mArduino\x1b[0m / ESP-IDF %s", snapshot.sdk_version);
 78  
 79    uint32_t d = snapshot.uptime_seconds / 86400, h = (snapshot.uptime_seconds % 86400) / 3600;
 80    uint32_t m = (snapshot.uptime_seconds % 3600) / 60, s = snapshot.uptime_seconds % 60;
 81    if (d > 0) row("34", NF_FA_CLOCK, "Uptime", "\x1b[1m%u\x1b[0md %uh %um %us", d, h, m, s);
 82    else if (h > 0) row("34", NF_FA_CLOCK, "Uptime", "\x1b[1m%u\x1b[0mh %um %us", h, m, s);
 83    else row("34", NF_FA_CLOCK, "Uptime", "\x1b[1m%u\x1b[0mm %us", m, s);
 84  
 85    row("32", NF_FA_TERMINAL, "Shell", "\x1b[1mMicroshell\x1b[0m (%s)", transport);
 86    row("31", NF_FA_MICROCHIP, "CPU", "\x1b[1mXtensa LX7\x1b[0m (%d) @ \x1b[1m%u MHz\x1b[0m",
 87        snapshot.chip_cores, (unsigned)snapshot.cpu_mhz);
 88    row("36", NF_FA_MEMORY, "RAM", "\x1b[1m%u/%u KiB\x1b[0m (\x1b[1;32m%u%%\x1b[0m)",
 89        (snapshot.heap_total - snapshot.heap_free) / 1024, snapshot.heap_total / 1024, heap_pct);
 90  
 91    StorageQuery sd_query = {
 92      .kind = StorageKind::SD,
 93      .snapshot = {},
 94    };
 95    if (hardware::storage::accessSnapshot(&sd_query))
 96      row("32", NF_FA_HDD, "Disk (SD)", "\x1b[1m%llu MiB\x1b[0m", sd_query.snapshot.total_bytes / (1024*1024));
 97    else
 98      row("32", NF_FA_HDD, "Disk (SD)", "\x1b[2mnot detected\x1b[0m");
 99  
100    if (snapshot.storage.mounted)
101      row("32", NF_FA_DATABASE, "Disk (LFS)", "\x1b[1m%u/%u KiB\x1b[0m",
102          (unsigned)(snapshot.storage.used_bytes/1024), (unsigned)(snapshot.storage.total_bytes/1024));
103  
104    n = snprintf(fetch_buf + fetch_pos, fetch_remaining, "\r\n");
105    fetch_pos += n; fetch_remaining -= n;
106  
107    if (snapshot.network.connected) {
108      row("33", NF_FA_WIFI, "WiFi", "\x1b[1m%s\x1b[0m (%ld dBm)", snapshot.network.ssid, snapshot.network.rssi);
109      row("33", NF_FA_GLOBE, "Local IP", "\x1b[1m%s\x1b[0m", snapshot.network.ip);
110    } else if (snapshot.network.ap.active) {
111      row("33", NF_FA_WIFI, "WiFi", "\x1b[1mAP mode\x1b[0m (%u clients)", snapshot.network.ap.clients);
112      row("33", NF_FA_GLOBE, "AP IP", "\x1b[1m%s\x1b[0m", snapshot.network.ap.ip);
113    } else {
114      row("33", NF_FA_WIFI, "WiFi", "\x1b[2mnot connected\x1b[0m");
115    }
116  
117    row("35", NF_FA_SERVER, "Hostname", "\x1b[1m%s\x1b[0m.local", hostname);
118    row("34", NF_FA_GLOBE, "NTP", "\x1b[1m%s\x1b[0m", config::sntp::SERVER_1);
119    row("36", NF_FA_PLUG, "Ports", "SSH:\x1b[1m%d\x1b[0m  HTTP:\x1b[1m%d\x1b[0m", config::ssh::PORT, config::http::PORT);
120  
121    n = snprintf(fetch_buf + fetch_pos, fetch_remaining, "\r\n");
122    fetch_pos += n; fetch_remaining -= n;
123  
124    row("36", NF_FA_SITEMAP, "I2C Mux", "\x1b[1mTCA9548A\x1b[0m @ 0x%02X", config::i2c::MUX_ADDR);
125  
126    if (inventory.temperature_humidity_count > 0)
127      row("35", NF_FA_THERMOMETER, "Temp/Hum", "\x1b[1mI2C sensors\x1b[0m x%d",
128          inventory.temperature_humidity_count);
129    
130  
131    row("35", NF_FA_SIGNAL, "Voltage", "\x1b[1mADS1115\x1b[0m @ 0x%02X", config::voltage::I2C_ADDR);
132  
133    n = snprintf(fetch_buf + fetch_pos, fetch_remaining, "\r\n");
134    fetch_pos += n; fetch_remaining -= n;
135  
136    fetch_buf[fetch_pos] = '\0';
137    return fetch_buf;
138  }
139  
140  static int cmd_microfetch(int argc, char **argv) {
141    (void)argc; (void)argv;
142    printf("%s", programs::shell::microfetch::generate());
143    return 0;
144  }
145  
146  void programs::shell::microfetch::registerCmd() {
147    Console.addCmd("microfetch", "system info summary", cmd_microfetch);
148  }