summaryrefslogtreecommitdiffstats
path: root/widgets
diff options
context:
space:
mode:
authorSean E. Russell <ser@ser1.net>2020-02-28 14:38:32 -0600
committerSean E. Russell <ser@ser1.net>2020-02-28 14:38:32 -0600
commitc6af0ab404e54713f7b4039eaf9a0f21340cb00b (patch)
treef279ae965acca840ff335698287046e22f1a4a09 /widgets
parentd16cf1c6d2b91f6ca75da1ded02bde25782b7a3f (diff)
parent231b0d03fed93ccc4b5f953f503763966341ec48 (diff)
Merge branch 'v3.4.x'
Diffstat (limited to 'widgets')
-rw-r--r--widgets/battery.go27
-rw-r--r--widgets/batterygauge.go86
-rw-r--r--widgets/cpu.go103
-rw-r--r--widgets/disk.go24
-rw-r--r--widgets/include/smc.c700
-rw-r--r--widgets/include/smc.h254
-rw-r--r--widgets/mem.go86
-rw-r--r--widgets/mem_freebsd.go61
-rw-r--r--widgets/mem_other.go22
-rw-r--r--widgets/net.go23
-rw-r--r--widgets/proc.go4
-rw-r--r--widgets/temp.go58
-rw-r--r--widgets/temp_darwin.go74
-rw-r--r--widgets/temp_freebsd.go73
-rw-r--r--widgets/temp_linux.go32
-rw-r--r--widgets/temp_openbsd.go74
-rw-r--r--widgets/temp_windows.go29
17 files changed, 312 insertions, 1418 deletions
diff --git a/widgets/battery.go b/widgets/battery.go
index 00764c0..b47cac4 100644
--- a/widgets/battery.go
+++ b/widgets/battery.go
@@ -8,6 +8,7 @@ import (
"time"
"github.com/distatus/battery"
+ "github.com/prometheus/client_golang/prometheus"
ui "github.com/xxxserxxx/gotop/termui"
)
@@ -15,6 +16,7 @@ import (
type BatteryWidget struct {
*ui.LineGraph
updateInterval time.Duration
+ metric []prometheus.Gauge
}
func NewBatteryWidget(horizontalScale int) *BatteryWidget {
@@ -41,6 +43,25 @@ func NewBatteryWidget(horizontalScale int) *BatteryWidget {
return self
}
+func (b *BatteryWidget) EnableMetric() {
+ bats, err := battery.GetAll()
+ if err != nil {
+ log.Printf("error setting up metrics: %v", err)
+ return
+ }
+ b.metric = make([]prometheus.Gauge, len(bats))
+ for i, bat := range bats {
+ gauge := prometheus.NewGauge(prometheus.GaugeOpts{
+ Namespace: "gotop",
+ Subsystem: "battery",
+ Name: fmt.Sprintf("%d", i),
+ })
+ gauge.Set(bat.Current / bat.Full)
+ b.metric[i] = gauge
+ prometheus.MustRegister(gauge)
+ }
+}
+
func makeId(i int) string {
return "Batt" + strconv.Itoa(i)
}
@@ -74,8 +95,12 @@ func (self *BatteryWidget) update() {
}
for i, battery := range batteries {
id := makeId(i)
- percentFull := math.Abs(battery.Current/battery.Full) * 100.0
+ perc := battery.Current / battery.Full
+ percentFull := math.Abs(perc) * 100.0
self.Data[id] = append(self.Data[id], percentFull)
self.Labels[id] = fmt.Sprintf("%3.0f%% %.0f/%.0f", percentFull, math.Abs(battery.Current), math.Abs(battery.Full))
+ if self.metric != nil {
+ self.metric[i].Set(perc)
+ }
}
}
diff --git a/widgets/batterygauge.go b/widgets/batterygauge.go
new file mode 100644
index 0000000..59accfb
--- /dev/null
+++ b/widgets/batterygauge.go
@@ -0,0 +1,86 @@
+package widgets
+
+import (
+ "fmt"
+ "log"
+
+ "time"
+
+ "github.com/distatus/battery"
+ "github.com/prometheus/client_golang/prometheus"
+
+ . "github.com/xxxserxxx/gotop/termui"
+)
+
+type BatteryGauge struct {
+ *Gauge
+ metric prometheus.Gauge
+}
+
+func NewBatteryGauge() *BatteryGauge {
+ self := &BatteryGauge{Gauge: NewGauge()}
+ self.Title = " Power Level "
+
+ self.update()
+
+ go func() {
+ for range time.NewTicker(time.Second).C {
+ self.Lock()
+ self.update()
+ self.Unlock()
+ }
+ }()
+
+ return self
+}
+
+func (b *BatteryGauge) EnableMetric() {
+ bats, err := battery.GetAll()
+ if err != nil {
+ log.Printf("error setting up metrics: %v", err)
+ return
+ }
+ mx := 0.0
+ cu := 0.0
+ for _, bat := range bats {
+ mx += bat.Full
+ cu += bat.Current
+ gauge := prometheus.NewGauge(prometheus.GaugeOpts{
+ Namespace: "gotop",
+ Subsystem: "battery",
+ Name: "total",
+ })
+ gauge.Set(cu / mx)
+ b.metric = gauge
+ prometheus.MustRegister(gauge)
+ }
+}
+
+func (self *BatteryGauge) update() {
+ bats, err := battery.GetAll()
+ if err != nil {
+ log.Printf("error setting up batteries: %v", err)
+ return
+ }
+ mx := 0.0
+ cu := 0.0
+ charging := "%d%% ⚡%s"
+ rate := 0.0
+ for _, bat := range bats {
+ mx += bat.Full
+ cu += bat.Current
+ if rate < bat.ChargeRate {
+ rate = bat.ChargeRate
+ }
+ if bat.State == battery.Charging {
+ charging = "%d%% 🔌%s"
+ }
+ }
+ tn := (mx - cu) / rate
+ d, _ := time.ParseDuration(fmt.Sprintf("%fh", tn))
+ self.Percent = int((cu / mx) * 100.0)
+ self.Label = fmt.Sprintf(charging, self.Percent, d.Truncate(time.Minute))
+ if self.metric != nil {
+ self.metric.Set(cu / mx)
+ }
+}
diff --git a/widgets/cpu.go b/widgets/cpu.go
index 8e8819c..53f5529 100644
--- a/widgets/cpu.go
+++ b/widgets/cpu.go
@@ -6,7 +6,8 @@ import (
"sync"
"time"
- psCpu "github.com/shirou/gopsutil/cpu"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/xxxserxxx/gotop/devices"
ui "github.com/xxxserxxx/gotop/termui"
)
@@ -17,26 +18,19 @@ type CpuWidget struct {
ShowAverageLoad bool
ShowPerCpuLoad bool
updateInterval time.Duration
- formatString string
updateLock sync.Mutex
+ metric map[string]prometheus.Gauge
}
+var cpuLabels []string
+
func NewCpuWidget(updateInterval time.Duration, horizontalScale int, showAverageLoad bool, showPerCpuLoad bool) *CpuWidget {
- cpuCount, err := psCpu.Counts(false)
- if err != nil {
- log.Printf("failed to get CPU count from gopsutil: %v", err)
- }
- formatString := "CPU%1d"
- if cpuCount > 10 {
- formatString = "CPU%02d"
- }
self := &CpuWidget{
LineGraph: ui.NewLineGraph(),
- CpuCount: cpuCount,
+ CpuCount: len(cpuLabels),
updateInterval: updateInterval,
ShowAverageLoad: showAverageLoad,
ShowPerCpuLoad: showPerCpuLoad,
- formatString: formatString,
}
self.Title = " CPU Usage "
self.HorizontalScale = horizontalScale
@@ -54,9 +48,10 @@ func NewCpuWidget(updateInterval time.Duration, horizontalScale int, showAverage
}
if self.ShowPerCpuLoad {
- for i := 0; i < int(self.CpuCount); i++ {
- key := fmt.Sprintf(formatString, i)
- self.Data[key] = []float64{0}
+ cpus := make(map[string]int)
+ devices.UpdateCPU(cpus, self.updateInterval, self.ShowPerCpuLoad)
+ for k, v := range cpus {
+ self.Data[k] = []float64{float64(v)}
}
}
@@ -71,6 +66,30 @@ func NewCpuWidget(updateInterval time.Duration, horizontalScale int, showAverage
return self
}
+func (self *CpuWidget) EnableMetric() {
+ if self.ShowAverageLoad {
+ self.metric = make(map[string]prometheus.Gauge)
+ self.metric["AVRG"] = prometheus.NewGauge(prometheus.GaugeOpts{
+ Subsystem: "cpu",
+ Name: "avg",
+ })
+ } else {
+ cpus := make(map[string]int)
+ devices.UpdateCPU(cpus, self.updateInterval, self.ShowPerCpuLoad)
+ self.metric = make(map[string]prometheus.Gauge)
+ for key, perc := range cpus {
+ gauge := prometheus.NewGauge(prometheus.GaugeOpts{
+ Namespace: "gotop",
+ Subsystem: "cpu",
+ Name: key,
+ })
+ gauge.Set(float64(perc))
+ prometheus.MustRegister(gauge)
+ self.metric[key] = gauge
+ }
+ }
+}
+
func (b *CpuWidget) Scale(i int) {
b.LineGraph.HorizontalScale = i
}
@@ -78,37 +97,41 @@ func (b *CpuWidget) Scale(i int) {
func (self *CpuWidget) update() {
if self.ShowAverageLoad {
go func() {
- percent, err := psCpu.Percent(self.updateInterval, false)
- if err != nil {
- log.Printf("failed to get average CPU usage percent from gopsutil: %v. self.updateInterval: %v. percpu: %v", err, self.updateInterval, false)
- } else {
- self.Lock()
- defer self.Unlock()
- self.updateLock.Lock()
- defer self.updateLock.Unlock()
- self.Data["AVRG"] = append(self.Data["AVRG"], percent[0])
- self.Labels["AVRG"] = fmt.Sprintf("%3.0f%%", percent[0])
+ cpus := make(map[string]int)
+ devices.UpdateCPU(cpus, self.updateInterval, false)
+ self.Lock()
+ defer self.Unlock()
+ self.updateLock.Lock()
+ defer self.updateLock.Unlock()
+ var val float64
+ for _, v := range cpus {
+ val = float64(v)
+ break
+ }
+ self.Data["AVRG"] = append(self.Data["AVRG"], val)
+ self.Labels["AVRG"] = fmt.Sprintf("%3.0f%%", val)
+ if self.metric != nil {
+ self.metric["AVRG"].Set(val)
}
}()
}
if self.ShowPerCpuLoad {
go func() {
- percents, err := psCpu.Percent(self.updateInterval, true)
- if err != nil {
- log.Printf("failed to get CPU usage percents from gopsutil: %v. self.updateInterval: %v. percpu: %v", err, self.updateInterval, true)
- } else {
- if len(percents) != int(self.CpuCount) {
- log.Printf("error: number of CPU usage percents from gopsutil doesn't match CPU count. percents: %v. self.Count: %v", percents, self.CpuCount)
- } else {
- self.Lock()
- defer self.Unlock()
- self.updateLock.Lock()
- defer self.updateLock.Unlock()
- for i, percent := range percents {
- key := fmt.Sprintf(self.formatString, i)
- self.Data[key] = append(self.Data[key], percent)
- self.Labels[key] = fmt.Sprintf("%3.0f%%", percent)
+ cpus := make(map[string]int)
+ devices.UpdateCPU(cpus, self.updateInterval, true)
+ self.Lock()
+ defer self.Unlock()
+ self.updateLock.Lock()
+ defer self.updateLock.Unlock()
+ for key, percent := range cpus {
+ self.Data[key] = append(self.Data[key], float64(percent))
+ self.Labels[key] = fmt.Sprintf("%d%%", percent)
+ if self.metric != nil {
+ if self.metric[key] == nil {
+ log.Printf("no metrics for %s", key)
+ } else {
+ self.metric[key].Set(float64(percent))
}
}
}
diff --git a/widgets/disk.go b/widgets/disk.go
index d20b078..d1da7a6 100644
--- a/widgets/disk.go
+++ b/widgets/disk.go
@@ -7,6 +7,7 @@ import (
"strings"
"time"
+ "github.com/prometheus/client_golang/prometheus"
psDisk "github.com/shirou/gopsutil/disk"
ui "github.com/xxxserxxx/gotop/termui"
@@ -28,6 +29,7 @@ type DiskWidget struct {
*ui.Table
updateInterval time.Duration
Partitions map[string]*Partition
+ metric map[string]prometheus.Gauge
}
func NewDiskWidget() *DiskWidget {
@@ -60,6 +62,21 @@ func NewDiskWidget() *DiskWidget {
return self
}
+func (self *DiskWidget) EnableMetric() {
+ self.metric = make(map[string]prometheus.Gauge)
+ for key, part := range self.Partitions {
+ gauge := prometheus.NewGauge(prometheus.GaugeOpts{
+ Namespace: "gotop",
+ Subsystem: "disk",
+ Name: strings.ReplaceAll(key, "/", ":"),
+ //Name: strings.Replace(strings.Replace(part.Device, "/dev/", "", -1), "mapper/", "", -1),
+ })
+ gauge.Set(float64(part.UsedPercent) / 100.0)
+ prometheus.MustRegister(gauge)
+ self.metric[key] = gauge
+ }
+}
+
func (self *DiskWidget) update() {
partitions, err := psDisk.Partitions(false)
if err != nil {
@@ -158,5 +175,12 @@ func (self *DiskWidget) update() {
self.Rows[i][3] = partition.Free
self.Rows[i][4] = partition.BytesReadRecently
self.Rows[i][5] = partition.BytesWrittenRecently
+ if self.metric != nil {
+ if self.metric[key] == nil {
+ log.Printf("ERROR: missing metric %s", key)
+ } else {
+ self.metric[key].Set(float64(partition.UsedPercent) / 100.0)
+ }
+ }
}
}
diff --git a/widgets/include/smc.c b/widgets/include/smc.c
deleted file mode 100644
index 0c200d6..0000000
--- a/widgets/include/smc.c
+++ /dev/null
@@ -1,700 +0,0 @@
-/*
- * Apple System Management Controller (SMC) API from user space for Intel based
- * Macs. Works by talking to the AppleSMC.kext (kernel extension), the driver
- * for the SMC.
- *
- * smc.c
- * libsmc
- *
- * Copyright (C) 2014 beltex <https://github.com/beltex>
- *
- * Based off of fork from:
- * osx-cpu-temp <https://github.com/lavoiesl/osx-cpu-temp>
- *
- * With credits to:
- *
- * Copyright (C) 2006 devnull
- * Apple System Management Control (SMC) Tool
- *
- * Copyright (C) 2006 Hendrik Holtmann
- * smcFanControl <https://github.com/hholtmann/smcFanControl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include "smc.h"
-
-
-//------------------------------------------------------------------------------
-// MARK: MACROS
-//------------------------------------------------------------------------------
-
-
-/**
-Name of the SMC IOService as seen in the IORegistry. You can view it either via
-command line with ioreg or through the IORegistryExplorer app (found on Apple's
-developer site - Hardware IO Tools for Xcode)
-*/
-#define IOSERVICE_SMC "AppleSMC"
-
-
-/**
-IOService for getting machine model name
-*/
-#define IOSERVICE_MODEL "IOPlatformExpertDevice"
-
-
-/**
-SMC data types - 4 byte multi-character constants
-
-Sources: See TMP SMC keys in smc.h
-
-http://stackoverflow.com/questions/22160746/fpe2-and-sp78-data-types
-*/
-#define DATA_TYPE_UINT8 "ui8 "
-#define DATA_TYPE_UINT16 "ui16"
-#define DATA_TYPE_UINT32 "ui32"
-#define DATA_TYPE_FLAG "flag"
-#define DATA_TYPE_FPE2 "fpe2"
-#define DATA_TYPE_SFDS "{fds"
-#define DATA_TYPE_SP78 "sp78"
-
-
-//------------------------------------------------------------------------------
-// MARK: GLOBAL VARS
-//------------------------------------------------------------------------------
-
-
-/**
-Our connection to the SMC
-*/
-static io_connect_t conn;
-
-
-/**
-Number of characters in an SMC key
-*/
-static const int SMC_KEY_SIZE = 4;
-
-
-/**
-Number of characters in a data type "key" returned from the SMC. See data type
-macros.
-*/
-static const int DATA_TYPE_SIZE = 4;
-
-
-//------------------------------------------------------------------------------
-// MARK: ENUMS
-//------------------------------------------------------------------------------
-
-
-/**
-Defined by AppleSMC.kext. See SMCParamStruct.
-
-These are SMC specific return codes
-*/
-typedef enum {
- kSMCSuccess = 0,
- kSMCError = 1,
- kSMCKeyNotFound = 0x84
-} kSMC_t;
-
-
-/**
-Defined by AppleSMC.kext. See SMCParamStruct.
-
-Function selectors. Used to tell the SMC which function inside it to call.
-*/
-typedef enum {
- kSMCUserClientOpen = 0,
- kSMCUserClientClose = 1,
- kSMCHandleYPCEvent = 2,
- kSMCReadKey = 5,
- kSMCWriteKey = 6,
- kSMCGetKeyCount = 7,
- kSMCGetKeyFromIndex = 8,
- kSMCGetKeyInfo = 9
-} selector_t;
-
-
-//------------------------------------------------------------------------------
-// MARK: STRUCTS
-//------------------------------------------------------------------------------
-
-
-/**
-Defined by AppleSMC.kext. See SMCParamStruct.
-*/
-typedef struct {
- unsigned char major;
- unsigned char minor;
- unsigned char build;
- unsigned char reserved;
- unsigned short release;
-} SMCVersion;
-
-
-/**
-Defined by AppleSMC.kext. See SMCParamStruct.
-*/
-typedef struct {
- uint16_t version;
- uint16_t length;
- uint32_t cpuPLimit;
- uint32_t gpuPLimit;
- uint32_t memPLimit;
-} SMCPLimitData;
-
-
-/**
-Defined by AppleSMC.kext. See SMCParamStruct.
-
-- dataSize : How many values written to SMCParamStruct.bytes
-- dataType : Type of data written to SMCParamStruct.bytes. This lets us know how
- to interpret it (translate it to human readable)
-*/
-typedef struct {
- IOByteCount dataSize;
- uint32_t dataType;
- uint8_t dataColors;
-} SMCKeyInfoData;
-
-
-/**
-Defined by AppleSMC.kext.
-
-This is the predefined struct that must be passed to communicate with the
-AppleSMC driver. While the driver is closed source, the definition of this
-struct happened to appear in the Apple PowerManagement project at around
-version 211, and soon after disappeared. It can be seen in the PrivateLib.c
-file under pmconfigd.
-
-https://www.opensource.apple.com/source/PowerManagement/PowerManagement-211/
-*/
-typedef struct {
- uint32_t key;
- SMCVersion vers;
- SMCPLimitData pLimitData;
- SMCKeyInfoData keyInfo;
- uint8_t result;
- uint8_t status;
- uint8_t data8;
- uint32_t data32;
- uint8_t bytes[32];
-} SMCParamStruct;
-
-
-/**
-Used for returning data from the SMC.
-*/
-typedef struct {
- uint8_t data[32];
- uint32_t dataType;
- uint32_t dataSize;
- kSMC_t kSMC;
-} smc_return_t;
-
-
-//------------------------------------------------------------------------------
-// MARK: HELPERS - TYPE CONVERSION
-//------------------------------------------------------------------------------
-
-
-/**
-Convert data from SMC of fpe2 type to human readable.
-
-:param: data Data from the SMC to be converted. Assumed data size of 2.
-:returns: Converted data
-*/
-static unsigned int from_fpe2(uint8_t data[32])
-{
- unsigned int ans = 0;
-
- // Data type for fan calls - fpe2
- // This is assumend to mean floating point, with 2 exponent bits
- // http://stackoverflow.com/questions/22160746/fpe2-and-sp78-data-types
- ans += data[0] << 6;
- ans += data[1] << 2;
-
- return ans;
-}
-
-
-/**
-Convert to fpe2 data type to be passed to SMC.
-
-:param: val Value to convert
-:param: data Pointer to data array to place result
-*/
-static void to_fpe2(unsigned int val, uint8_t *data)
-{
- data[0] = val >> 6;
- data[1] = (val << 2) ^ (data[0] << 8);
-}
-
-
-/**
-Convert SMC key to uint32_t. This must be done to pass it to the SMC.
-
-:param: key The SMC key to convert
-:returns: uint32_t translation.
- Returns zero if key is not 4 characters in length.
-*/
-static uint32_t to_uint32_t(char *key)
-{
- uint32_t ans = 0;
- uint32_t shift = 24;
-
- // SMC key is expected to be 4 bytes - thus 4 chars
- if (strlen(key) != SMC_KEY_SIZE) {
- return 0;
- }
-
- for (int i = 0; i < SMC_KEY_SIZE; i++) {
- ans += key[i] << shift;
- shift -= 8;
- }
-
- return ans;
-}
-
-
-/**
-For converting the dataType return from the SMC to human readable 4 byte
-multi-character constant.
-*/
-static void to_string(uint32_t val, char *dataType)
-{
- int shift = 24;
-
- for (int i = 0; i < DATA_TYPE_SIZE; i++) {
- // To get each char, we shift it into the lower 8 bits, and then & by
- // 255 to insolate it
- dataType[i] = (val >> shift) & 0xff;
- shift -= 8;
- }
-}
-
-
-//------------------------------------------------------------------------------
-// MARK: HELPERS - TMP CONVERSION
-//------------------------------------------------------------------------------
-
-
-/**
-Celsius to Fahrenheit
-*/
-static double to_fahrenheit(double tmp)
-{
- // http://en.wikipedia.org/wiki/Fahrenheit#Definition_and_conversions
- return (tmp * 1.8) + 32;
-}
-
-
-/**
-Celsius to Kelvin
-*/
-static double to_kelvin(double tmp)
-{
- // http://en.wikipedia.org/wiki/Kelvin
- return tmp + 273.15;
-}
-
-
-//------------------------------------------------------------------------------
-// MARK: "PRIVATE" FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-/**
-Make a call to the SMC
-
-:param: inputStruct Struct that holds data telling the SMC what you want
-:param: outputStruct Struct holding the SMC's response
-:returns: I/O Kit return code
-*/
-static kern_return_t call_smc(SMCParamStruct *inputStruct,
- SMCParamStruct *outputStruct)
-{
- kern_return_t result;
- size_t inputStructCnt = sizeof(SMCParamStruct);
- size_t outputStructCnt = sizeof(SMCParamStruct);
-
- result = IOConnectCallStructMethod(conn, kSMCHandleYPCEvent,
- inputStruct,
- inputStructCnt,
- outputStruct,
- &outputStructCnt);
-
- if (result != kIOReturnSuccess) {
- // IOReturn error code lookup. See "Accessing Hardware From Applications
- // -> Handling Errors" Apple doc
- result = err_get_code(result);
- }
-
- return result;
-}
-
-
-/**
-Read data from the SMC
-
-:param: key The SMC key
-*/
-static kern_return_t read_smc(char *key, smc_return_t *result_smc)
-{
- kern_return_t result;
- SMCParamStruct inputStruct;
- SMCParamStruct outputStruct;
-
- memset(&inputStruct, 0, sizeof(SMCParamStruct));
- memset(&outputStruct, 0, sizeof(SMCParamStruct));
- memset(result_smc, 0, sizeof(smc_return_t));
-
- // First call to AppleSMC - get key info
- inputStruct.key = to_uint32_t(key);
- inputStruct.data8 = kSMCGetKeyInfo;
-
- result = call_smc(&inputStruct, &outputStruct);
- result_smc->kSMC = outputStruct.result;
-
- if (result != kIOReturnSuccess || outputStruct.result != kSMCSuccess) {
- return result;
- }
-
- // Store data for return
- result_smc->dataSize = outputStruct.keyInfo.dataSize;
- result_smc->dataType = outputStruct.keyInfo.dataType;
-
-
- // Second call to AppleSMC - now we can get the data
- inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize;
- inputStruct.data8 = kSMCReadKey;
-
- result = call_smc(&inputStruct, &outputStruct);
- result_smc->kSMC = outputStruct.result;
-
- if (result != kIOReturnSuccess || outputStruct.result != kSMCSuccess) {
- return result;
- }
-
- memcpy(result_smc->data, outputStruct.bytes, sizeof(outputStruct.bytes));
-
- return result;
-}
-
-
-/**
-Write data to the SMC.
-
-:returns: IOReturn IOKit return code
-*/
-static kern_return_t write_smc(char *key, smc_return_t *result_smc)
-{
- kern_return_t result;
- SMCParamStruct inputStruct;
- SMCParamStruct outputStruct;
-
- memset(&inputStruct, 0, sizeof(SMCParamStruct));
- memset(&outputStruct, 0, sizeof(SMCParamStruct));
-
- // First call to AppleSMC - get key info
- inputStruct.key = to_uint32_t(key);
- inputStruct.data8 = kSMCGetKeyInfo;
-
- result = call_smc(&inputStruct, &outputStruct);
- result_smc->kSMC = outputStruct.result;
-
- if (result != kIOReturnSuccess || outputStruct.result != kSMCSuccess) {
- return result;
- }
-
- // Check data is correct
- if (result_smc->dataSize != outputStruct.keyInfo.dataSize ||
- result_smc->dataType != outputStruct.keyInfo.dataType) {
- return kIOReturnBadArgument;
- }
-
- // Second call to AppleSMC - now we can write the data
- inputStruct.data8 = kSMCWriteKey;
- inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize;
-
- // Set data to write
- memcpy(inputStruct.bytes, result_smc->data, sizeof(result_smc->data));
-
- result = call_smc(&inputStruct, &outputStruct);
- result_smc->kSMC = outputStruct.result;
-
- return result;
-}
-
-
-/**
-Get the model name of the machine.
-*/
-static kern_return_t get_machine_model(io_name_t model)
-{
- io_service_t service;
- kern_return_t result;
-
- service = IOServiceGetMatchingService(kIOMasterPortDefault,
- IOServiceMatching(IOSERVICE_MODEL));
-
- if (service == 0) {
- printf("ERROR: %s NOT FOUND\n", IOSERVICE_MODEL);
- return kIOReturnError;
- }
-
- // Get the model name
- result = IORegistryEntryGetName(service, model);
- IOObjectRelease(service);
-
- return result;
-}
-
-
-//------------------------------------------------------------------------------
-// MARK: "PUBLIC" FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-kern_return_t open_smc(void)
-{
- kern_return_t result;
- io_service_t service;
-
- service = IOServiceGetMatchingService(kIOMasterPortDefault,
- IOServiceMatching(IOSERVICE_SMC));
-
- if (service == 0) {
- // NOTE: IOServiceMatching documents 0 on failure
- printf("ERROR: %s NOT FOUND\n", IOSERVICE_SMC);
- return kIOReturnError;
- }
-
- result = IOServiceOpen(service, mach_task_self(), 0, &conn);
- IOObjectRelease(service);
-
- return result;
-}
-
-
-kern_return_t close_smc(void)
-{
- return IOServiceClose(conn);
-}
-
-
-bool is_key_valid(char *key)
-{
- bool ans = false;
- kern_return_t result;
- smc_return_t result_smc;
-
- if (strlen(key) != SMC_KEY_SIZE) {
- printf("ERROR: Invalid key size - must be 4 chars\n");
- return ans;
- }
-
- // Try a read and see if it succeeds
- result = read_smc(key, &result_smc);
-
- if (result == kIOReturnSuccess && result_smc.kSMC == kSMCSuccess) {
- ans = true;
- }
-
- return ans;
-}
-
-
-double get_tmp(char *key, tmp_unit_t unit)
-{
- kern_return_t result;
- smc_return_t result_smc;
-
- result = read_smc(key, &result_smc);
-
- if (!(result == kIOReturnSuccess &&
- result_smc.dataSize == 2 &&
- result_smc.dataType == to_uint32_t(DATA_TYPE_SP78))) {
- // Error
- return 0.0;
- }
-
- // TODO: Create from_sp78() convert function
- double tmp = result_smc.data[0];
-
- switch (unit) {
- case CELSIUS:
- break;
- case FAHRENHEIT:
- tmp = to_fahrenheit(tmp);
- break;
- case KELVIN:
- tmp = to_kelvin(tmp);
- break;
- }
-
- return tmp;
-}
-
-
-bool is_battery_powered(void)
-{
- kern_return_t result;
- smc_return_t result_smc;
-
- result = read_smc(BATT_PWR, &result_smc);
-
- if (!(result == kIOReturnSuccess &&
- result_smc.dataSize == 1 &&
- result_smc.dataType == to_uint32_t(DATA_TYPE_FLAG))) {
- // Error
- return false;
- }
-
- return result_smc.data[0];
-}
-
-
-bool is_optical_disk_drive_full(void)
-{
- kern_return_t result;
- smc_return_t result_smc;
-
- result = read_smc(ODD_FULL, &result_smc);
-
- if (!(result == kIOReturnSuccess &&
- result_smc.dataSize == 1 &&
- result_smc.dataType == to_uint32_t(DATA_TYPE_FLAG))) {
- // Error
- return false;
- }
-
- return result_smc.data[0];
-}
-
-
-//------------------------------------------------------------------------------
-// MARK: FAN FUNCTIONS
-//------------------------------------------------------------------------------
-
-
-bool get_fan_name(unsigned int fan_num, fan_name_t name)
-{
- char key[5];
- kern_return_t result;
- smc_return_t result_smc;
-
- sprintf(key, "F%dID", fan_num);
- result = read_smc(key, &result_smc);
-
- if (!(result == kIOReturnSuccess &&
- result_smc.dataSize == 16 &&
- result_smc.dataType == to_uint32_t(DATA_TYPE_SFDS))) {
- return false;
- }
-
-
- /*
- We know the data size is 16 bytes and the type is "{fds", a custom
- struct defined by the AppleSMC.kext. See TMP enum sources for the
- struct.
-
- The last 12 bytes contain the name of the fan, an array of chars, hence
- the loop range.
- */
- int index = 0;
- for (int i = 4; i < 16; i++) {
- // Check if at the end (name may not be full 12 bytes)
- // Could check for 0 (null), but instead we check for 32 (space). This
- // is a hack to remove whitespace. :)
- if (result_smc.data[i] == 32) {
- break;
- }
-
- name[index] = result_smc.data[i];
- index++;
- }
-
- return true;
-}
-
-
-int get_num_fans(void)
-{
- kern_return_t result;
- smc_return_t result_smc;
-
- result = read_smc(NUM_FANS, &result_smc);
-
- if (!(result == kIOReturnSuccess &&
- result_smc.dataSize == 1 &&
- result_smc.dataType == to_uint32_t(DATA_TYPE_UINT8))) {
- // Error
- return -1;
- }
-
- return result_smc.data[0];
-}
-
-
-unsigned int get_fan_rpm(unsigned int fan_num)
-{
- char key[5];
- kern_return_t result;
- smc_return_t result_smc;
-
- sprintf(key, "F%dAc", fan_num);
- result = read_smc(key, &result_smc);
-
- if (!(result == kIOReturnSuccess &&
- result_smc.dataSize == 2 &&
- result_smc.dataType == to_uint32_t(DATA_TYPE_FPE2))) {
- // Error
- return 0;
- }
-
- return from_fpe2(result_smc.data);
-}
-
-
-bool set_fan_min_rpm(unsigned int fan_num, unsigned int rpm, bool auth)
-{
- // TODO: Add rpm val safety check
- char key[5];
- bool ans = false;
- kern_return_t result;
- smc_return_t result_smc;
-
- memset(&result_smc, 0, sizeof(smc_return_t));
-
- // TODO: Don't use magic number
- result_smc.dataSize = 2;
- result_smc.d