Last active
April 2, 2018 16:36
-
-
Save bathtime/0ea6a0f69703b6d888aa02093dabd476 to your computer and use it in GitHub Desktop.
Bar
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compile with: | |
// | |
// g++ -std=c++11 -O2 -Wall bar.cpp -o bar -lasound -lpthread | |
// | |
#include<alsa/asoundlib.h> // install libasound2-dev | |
#include<fstream> | |
#include<iostream> | |
#include<string> | |
#include<chrono> | |
#include<thread> | |
#include"sys/sysinfo.h" | |
#include<future> | |
#include<sstream> | |
using namespace std; | |
static unsigned int mSec = 250; | |
std::string cpuPercent(){ | |
static unsigned long long lastTotalUser, lastTotalUserLow, lastTotalSys, lastTotalIdle; | |
double percent; | |
long int intPercent; | |
std::string s; | |
FILE* file; | |
unsigned long long totalUser, totalUserLow, totalSys, totalIdle, total; | |
file = fopen("/proc/stat", "r"); | |
fscanf(file, "cpu %llu %llu %llu %llu", &totalUser, &totalUserLow, &totalSys, &totalIdle); | |
fclose(file); | |
if ( totalUser < lastTotalUser || totalUserLow < lastTotalUserLow || | |
totalSys < lastTotalSys || totalIdle < lastTotalIdle){ | |
//Overflow detection. Just skip this value. | |
percent = -1.0; | |
}else{ | |
total = (totalUser - lastTotalUser) + (totalUserLow - lastTotalUserLow) + (totalSys - lastTotalSys); | |
percent = total * 100; | |
total += (totalIdle - lastTotalIdle); | |
percent /= total; | |
} | |
lastTotalUser = totalUser; | |
lastTotalUserLow = totalUserLow; | |
lastTotalSys = totalSys; | |
lastTotalIdle = totalIdle; | |
intPercent = percent; | |
s = to_string(intPercent); | |
// Stop overflow by making all numbers '100' if above 2 digits | |
return (s.length() > 2 ? "100" : s); | |
} | |
std::string exec(const char* cmd) { | |
std::array<char, 128> buffer; | |
std::string result; | |
std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose); | |
if (!pipe) throw std::runtime_error("popen() failed!"); | |
while (!feof(pipe.get())) | |
if (fgets(buffer.data(), 128, pipe.get()) != nullptr){ | |
result += buffer.data(); | |
} | |
return result.substr(0, result.length() - 1); | |
} | |
std::string procs(void){ | |
struct sysinfo s; | |
sysinfo(&s); | |
return to_string(s.procs); | |
} | |
std::string date_and_time(void){ | |
char date[48]; | |
time_t now = time(0); | |
strftime(date, 48, "%a %b %d, %H:%M:%S", localtime(&now)); | |
std::string charToStr (date); | |
return charToStr; | |
} | |
std::string get_vol(void) | |
{ | |
int vol; | |
std::string volume; | |
snd_hctl_t *hctl; | |
snd_ctl_elem_id_t *id; | |
snd_ctl_elem_value_t *control; | |
// To find card and subdevice: /proc/asound/, aplay -L, amixer controls | |
snd_hctl_open(&hctl, "hw:0", 0); | |
snd_hctl_load(hctl); | |
snd_ctl_elem_id_alloca(&id); | |
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); | |
// amixer controls | |
snd_ctl_elem_id_set_name(id, "Master Playback Volume"); | |
snd_hctl_elem_t *elem = snd_hctl_find_elem(hctl, id); | |
snd_ctl_elem_value_alloca(&control); | |
snd_ctl_elem_value_set_id(control, id); | |
snd_hctl_elem_read(elem, control); | |
snd_hctl_close(hctl); | |
vol = (int)snd_ctl_elem_value_get_integer(control,0); | |
volume = to_string(vol*100/127); | |
return volume; | |
} | |
std::string get_mem_total() { | |
const std::string info[] = {"MemTotal:", "MemFree:", "Buffers:", "Cached:"}; | |
int intInfo[4]; | |
std::string token; | |
std::ifstream file("/proc/meminfo"); | |
while(file >> token) | |
{ | |
for(int i = 0; i < 4; i++) | |
if(token == info[i]){ | |
file >> intInfo[i]; | |
if(i == 3) | |
return std::to_string((intInfo[0] - intInfo[1] - (intInfo[2] + intInfo[3])) / 1024); | |
} | |
} | |
return "Information unavailable."; | |
} | |
std::string get_net() { | |
std::string netInd; | |
char txChar[16]; // Just grab the first 16 bytes | |
char rxChar[16]; | |
long int trInt = 0; | |
long int rxInt = 0; | |
/* The machine seems to update these files only about every 1 second, | |
so if this program checks within this time frame, there would be no | |
difference in net activity, where perhaps there is net activity. | |
The result is a blinking net indicator even when net activity is | |
constant. To avoid this, a delay is used, which will allow the | |
indicator to remain on until the file updates. */ | |
const unsigned int delay = (1100 / mSec); // delay for 1 cycle per 1100ms (auto-adjust to rest interval) | |
static unsigned int TXdelay = 0; | |
static unsigned int RXdelay = 0; | |
std::ifstream fileTX("/sys/class/net/eth0/statistics/tx_bytes"); | |
fileTX.getline(txChar, 16); | |
fileTX.close(); | |
std::ifstream fileRX("/sys/class/net/eth0/statistics/rx_bytes"); | |
fileRX.getline(rxChar, 16); | |
fileRX.close(); | |
// Calculate current reading by comparing past to present usage | |
trInt = std::stoi(txChar); | |
rxInt = std::stoi(txChar); | |
// Avoid net indicators flashing at program startup | |
static long int lastNetTX = trInt; | |
static long int lastNetRX = rxInt; | |
/* Net activity is in bytes, so '1000 > 0' is 1kb of net usage. | |
Although the might be temptation to set this lower, keep in | |
mind that the networking system sends out data every now | |
then. Too low a setting will mean that indicators keep flashing | |
regardless. */ | |
if ((trInt - lastNetTX) / 1000 > 0) TXdelay = delay; | |
if ((rxInt - lastNetRX) / 1000 > 0) RXdelay = delay; | |
if (TXdelay--) | |
netInd += "."; | |
else{ | |
netInd += " "; | |
TXdelay = 0; } | |
if (RXdelay--) | |
netInd += "."; | |
else{ | |
netInd += " "; | |
RXdelay = 0; } | |
lastNetTX = trInt; | |
lastNetRX = rxInt; | |
return netInd; | |
} | |
void execFunc(const char * e, std::string &s, bool &done) | |
{ | |
s = exec(e); | |
done = true; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
if (argc > 1) mSec = atoi(argv[1]); // Check if delay was entered as parameter | |
unsigned int threadTicksGoal = (1000 / mSec) * 300; // Seconds until threads update | |
unsigned int refreshTicksGoal = (1000 / mSec) / 2; // 1x per 1000ms (adjusted to mSec cycles) | |
unsigned int threadTicks = 0; | |
unsigned int refreshTicks = 0; | |
// Variables to draw from until update | |
std::string cpu; | |
std::string vol; | |
std::string datetime; | |
std::string txrx; | |
// Setup commands which you would like to run as threads | |
const char* const command[] = { "Bennetto", "mailnum", "Canada.sh" }; | |
size_t nThreads = (sizeof command / sizeof command[0]); | |
// Get thread stuff ready | |
std::thread myThreads[nThreads]; | |
std::string funcStr[nThreads]; // The original string from the thread | |
std::string readyStr[nThreads]; // The string which will take a copy of funcStr which it completes | |
bool tReady[nThreads]; // A means of indicating the thread has ran and is OK to copy strings | |
// Timer function to sleep between checks | |
std::chrono::milliseconds timespan(mSec); | |
// const char * sysCharCmd; | |
while(1) | |
{ | |
if (!threadTicks--) // Ticktimer reached 0, so refresh threads | |
{ | |
for (unsigned int i = 0; i < nThreads; i++) | |
{ | |
myThreads[i] = std::thread(&execFunc, ref(command[i]), std::ref(funcStr[i]), ref(tReady[i])); | |
myThreads[i].detach(); | |
} | |
threadTicks = threadTicksGoal; | |
} | |
// Update every one second; cpu cannot be updated sooner; volume need not be | |
if (!refreshTicks--) | |
{ | |
cpu = cpuPercent(); | |
vol = get_vol(); | |
datetime = date_and_time(); | |
refreshTicks = refreshTicksGoal; | |
// Keep checking to see if the threads are finished and update strings immediately | |
for (unsigned int i = 0; i < nThreads; i++) | |
if (tReady[i]) | |
{ // Is the thread is done? | |
tReady[i] = 0; // Reset for now | |
readyStr[i] = funcStr[i]; // Finally, the string is copied | |
} | |
} | |
std::string sysStrCmd = | |
"C:" + | |
cpu + "% " + | |
get_mem_total() + "m " + | |
"P:" + procs() + " " + | |
"V:" + vol + "% " + | |
readyStr[0] + (readyStr[0] == "" ? "": " ") + | |
readyStr[1] + (readyStr[1] == "" ? "": " ") + | |
readyStr[2] + (readyStr[2] == "" ? "": " ") + | |
datetime + | |
get_net(); | |
// sysCharCmd = sysStrCmd.c_str(); | |
// system(sysCharCmd); | |
std::cout << "\r" << sysStrCmd << std::flush; | |
std::this_thread::sleep_for(timespan); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment