This patch file contains code from @avafinger's htop_2.2.2 repository. It is the result of diff between: https://github.com/avafinger/htop_2.2.2/commit/dc21e5f6 and: https://github.com/hishamhm/htop/tree/2.2.0 --- diff --git a/Armbian_Meter.c b/Armbian_Meter.c new file mode 100644 index 0000000..183032b --- /dev/null +++ b/Armbian_Meter.c @@ -0,0 +1,55 @@ +/* +htop - Armbianversion_Meter.c +(C) 2018 @lex +*/ + +#include "Armbian_Meter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int Armbianversion_Meter_attributes[] = { + ARMBIAN_VERSION +}; + +static void Armbianversion_Meter_setValues(Meter* this, char* buffer, int len) { + int ret; + static char version[256]; + static unsigned int use_cached = 0; + + if ((use_cached++ % 10)) { + xSnprintf(buffer, len, "%s", version); + return; + } + + ret = ReadKeyValue( "/etc/armbian-release", "VERSION=", version); + + if (ret) { + xSnprintf(buffer, len, "%s", version); + } else { + xSnprintf(buffer, len, "%s", "unknown"); + } +} + +MeterClass Armbianversion_Meter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = Armbianversion_Meter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = Armbianversion_Meter_attributes, + .name = "Armbianversion", + .uiName = "Armbian version", + .caption = "Armbian : ", +}; + + diff --git a/Armbian_Meter.h b/Armbian_Meter.h new file mode 100644 index 0000000..146a1ee --- /dev/null +++ b/Armbian_Meter.h @@ -0,0 +1,17 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Armbian_Meter +#define HEADER_Armbian_Meter +/* +htop - Armbianversion_Meter.h +(C) 2018 @lex +*/ + +#include "Meter.h" + +extern int Armbianversion_Meter_attributes[]; + +extern MeterClass Armbianversion_Meter_class; + + +#endif diff --git a/AvailableMetersPanel.c b/AvailableMetersPanel.c index ddb5536..01ee3cd 100644 --- a/AvailableMetersPanel.c +++ b/AvailableMetersPanel.c @@ -9,6 +9,8 @@ in the source distribution for its full text. #include "MetersPanel.h" #include "CPUMeter.h" +#include "CpuFreqMeter.h" +#include "CpuTempMeter.h" #include "Header.h" #include "ListItem.h" #include "Platform.h" @@ -100,6 +102,8 @@ PanelClass AvailableMetersPanel_class = { }; AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* header, Panel* leftMeters, Panel* rightMeters, ScreenManager* scr, ProcessList* pl) { + int i; + AvailableMetersPanel* this = AllocThis(AvailableMetersPanel); Panel* super = (Panel*) this; FunctionBar* fuBar = FunctionBar_newEnterEsc("Add ", "Done "); @@ -114,7 +118,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade Panel_setHeader(super, "Available meters"); // Platform_meterTypes[0] should be always (&CPUMeter_class), which we will // handle separately in the code below. - for (int i = 1; Platform_meterTypes[i]; i++) { + for (i = 1; Platform_meterTypes[i]; i++) { MeterClass* type = Platform_meterTypes[i]; assert(type != &CPUMeter_class); const char* label = type->description ? type->description : type->uiName; @@ -125,7 +129,7 @@ AvailableMetersPanel* AvailableMetersPanel_new(Settings* settings, Header* heade int cpus = pl->cpuCount; if (cpus > 1) { Panel_add(super, (Object*) ListItem_new("CPU average", 0)); - for (int i = 1; i <= cpus; i++) { + for (i = 1; i <= cpus; i++) { char buffer[50]; xSnprintf(buffer, 50, "%s %d", type->uiName, i); Panel_add(super, (Object*) ListItem_new(buffer, i)); diff --git a/BlockDevice_ioStatsMeter.c b/BlockDevice_ioStatsMeter.c new file mode 100644 index 0000000..9dccbde --- /dev/null +++ b/BlockDevice_ioStatsMeter.c @@ -0,0 +1,711 @@ +/* +htop - BlockDevice_ioStatsMeter.c +(C) 2020 @lex +*/ + +#include "BlockDevice_ioStatsMeter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int BlockDevice_ioStatsMeter_attributes[] = { + ETH1_INTERFACE +}; + +static void BlockDevice_sda_ioStatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float readspeed; + float writespeed; + double refreshdelay; + char block_device[80]; + static double old = 0.; + static double now = 0.; + static int flash = 0; + static unsigned long sec_size = 0; + FILE *fp; + + if (sec_size == 0) { + xSnprintf(block_device, sizeof(block_device), "/sys/block/%s/queue/hw_sector_size", "sda"); + if ((fp = fopen(block_device, "r")) == NULL) { + xSnprintf(buffer, len, "%s", "unavailable"); + return; + } + if (fgets(block_device, 79, fp) != NULL) { + sscanf(block_device, "%lu", &sec_size); + } + fclose(fp); + if (sec_size == 0) + sec_size = 1; + } + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + ret = Platform_getIO_stats("sda", 0, 0); + if (ret) { + if (Platform_BlockDevice_sda_stats.read_sectors_comp > Platform_BlockDevice_sda_stats.read_sectors) + Platform_BlockDevice_sda_stats.read_sectors_comp = 0; + if (Platform_BlockDevice_sda_stats.write_sectors_comp > Platform_BlockDevice_sda_stats.write_sectors) + Platform_BlockDevice_sda_stats.write_sectors_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + readspeed = (Platform_BlockDevice_sda_stats.read_sectors - Platform_BlockDevice_sda_stats.read_sectors_comp) / refreshdelay; + writespeed = (Platform_BlockDevice_sda_stats.write_sectors - Platform_BlockDevice_sda_stats.write_sectors_comp) / refreshdelay; + + writespeed = writespeed * sec_size / 1000; + readspeed = readspeed * sec_size / 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + xSnprintf(buffer, len, "%.2f GB/s - %.2f GB/s (R/W)", (float) readspeed, (float) writespeed); + } else { + xSnprintf(buffer, len, "%.2f MB/s - %.2f MB/s (R/W)", (float) readspeed, (float) writespeed); + } + } else { + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (R/W)", (float) readspeed, (float) writespeed); + } + + Platform_BlockDevice_sda_stats.read_sectors_comp = Platform_BlockDevice_sda_stats.read_sectors; + Platform_BlockDevice_sda_stats.write_sectors_comp = Platform_BlockDevice_sda_stats.write_sectors; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavailable"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass BlockDevice_sda_ioStatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = BlockDevice_sda_ioStatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = BlockDevice_ioStatsMeter_attributes, + .name = "sdastat", + .uiName = "sda speed stat", + .caption = "sda stat: ", +}; + +static void BlockDevice_sdb_ioStatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float readspeed; + float writespeed; + double refreshdelay; + char block_device[80]; + static double old = 0.; + static double now = 0.; + static int flash = 0; + static unsigned long sec_size = 0; + FILE *fp; + + if (sec_size == 0) { + xSnprintf(block_device, sizeof(block_device), "/sys/block/%s/queue/hw_sector_size", "sdb"); + if ((fp = fopen(block_device, "r")) == NULL) { + xSnprintf(buffer, len, "%s", "unavailable"); + return; + } + if (fgets(block_device, 79, fp) != NULL) { + sscanf(block_device, "%lu", &sec_size); + } + fclose(fp); + if (sec_size == 0) + sec_size = 1; + } + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + ret = Platform_getIO_stats("sdb", 1, 0); + if (ret) { + if (Platform_BlockDevice_sdb_stats.read_sectors_comp > Platform_BlockDevice_sdb_stats.read_sectors) + Platform_BlockDevice_sdb_stats.read_sectors_comp = 0; + if (Platform_BlockDevice_sdb_stats.write_sectors_comp > Platform_BlockDevice_sdb_stats.write_sectors) + Platform_BlockDevice_sdb_stats.write_sectors_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + readspeed = (Platform_BlockDevice_sdb_stats.read_sectors - Platform_BlockDevice_sdb_stats.read_sectors_comp) / refreshdelay; + writespeed = (Platform_BlockDevice_sdb_stats.write_sectors - Platform_BlockDevice_sdb_stats.write_sectors_comp) / refreshdelay; + + writespeed = writespeed * sec_size / 1000; + readspeed = readspeed * sec_size / 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + xSnprintf(buffer, len, "%.2f GB/s - %.2f GB/s (R/W)", (float) readspeed, (float) writespeed); + } else { + xSnprintf(buffer, len, "%.2f MB/s - %.2f MB/s (R/W)", (float) readspeed, (float) writespeed); + } + } else { + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (R/W)", (float) readspeed, (float) writespeed); + } + + Platform_BlockDevice_sdb_stats.read_sectors_comp = Platform_BlockDevice_sdb_stats.read_sectors; + Platform_BlockDevice_sdb_stats.write_sectors_comp = Platform_BlockDevice_sdb_stats.write_sectors; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavailable"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass BlockDevice_sdb_ioStatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = BlockDevice_sdb_ioStatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = BlockDevice_ioStatsMeter_attributes, + .name = "sdbstat", + .uiName = "sdb speed stat", + .caption = "sdb stat: ", +}; + +static void BlockDevice_sdc_ioStatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float readspeed; + float writespeed; + double refreshdelay; + char block_device[80]; + static double old = 0.; + static double now = 0.; + static int flash = 0; + static unsigned long sec_size = 0; + FILE *fp; + + if (sec_size == 0) { + xSnprintf(block_device, sizeof(block_device), "/sys/block/%s/queue/hw_sector_size", "sdc"); + if ((fp = fopen(block_device, "r")) == NULL) { + xSnprintf(buffer, len, "%s", "unavailable"); + return; + } + if (fgets(block_device, 79, fp) != NULL) { + sscanf(block_device, "%lu", &sec_size); + } + fclose(fp); + if (sec_size == 0) + sec_size = 1; + } + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + ret = Platform_getIO_stats("sdc", 2, 0); + if (ret) { + if (Platform_BlockDevice_sdc_stats.read_sectors_comp > Platform_BlockDevice_sdc_stats.read_sectors) + Platform_BlockDevice_sdc_stats.read_sectors_comp = 0; + if (Platform_BlockDevice_sdc_stats.write_sectors_comp > Platform_BlockDevice_sdc_stats.write_sectors) + Platform_BlockDevice_sdc_stats.write_sectors_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + readspeed = (Platform_BlockDevice_sdc_stats.read_sectors - Platform_BlockDevice_sdc_stats.read_sectors_comp) / refreshdelay; + writespeed = (Platform_BlockDevice_sdc_stats.write_sectors - Platform_BlockDevice_sdc_stats.write_sectors_comp) / refreshdelay; + + writespeed = writespeed * sec_size / 1000; + readspeed = readspeed * sec_size / 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + xSnprintf(buffer, len, "%.2f GB/s - %.2f GB/s (R/W)", (float) readspeed, (float) writespeed); + } else { + xSnprintf(buffer, len, "%.2f MB/s - %.2f MB/s (R/W)", (float) readspeed, (float) writespeed); + } + } else { + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (R/W)", (float) readspeed, (float) writespeed); + } + + Platform_BlockDevice_sdc_stats.read_sectors_comp = Platform_BlockDevice_sdc_stats.read_sectors; + Platform_BlockDevice_sdc_stats.write_sectors_comp = Platform_BlockDevice_sdc_stats.write_sectors; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavailable"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass BlockDevice_sdc_ioStatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = BlockDevice_sdc_ioStatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = BlockDevice_ioStatsMeter_attributes, + .name = "sdcstat", + .uiName = "sdc speed stat", + .caption = "sdc stat: ", +}; + +static void BlockDevice_sdd_ioStatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float readspeed; + float writespeed; + double refreshdelay; + char block_device[80]; + static double old = 0.; + static double now = 0.; + static int flash = 0; + static unsigned long sec_size = 0; + FILE *fp; + + if (sec_size == 0) { + xSnprintf(block_device, sizeof(block_device), "/sys/block/%s/queue/hw_sector_size", "sdd"); + if ((fp = fopen(block_device, "r")) == NULL) { + xSnprintf(buffer, len, "%s", "unavailable"); + return; + } + if (fgets(block_device, 79, fp) != NULL) { + sscanf(block_device, "%lu", &sec_size); + } + fclose(fp); + if (sec_size == 0) + sec_size = 1; + } + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + ret = Platform_getIO_stats("sdd", 3, 0); + if (ret) { + if (Platform_BlockDevice_sdd_stats.read_sectors_comp > Platform_BlockDevice_sdd_stats.read_sectors) + Platform_BlockDevice_sdd_stats.read_sectors_comp = 0; + if (Platform_BlockDevice_sdd_stats.write_sectors_comp > Platform_BlockDevice_sdd_stats.write_sectors) + Platform_BlockDevice_sdd_stats.write_sectors_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + readspeed = (Platform_BlockDevice_sdd_stats.read_sectors - Platform_BlockDevice_sdd_stats.read_sectors_comp) / refreshdelay; + writespeed = (Platform_BlockDevice_sdd_stats.write_sectors - Platform_BlockDevice_sdd_stats.write_sectors_comp) / refreshdelay; + + writespeed = writespeed * sec_size / 1000; + readspeed = readspeed * sec_size / 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + xSnprintf(buffer, len, "%.2f GB/s - %.2f GB/s (R/W)", (float) readspeed, (float) writespeed); + } else { + xSnprintf(buffer, len, "%.2f MB/s - %.2f MB/s (R/W)", (float) readspeed, (float) writespeed); + } + } else { + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (R/W)", (float) readspeed, (float) writespeed); + } + + Platform_BlockDevice_sdd_stats.read_sectors_comp = Platform_BlockDevice_sdd_stats.read_sectors; + Platform_BlockDevice_sdd_stats.write_sectors_comp = Platform_BlockDevice_sdd_stats.write_sectors; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavailable"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass BlockDevice_sdd_ioStatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = BlockDevice_sdd_ioStatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = BlockDevice_ioStatsMeter_attributes, + .name = "sddstat", + .uiName = "sdd speed stat", + .caption = "sdd stat: ", +}; + +static void BlockDevice_mmcblk0_ioStatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float readspeed; + float writespeed; + double refreshdelay; + char block_device[80]; + static double old = 0.; + static double now = 0.; + static int flash = 0; + static unsigned long sec_size = 0; + FILE *fp; + + if (sec_size == 0) { + xSnprintf(block_device, sizeof(block_device), "/sys/block/%s/queue/hw_sector_size", "mmcblk0"); + if ((fp = fopen(block_device, "r")) == NULL) { + xSnprintf(buffer, len, "%s", "unavailable"); + return; + } + if (fgets(block_device, 79, fp) != NULL) { + sscanf(block_device, "%lu", &sec_size); + } + fclose(fp); + if (sec_size == 0) + sec_size = 1; + } + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + ret = Platform_getIO_stats("mmcblk0", 4, 0); + if (ret) { + if (Platform_BlockDevice_mmcblk0_stats.read_sectors_comp > Platform_BlockDevice_mmcblk0_stats.read_sectors) + Platform_BlockDevice_mmcblk0_stats.read_sectors_comp = 0; + if (Platform_BlockDevice_mmcblk0_stats.write_sectors_comp > Platform_BlockDevice_mmcblk0_stats.write_sectors) + Platform_BlockDevice_mmcblk0_stats.write_sectors_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + readspeed = (Platform_BlockDevice_mmcblk0_stats.read_sectors - Platform_BlockDevice_mmcblk0_stats.read_sectors_comp) / refreshdelay; + writespeed = (Platform_BlockDevice_mmcblk0_stats.write_sectors - Platform_BlockDevice_mmcblk0_stats.write_sectors_comp) / refreshdelay; + + writespeed = writespeed * sec_size / 1000; + readspeed = readspeed * sec_size / 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + xSnprintf(buffer, len, "%.2f GB/s - %.2f GB/s (R/W)", (float) readspeed, (float) writespeed); + } else { + xSnprintf(buffer, len, "%.2f MB/s - %.2f MB/s (R/W)", (float) readspeed, (float) writespeed); + } + } else { + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (R/W)", (float) readspeed, (float) writespeed); + } + + Platform_BlockDevice_mmcblk0_stats.read_sectors_comp = Platform_BlockDevice_mmcblk0_stats.read_sectors; + Platform_BlockDevice_mmcblk0_stats.write_sectors_comp = Platform_BlockDevice_mmcblk0_stats.write_sectors; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavailable"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass BlockDevice_mmcblk0_ioStatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = BlockDevice_mmcblk0_ioStatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = BlockDevice_ioStatsMeter_attributes, + .name = "mmcblk0stat", + .uiName = "mmcblk0 speed stat", + .caption = "mmcblk0 stat: ", +}; + +static void BlockDevice_mmcblk1_ioStatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float readspeed; + float writespeed; + double refreshdelay; + char block_device[80]; + static double old = 0.; + static double now = 0.; + static int flash = 0; + static unsigned long sec_size = 0; + FILE *fp; + + if (sec_size == 0) { + xSnprintf(block_device, sizeof(block_device), "/sys/block/%s/queue/hw_sector_size", "mmcblk1"); + if ((fp = fopen(block_device, "r")) == NULL) { + xSnprintf(buffer, len, "%s", "unavailable"); + return; + } + if (fgets(block_device, 79, fp) != NULL) { + sscanf(block_device, "%lu", &sec_size); + } + fclose(fp); + if (sec_size == 0) + sec_size = 1; + } + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + ret = Platform_getIO_stats("mmcblk1", 5, 0); + if (ret) { + if (Platform_BlockDevice_mmcblk1_stats.read_sectors_comp > Platform_BlockDevice_mmcblk1_stats.read_sectors) + Platform_BlockDevice_mmcblk1_stats.read_sectors_comp = 0; + if (Platform_BlockDevice_mmcblk1_stats.write_sectors_comp > Platform_BlockDevice_mmcblk1_stats.write_sectors) + Platform_BlockDevice_mmcblk1_stats.write_sectors_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + readspeed = (Platform_BlockDevice_mmcblk1_stats.read_sectors - Platform_BlockDevice_mmcblk1_stats.read_sectors_comp) / refreshdelay; + writespeed = (Platform_BlockDevice_mmcblk1_stats.write_sectors - Platform_BlockDevice_mmcblk1_stats.write_sectors_comp) / refreshdelay; + + writespeed = writespeed * sec_size / 1000; + readspeed = readspeed * sec_size / 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + xSnprintf(buffer, len, "%.2f GB/s - %.2f GB/s (R/W)", (float) readspeed, (float) writespeed); + } else { + xSnprintf(buffer, len, "%.2f MB/s - %.2f MB/s (R/W)", (float) readspeed, (float) writespeed); + } + } else { + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (R/W)", (float) readspeed, (float) writespeed); + } + + Platform_BlockDevice_mmcblk1_stats.read_sectors_comp = Platform_BlockDevice_mmcblk1_stats.read_sectors; + Platform_BlockDevice_mmcblk1_stats.write_sectors_comp = Platform_BlockDevice_mmcblk1_stats.write_sectors; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavailable"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass BlockDevice_mmcblk1_ioStatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = BlockDevice_mmcblk1_ioStatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = BlockDevice_ioStatsMeter_attributes, + .name = "mmcblk1stat", + .uiName = "mmcblk1 speed stat", + .caption = "mmcblk1 stat: ", +}; + +static void BlockDevice_mmcblk2_ioStatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float readspeed; + float writespeed; + double refreshdelay; + char block_device[80]; + static double old = 0.; + static double now = 0.; + static int flash = 0; + static unsigned long sec_size = 0; + FILE *fp; + + if (sec_size == 0) { + xSnprintf(block_device, sizeof(block_device), "/sys/block/%s/queue/hw_sector_size", "mmcblk2"); + if ((fp = fopen(block_device, "r")) == NULL) { + xSnprintf(buffer, len, "%s", "unavailable"); + return; + } + if (fgets(block_device, 79, fp) != NULL) { + sscanf(block_device, "%lu", &sec_size); + } + fclose(fp); + if (sec_size == 0) + sec_size = 1; + } + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + ret = Platform_getIO_stats("mmcblk2", 6, 0); + if (ret) { + if (Platform_BlockDevice_mmcblk2_stats.read_sectors_comp > Platform_BlockDevice_mmcblk2_stats.read_sectors) + Platform_BlockDevice_mmcblk2_stats.read_sectors_comp = 0; + if (Platform_BlockDevice_mmcblk2_stats.write_sectors_comp > Platform_BlockDevice_mmcblk2_stats.write_sectors) + Platform_BlockDevice_mmcblk2_stats.write_sectors_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + readspeed = (Platform_BlockDevice_mmcblk2_stats.read_sectors - Platform_BlockDevice_mmcblk2_stats.read_sectors_comp) / refreshdelay; + writespeed = (Platform_BlockDevice_mmcblk2_stats.write_sectors - Platform_BlockDevice_mmcblk2_stats.write_sectors_comp) / refreshdelay; + + writespeed = writespeed * sec_size / 1000; + readspeed = readspeed * sec_size / 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + xSnprintf(buffer, len, "%.2f GB/s - %.2f GB/s (R/W)", (float) readspeed, (float) writespeed); + } else { + xSnprintf(buffer, len, "%.2f MB/s - %.2f MB/s (R/W)", (float) readspeed, (float) writespeed); + } + } else { + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (R/W)", (float) readspeed, (float) writespeed); + } + + Platform_BlockDevice_mmcblk2_stats.read_sectors_comp = Platform_BlockDevice_mmcblk2_stats.read_sectors; + Platform_BlockDevice_mmcblk2_stats.write_sectors_comp = Platform_BlockDevice_mmcblk2_stats.write_sectors; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavailable"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass BlockDevice_mmcblk2_ioStatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = BlockDevice_mmcblk2_ioStatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = BlockDevice_ioStatsMeter_attributes, + .name = "mmcblk2stat", + .uiName = "mmcblk2 speed stat", + .caption = "mmcblk2 stat: ", +}; + +static void BlockDevice_mmcblk3_ioStatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float readspeed; + float writespeed; + double refreshdelay; + char block_device[80]; + static double old = 0.; + static double now = 0.; + static int flash = 0; + static unsigned long sec_size = 0; + FILE *fp; + + if (sec_size == 0) { + xSnprintf(block_device, sizeof(block_device), "/sys/block/%s/queue/hw_sector_size", "mmcblk3"); + if ((fp = fopen(block_device, "r")) == NULL) { + xSnprintf(buffer, len, "%s", "unavailable"); + return; + } + if (fgets(block_device, 79, fp) != NULL) { + sscanf(block_device, "%lu", &sec_size); + } + fclose(fp); + if (sec_size == 0) + sec_size = 1; + } + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + ret = Platform_getIO_stats("mmcblk3", 7, 0); + if (ret) { + if (Platform_BlockDevice_mmcblk3_stats.read_sectors_comp > Platform_BlockDevice_mmcblk3_stats.read_sectors) + Platform_BlockDevice_mmcblk3_stats.read_sectors_comp = 0; + if (Platform_BlockDevice_mmcblk3_stats.write_sectors_comp > Platform_BlockDevice_mmcblk3_stats.write_sectors) + Platform_BlockDevice_mmcblk3_stats.write_sectors_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + readspeed = (Platform_BlockDevice_mmcblk3_stats.read_sectors - Platform_BlockDevice_mmcblk3_stats.read_sectors_comp) / refreshdelay; + writespeed = (Platform_BlockDevice_mmcblk3_stats.write_sectors - Platform_BlockDevice_mmcblk3_stats.write_sectors_comp) / refreshdelay; + + writespeed = writespeed * sec_size / 1000; + readspeed = readspeed * sec_size / 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + if (writespeed >= 1000 || readspeed >= 1000) { + writespeed /= 1000; + readspeed /= 1000; + xSnprintf(buffer, len, "%.2f GB/s - %.2f GB/s (R/W)", (float) readspeed, (float) writespeed); + } else { + xSnprintf(buffer, len, "%.2f MB/s - %.2f MB/s (R/W)", (float) readspeed, (float) writespeed); + } + } else { + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (R/W)", (float) readspeed, (float) writespeed); + } + + Platform_BlockDevice_mmcblk3_stats.read_sectors_comp = Platform_BlockDevice_mmcblk3_stats.read_sectors; + Platform_BlockDevice_mmcblk3_stats.write_sectors_comp = Platform_BlockDevice_mmcblk3_stats.write_sectors; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavailable"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass BlockDevice_mmcblk3_ioStatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = BlockDevice_mmcblk3_ioStatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = BlockDevice_ioStatsMeter_attributes, + .name = "mmcblk3stat", + .uiName = "mmcblk3 speed stat", + .caption = "mmcblk3 stat: ", +}; + + + + diff --git a/BlockDevice_ioStatsMeter.h b/BlockDevice_ioStatsMeter.h new file mode 100644 index 0000000..ce707c8 --- /dev/null +++ b/BlockDevice_ioStatsMeter.h @@ -0,0 +1,31 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_BlockDevice_ioStatsMeter +#define HEADER_BlockDevice_ioStatsMeter +/* +htop - BlockDevice_ioStatsMeter.h +(C) 2020 @lex +*/ + +#include "Meter.h" + +extern int BlockDevice_ioStatsMeter_attributes[]; + +extern MeterClass BlockDevice_sda_ioStatsMeter_class; + +extern MeterClass BlockDevice_sdb_ioStatsMeter_class; + +extern MeterClass BlockDevice_sdc_ioStatsMeter_class; + +extern MeterClass BlockDevice_sdd_ioStatsMeter_class; + +extern MeterClass BlockDevice_mmcblk0_ioStatsMeter_class; + +extern MeterClass BlockDevice_mmcblk1_ioStatsMeter_class; + +extern MeterClass BlockDevice_mmcblk2_ioStatsMeter_class; + +extern MeterClass BlockDevice_mmcblk3_ioStatsMeter_class; + + +#endif diff --git a/CPUMeter.c b/CPUMeter.c index de5490d..0825dba 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -6,6 +6,7 @@ in the source distribution for its full text. */ #include "CPUMeter.h" +#include "CpuFreqMeter.h" #include "CRT.h" #include "Settings.h" diff --git a/CRT.c b/CRT.c index ca9a10d..1fefaff 100644 --- a/CRT.c +++ b/CRT.c @@ -128,6 +128,20 @@ typedef enum ColorElements_ { CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, + CPU_TEMP, + CPU_FREQ, + CPU_VCORE, + GPU_TEMP, + ETH0_INTERFACE, + ETH1_INTERFACE, + WLAN0_INTERFACE, + WLAN1_INTERFACE, + KERNEL_VERSION, + DISTRO_VERSION, + OS_VERSION, + ARMBIAN_VERSION, + ETH0_STATS, + ETH1_STATS, LAST_COLORELEMENT } ColorElements; @@ -232,6 +246,18 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Magenta,Black), [CPU_STEAL] = ColorPair(Cyan,Black), [CPU_GUEST] = ColorPair(Cyan,Black), + [CPU_FREQ] = A_BOLD | ColorPair(Yellow,Black), + [CPU_TEMP] = A_BOLD | ColorPair(Red,Black), + [CPU_VCORE] = A_BOLD | ColorPair(Yellow,Black), + [GPU_TEMP] = ColorPair(Cyan,Black), + [ETH0_INTERFACE] = A_BOLD | ColorPair(Cyan,Black), + [ETH1_INTERFACE] = A_BOLD | ColorPair(Cyan,Black), + [WLAN0_INTERFACE] = A_BOLD | ColorPair(Cyan,Black), + [WLAN1_INTERFACE] = A_BOLD | ColorPair(Cyan,Black), + [KERNEL_VERSION] = A_BOLD | ColorPair(Cyan,Black), + [DISTRO_VERSION] = A_BOLD | ColorPair(Cyan,Black), + [OS_VERSION] = A_BOLD | ColorPair(Cyan,Black), + [ARMBIAN_VERSION] = A_BOLD | ColorPair(Cyan,Black), }, [COLORSCHEME_MONOCHROME] = { [RESET_COLOR] = A_NORMAL, @@ -291,6 +317,18 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = A_BOLD, [CPU_STEAL] = A_REVERSE, [CPU_GUEST] = A_REVERSE, + [CPU_FREQ] = A_BOLD, + [CPU_TEMP] = A_BOLD, + [CPU_VCORE] = A_BOLD, + [GPU_TEMP] = A_BOLD, + [ETH0_INTERFACE] = A_BOLD, + [ETH1_INTERFACE] = A_BOLD, + [WLAN0_INTERFACE] = A_BOLD, + [WLAN1_INTERFACE] = A_BOLD, + [KERNEL_VERSION] = A_BOLD, + [DISTRO_VERSION] = A_BOLD, + [OS_VERSION] = A_BOLD, + [ARMBIAN_VERSION] = A_BOLD, }, [COLORSCHEME_BLACKONWHITE] = { [RESET_COLOR] = ColorPair(Black,White), @@ -350,6 +388,18 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Blue,White), [CPU_STEAL] = ColorPair(Cyan,White), [CPU_GUEST] = ColorPair(Cyan,White), + [CPU_FREQ] = A_BOLD | ColorPair(Yellow,White), + [CPU_TEMP] = A_BOLD | ColorPair(Yellow,White), + [CPU_VCORE] = A_BOLD | ColorPair(Yellow,White), + [GPU_TEMP] = A_BOLD | ColorPair(Yellow,White), + [ETH0_INTERFACE] = A_BOLD | ColorPair(Yellow,White), + [ETH1_INTERFACE] = A_BOLD | ColorPair(Yellow,White), + [WLAN0_INTERFACE] = A_BOLD | ColorPair(Yellow,White), + [WLAN1_INTERFACE] = A_BOLD | ColorPair(Yellow,White), + [KERNEL_VERSION] = A_BOLD | ColorPair(Yellow,White), + [DISTRO_VERSION] = A_BOLD | ColorPair(Yellow,White), + [OS_VERSION] = A_BOLD | ColorPair(Yellow,White), + [ARMBIAN_VERSION] = A_BOLD | ColorPair(Yellow,White), }, [COLORSCHEME_LIGHTTERMINAL] = { [RESET_COLOR] = ColorPair(Black,Black), @@ -409,6 +459,18 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Blue,Black), [CPU_STEAL] = ColorPair(Black,Black), [CPU_GUEST] = ColorPair(Black,Black), + [CPU_FREQ] = A_BOLD | ColorPair(Yellow,Black), + [CPU_TEMP] = A_BOLD | ColorPair(Yellow,Black), + [CPU_VCORE] = A_BOLD | ColorPair(Yellow,Black), + [GPU_TEMP] = A_BOLD | ColorPair(Yellow,Black), + [ETH0_INTERFACE] = A_BOLD | ColorPair(Yellow,Black), + [ETH1_INTERFACE] = A_BOLD | ColorPair(Yellow,Black), + [WLAN0_INTERFACE] = A_BOLD | ColorPair(Yellow,Black), + [WLAN1_INTERFACE] = A_BOLD | ColorPair(Yellow,Black), + [KERNEL_VERSION] = A_BOLD | ColorPair(Yellow,Black), + [DISTRO_VERSION] = A_BOLD | ColorPair(Yellow,Black), + [OS_VERSION] = A_BOLD | ColorPair(Yellow,Black), + [ARMBIAN_VERSION] = A_BOLD | ColorPair(Yellow,Black), }, [COLORSCHEME_MIDNIGHT] = { [RESET_COLOR] = ColorPair(White,Blue), @@ -468,6 +530,18 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Black,Blue), [CPU_STEAL] = ColorPair(White,Blue), [CPU_GUEST] = ColorPair(White,Blue), + [CPU_FREQ] = A_BOLD | ColorPair(Red,Black), + [CPU_TEMP] = A_BOLD | ColorPair(Red,Black), + [CPU_VCORE] = A_BOLD | ColorPair(Yellow,Black), + [GPU_TEMP] = A_BOLD | ColorPair(Yellow,Black), + [ETH0_INTERFACE] = A_BOLD | ColorPair(Cyan,Blue), + [ETH1_INTERFACE] = A_BOLD | ColorPair(Cyan,Blue), + [WLAN0_INTERFACE] = A_BOLD | ColorPair(Cyan,Blue), + [WLAN1_INTERFACE] = A_BOLD | ColorPair(Cyan,Blue), + [KERNEL_VERSION] = A_BOLD | ColorPair(Cyan,Black), + [DISTRO_VERSION] = A_BOLD | ColorPair(Cyan,Black), + [OS_VERSION] = A_BOLD | ColorPair(Cyan,Black), + [ARMBIAN_VERSION] = A_BOLD | ColorPair(Cyan,Black), }, [COLORSCHEME_BLACKNIGHT] = { [RESET_COLOR] = ColorPair(Cyan,Black), @@ -527,6 +601,18 @@ int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = { [CPU_SOFTIRQ] = ColorPair(Blue,Black), [CPU_STEAL] = ColorPair(Cyan,Black), [CPU_GUEST] = ColorPair(Cyan,Black), + [CPU_FREQ] = A_BOLD | ColorPair(Red,Black), + [CPU_TEMP] = A_BOLD | ColorPair(Red,Black), + [CPU_VCORE] = A_BOLD | ColorPair(Yellow,Black), + [GPU_TEMP] = A_BOLD | ColorPair(Yellow,Black), + [ETH0_INTERFACE] = A_BOLD | ColorPair(Blue,Black), + [ETH1_INTERFACE] = A_BOLD | ColorPair(Blue,Black), + [WLAN0_INTERFACE] = A_BOLD | ColorPair(Blue,Black), + [WLAN1_INTERFACE] = A_BOLD | ColorPair(Blue,Black), + [KERNEL_VERSION] = A_BOLD | ColorPair(Blue,Black), + [DISTRO_VERSION] = A_BOLD | ColorPair(Blue,Black), + [OS_VERSION] = A_BOLD | ColorPair(Blue,Black), + [ARMBIAN_VERSION] = A_BOLD | ColorPair(Blue,Black), }, [COLORSCHEME_BROKENGRAY] = { 0 } // dynamically generated. }; @@ -596,6 +682,15 @@ void CRT_restorePrivileges() { // TODO: pass an instance of Settings instead. void CRT_init(int delay, int colorScheme) { +#ifdef DEBUG + setenv("TERM", "xterm", 1); + CRT_termType = getenv("TERM"); + if (String_eq(CRT_termType, "linux")) + CRT_scrollHAmount = 20; + else + CRT_scrollHAmount = 5; + setenv("TERM", "xterm", 1); +#endif initscr(); noecho(); CRT_delay = delay; diff --git a/CRT.h b/CRT.h index 933fe06..29ba16b 100644 --- a/CRT.h +++ b/CRT.h @@ -116,6 +116,20 @@ typedef enum ColorElements_ { CPU_SOFTIRQ, CPU_STEAL, CPU_GUEST, + CPU_TEMP, + CPU_FREQ, + CPU_VCORE, + GPU_TEMP, + ETH0_INTERFACE, + ETH1_INTERFACE, + WLAN0_INTERFACE, + WLAN1_INTERFACE, + KERNEL_VERSION, + DISTRO_VERSION, + OS_VERSION, + ARMBIAN_VERSION, + ETH0_STATS, + ETH1_STATS, LAST_COLORELEMENT } ColorElements; diff --git a/CpuFreqMeter.c b/CpuFreqMeter.c new file mode 100644 index 0000000..6508180 --- /dev/null +++ b/CpuFreqMeter.c @@ -0,0 +1,109 @@ +/* +htop - CpuFreqMeter.c +(C) 2020 Alexander Finger +*/ + +#include "CpuFreqMeter.h" +#include "Platform.h" +#include "CRT.h" + +/*{ +#include "Meter.h" +}*/ + + +int CpuFreqMeter_attributes[] = { + CPU_FREQ +}; + +static void CpuFreqMeter_setValues(Meter* this, char* buffer, int len) { + int ghz,mhz,roundup; + int cpu, Freq; + int bigLITTLE; + char buf_b[32]; + char buf_l[32]; + int ln = sizeof(buf_l); + static int pulse = 0; + + memset(buf_l, 0, sizeof(buf_l)); + memset(buf_b, 0, sizeof(buf_b)); + + bigLITTLE = Platform_getCpuBigLITTLE(); + if (bigLITTLE) { + cpu = bigLITTLE; + if (cpu < 0) + cpu = 0; + Freq = Platform_getCpuFreq(this, cpu); + if (Freq > 1000) { + Freq /= 1000; + } + if (Freq > 1000) { + ghz = Freq / 1000; + mhz = Freq % 1000; + roundup = ((mhz % 10) > 5); + mhz /= 10; + mhz += roundup; + xSnprintf(buf_b, ln, "%d.%02d GHz", ghz, mhz); + } else { + xSnprintf(buf_b, ln, "%4d MHz", Freq); + } + + cpu--; + if (cpu < 0) + cpu = 0; + Freq = Platform_getCpuFreq(this, cpu); + if (Freq > 1000) { + Freq /= 1000; + } + if (Freq > 1000) { + ghz = Freq / 1000; + mhz = Freq % 1000; + roundup = ((mhz % 10) > 5); + mhz /= 10; + mhz += roundup; + xSnprintf(buf_l, ln, "%d.%02d GHz", ghz, mhz); + } else { + xSnprintf(buf_l, ln, "%4d MHz", Freq); + } + + if (pulse) + xSnprintf(buffer, len, "%s %s (big.LITTLE)", buf_b, buf_l, pulse); + else + xSnprintf(buffer, len, "%s %s ", buf_b, buf_l, pulse); + pulse = !pulse; + return; + } + + cpu = 0; + Freq = Platform_getCpuFreq(this, cpu); + if (Freq > 1000) { + Freq /= 1000; + } + if (Freq > 1000) { + ghz = Freq / 1000; + mhz = Freq % 1000; + roundup = ((mhz % 10) > 5); + mhz /= 10; + mhz += roundup; + xSnprintf(buffer, len, "%d.%02d GHz", ghz, mhz); + } else { + xSnprintf(buffer, len, "%4d MHz", Freq); + } + pulse = !pulse; +} + +MeterClass CpuFreqMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = CpuFreqMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 1, + .total = 100.0, + .attributes = CpuFreqMeter_attributes, + .name = "CpuFreq", + .uiName = "CpuFreq", + .caption = "Cpu Freq: ", +}; + diff --git a/CpuFreqMeter.h b/CpuFreqMeter.h new file mode 100644 index 0000000..151a58c --- /dev/null +++ b/CpuFreqMeter.h @@ -0,0 +1,17 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_CpuFreqMeter +#define HEADER_CpuFreqMeter +/* +htop - CpuFreqMeter.h +(C) 2020 Alexander Finger +*/ + +#include "Meter.h" + +extern int CpuFreqMeter_attributes[]; + +extern MeterClass CpuFreqMeter_class; + + +#endif diff --git a/CpuTempMeter.c b/CpuTempMeter.c new file mode 100644 index 0000000..4052256 --- /dev/null +++ b/CpuTempMeter.c @@ -0,0 +1,39 @@ +/* +htop - CpuTempMeter.c +(C) 2020 @lex +*/ + +#include "CpuTempMeter.h" +#include "Platform.h" +#include "CRT.h" + +/*{ +#include "Meter.h" +}*/ + +int CpuTempMeter_attributes[] = { + CPU_TEMP +}; + +static void CpuTempMeter_setValues(Meter* this, char* buffer, int len) { + int Temp = Platform_getCpuTemp(this); + if (Temp > 1000) { + Temp /= 1000; + } + xSnprintf(buffer, len, "%4d C", Temp); +} + +MeterClass CpuTempMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = CpuTempMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 1, + .total = 100.0, + .attributes = CpuTempMeter_attributes, + .name = "CpuTemp", + .uiName = "CpuTemp", + .caption = "Cpu Temp: " +}; diff --git a/CpuTempMeter.h b/CpuTempMeter.h new file mode 100644 index 0000000..3538ac3 --- /dev/null +++ b/CpuTempMeter.h @@ -0,0 +1,16 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_CpuTempMeter +#define HEADER_CpuTempMeter +/* +htop - CpuTempMeter.h +(C) 2020 @lex +*/ + +#include "Meter.h" + +extern int CpuTempMeter_attributes[]; + +extern MeterClass CpuTempMeter_class; + +#endif diff --git a/CpuVcoreMeter.c b/CpuVcoreMeter.c new file mode 100644 index 0000000..03adb6d --- /dev/null +++ b/CpuVcoreMeter.c @@ -0,0 +1,84 @@ +/* +htop - CpuVcoreMeter.c +(C) 2020 Alexander Finger +*/ + +#include "CpuVcoreMeter.h" +#include "Platform.h" +#include "CRT.h" + +/*{ +#include "Meter.h" +}*/ + + +int CpuVcoreMeter_attributes[] = { + CPU_VCORE +}; + +static void CpuVcoreMeter_setValues(Meter* this, char* buffer, int len) { + int v1,v2; + int Vcore, Vcore_l, Vcore_b; + char buf1[80], buf2[80]; + int h; + + if (Platform_getCpuBigLITTLE()) { + h = len / 2; + if (h > 79) + h = 79; + Vcore_b = Platform_getCpuVcore_b(this); + if (Vcore_b > 1000) { + Vcore_b /= 1000; + } + if (Vcore_b >= 1000) { + Vcore_b /= 10; + v1 = Vcore_b / 100; + v2 = Vcore_b % 100; + xSnprintf(buf1, h, "%d.%02d V ", v1, v2); + } else { + xSnprintf(buf1, h, "%4d mV", Vcore_b); + } + Vcore_l = Platform_getCpuVcore_l(this); + if (Vcore_l > 1000) { + Vcore_l /= 1000; + } + if (Vcore_l >= 1000) { + Vcore_l /= 10; + v1 = Vcore_l / 100; + v2 = Vcore_l % 100; + xSnprintf(buf2, h, "%d.%02d V ", v1, v2); + } else { + xSnprintf(buf2, h, "%4d mV", Vcore_l); + } + xSnprintf(buffer, len, "%s %s (big.LITTLE)", buf1, buf2); + return; + } + + Vcore = Platform_getCpuVcore(this); + if (Vcore > 1000) { + Vcore /= 1000; + } + if (Vcore >= 1000) { + Vcore /= 10; + v1 = Vcore / 100; + v2 = Vcore % 100; + xSnprintf(buffer, len, "%d.%02d V", v1, v2); + } else { + xSnprintf(buffer, len, "%4d mV", Vcore); + } +} + +MeterClass CpuVcoreMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = CpuVcoreMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 1, + .total = 100.0, + .attributes = CpuVcoreMeter_attributes, + .name = "CpuVcore", + .uiName = "CpuVcore", + .caption = "Cpu Vcor: " +}; diff --git a/CpuVcoreMeter.h b/CpuVcoreMeter.h new file mode 100644 index 0000000..603e8e2 --- /dev/null +++ b/CpuVcoreMeter.h @@ -0,0 +1,16 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_CpuVcoreMeter +#define HEADER_CpuVcoreMeter +/* +htop - CpuVcoreMeter.h +(C) 2020 Alexander Finger +*/ + +#include "Meter.h" + +extern int CpuVcoreMeter_attributes[]; + +extern MeterClass CpuVcoreMeter_class; + +#endif diff --git a/Eth0_Meter.c b/Eth0_Meter.c new file mode 100644 index 0000000..90e512a --- /dev/null +++ b/Eth0_Meter.c @@ -0,0 +1,60 @@ +/* +htop - Eth0_Meter.c +(C) 2018 @lex +*/ + +#include "Eth0_Meter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int Eth0_Meter_attributes[] = { + ETH0_INTERFACE +}; + +static void Eth0_Meter_setValues(Meter* this, char* buffer, int len) { + int ret; + static char szIP[48]; + static unsigned int use_cached = 0; + Settings* settings = this->pl->settings; + + if ((use_cached++ % 2)) { + xSnprintf(buffer, len, "%s", szIP); + return; + } + + if (settings->eth0_alias[0] != 0) { + ret = findIP_interface(settings->eth0_alias, szIP, sizeof(szIP)); + } else { + ret = findIP_interface("eth0", szIP, sizeof(szIP)); + } + + if (ret) { + xSnprintf(buffer, len, "%s", szIP); + } else { + xSnprintf(buffer, len, "%s", "down"); + } +} + +MeterClass Eth0_Meter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = Eth0_Meter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = Eth0_Meter_attributes, + .name = "Eth0", + .uiName = "Eth0 IP", + .caption = "Eth0 IP: ", +}; + + diff --git a/Eth0_Meter.h b/Eth0_Meter.h new file mode 100644 index 0000000..5443abc --- /dev/null +++ b/Eth0_Meter.h @@ -0,0 +1,17 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Eth0_Meter +#define HEADER_Eth0_Meter +/* +htop - Eth0_Meter.h +(C) 2018 @lex +*/ + +#include "Meter.h" + +extern int Eth0_Meter_attributes[]; + +extern MeterClass Eth0_Meter_class; + + +#endif diff --git a/Eth0_StatsMeter.c b/Eth0_StatsMeter.c new file mode 100644 index 0000000..974c656 --- /dev/null +++ b/Eth0_StatsMeter.c @@ -0,0 +1,83 @@ +/* +htop - Eth0_StatsMeter.c +(C) 2020 @lex +*/ + +#include "Eth0_StatsMeter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int Eth0_StatsMeter_attributes[] = { + ETH0_INTERFACE +}; + +/* borrowed from slurm */ +static void Eth0_StatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float rxspeed; + float txspeed; + Settings* settings = this->pl->settings; + double refreshdelay; + static double old = 0.; + static double now = 0.; + static int flash = 0; + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + if (settings->eth0_alias[0] != 0) { + ret = Platform_getEth_stats(settings->eth0_alias, 0, 0); + } else { + ret = Platform_getEth_stats("eth0", 0, 0); + } + + if (ret) { + if (Platform_Eth0_stats.rx_bytes_comp > Platform_Eth0_stats.rx_bytes) + Platform_Eth0_stats.rx_bytes_comp = 0; + if (Platform_Eth0_stats.tx_bytes_comp > Platform_Eth0_stats.tx_bytes) + Platform_Eth0_stats.tx_bytes_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + rxspeed = (Platform_Eth0_stats.rx_bytes - Platform_Eth0_stats.rx_bytes_comp) / refreshdelay; + txspeed = (Platform_Eth0_stats.tx_bytes - Platform_Eth0_stats.tx_bytes_comp) / refreshdelay; + + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (TX/RX)", (float) txspeed / 1024, (float) rxspeed / 1024); + + Platform_Eth0_stats.rx_bytes_comp = Platform_Eth0_stats.rx_bytes; + Platform_Eth0_stats.tx_bytes_comp = Platform_Eth0_stats.tx_bytes; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavail"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass Eth0_StatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = Eth0_StatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = Eth0_StatsMeter_attributes, + .name = "Eth0stat", + .uiName = "Eth0 stat", + .caption = "Eth0 stat: ", +}; + + diff --git a/Eth0_StatsMeter.h b/Eth0_StatsMeter.h new file mode 100644 index 0000000..e44a5cc --- /dev/null +++ b/Eth0_StatsMeter.h @@ -0,0 +1,18 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Eth0_StatsMeter +#define HEADER_Eth0_StatsMeter +/* +htop - Eth0_StatsMeter.h +(C) 2020 @lex +*/ + +#include "Meter.h" + +extern int Eth0_StatsMeter_attributes[]; + +/* borrowed from slurm */ +extern MeterClass Eth0_StatsMeter_class; + + +#endif diff --git a/Eth1_Meter.c b/Eth1_Meter.c new file mode 100644 index 0000000..41cfa05 --- /dev/null +++ b/Eth1_Meter.c @@ -0,0 +1,60 @@ +/* +htop - Eth1_Meter.c +(C) 2018 @lex +*/ + +#include "Eth1_Meter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int Eth1_Meter_attributes[] = { + ETH1_INTERFACE +}; + +static void Eth1_Meter_setValues(Meter* this, char* buffer, int len) { + int ret; + static char szIP[48]; + static unsigned int use_cached = 0; + Settings* settings = this->pl->settings; + + if ((use_cached++ % 2)) { + xSnprintf(buffer, len, "%s", szIP); + return; + } + + if (settings->eth1_alias[0] != 0) { + ret = findIP_interface(settings->eth1_alias, szIP, sizeof(szIP)); + } else { + ret = findIP_interface("eth1", szIP, sizeof(szIP)); + } + + if (ret) { + xSnprintf(buffer, len, "%s", szIP); + } else { + xSnprintf(buffer, len, "%s", "down"); + } +} + +MeterClass Eth1_Meter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = Eth1_Meter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = Eth1_Meter_attributes, + .name = "Eth1", + .uiName = "Eth1 IP", + .caption = "Eth1 IP: ", +}; + + diff --git a/Eth1_Meter.h b/Eth1_Meter.h new file mode 100644 index 0000000..7f7f4fc --- /dev/null +++ b/Eth1_Meter.h @@ -0,0 +1,17 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Eth1_Meter +#define HEADER_Eth1_Meter +/* +htop - Eth1_Meter.h +(C) 2018 @lex +*/ + +#include "Meter.h" + +extern int Eth1_Meter_attributes[]; + +extern MeterClass Eth1_Meter_class; + + +#endif diff --git a/Eth1_StatsMeter.c b/Eth1_StatsMeter.c new file mode 100644 index 0000000..85e6dc9 --- /dev/null +++ b/Eth1_StatsMeter.c @@ -0,0 +1,83 @@ +/* +htop - Eth1_StatsMeter.c +(C) 2020 @lex +*/ + +#include "Eth1_StatsMeter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int Eth1_StatsMeter_attributes[] = { + ETH1_INTERFACE +}; + +/* borrowed from slurm */ +static void Eth1_StatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float rxspeed; + float txspeed; + Settings* settings = this->pl->settings; + double refreshdelay; + static double old = 0.; + static double now = 0.; + static int flash = 0; + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + if (settings->eth1_alias[0] != 0) { + ret = Platform_getEth_stats(settings->eth1_alias, 1, 0); + } else { + ret = Platform_getEth_stats("eth1", 1, 0); + } + + if (ret) { + if (Platform_Eth1_stats.rx_bytes_comp > Platform_Eth1_stats.rx_bytes) + Platform_Eth1_stats.rx_bytes_comp = 0; + if (Platform_Eth1_stats.tx_bytes_comp > Platform_Eth1_stats.tx_bytes) + Platform_Eth1_stats.tx_bytes_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + rxspeed = (Platform_Eth1_stats.rx_bytes - Platform_Eth1_stats.rx_bytes_comp) / refreshdelay; + txspeed = (Platform_Eth1_stats.tx_bytes - Platform_Eth1_stats.tx_bytes_comp) / refreshdelay; + + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (TX/RX)", (float) txspeed / 1024, (float) rxspeed / 1024); + + Platform_Eth1_stats.rx_bytes_comp = Platform_Eth1_stats.rx_bytes; + Platform_Eth1_stats.tx_bytes_comp = Platform_Eth1_stats.tx_bytes; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavail"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass Eth1_StatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = Eth1_StatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = Eth1_StatsMeter_attributes, + .name = "Eth1stat", + .uiName = "Eth1 stat", + .caption = "Eth1 stat: ", +}; + + diff --git a/Eth1_StatsMeter.h b/Eth1_StatsMeter.h new file mode 100644 index 0000000..c173b15 --- /dev/null +++ b/Eth1_StatsMeter.h @@ -0,0 +1,18 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Eth1_StatsMeter +#define HEADER_Eth1_StatsMeter +/* +htop - Eth1_StatsMeter.h +(C) 2020 @lex +*/ + +#include "Meter.h" + +extern int Eth1_StatsMeter_attributes[]; + +/* borrowed from slurm */ +extern MeterClass Eth1_StatsMeter_class; + + +#endif diff --git a/GpuTempMeter.c b/GpuTempMeter.c new file mode 100644 index 0000000..92394b3 --- /dev/null +++ b/GpuTempMeter.c @@ -0,0 +1,39 @@ +/* +htop - GpuTempMeter.c +(C) 2018 @lex +*/ + +#include "GpuTempMeter.h" +#include "Platform.h" +#include "CRT.h" + +/*{ +#include "Meter.h" +}*/ + +int GpuTempMeter_attributes[] = { + GPU_TEMP +}; + +static void GpuTempMeter_setValues(Meter* this, char* buffer, int len) { + int Temp = Platform_getGpuTemp(this); + if (Temp > 1000) { + Temp /= 1000; + } + xSnprintf(buffer, len, "%4d C", Temp); +} + +MeterClass GpuTempMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = GpuTempMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 1, + .total = 100.0, + .attributes = GpuTempMeter_attributes, + .name = "GpuTemp", + .uiName = "GpuTemp", + .caption = "Gpu Temp: " +}; diff --git a/GpuTempMeter.h b/GpuTempMeter.h new file mode 100644 index 0000000..40dab90 --- /dev/null +++ b/GpuTempMeter.h @@ -0,0 +1,16 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_GpuTempMeter +#define HEADER_GpuTempMeter +/* +htop - GpuTempMeter.h +(C) 2018 @lex +*/ + +#include "Meter.h" + +extern int GpuTempMeter_attributes[]; + +extern MeterClass GpuTempMeter_class; + +#endif diff --git a/Kernel_Meter.c b/Kernel_Meter.c new file mode 100644 index 0000000..45c675f --- /dev/null +++ b/Kernel_Meter.c @@ -0,0 +1,55 @@ +/* +htop - Kernelversion_Meter.c +(C) 2018 @lex +*/ + +#include "Kernel_Meter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int Kernelversion_Meter_attributes[] = { + KERNEL_VERSION +}; + +static void Kernelversion_Meter_setValues(Meter* this, char* buffer, int len) { + int ret; + static char version[256]; + static int use_cached = 0; + + if ((use_cached++ % 10)) { + xSnprintf(buffer, len, "%s", version); + return; + } + + ret = ReadTokenValue( "/proc/version", "Linux version", version); + + if (ret) { + xSnprintf(buffer, len, "%s", version); + } else { + xSnprintf(buffer, len, "%s", "down"); + } +} + +MeterClass Kernelversion_Meter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = Kernelversion_Meter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = Kernelversion_Meter_attributes, + .name = "Kernelversion", + .uiName = "Kernel version", + .caption = "Kernel: ", +}; + + diff --git a/Kernel_Meter.h b/Kernel_Meter.h new file mode 100644 index 0000000..98f9a1f --- /dev/null +++ b/Kernel_Meter.h @@ -0,0 +1,17 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Kernel_Meter +#define HEADER_Kernel_Meter +/* +htop - Kernelversion_Meter.h +(C) 2018 @lex +*/ + +#include "Meter.h" + +extern int Kernelversion_Meter_attributes[]; + +extern MeterClass Kernelversion_Meter_class; + + +#endif diff --git a/Makefile.am b/Makefile.am index cd5209c..6557c6a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,9 @@ ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c MainPanel.c \ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \ LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \ BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \ -SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c \ +SignalsPanel.c StringUtils.c SwapMeter.c TasksMeter.c UptimeMeter.c CpuFreqMeter.c CpuTempMeter.c GpuTempMeter.c CpuVcoreMeter.c \ +interfaces.c OS_Meter.c Eth0_Meter.c Eth1_Meter.c Wlan0_Meter.c Wlan1_Meter.c Kernel_Meter.c Armbian_Meter.c \ +Wlan0_StatsMeter.c Eth0_StatsMeter.c Eth1_StatsMeter.c BlockDevice_ioStatsMeter.c \ TraceScreen.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c \ HostnameMeter.c OpenFilesScreen.c Affinity.c IncSet.c Action.c EnvScreen.c \ InfoScreen.c XAlloc.c @@ -32,7 +34,9 @@ CPUMeter.h CRT.h MainPanel.h DisplayOptionsPanel.h FunctionBar.h \ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \ BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \ ScreenManager.h Settings.h SignalsPanel.h StringUtils.h SwapMeter.h \ -TasksMeter.h UptimeMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \ +TasksMeter.h UptimeMeter.h CpuFreqMeter.h CpuTempMeter.h GpuTempMeter.h CpuVcoreMeter.h TraceScreen.h UsersTable.h Vector.h Process.h \ +interfaces.h OS_Meter.h Eth0_Meter.h Eth1_Meter.h Wlan0_Meter.h Wlan1_Meter.h Kernel_Meter.h Armbian_Meter.h \ +Wlan0_StatsMeter.h Eth0_StatsMeter.h Eth1_StatsMeter.h BlockDevice_ioStatsMeter.h \ AffinityPanel.h HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h \ EnvScreen.h InfoScreen.h XAlloc.h diff --git a/OS_Meter.c b/OS_Meter.c new file mode 100644 index 0000000..588c234 --- /dev/null +++ b/OS_Meter.c @@ -0,0 +1,55 @@ +/* +htop - OSversion_Meter.c +(C) 2018 @lex +*/ + +#include "OS_Meter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int OSversion_Meter_attributes[] = { + OS_VERSION +}; + +static void OSversion_Meter_setValues(Meter* this, char* buffer, int len) { + int ret; + static char version[256]; + static int use_cached = 0; + + if ((use_cached++ % 10)) { + xSnprintf(buffer, len, "%s", version); + return; + } + + ret = ReadKeyValue( "/etc/os-release", "PRETTY_NAME=", version); + + if (ret) { + xSnprintf(buffer, len, "%s", version); + } else { + xSnprintf(buffer, len, "%s", "down"); + } +} + +MeterClass OSversion_Meter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = OSversion_Meter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = OSversion_Meter_attributes, + .name = "OSversion", + .uiName = "OS version", + .caption = "OS vers: ", +}; + + diff --git a/OS_Meter.h b/OS_Meter.h new file mode 100644 index 0000000..c5cccb2 --- /dev/null +++ b/OS_Meter.h @@ -0,0 +1,17 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_OS_Meter +#define HEADER_OS_Meter +/* +htop - OSversion_Meter.h +(C) 2018 @lex +*/ + +#include "Meter.h" + +extern int OSversion_Meter_attributes[]; + +extern MeterClass OSversion_Meter_class; + + +#endif diff --git a/Process.c b/Process.c index 471f529..9ac5fa6 100644 --- a/Process.c +++ b/Process.c @@ -1,6 +1,7 @@ /* htop - Process.c (C) 2004-2015 Hisham H. Muhammad +(C) 2020 Alexander Finger Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ diff --git a/Process.h b/Process.h index f702ca0..fbd9ef5 100644 --- a/Process.h +++ b/Process.h @@ -5,6 +5,7 @@ /* htop - Process.h (C) 2004-2015 Hisham H. Muhammad +(C) 2020 Alexander Finger Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ diff --git a/ProcessList.c b/ProcessList.c index 7482b03..4ef1e83 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -69,6 +69,7 @@ typedef struct ProcessList_ { unsigned long long int freeSwap; int cpuCount; + int cpuBigLITTLE; } ProcessList; diff --git a/ProcessList.h b/ProcessList.h index 572d484..aa0e6c0 100644 --- a/ProcessList.h +++ b/ProcessList.h @@ -63,6 +63,7 @@ typedef struct ProcessList_ { unsigned long long int freeSwap; int cpuCount; + int cpuBigLITTLE; } ProcessList; diff --git a/ScreenManager.c b/ScreenManager.c index 05e1c02..3ae6670 100644 --- a/ScreenManager.c +++ b/ScreenManager.c @@ -130,6 +130,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi if (newTime < *oldTime) *rescan = true; // clock was adjusted? if (*rescan) { *oldTime = newTime; + Header_draw(this->header); ProcessList_scan(pl); if (*sortTimeout == 0 || this->settings->treeView) { ProcessList_sort(pl); @@ -139,7 +140,7 @@ static void checkRecalculation(ScreenManager* this, double* oldTime, int* sortTi } if (*redraw) { ProcessList_rebuildPanel(pl); - Header_draw(this->header); + // Header_draw(this->header); } *rescan = false; } diff --git a/Settings.c b/Settings.c index db2fa06..912ad7d 100644 --- a/Settings.c +++ b/Settings.c @@ -59,6 +59,28 @@ typedef struct Settings_ { bool accountGuestInCPUMeter; bool headerMargin; + char CpuFreq_handler[256]; + char CpuTemp_handler[256]; + char CpuVCore_l_handler[256]; + char CpuVCore_b_handler[256]; + + char GpuVCore_handler[256]; + char GpuTemp_handler[256]; + + char BoardName[128]; + char KernelVersionFull[256]; + char KernelVersionShort[64]; + + char IP_wlan0[32]; + char IP_wlan1[32]; + char IP_eth0[32]; + char IP_eth1[32]; + + char eth0_alias[32]; + char eth1_alias[32]; + char wlan0_alias[32]; + char wlan1_alias[32]; + bool changed; } Settings; @@ -141,6 +163,12 @@ static void Settings_defaultMeters(Settings* this) { this->columns[1].modes[r++] = TEXT_METERMODE; this->columns[1].names[r] = xStrdup("Uptime"); this->columns[1].modes[r++] = TEXT_METERMODE; + + this->columns[1].names[r] = xStrdup("CpuTemp"); + this->columns[1].modes[r++] = TEXT_METERMODE; + this->columns[1].names[r] = xStrdup("CpuFreq"); + this->columns[1].modes[r++] = TEXT_METERMODE; + } static void readFields(ProcessField* fields, int* flags, const char* line) { @@ -244,7 +272,41 @@ static bool Settings_read(Settings* this, const char* fileName) { } else if (String_eq(option[0], "right_meter_modes")) { Settings_readMeterModes(this, option[1], 1); didReadMeters = true; - } + } else if (String_eq(option[0], "BoardName")) { + strcpy(this->BoardName,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "CpuFreq_handler")) { + strcpy(this->CpuFreq_handler,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "CpuTemp_handler")) { + strcpy(this->CpuTemp_handler,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "CpuVCore_l_handler")) { + strcpy(this->CpuVCore_l_handler,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "CpuVCore_b_handler")) { + strcpy(this->CpuVCore_b_handler,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "GpuVCore_handler")) { + strcpy(this->GpuVCore_handler,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "GpuTemp_handler")) { + strcpy(this->GpuTemp_handler,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "eth0_alias")) { + strcpy(this->eth0_alias,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "eth1_alias")) { + strcpy(this->eth1_alias,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "wlan0_alias")) { + strcpy(this->wlan0_alias,option[1]); + didReadMeters = true; + } else if (String_eq(option[0], "wlan1_alias")) { + strcpy(this->wlan1_alias,option[1]); + didReadMeters = true; + } + String_freeArray(option); } fclose(fd); @@ -320,6 +382,23 @@ bool Settings_write(Settings* this) { fprintf(fd, "left_meter_modes="); writeMeterModes(this, fd, 0); fprintf(fd, "right_meters="); writeMeters(this, fd, 1); fprintf(fd, "right_meter_modes="); writeMeterModes(this, fd, 1); + + fprintf(fd, "# SBC hardware and Kernel specific path.\n"); + fprintf(fd, "# Editable manually.\n"); + fprintf(fd, "BoardName=%s\n", this->BoardName); + fprintf(fd, "CpuFreq_handler=%s\n", this->CpuFreq_handler); + fprintf(fd, "CpuTemp_handler=%s\n", this->CpuTemp_handler); + fprintf(fd, "CpuVCore_l_handler=%s\n", this->CpuVCore_l_handler); + fprintf(fd, "CpuVCore_b_handler=%s\n", this->CpuVCore_b_handler); + fprintf(fd, "GpuVCore_handler=%s\n", this->GpuVCore_handler); + fprintf(fd, "GpuTemp_handler=%s\n", this->GpuTemp_handler); + + fprintf(fd, "# Wlan / Eth alias\n"); + fprintf(fd, "eth0_alias=%s\n",this->eth0_alias); + fprintf(fd, "eth1_alias=%s\n",this->eth1_alias); + fprintf(fd, "wlan0_alias=%s\n",this->wlan0_alias); + fprintf(fd, "wlan1_alias=%s\n",this->wlan1_alias); + fclose(fd); return true; } diff --git a/Settings.h b/Settings.h index d9dc068..4fcd885 100644 --- a/Settings.h +++ b/Settings.h @@ -50,6 +50,28 @@ typedef struct Settings_ { bool accountGuestInCPUMeter; bool headerMargin; + char CpuFreq_handler[256]; + char CpuTemp_handler[256]; + char CpuVCore_l_handler[256]; + char CpuVCore_b_handler[256]; + + char GpuVCore_handler[256]; + char GpuTemp_handler[256]; + + char BoardName[128]; + char KernelVersionFull[256]; + char KernelVersionShort[64]; + + char IP_wlan0[32]; + char IP_wlan1[32]; + char IP_eth0[32]; + char IP_eth1[32]; + + char eth0_alias[32]; + char eth1_alias[32]; + char wlan0_alias[32]; + char wlan1_alias[32]; + bool changed; } Settings; diff --git a/Wlan0_Meter.c b/Wlan0_Meter.c new file mode 100644 index 0000000..bf75623 --- /dev/null +++ b/Wlan0_Meter.c @@ -0,0 +1,58 @@ +/* +htop - Wlan0_Meter.c +(C) 2020 @lex +*/ + +#include "Wlan0_Meter.h" +#include "Platform.h" +#include "CRT.h" + +/*{ +#include "Meter.h" +}*/ + + +int Wlan0_Meter_attributes[] = { + WLAN0_INTERFACE +}; + +static void Wlan0_Meter_setValues(Meter* this, char* buffer, int len) { + int ret; + static char szIP[48]; + static unsigned int use_cached = 0; + Settings* settings = this->pl->settings; + + if ((use_cached++ % 2)) { + xSnprintf(buffer, len, "%s", szIP); + return; + } + + if (settings->wlan0_alias[0] != 0) { + ret = findIP_interface(settings->wlan0_alias, szIP, sizeof(szIP)); + } else { + ret = findIP_interface("wlan0", szIP, sizeof(szIP)); + } + + if (ret) { + xSnprintf(buffer, len, "%s", szIP); + } else { + xSnprintf(buffer, len, "%s", "down"); + } +} + +MeterClass Wlan0_Meter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = Wlan0_Meter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = Wlan0_Meter_attributes, + .name = "Wlan0", + .uiName = "Wlan0 IP", + .caption = "Wlan0 IP: ", +}; + + diff --git a/Wlan0_Meter.h b/Wlan0_Meter.h new file mode 100644 index 0000000..59761ff --- /dev/null +++ b/Wlan0_Meter.h @@ -0,0 +1,17 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Wlan0_Meter +#define HEADER_Wlan0_Meter +/* +htop - Wlan0_Meter.h +(C) 2020 @lex +*/ + +#include "Meter.h" + +extern int Wlan0_Meter_attributes[]; + +extern MeterClass Wlan0_Meter_class; + + +#endif diff --git a/Wlan0_StatsMeter.c b/Wlan0_StatsMeter.c new file mode 100644 index 0000000..f920f9c --- /dev/null +++ b/Wlan0_StatsMeter.c @@ -0,0 +1,83 @@ +/* +htop - Wlan0_StatsMeter.c +(C) 2020 @lex +*/ + +#include "Wlan0_StatsMeter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int Wlan0_StatsMeter_attributes[] = { + ETH0_INTERFACE +}; + +/* borrowed from slurm */ +static void Wlan0_StatsMeter_setValues(Meter* this, char* buffer, int len) { + int ret; + float rxspeed; + float txspeed; + Settings* settings = this->pl->settings; + double refreshdelay; + static double old = 0.; + static double now = 0.; + static int flash = 0; + + now = get_wall_time(); + refreshdelay = now - old; + if (old == 0.) + refreshdelay = 1.; + old = now; + + if (settings->wlan0_alias[0] != 0) { + ret = Platform_getEth_stats(settings->wlan0_alias, 2, 0); + } else { + ret = Platform_getEth_stats("wlan0", 0, 0); + } + + if (ret) { + if (Platform_Wlan0_stats.rx_bytes_comp > Platform_Wlan0_stats.rx_bytes) + Platform_Wlan0_stats.rx_bytes_comp = 0; + if (Platform_Wlan0_stats.tx_bytes_comp > Platform_Wlan0_stats.tx_bytes) + Platform_Wlan0_stats.tx_bytes_comp = 0; + + /* we assume here the refresdelay is 1 sec which sometimes is 1.5, so we have a peak */ + rxspeed = (Platform_Wlan0_stats.rx_bytes - Platform_Wlan0_stats.rx_bytes_comp) / refreshdelay; + txspeed = (Platform_Wlan0_stats.tx_bytes - Platform_Wlan0_stats.tx_bytes_comp) / refreshdelay; + + xSnprintf(buffer, len, "%.2f KB/s - %.2f KB/s (TX/RX)", (float) txspeed / 1024, (float) rxspeed / 1024); + + Platform_Wlan0_stats.rx_bytes_comp = Platform_Wlan0_stats.rx_bytes; + Platform_Wlan0_stats.tx_bytes_comp = Platform_Wlan0_stats.tx_bytes; + + } else { + if (!(flash % 2)) + xSnprintf(buffer, len, "%s", "unavail"); + else + xSnprintf(buffer, len, "%s", ""); + flash++; + } +} + +MeterClass Wlan0_StatsMeter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = Wlan0_StatsMeter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = Wlan0_StatsMeter_attributes, + .name = "Wlan0stat", + .uiName = "Wlan0 stat", + .caption = "Wlan0 stat: ", +}; + + diff --git a/Wlan0_StatsMeter.h b/Wlan0_StatsMeter.h new file mode 100644 index 0000000..2880f9d --- /dev/null +++ b/Wlan0_StatsMeter.h @@ -0,0 +1,18 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Wlan0_StatsMeter +#define HEADER_Wlan0_StatsMeter +/* +htop - Wlan0_StatsMeter.h +(C) 2020 @lex +*/ + +#include "Meter.h" + +extern int Wlan0_StatsMeter_attributes[]; + +/* borrowed from slurm */ +extern MeterClass Wlan0_StatsMeter_class; + + +#endif diff --git a/Wlan1_Meter.c b/Wlan1_Meter.c new file mode 100644 index 0000000..c5acd69 --- /dev/null +++ b/Wlan1_Meter.c @@ -0,0 +1,60 @@ +/* +htop - Eth0_Meter.c +(C) 2018 @lex +*/ + +#include "Wlan1_Meter.h" +#include "Platform.h" +#include "CRT.h" + +#include "interfaces.h" + +/*{ +#include "Meter.h" +}*/ + + +int Wlan1_Meter_attributes[] = { + WLAN1_INTERFACE +}; + +static void Wlan1_Meter_setValues(Meter* this, char* buffer, int len) { + int ret; + static char szIP[48]; + static unsigned int use_cached = 0; + Settings* settings = this->pl->settings; + + if ((use_cached++ % 2)) { + xSnprintf(buffer, len, "%s", szIP); + return; + } + + if (settings->wlan1_alias[0] != 0) { + ret = findIP_interface(settings->wlan1_alias, szIP, sizeof(szIP)); + } else { + ret = findIP_interface("wlan1", szIP, sizeof(szIP)); + } + + if (ret) { + xSnprintf(buffer, len, "%s", szIP); + } else { + xSnprintf(buffer, len, "%s", "down"); + } +} + +MeterClass Wlan1_Meter_class = { + .super = { + .extends = Class(Meter), + .delete = Meter_delete + }, + .updateValues = Wlan1_Meter_setValues, + .defaultMode = TEXT_METERMODE, + .maxItems = 8, + .total = 100.0, + .attributes = Wlan1_Meter_attributes, + .name = "Wlan1", + .uiName = "Wlan1 IP", + .caption = "Wlan1 IP: ", +}; + + diff --git a/Wlan1_Meter.h b/Wlan1_Meter.h new file mode 100644 index 0000000..4bba228 --- /dev/null +++ b/Wlan1_Meter.h @@ -0,0 +1,17 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Wlan1_Meter +#define HEADER_Wlan1_Meter +/* +htop - Eth0_Meter.h +(C) 2018 @lex +*/ + +#include "Meter.h" + +extern int Wlan1_Meter_attributes[]; + +extern MeterClass Wlan1_Meter_class; + + +#endif diff --git a/htop.c b/htop.c index 6db81dd..0044eb8 100644 --- a/htop.c +++ b/htop.c @@ -1,6 +1,7 @@ /* htop - htop.c (C) 2004-2011 Hisham H. Muhammad +(C) 2020 Alexander Finger Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ @@ -170,7 +171,6 @@ static void millisleep(unsigned long millisec) { } int main(int argc, char** argv) { - char *lc_ctype = getenv("LC_CTYPE"); if(lc_ctype != NULL) setlocale(LC_CTYPE, lc_ctype); @@ -193,6 +193,8 @@ int main(int argc, char** argv) { UsersTable* ut = UsersTable_new(); ProcessList* pl = ProcessList_new(ut, flags.pidWhiteList, flags.userId); + Platform_findCpuBigLITTLE(pl->cpuCount, &pl->cpuBigLITTLE); + Settings* settings = Settings_new(pl->cpuCount); pl->settings = settings; @@ -243,7 +245,16 @@ int main(int argc, char** argv) { mvhline(LINES-1, 0, ' ', COLS); attroff(CRT_colors[RESET_COLOR]); refresh(); - + + Platform_getEth_stats("", -1, 1); + Platform_getIO_stats("", 0, 1); + Platform_getIO_stats("", 1, 1); + Platform_getIO_stats("", 2, 1); + Platform_getIO_stats("", 3, 1); + Platform_getIO_stats("", 4, 1); + Platform_getIO_stats("", 5, 1); + Platform_getIO_stats("", 6, 1); + Platform_getIO_stats("", 7, 1); CRT_done(); if (settings->changed) Settings_write(settings); diff --git a/htop.h b/htop.h index 7faa6c6..05d5fd4 100644 --- a/htop.h +++ b/htop.h @@ -5,6 +5,7 @@ /* htop - htop.h (C) 2004-2011 Hisham H. Muhammad +(C) 2020 Alexander Finger Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ diff --git a/interfaces.c b/interfaces.c new file mode 100644 index 0000000..aa41d2a --- /dev/null +++ b/interfaces.c @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interfaces.h" +#include "Settings.h" + +#define BLEN 256 +/* + /etc/armbian-release + VERSION=20.02.1 + + /etc/debian_version + buster/sid + + cat /etc/lsb-release + DISTRIB_DESCRIPTION="Ubuntu 18.04.5 LTS" + + cat /etc/os-release + PRETTY_NAME="Ubuntu 18.04.5 LTS" + VERSION="18.04.5 LTS (Bionic Beaver)" + ID=ubuntu + + cat /proc/version + Linux version 5.3.0-52-generic (buildd@lgw01-amd64-037) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #46~18.04.1-Ubuntu SMP Thu Apr 30 16:13:51 UTC 2020 +*/ + + +int ReadKeyValue( char *fname, char *key, char *value) { + FILE* fp; + char buffer[BLEN]; + int fd = 0; + int len = strlen(key); + char *str; + char *str_end; + + fp = fopen(fname, "r"); + if (fp == NULL) + return fd; + + while (fgets(buffer, BLEN, fp) != NULL) { + str = strstr(buffer, key); + if (str != NULL) { + fd = 1; + str += len; + if (*str == '\"') { + str++; + len = strlen(str); + str_end = str + len; + while (*str_end != '\"') { + *str_end = 0; + str_end--; + if (str_end == str) + break; + } + *str_end = 0; + strcpy(value, str); + fd = 1; + } else { + strcpy(value, str); + fd = 1; + } + } + } + fclose(fp); + return fd; +} + +int ReadTokenValue( char *fname, char *key, char *value) { + FILE* fp; + char buffer[BLEN]; + int fd = 0; + int len = strlen(key); + char *str; + char *str_end; + + fp = fopen(fname, "r"); + if (fp == NULL) + return fd; + + while (fgets(buffer, BLEN, fp) != NULL) { + str = strstr(buffer, key); + if (str != NULL) { + fd = 1; + str += len; + str++; + str_end = str; + while (*str_end != ' ' && *str_end != 0) { + str_end++; + } + *str_end = 0; + strcpy(value, str); + fd = 1; + } + } + fclose(fp); + return fd; +} + +char *ltrim(char *str) { + while(isspace(*str)) + str++; + return str; +} + +char *rtrim(char *str) { + char* end = str + strlen(str); + while (isspace(*--end)) + ; + *(end + 1) = '\0'; + return str; +} + +char *trim(char *str) { + return rtrim(ltrim(str)); +} + +int FindDataValueFromKey( char *fname, char *key, char *value) { + FILE* fp; + char buffer[BLEN]; + int fd = 0; + char *str; + char *str_end; + char *str_start; + + fp = fopen(fname, "r"); + if (fp == NULL) + return fd; + + while (fgets(buffer, BLEN, fp) != NULL) { + str_start = buffer; + str_end = strchr(buffer, ':'); + if (str_end != NULL) { + *str_end = 0; + str_start = trim(str_start); + if (strcasecmp(str_start, key) == 0) { + str = str_end + 1; + str = trim(str); + strcpy(value, str); + printf("key: %s, value: %s\n", str_start, str); + fd = 1; + break; + } + } + } + fclose(fp); + return fd; +} + + +int findIP_interface(char *dev, char *szIP, int bufsz) { + struct ifaddrs *ifaddr, *ifa; + int family, s, n; + char host[NI_MAXHOST]; + int found_if = 0; + int len = strlen(dev); + + /* get interface information */ + if (getifaddrs(&ifaddr) != -1) { + for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) { + if (ifa->ifa_addr == NULL) + continue; + + family = ifa->ifa_addr->sa_family; + if ((strncmp (dev, ifa->ifa_name, len ) == 0) && (family == AF_INET || family == AF_INET6)) { + s = getnameinfo(ifa->ifa_addr, + (ifa->ifa_addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6), + host, NI_MAXHOST, + NULL, 0, NI_NUMERICHOST); + if (s != 0) { + break; + } + if ((ifa->ifa_flags & IFF_UP) == 0) + continue; + if ((ifa->ifa_flags & IFF_RUNNING) == 0) + continue; + found_if = 1; + break; + } + } + if (found_if) { + snprintf ( szIP, bufsz, "%s", host ); + } + freeifaddrs(ifaddr); + } + return found_if; +} diff --git a/interfaces.h b/interfaces.h new file mode 100644 index 0000000..adb4e5b --- /dev/null +++ b/interfaces.h @@ -0,0 +1,40 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_interfaces +#define HEADER_interfaces + +#define BLEN 256 +/* + /etc/armbian-release + VERSION=20.02.1 + + /etc/debian_version + buster/sid + + cat /etc/lsb-release + DISTRIB_DESCRIPTION="Ubuntu 18.04.5 LTS" + + cat /etc/os-release + PRETTY_NAME="Ubuntu 18.04.5 LTS" + VERSION="18.04.5 LTS (Bionic Beaver)" + ID=ubuntu + + cat /proc/version + Linux version 5.3.0-52-generic (buildd@lgw01-amd64-037) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #46~18.04.1-Ubuntu SMP Thu Apr 30 16:13:51 UTC 2020 +*/ + +int ReadKeyValue( char *fname, char *key, char *value); + +int ReadTokenValue( char *fname, char *key, char *value); + +char *ltrim(char *str); + +char *rtrim(char *str); + +char *trim(char *str); + +int FindDataValueFromKey( char *fname, char *key, char *value); + +int findIP_interface(char *dev, char *szIP, int bufsz); + +#endif diff --git a/linux/Platform.c b/linux/Platform.c index ab90ca7..e87089c 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -1,6 +1,7 @@ /* htop - linux/Platform.c (C) 2014 Hisham H. Muhammad +(C) 2020 Alexander Finger Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ @@ -14,6 +15,21 @@ in the source distribution for its full text. #include "Meter.h" #include "CPUMeter.h" +#include "CpuFreqMeter.h" +#include "CpuTempMeter.h" +#include "GpuTempMeter.h" +#include "CpuVcoreMeter.h" +#include "Eth0_StatsMeter.h" +#include "Eth1_StatsMeter.h" +#include "Wlan0_StatsMeter.h" +#include "BlockDevice_ioStatsMeter.h" +#include "Eth0_Meter.h" +#include "Eth1_Meter.h" +#include "Wlan0_Meter.h" +#include "Wlan1_Meter.h" +#include "Armbian_Meter.h" +#include "OS_Meter.h" +#include "Kernel_Meter.h" #include "MemoryMeter.h" #include "SwapMeter.h" #include "TasksMeter.h" @@ -22,12 +38,23 @@ in the source distribution for its full text. #include "ClockMeter.h" #include "HostnameMeter.h" #include "LinuxProcess.h" +#include "Settings.h" +#include "interfaces.h" + +#ifdef WIN32 +#include +#elif _POSIX_C_SOURCE >= 199309L +#include /* for nanosleep */ +#else +#include /* for usleep */ +#endif #include #include #include #include #include +#include /*{ #include "Action.h" @@ -35,6 +62,50 @@ in the source distribution for its full text. #include "BatteryMeter.h" #include "LinuxProcess.h" #include "SignalsPanel.h" +#ifdef WIN32 +#include +#elif _POSIX_C_SOURCE >= 199309L +#include +#else +#include +#endif +#include + + +typedef enum vendor_id_ { + VENDOR_INTEL, + VENDOR_AMD, + VENDOR_CYRIX, + VENDOR_VIA, + VENDOR_TRANSMETA, + VENDOR_UMC, + VENDOR_NEXGEN, + VENDOR_RISE, + VENDOR_SIS, + VENDOR_NSC, + VENDOR_VORTEX, + VENDOR_RDC, + VENDOR_UNKNOWN +} vendor_id; + +typedef struct Stats_ { + int rx_over; + int tx_over; + double rx_bytes; + double tx_bytes; + double rx_bytes_comp; + double tx_bytes_comp; +} Stats; + +typedef struct ioStats_ { + int read_over; + int write_over; + double read_sectors; + double write_sectors; + double read_sectors_comp; + double write_sectors_comp; +} ioStats; + }*/ #ifndef CLAMP @@ -45,6 +116,7 @@ ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_R //static ProcessField defaultIoFields[] = { PID, IO_PRIORITY, USER, IO_READ_RATE, IO_WRITE_RATE, IO_RATE, COMM, 0 }; +int Platform_cpuBigLITTLE = 0; int Platform_numberOfFields = LAST_PROCESSFIELD; const SignalItem Platform_signals[] = { @@ -126,9 +198,270 @@ MeterClass* Platform_meterTypes[] = { &LeftCPUs2Meter_class, &RightCPUs2Meter_class, &BlankMeter_class, + &CpuTempMeter_class, + &CpuFreqMeter_class, + /* --- fix me --- &AllCpuFreqMeter_class, */ + &CpuVcoreMeter_class, + &GpuTempMeter_class, + /* interfaces */ + &Eth0_Meter_class, + &Eth1_Meter_class, + &Wlan0_Meter_class, + &Wlan0_StatsMeter_class, + &Wlan1_Meter_class, + &OSversion_Meter_class, + &Kernelversion_Meter_class, + &Armbianversion_Meter_class, + &Eth0_StatsMeter_class, + &Eth1_StatsMeter_class, + &BlockDevice_sda_ioStatsMeter_class, + &BlockDevice_sdb_ioStatsMeter_class, + &BlockDevice_sdc_ioStatsMeter_class, + &BlockDevice_sdd_ioStatsMeter_class, + &BlockDevice_mmcblk0_ioStatsMeter_class, + &BlockDevice_mmcblk1_ioStatsMeter_class, + &BlockDevice_mmcblk2_ioStatsMeter_class, + &BlockDevice_mmcblk3_ioStatsMeter_class, NULL }; +/* cross-platform sleep function */ +void sleep_ms(int milliseconds) { +#ifdef WIN32 + Sleep(milliseconds); +#elif _POSIX_C_SOURCE >= 199309L + struct timespec ts; + ts.tv_sec = milliseconds / 1000; + ts.tv_nsec = (milliseconds % 1000) * 1000000; + nanosleep(&ts, NULL); +#else + usleep(milliseconds * 1000); +#endif +} + +int Platform_getGpuTemp(Meter* this) { + int Temp = 0; + char szbuf[256]; + Settings* settings = this->pl->settings; + char *handler; + char *cpu_core_policy; + + handler = settings->GpuTemp_handler; + if (handler[0] != 0) { + cpu_core_policy = strchr(handler, '%'); + if (cpu_core_policy) { + xSnprintf(szbuf, sizeof(szbuf), "%s", "/sys/class/thermal/thermal_zone1/temp"); + } else { + xSnprintf(szbuf, sizeof(szbuf), "%s", handler); + } + } else { + xSnprintf(szbuf, sizeof(szbuf), "%s", "/sys/class/thermal/thermal_zone1/temp"); + } + + FILE* fd = fopen(szbuf, "r"); + if (!fd) { + fd = fopen("/sys/devices/virtual/thermal/thermal_zone1/temp", "r"); + } + if (fd) { + int n = fscanf(fd, "%d", &Temp); + fclose(fd); + if (n <= 0) return 0; + } + return Temp; +} + +int Platform_getCpuTemp(Meter* this) { + int Temp = 0; + char szbuf[256]; + Settings* settings = this->pl->settings; + char *handler; + char *cpu_core_policy; + + handler = settings->CpuTemp_handler; + if (handler[0] != 0) { + cpu_core_policy = strchr(handler, '%'); + if (cpu_core_policy) { + xSnprintf(szbuf, sizeof(szbuf), "%s", "/sys/class/thermal/thermal_zone0/temp"); + } else { + xSnprintf(szbuf, sizeof(szbuf), "%s", handler); + } + } else { + // sleep_ms(30); + // xSnprintf(szbuf, sizeof(szbuf), "/sys/devices/system/cpu/cpufreq/policy%d/cpuinfo_cur_freq", cpu); + xSnprintf(szbuf, sizeof(szbuf), "%s", "/sys/class/thermal/thermal_zone0/temp"); + } + FILE *fd = fopen(szbuf, "r"); + if (!fd) { + fd = fopen("/sys/devices/virtual/thermal/thermal_zone0/temp", "r"); + } + if (fd) { + int n = fscanf(fd, "%d", &Temp); + fclose(fd); + if (n <= 0) return 0; + } + return Temp; +} + +int Platform_getCpuFreq(Meter* this, int cpu) { + int Freq = 0; + FILE* fd; + char szbuf[256]; + Settings* settings = this->pl->settings; + char *handler; + char *cpu_core_policy; + + handler = settings->CpuFreq_handler; + if (handler[0] != 0) { + cpu_core_policy = strchr(handler, '%'); + if (cpu_core_policy) { + xSnprintf(szbuf, sizeof(szbuf), handler, cpu); + } else { + xSnprintf(szbuf, sizeof(szbuf), "%s", handler); + } + } else { + // sleep_ms(30); + // xSnprintf(szbuf, sizeof(szbuf), "/sys/devices/system/cpu/cpufreq/policy%d/cpuinfo_cur_freq", cpu); + xSnprintf(szbuf, sizeof(szbuf), "%s", "/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq"); + } + fd = fopen(szbuf, "r"); + if (fd) { + int n; + n = fscanf(fd, "%d", &Freq); + fclose(fd); + if (n <= 0) return 0; + } + return Freq; +} + +int Platform_getCpuVcore(Meter* this) { + int Vcore = 0; + FILE* fd; + char szbuf[256]; + Settings* settings = this->pl->settings; + char *handler; + char *cpu_core_policy; + handler = settings->CpuVCore_l_handler; + if (handler[0] != 0) { + cpu_core_policy = strchr(handler, '%'); + if (cpu_core_policy) { + xSnprintf(szbuf, sizeof(szbuf), "%s", "/sys/devices/platform/ff3c0000.i2c/i2c-0/0-001b/regulator/regulator.13/microvolts"); + } else { + xSnprintf(szbuf, sizeof(szbuf), "%s", handler); + } + } else { + xSnprintf(szbuf, sizeof(szbuf), "%s", "/sys/devices/platform/ff3c0000.i2c/i2c-0/0-001b/regulator/regulator.13/microvolts"); + } + + // sleep_ms(10); + fd = fopen(szbuf, "r"); + if (fd) { + int n; + n = fscanf(fd, "%d", &Vcore); + fclose(fd); + if (n <= 0) return 0; + } + return Vcore; +} + +int Platform_getCpuVcore_l(Meter* this) { + int Vcore = 0; + FILE* fd; + char szbuf[256]; + Settings* settings = this->pl->settings; + char *handler; + char *cpu_core_policy; + handler = settings->CpuVCore_l_handler; + if (handler[0] != 0) { + cpu_core_policy = strchr(handler, '%'); + if (cpu_core_policy) { + strcpy(szbuf, "/sys/devices/platform/ff3c0000.i2c/i2c-0/0-001b/regulator/regulator.13/microvolts"); + } else { + strcpy(szbuf, handler); + } + } else { + strcpy(szbuf, "/sys/devices/platform/ff3c0000.i2c/i2c-0/0-001b/regulator/regulator.13/microvolts"); + } + + // sleep_ms(10); + fd = fopen(szbuf, "r"); + if (fd) { + int n; + n = fscanf(fd, "%d", &Vcore); + fclose(fd); + if (n <= 0) return 0; + } + return Vcore; +} + +int Platform_getCpuVcore_b(Meter* this) { + int Vcore = 0; + FILE* fd; + char szbuf[256]; + Settings* settings = this->pl->settings; + char *handler; + char *cpu_core_policy; + handler = settings->CpuVCore_b_handler; + if (handler[0] != 0) { + cpu_core_policy = strchr(handler, '%'); + if (cpu_core_policy) { + strcpy(szbuf, "/sys/devices/platform/ff3c0000.i2c/i2c-0/0-0040/regulator/regulator.10/microvolts"); + } else { + strcpy(szbuf, handler); + } + } else { + strcpy(szbuf, "/sys/devices/platform/ff3c0000.i2c/i2c-0/0-0040/regulator/regulator.10/microvolts"); + } + // sleep_ms(10); + fd = fopen(szbuf, "r"); + if (fd) { + int n; + n = fscanf(fd, "%d", &Vcore); + fclose(fd); + if (n <= 0) return 0; + } + return Vcore; +} + + +int Platform_getCpuBigLITTLE() { + return Platform_cpuBigLITTLE; +} + +int Platform_findCpuBigLITTLE(int cpucount, int *cpuBigLITTLE) { + char buf[256]; + int n, prev, next; + FILE* fd; + + *cpuBigLITTLE = 0; + prev = next = -1; + int cpu = 0; + while (cpu < cpucount) { + xSnprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu); + fd = fopen(buf, "r"); + if (fd) { + n = fscanf(fd, "%d", &next); + fclose(fd); + if (n <= 0) + break; + if (prev == -1) { + prev = next; + } else { + if (prev != next) { + if (prev < next) { + Platform_cpuBigLITTLE = cpu; + } else { + Platform_cpuBigLITTLE = cpu * -1; /* fix me */ + } + *cpuBigLITTLE = Platform_cpuBigLITTLE; + break; + } + } + } + cpu++; + } + return cpu; +} + int Platform_getUptime() { double uptime = 0; FILE* fd = fopen(PROCDIR "/uptime", "r"); @@ -237,3 +570,177 @@ char* Platform_getProcessEnv(pid_t pid) { } return env; } + +Stats Platform_Eth0_stats; +Stats Platform_Eth1_stats; +Stats Platform_Wlan0_stats; + +int Platform_getEth_stats(char *devname, int id, int close_fp) { + char buffer[BLEN]; + char *str; + char *str_end; + char *str_start; + unsigned long dump; + int ifound; + unsigned long rx_o, tx_o; + Stats *Platform_Eth_stats; + static FILE *fp_proc_net_dev = NULL; + + if (close_fp) { + if (fp_proc_net_dev) + fclose(fp_proc_net_dev); + return 0; + } + + if (fp_proc_net_dev == NULL) { + if ((fp_proc_net_dev = fopen("/proc/net/dev", "r")) == NULL) { + return 0; + } + } + if (id == 0) { + Platform_Eth_stats = &Platform_Eth0_stats; + } else { + if (id == 1) { + Platform_Eth_stats = &Platform_Eth1_stats; + } else { + Platform_Eth_stats = &Platform_Wlan0_stats; + } + } + + /* save rx/tx values */ + rx_o = Platform_Eth_stats->rx_bytes; + tx_o = Platform_Eth_stats->tx_bytes; + + /* do not parse the first two lines as they only contain static garbage */ + fseek(fp_proc_net_dev, 0, SEEK_SET); + fgets(buffer, BLEN, fp_proc_net_dev); + fgets(buffer, BLEN, fp_proc_net_dev); + + ifound = 0; + while (fgets(buffer, BLEN, fp_proc_net_dev) != NULL) { + str_start = buffer; + str_end = strchr(buffer, ':'); + if (str_end != NULL) { + *str_end = 0; + str_start = trim(str_start); + if (strcasecmp(str_start, devname) == 0) { + str = str_end + 1; + str = ltrim(str); + sscanf(str, + "%lg %lu %lu %lu %lu %lu %lu %lu %lg %lu %lu %lu %lu %lu %lu %lu", + &Platform_Eth_stats->rx_bytes, &dump, &dump, + &dump, &dump, &dump, &dump, &dump, &Platform_Eth_stats->tx_bytes, + &dump, &dump, &dump, &dump, &dump, &dump, &dump); + ifound = 1; + continue; + } + } + } + if (ifound) { + if (rx_o > Platform_Eth_stats->rx_bytes) + Platform_Eth_stats->rx_over++; + if (tx_o > Platform_Eth_stats->tx_bytes) + Platform_Eth_stats->tx_over++; + } + return ifound; +} + +double get_wall_time(void) { + struct timeval time; + if (gettimeofday(&time, NULL)) + return 0.; + return (double) time.tv_sec + (double) time.tv_usec * .000001; +} + +ioStats Platform_BlockDevice_sda_stats; +ioStats Platform_BlockDevice_sdb_stats; +ioStats Platform_BlockDevice_sdc_stats; +ioStats Platform_BlockDevice_sdd_stats; +ioStats Platform_BlockDevice_mmcblk0_stats; +ioStats Platform_BlockDevice_mmcblk1_stats; +ioStats Platform_BlockDevice_mmcblk2_stats; +ioStats Platform_BlockDevice_mmcblk3_stats; + +FILE *fp_block_dev_a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +int Platform_getIO_stats(char *devname, int idx, int close_fp) { + char block_device[80] = {0}; + char buffer[BLEN] = {0}; + unsigned long dump; + unsigned long read_o, write_o; + ioStats *Platform_io_stats; + FILE *fp_block_dev = NULL; + + if (idx > 7) + idx = 0; + + fp_block_dev = fp_block_dev_a[idx]; + + if (close_fp) { + if (fp_block_dev) + fclose(fp_block_dev); + return 0; + } + if (devname && *devname == 0) + return 0; + + if (fp_block_dev == NULL) { + xSnprintf(block_device, sizeof(block_device), "/sys/block/%s/stat", devname); + if ((fp_block_dev = fopen(block_device, "r")) == NULL) { + return 0; + } + fp_block_dev_a[idx] = fp_block_dev; + } + + switch(idx) { + case 0: + Platform_io_stats = &Platform_BlockDevice_sda_stats; + break; + case 1: + Platform_io_stats = &Platform_BlockDevice_sdb_stats; + break; + case 2: + Platform_io_stats = &Platform_BlockDevice_sdc_stats; + break; + case 3: + Platform_io_stats = &Platform_BlockDevice_sdd_stats; + break; + case 4: + Platform_io_stats = &Platform_BlockDevice_mmcblk0_stats; + break; + case 5: + Platform_io_stats = &Platform_BlockDevice_mmcblk1_stats; + break; + case 6: + Platform_io_stats = &Platform_BlockDevice_mmcblk2_stats; + break; + case 7: + Platform_io_stats = &Platform_BlockDevice_mmcblk3_stats; + break; + default: + Platform_io_stats = &Platform_BlockDevice_sda_stats; + break; + } + /* save read/write values */ + read_o = Platform_io_stats->read_sectors; + write_o = Platform_io_stats->write_sectors; + fseek(fp_block_dev, 0, SEEK_SET); + if (fgets(buffer, BLEN - 1, fp_block_dev) != NULL) { + sscanf(buffer, + "%lu %lu %lg %lu %lu %lu %lg %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &dump, &dump, &Platform_io_stats->read_sectors, &dump, &dump, + &dump, &Platform_io_stats->write_sectors, &dump, &dump, &dump, &dump, + &dump, &dump, &dump, &dump, &dump, &dump); + } else { + return 0; + } + + while (fgets(buffer, BLEN - 1, fp_block_dev) != NULL) + ; + + if (read_o > Platform_io_stats->read_sectors) + Platform_io_stats->read_over++; + if (write_o > Platform_io_stats->write_sectors) + Platform_io_stats->write_over++; + return 1; +} diff --git a/linux/Platform.h b/linux/Platform.h index b0456e5..54dbf80 100644 --- a/linux/Platform.h +++ b/linux/Platform.h @@ -5,15 +5,65 @@ /* htop - linux/Platform.h (C) 2014 Hisham H. Muhammad +(C) 2020 Alexander Finger Released under the GNU GPL, see the COPYING file in the source distribution for its full text. */ +#ifdef WIN32 +#elif _POSIX_C_SOURCE >= 199309L +#else +#endif + #include "Action.h" #include "MainPanel.h" #include "BatteryMeter.h" #include "LinuxProcess.h" #include "SignalsPanel.h" +#ifdef WIN32 +#include +#elif _POSIX_C_SOURCE >= 199309L +#include +#else +#include +#endif +#include + + +typedef enum vendor_id_ { + VENDOR_INTEL, + VENDOR_AMD, + VENDOR_CYRIX, + VENDOR_VIA, + VENDOR_TRANSMETA, + VENDOR_UMC, + VENDOR_NEXGEN, + VENDOR_RISE, + VENDOR_SIS, + VENDOR_NSC, + VENDOR_VORTEX, + VENDOR_RDC, + VENDOR_UNKNOWN +} vendor_id; + +typedef struct Stats_ { + int rx_over; + int tx_over; + double rx_bytes; + double tx_bytes; + double rx_bytes_comp; + double tx_bytes_comp; +} Stats; + +typedef struct ioStats_ { + int read_over; + int write_over; + double read_sectors; + double write_sectors; + double read_sectors_comp; + double write_sectors_comp; +} ioStats; + #ifndef CLAMP #define CLAMP(x,low,high) (((x)>(high))?(high):(((x)<(low))?(low):(x))) @@ -21,6 +71,7 @@ in the source distribution for its full text. extern ProcessField Platform_defaultFields[]; +extern int Platform_cpuBigLITTLE; extern int Platform_numberOfFields; extern const SignalItem Platform_signals[]; @@ -31,6 +82,25 @@ void Platform_setBindings(Htop_Action* keys); extern MeterClass* Platform_meterTypes[]; +/* cross-platform sleep function */ +void sleep_ms(int milliseconds); + +int Platform_getGpuTemp(Meter* this); + +int Platform_getCpuTemp(Meter* this); + +int Platform_getCpuFreq(Meter* this, int cpu); + +int Platform_getCpuVcore(Meter* this); + +int Platform_getCpuVcore_l(Meter* this); + +int Platform_getCpuVcore_b(Meter* this); + +int Platform_getCpuBigLITTLE(); + +int Platform_findCpuBigLITTLE(int cpucount, int *cpuBigLITTLE); + int Platform_getUptime(); void Platform_getLoadAverage(double* one, double* five, double* fifteen); @@ -45,4 +115,25 @@ void Platform_setSwapValues(Meter* this); char* Platform_getProcessEnv(pid_t pid); +Stats Platform_Eth0_stats; +Stats Platform_Eth1_stats; +Stats Platform_Wlan0_stats; + +int Platform_getEth_stats(char *devname, int id, int close_fp); + +double get_wall_time(void); + +ioStats Platform_BlockDevice_sda_stats; +ioStats Platform_BlockDevice_sdb_stats; +ioStats Platform_BlockDevice_sdc_stats; +ioStats Platform_BlockDevice_sdd_stats; +ioStats Platform_BlockDevice_mmcblk0_stats; +ioStats Platform_BlockDevice_mmcblk1_stats; +ioStats Platform_BlockDevice_mmcblk2_stats; +ioStats Platform_BlockDevice_mmcblk3_stats; + +extern FILE *fp_block_dev_a[8]; + +int Platform_getIO_stats(char *devname, int idx, int close_fp); + #endif