// main.cpp — Info display for SSD1306 128x64 using gfx::LinuxFBDisplay. // // Build: see CMakeLists.txt // Run: ./gfx_info_display # defaults to /dev/fb1 // ./gfx_info_display /dev/fb0 # override #include "gfx_canvas.h" #include "gfx_font_5x7.h" #include "linux_fb_display.h" #include #include #include #include #include #include #include #include #include #include // --------------------------------------------------------------------------- // Configuration // --------------------------------------------------------------------------- constexpr int16_t SCREEN_W = 128; constexpr int16_t SCREEN_H = 64; // 16 yellow on top and 48 blue on bottom constexpr const char* ETH_IFACE = "eth0"; constexpr const char* WLAN_IFACE = "wlan0"; // --------------------------------------------------------------------------- // Network helper // --------------------------------------------------------------------------- static std::string get_ip(const char* iface_name) { struct ifaddrs* ifaddr = nullptr; if (getifaddrs(&ifaddr) == -1) return "err"; std::string result = "down"; for (auto* ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; if (ifa->ifa_addr->sa_family != AF_INET) continue; if (std::strcmp(ifa->ifa_name, iface_name) != 0) continue; char buf[INET_ADDRSTRLEN]; auto* sa = reinterpret_cast(ifa->ifa_addr); inet_ntop(AF_INET, &sa->sin_addr, buf, sizeof(buf)); result = buf; break; } freeifaddrs(ifaddr); return result; } // --------------------------------------------------------------------------- // Text centering helper // --------------------------------------------------------------------------- static void draw_centered(gfx::GfxCanvas& disp, int16_t y, const char* text) { int16_t bx, by; uint16_t bw, bh; disp.getTextBounds(text, 0, 0, bx, by, bw, bh); disp.drawString((SCREEN_W - static_cast(bw)) / 2, y, text, gfx::colors::white); } // --------------------------------------------------------------------------- // Signal handling // --------------------------------------------------------------------------- static volatile sig_atomic_t g_running = 1; static void signal_handler(int) { g_running = 0; } // --------------------------------------------------------------------------- // Main // --------------------------------------------------------------------------- int main(int argc, char* argv[]) { const char* fb_device = "/dev/fb1"; if (argc > 1) fb_device = argv[1]; gfx::LinuxFBDisplay display(SCREEN_W, SCREEN_H); if (!display.open(fb_device)) return EXIT_FAILURE; display.setFont(gfx::font_5x7); display.setTextColor(gfx::colors::white); display.setTextWrap(false); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); char line_buf[64]; while (g_running) { display.fillScreen(gfx::colors::black); // --- Network info --- std::string eth_ip = get_ip(ETH_IFACE); std::string wlan_ip = get_ip(WLAN_IFACE); std::snprintf(line_buf, sizeof(line_buf), "ETH: %s", eth_ip.c_str()); display.setCursor(0, 0); display.print(line_buf); std::snprintf(line_buf, sizeof(line_buf), "WLAN: %s", wlan_ip.c_str()); display.setCursor(0, 8); display.print(line_buf); // --- Separator --- display.drawHLine(0, 17, SCREEN_W, gfx::colors::white); // --- Date and time --- std::time_t now = std::time(nullptr); std::tm* tm = std::localtime(&now); std::snprintf(line_buf, sizeof(line_buf), "%04d-%02d-%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); draw_centered(display, 29, line_buf); std::snprintf(line_buf, sizeof(line_buf), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); draw_centered(display, 41, line_buf); display.update(); // --- Sleep aligned to next whole second --- struct timespec ts{}; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 1; ts.tv_nsec = 0; clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, nullptr); } display.fillScreen(gfx::colors::black); std::printf("Exiting.\n"); return EXIT_SUCCESS; }