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 <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <linux/i2c-dev.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <ifaddrs.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <linux/if_link.h>
+#include <linux/if.h>
+#include <signal.h>
+
+#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 <windows.h>
+#elif _POSIX_C_SOURCE >= 199309L
+#include <time.h>   /* for nanosleep */
+#else
+#include <unistd.h> /* for usleep */
+#endif
 
 #include <math.h>
 #include <assert.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/time.h>
 
 /*{
 #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 <windows.h>
+#elif _POSIX_C_SOURCE >= 199309L
+#include <time.h>   
+#else
+#include <unistd.h> 
+#endif
+#include <string.h>
+
+
+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 <windows.h>
+#elif _POSIX_C_SOURCE >= 199309L
+#include <time.h>   
+#else
+#include <unistd.h> 
+#endif
+#include <string.h>
+
+
+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
