first commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.o
|
||||
linuxSmartie
|
||||
75
.vscode/settings.json
vendored
Normal file
75
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.bu": "yaml",
|
||||
"*ign": "json",
|
||||
"iostream": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"format": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"ranges": "cpp",
|
||||
"span": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"text_encoding": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"variant": "cpp",
|
||||
"fstream": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"ratio": "cpp",
|
||||
"chrono": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"thread": "cpp"
|
||||
},
|
||||
"makefile.configureOnOpen": true,
|
||||
"makefile.launchConfigurations": [
|
||||
{
|
||||
"cwd": "/var/home/drath/lcdtest",
|
||||
"binaryPath": "/var/home/drath/lcdtest/lcd",
|
||||
"binaryArgs": []
|
||||
}
|
||||
]
|
||||
}
|
||||
25
.vscode/tasks.json
vendored
Normal file
25
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"type": "shell",
|
||||
"command": "make",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": "$gcc"
|
||||
},
|
||||
{
|
||||
"label": "clean",
|
||||
"type": "shell",
|
||||
"command": "make clean",
|
||||
"group": {
|
||||
"kind": "none",
|
||||
"isDefaut": false
|
||||
},
|
||||
"problemMatcher": "$gcc"
|
||||
}
|
||||
]
|
||||
}
|
||||
13
Makefile
Normal file
13
Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
MAKEFLAGS := --jobs=$(shell nproc)
|
||||
# MAKEFLAGS += --output-sync=target
|
||||
|
||||
# compiling with C++26
|
||||
BUILD_OPTS = -std=c++2c -Ofast -fdiagnostics-color=always
|
||||
|
||||
build:
|
||||
g++ -c $(BUILD_OPTS) -o main.o main.cpp
|
||||
g++ -c $(BUILD_OPTS) -o LCDDisplay.o -Iinclude include/LCDDisplay.cpp
|
||||
g++ $(BUILD_OPTS) -o linuxSmartie LCDDisplay.o main.o
|
||||
|
||||
clean:
|
||||
rm linuxSmartie *.o
|
||||
80
include/LCDDisplay.cpp
Normal file
80
include/LCDDisplay.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include "LCDDisplay.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
/* lcd size hardcoded to 4x40 idgaf */
|
||||
LCDDisplay::LCDDisplay(std::string dev, uint32_t baud) {
|
||||
std::cout << "[LCDDisplay] Opening LCD at " << dev << std::endl;
|
||||
struct termios term;
|
||||
int lcd = open(dev.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
|
||||
// handle errors
|
||||
if (lcd < 0) {
|
||||
std::cerr << "[LCDDisplay] Error opening serial port " << dev << std::endl;
|
||||
exit(lcd);
|
||||
}
|
||||
|
||||
// Setup the serial port 8 data bits, no parity ,1 stopbit, no flow control
|
||||
term.c_cflag = baud | CS8 | CSTOPB | CLOCAL | CREAD;
|
||||
term.c_iflag = 0;
|
||||
term.c_oflag = 0;
|
||||
term.c_lflag = 0;
|
||||
tcflush(lcd, TCIFLUSH);
|
||||
tcsetattr(lcd, TCSANOW, &term);
|
||||
_lcd = lcd;
|
||||
}
|
||||
|
||||
LCDDisplay::~LCDDisplay() {
|
||||
std::cout << "[LCDDisplay] Closing LCD port" << std::endl;
|
||||
close(_lcd);
|
||||
}
|
||||
|
||||
void LCDDisplay::clear() {
|
||||
uint8_t cmdbuf[] = {254, 88};
|
||||
write(_lcd, cmdbuf, 2);
|
||||
}
|
||||
|
||||
void LCDDisplay::setContrast(uint8_t contrast) {
|
||||
std::cout << "[LCDDisplay] Set contrast to " << std::to_string(contrast) << std::endl;
|
||||
uint8_t cmdbuf[] = {254, 80, contrast};
|
||||
write(_lcd, cmdbuf, 3);
|
||||
}
|
||||
|
||||
void LCDDisplay::setCursor(uint8_t row, uint8_t col) {
|
||||
uint8_t cmdbuf[] = {254, 71, (uint8_t)(col + 1), (uint8_t)(row + 1)};
|
||||
write(_lcd, cmdbuf, 4);
|
||||
}
|
||||
|
||||
void LCDDisplay::writeStr(std::string str) {
|
||||
write(_lcd, str.c_str(), str.size());
|
||||
}
|
||||
|
||||
void LCDDisplay::writeLines(std::array<std::string, 4> lines) {
|
||||
for (auto& line : lines) {
|
||||
if(line.size() > 40) {
|
||||
std::cerr << "Line " << line << " too long! (" << line.size() << " chars)" << std::endl;
|
||||
continue;
|
||||
}
|
||||
line.insert(line.end(), 40 - line.size(), ' ');
|
||||
}
|
||||
|
||||
setCursor(0, 0);
|
||||
writeStr(lines[0] + lines[1]);
|
||||
setCursor(2, 0);
|
||||
writeStr(lines[2] + lines[3]);
|
||||
}
|
||||
|
||||
void LCDDisplay::writeSStream(std::stringstream& ss) {
|
||||
std::string s = ss.str();
|
||||
if (s.size() != 160)
|
||||
std::cerr << "[LCDDisplay] stringstream wrong (" + std::to_string((int)(160 - s.size())) + " chars too short)" << std::endl;
|
||||
setCursor(0, 0);
|
||||
writeStr(s.substr(0, 80));
|
||||
setCursor(2, 0);
|
||||
writeStr(s.substr(80, 159));
|
||||
}
|
||||
20
include/LCDDisplay.hpp
Normal file
20
include/LCDDisplay.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
class LCDDisplay {
|
||||
private:
|
||||
uint8_t _lcd;
|
||||
void writeStr(std::string str);
|
||||
|
||||
public:
|
||||
LCDDisplay(std::string dev, uint32_t baud);
|
||||
~LCDDisplay();
|
||||
|
||||
void clear();
|
||||
void setContrast(uint8_t contrast);
|
||||
void setCursor(uint8_t row, uint8_t col);
|
||||
void writeLines(std::array<std::string, 4> lines);
|
||||
void writeSStream(std::stringstream& ss);
|
||||
};
|
||||
201
include/linux-system-usage.hpp
Normal file
201
include/linux-system-usage.hpp
Normal file
@@ -0,0 +1,201 @@
|
||||
/* ---------------------------------------------------------------------
|
||||
* Luiz Carlos doleron @ 2021
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero Public License version 3 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Affero Public License for more details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _GET_CPU_USAGE_LINUX_
|
||||
#define _GET_CPU_USAGE_LINUX_
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
namespace get_system_usage_linux
|
||||
{
|
||||
|
||||
struct CPU_stats
|
||||
{
|
||||
// see http://www.linuxhowtos.org/manpages/5/proc.htm
|
||||
int user;
|
||||
int nice;
|
||||
int system;
|
||||
int idle;
|
||||
int iowait;
|
||||
int irq;
|
||||
int softirq;
|
||||
int steal;
|
||||
int guest;
|
||||
int guest_nice;
|
||||
|
||||
int get_total_idle()
|
||||
const {
|
||||
return idle + iowait;
|
||||
}
|
||||
|
||||
int get_total_active()
|
||||
const {
|
||||
return user + nice + system + irq + softirq + steal + guest + guest_nice;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Memory_stats
|
||||
{
|
||||
int total_memory;
|
||||
int available_memory;
|
||||
int total_swap;
|
||||
int free_swap;
|
||||
|
||||
float get_memory_usage() {
|
||||
const float result = static_cast<float>(total_memory - available_memory) / total_memory;
|
||||
return result;
|
||||
}
|
||||
|
||||
float get_swap_usage() {
|
||||
const float result = static_cast<float>(total_swap - free_swap) / total_swap;
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline CPU_stats read_cpu_data()
|
||||
{
|
||||
CPU_stats result;
|
||||
std::ifstream proc_stat("/proc/stat");
|
||||
|
||||
if (proc_stat.good())
|
||||
{
|
||||
std::string line;
|
||||
getline(proc_stat, line);
|
||||
|
||||
unsigned int *stats_p = (unsigned int *)&result;
|
||||
std::stringstream iss(line);
|
||||
std::string cpu;
|
||||
iss >> cpu;
|
||||
while (iss >> *stats_p)
|
||||
{
|
||||
stats_p++;
|
||||
};
|
||||
}
|
||||
|
||||
proc_stat.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline int get_val(const std::string &target, const std::string &content) {
|
||||
int result = -1;
|
||||
std::size_t start = content.find(target);
|
||||
if (start != std::string::npos) {
|
||||
int begin = start + target.length();
|
||||
std::size_t end = content.find("kB", start);
|
||||
std::string substr = content.substr(begin, end - begin);
|
||||
result = std::stoi(substr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Memory_stats read_memory_data()
|
||||
{
|
||||
Memory_stats result;
|
||||
std::ifstream proc_meminfo("/proc/meminfo");
|
||||
|
||||
if (proc_meminfo.good())
|
||||
{
|
||||
std::string content((std::istreambuf_iterator<char>(proc_meminfo)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
result.total_memory = get_val("MemTotal:", content);
|
||||
result.total_swap = get_val("SwapTotal:", content);
|
||||
result.free_swap = get_val("SwapFree:", content);
|
||||
result.available_memory = get_val("MemAvailable:", content);
|
||||
|
||||
}
|
||||
|
||||
proc_meminfo.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline float get_cpu_usage(const CPU_stats &first, const CPU_stats &second) {
|
||||
const float active_time = static_cast<float>(second.get_total_active() - first.get_total_active());
|
||||
const float idle_time = static_cast<float>(second.get_total_idle() - first.get_total_idle());
|
||||
const float total_time = active_time + idle_time;
|
||||
return active_time / total_time;
|
||||
}
|
||||
|
||||
inline float get_disk_usage(const std::string & disk) {
|
||||
struct statvfs diskData;
|
||||
|
||||
statvfs(disk.c_str(), &diskData);
|
||||
|
||||
auto total = diskData.f_blocks;
|
||||
auto free = diskData.f_bfree;
|
||||
auto diff = total - free;
|
||||
|
||||
float result = static_cast<float>(diff) / total;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//see https://unix.stackexchange.com/questions/304845/discrepancy-between-number-of-cores-and-thermal-zones-in-sys-class-thermal/342023
|
||||
|
||||
inline int find_thermalzone_index() {
|
||||
int result = 0;
|
||||
bool stop = false;
|
||||
// 20 must stop anyway
|
||||
for (int i = 0; !stop && i < 20; ++i) {
|
||||
std::ifstream thermal_file("/sys/class/thermal/thermal_zone" + std::to_string(i) + "/type");
|
||||
|
||||
if (thermal_file.good())
|
||||
{
|
||||
std::string line;
|
||||
getline(thermal_file, line);
|
||||
|
||||
if (line.compare("x86_pkg_temp") == 0) {
|
||||
result = i;
|
||||
stop = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
stop = true;
|
||||
}
|
||||
|
||||
thermal_file.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline int get_thermalzone_temperature(int thermal_index) {
|
||||
int result = -1;
|
||||
std::ifstream thermal_file("/sys/class/thermal/thermal_zone" + std::to_string(thermal_index) + "/temp");
|
||||
|
||||
if (thermal_file.good())
|
||||
{
|
||||
std::string line;
|
||||
getline(thermal_file, line);
|
||||
|
||||
std::stringstream iss(line);
|
||||
iss >> result;
|
||||
} else {
|
||||
throw std::invalid_argument(std::to_string(thermal_index) + " doesn't refer to a valid thermal zone.");
|
||||
}
|
||||
|
||||
thermal_file.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
180
main.cpp
Normal file
180
main.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "include/LCDDisplay.hpp"
|
||||
#include "include/linux-system-usage.hpp"
|
||||
|
||||
#define LCD_PORT "/dev/ttyACM0"
|
||||
#define LCD_INTERVAL_MS 1000
|
||||
#define LCD_CONTRAST 225
|
||||
|
||||
struct gpuHwmon_t {
|
||||
std::string fan_speed;
|
||||
std::string core_clock;
|
||||
std::string mem_clock;
|
||||
std::string core_mv;
|
||||
std::string power_avg;
|
||||
std::string power_cap;
|
||||
std::string power_max;
|
||||
std::string fan_pwm;
|
||||
std::string edge_temp;
|
||||
std::string junction_temp;
|
||||
std::string mem_temp;
|
||||
};
|
||||
|
||||
struct mem_usage_t {
|
||||
std::string free;
|
||||
std::string used;
|
||||
std::string total;
|
||||
};
|
||||
|
||||
std::string pBytes(double i, bool isKbytes = false) {
|
||||
std::stringstream ss;
|
||||
std::array suffix = {'K', 'M', 'G', 'T', 'P', 'E', 'Z'};
|
||||
for (auto &s : suffix) {
|
||||
if (s == 'K' && isKbytes) continue;
|
||||
i /= 1024.0;
|
||||
if (i < 1024) {
|
||||
ss << std::fixed << std::setprecision(i > 100 ? 1 : 2) << i << s;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
return "++++";
|
||||
}
|
||||
|
||||
std::string pad(std::string s, uint8_t w, bool ljust = false) {
|
||||
if (w > s.size()) s.insert(ljust ? s.end() : s.begin(), w - s.size(), ' ');
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string getAvgs() {
|
||||
std::stringstream ss;
|
||||
double avgs[3];
|
||||
getloadavg(avgs, 3);
|
||||
ss << std::fixed << std::setprecision(2);
|
||||
ss << avgs[0] << " " << avgs[1] << " " << avgs[2];
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::array<std::string, 2> getTimeDate() {
|
||||
std::array months = {"sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paz", "lis", "gru"};
|
||||
std::array wdays = {"nie", "pon", "wto", "sro", "czw", "pia", "sob"};
|
||||
auto now = std::time(nullptr);
|
||||
auto tm = *std::localtime(&now);
|
||||
std::stringstream time, date;
|
||||
time << std::setfill('0');
|
||||
time << std::setw(2) << tm.tm_hour << ":";
|
||||
time << std::setw(2) << tm.tm_min << ":";
|
||||
time << std::setw(2) << tm.tm_sec;
|
||||
date << wdays[tm.tm_wday] << ", " << tm.tm_mday << " " << months[tm.tm_mon];
|
||||
return {time.str(), date.str()};
|
||||
}
|
||||
|
||||
mem_usage_t getRam() {
|
||||
mem_usage_t mem;
|
||||
auto memory_data = get_system_usage_linux::read_memory_data();
|
||||
mem.free = pBytes(memory_data.available_memory, true);
|
||||
mem.used = pBytes(memory_data.total_memory - memory_data.available_memory, true);
|
||||
mem.total = pBytes(memory_data.total_memory, true);
|
||||
return mem;
|
||||
}
|
||||
|
||||
mem_usage_t getDisk(std::string mount) {
|
||||
mem_usage_t disk;
|
||||
struct statvfs diskData;
|
||||
statvfs(mount.c_str(), &diskData);
|
||||
disk.free = pBytes(diskData.f_bfree * diskData.f_frsize);
|
||||
disk.used = pBytes((diskData.f_blocks - diskData.f_bfree) * diskData.f_frsize);
|
||||
disk.total = pBytes(diskData.f_blocks * diskData.f_frsize);
|
||||
return disk;
|
||||
}
|
||||
|
||||
std::string readFile(std::string path, uint8_t trim = 0) {
|
||||
std::string ret;
|
||||
std::stringstream ss;
|
||||
std::ifstream fs(path);
|
||||
if (!fs.good()) {
|
||||
std::cerr << "Error reading " << path << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
ss << fs.rdbuf();
|
||||
fs.close();
|
||||
ret = ss.str();
|
||||
return ret.substr(0, ret.size() - trim - 1);
|
||||
}
|
||||
|
||||
gpuHwmon_t getGpu(std::string hw) {
|
||||
gpuHwmon_t gpu;
|
||||
|
||||
gpu.fan_speed = readFile(hw + "/fan1_input");
|
||||
gpu.core_clock = readFile(hw + "/freq1_input", 6);
|
||||
gpu.mem_clock = readFile(hw + "/freq2_input", 6);
|
||||
gpu.core_mv = readFile(hw + "/in0_input");
|
||||
gpu.power_avg = readFile(hw + "/power1_average", 6);
|
||||
gpu.power_cap = readFile(hw + "/power1_cap", 6);
|
||||
gpu.power_max = readFile(hw + "/power1_cap_max", 6);
|
||||
gpu.fan_pwm = readFile(hw + "/pwm1");
|
||||
gpu.edge_temp = readFile(hw + "/temp1_input", 3);
|
||||
gpu.junction_temp = readFile(hw + "/temp2_input", 3);
|
||||
gpu.mem_temp = readFile(hw + "/temp3_input", 3);
|
||||
|
||||
return gpu;
|
||||
}
|
||||
|
||||
std::string getCpuTemp() {
|
||||
return readFile("/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon3/temp1_input");
|
||||
}
|
||||
|
||||
void collectAndDraw(LCDDisplay *lcd) {
|
||||
auto td = getTimeDate();
|
||||
auto ram = getRam();
|
||||
auto anime = getDisk("/mnt/anime");
|
||||
auto home = getDisk("/var/home/drath");
|
||||
auto gpu = getGpu("/sys/devices/pci0000:00/0000:00:03.1/0000:08:00.0/0000:09:00.0/0000:0a:00.0/hwmon/hwmon2");
|
||||
|
||||
std::array<std::string, 4> lines;
|
||||
|
||||
lines[0] = td[1] + " " + td[0] + pad(getAvgs(), 20);
|
||||
|
||||
lines[1] = pad(ram.used + "/" + ram.total, 13, true) + " ";
|
||||
lines[1] += pad(gpu.fan_speed + "R", 5) + " ";
|
||||
lines[1] += pad(gpu.power_avg + "/" + gpu.power_cap + "W", 8) + " ";
|
||||
lines[1] += pad(gpu.edge_temp + "/" + gpu.junction_temp + "C", 8);
|
||||
|
||||
lines[2] = "/home/drath:" + pad(home.free + " free of " + home.total, 28);
|
||||
|
||||
lines[3] = "/mnt/anime: " + pad(anime.free + " free of " + anime.total, 28);
|
||||
|
||||
lcd->writeLines(lines);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
LCDDisplay lcd(LCD_PORT, 0010002);
|
||||
|
||||
if (argc > 1 && std::string(argv[1]) == "-d") {
|
||||
std::cout << "[Chrono] Running in daemon mode, " << LCD_INTERVAL_MS << "ms interval" << std::endl;
|
||||
lcd.setContrast(LCD_CONTRAST);
|
||||
std::chrono::milliseconds interval(LCD_INTERVAL_MS);
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (true) {
|
||||
collectAndDraw(&lcd);
|
||||
std::this_thread::sleep_until(start + interval);
|
||||
start += interval;
|
||||
}
|
||||
} else {
|
||||
collectAndDraw(&lcd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user