From 413674db3234bfc4587f87f99b1f5450af9d22ae Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Mon, 6 Apr 2020 18:22:12 +0200 Subject: [PATCH] - remove removable disks (dmg) from disk list; - rename Temperature module to Sensors; - fix ordering in temperature sensors list; - rewrote SMC from C to Swift; - now sensors list load automatically; - removed all C code; --- Stats.xcodeproj/project.pbxproj | 54 ++-- Stats/AppDelegate.swift | 10 +- Stats/MenuBar.swift | 2 +- Stats/Modules/Disk/DiskCapacityReader.swift | 12 +- Stats/Modules/Disk/DiskMenu.swift | 20 +- Stats/Modules/Module.swift | 4 +- Stats/Modules/Network/NetworkPopup.swift | 8 +- .../Sensors.swift} | 71 +++-- Stats/Modules/Sensors/SensorsMenu.swift | 151 ++++++++++ Stats/Modules/Sensors/SensorsType.swift | 151 ++++++++++ .../Modules/Temperature/TemperatureMenu.swift | 208 ------------- .../Temperature/TemperatureReader.swift | 44 --- .../SensorsWidget.swift} | 10 +- Stats/Widgets/Widget.swift | 2 +- Stats/libs/Extensions.swift | 51 +++- Stats/libs/SMC.c | 255 ---------------- Stats/libs/SMC.h | 273 ------------------ Stats/libs/SMC.swift | 254 ++++++++++++++++ Stats/libs/Stats.h | 2 - 19 files changed, 707 insertions(+), 875 deletions(-) rename Stats/Modules/{Temperature/Temperature.swift => Sensors/Sensors.swift} (59%) create mode 100644 Stats/Modules/Sensors/SensorsMenu.swift create mode 100644 Stats/Modules/Sensors/SensorsType.swift delete mode 100644 Stats/Modules/Temperature/TemperatureMenu.swift delete mode 100644 Stats/Modules/Temperature/TemperatureReader.swift rename Stats/Widgets/{Temperature/TemperatureWidget.swift => Sensors/SensorsWidget.swift} (96%) delete mode 100644 Stats/libs/SMC.c delete mode 100644 Stats/libs/SMC.h create mode 100644 Stats/libs/SMC.swift diff --git a/Stats.xcodeproj/project.pbxproj b/Stats.xcodeproj/project.pbxproj index 66af39ae..a3f798ea 100644 --- a/Stats.xcodeproj/project.pbxproj +++ b/Stats.xcodeproj/project.pbxproj @@ -51,11 +51,11 @@ 9A6CFC0122A1C9F5001E782D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A6CFC0022A1C9F5001E782D /* Assets.xcassets */; }; 9A74D59722B44498004FE1FA /* Mini.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A74D59622B44498004FE1FA /* Mini.swift */; }; 9A79B36A22D3BEE600BF1C3A /* Widget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A79B36922D3BEE600BF1C3A /* Widget.swift */; }; - 9AA28DC1243774ED00D2B196 /* Temperature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DC0243774ED00D2B196 /* Temperature.swift */; }; - 9AA28DC32437752D00D2B196 /* TemperatureMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DC22437752D00D2B196 /* TemperatureMenu.swift */; }; - 9AA28DC52437762C00D2B196 /* TemperatureReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DC42437762C00D2B196 /* TemperatureReader.swift */; }; - 9AA28DCF2437884200D2B196 /* SMC.c in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DCE2437884200D2B196 /* SMC.c */; }; - 9AA28DD1243799E500D2B196 /* TemperatureWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DD0243799E500D2B196 /* TemperatureWidget.swift */; }; + 9AA28DC1243774ED00D2B196 /* Sensors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DC0243774ED00D2B196 /* Sensors.swift */; }; + 9AA28DC32437752D00D2B196 /* SensorsMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DC22437752D00D2B196 /* SensorsMenu.swift */; }; + 9AA28DD1243799E500D2B196 /* SensorsWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DD0243799E500D2B196 /* SensorsWidget.swift */; }; + 9AA28DD6243A8A3D00D2B196 /* SMC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DD5243A8A3D00D2B196 /* SMC.swift */; }; + 9AA28DDB243B4AF500D2B196 /* SensorsType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AA28DDA243B4AF500D2B196 /* SensorsType.swift */; }; 9AF0F31B22DA924000026AE6 /* LineChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F31A22DA924000026AE6 /* LineChart.swift */; }; 9AF0F31D22DA925000026AE6 /* LineChartWithValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F31C22DA925000026AE6 /* LineChartWithValue.swift */; }; 9AF0F31F22DA925700026AE6 /* BarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F31E22DA925700026AE6 /* BarChart.swift */; }; @@ -144,13 +144,12 @@ 9A79B36922D3BEE600BF1C3A /* Widget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widget.swift; sourceTree = ""; }; 9A998CD722A199920087ADE7 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 9A998CD922A199970087ADE7 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; - 9AA28DC0243774ED00D2B196 /* Temperature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Temperature.swift; sourceTree = ""; }; - 9AA28DC22437752D00D2B196 /* TemperatureMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemperatureMenu.swift; sourceTree = ""; }; - 9AA28DC42437762C00D2B196 /* TemperatureReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemperatureReader.swift; sourceTree = ""; }; + 9AA28DC0243774ED00D2B196 /* Sensors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sensors.swift; sourceTree = ""; }; + 9AA28DC22437752D00D2B196 /* SensorsMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorsMenu.swift; sourceTree = ""; }; 9AA28DC9243780C500D2B196 /* Stats.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Stats.h; sourceTree = ""; }; - 9AA28DCD2437884200D2B196 /* SMC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SMC.h; sourceTree = ""; }; - 9AA28DCE2437884200D2B196 /* SMC.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SMC.c; sourceTree = ""; }; - 9AA28DD0243799E500D2B196 /* TemperatureWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemperatureWidget.swift; sourceTree = ""; }; + 9AA28DD0243799E500D2B196 /* SensorsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorsWidget.swift; sourceTree = ""; }; + 9AA28DD5243A8A3D00D2B196 /* SMC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMC.swift; sourceTree = ""; }; + 9AA28DDA243B4AF500D2B196 /* SensorsType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorsType.swift; sourceTree = ""; }; 9AF0F31A22DA924000026AE6 /* LineChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChart.swift; sourceTree = ""; }; 9AF0F31C22DA925000026AE6 /* LineChartWithValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChartWithValue.swift; sourceTree = ""; }; 9AF0F31E22DA925700026AE6 /* BarChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarChart.swift; sourceTree = ""; }; @@ -295,7 +294,7 @@ 9A2D15F123CE390500C4C417 /* Disk */, 9A2D15F823CE3BDA00C4C417 /* Battery */, 9A2D160123CE444D00C4C417 /* Network */, - 9AA28DBF243774DD00D2B196 /* Temperature */, + 9AA28DBF243774DD00D2B196 /* Sensors */, 9A2D15D123CCEC7600C4C417 /* Module.swift */, ); path = Modules; @@ -304,8 +303,7 @@ 9A5B1CBD229E78D2008B9D3C /* libs */ = { isa = PBXGroup; children = ( - 9AA28DCD2437884200D2B196 /* SMC.h */, - 9AA28DCE2437884200D2B196 /* SMC.c */, + 9AA28DD5243A8A3D00D2B196 /* SMC.swift */, 9A5B1CC4229E7B40008B9D3C /* Extensions.swift */, 9A426DB722C2B5EE00C064C4 /* MacAppUpdater.swift */, 9A59AE55231EE02F007989D6 /* ChartMarker.swift */, @@ -321,7 +319,7 @@ 9A54EF65232AB48100F7DC20 /* Battery */, 9AF0F31922DA923100026AE6 /* Network */, 9AF0F31822DA922800026AE6 /* Charts */, - 9AA28DD224379F8700D2B196 /* Temperature */, + 9AA28DD224379F8700D2B196 /* Sensors */, 9A74D59622B44498004FE1FA /* Mini.swift */, 9A79B36922D3BEE600BF1C3A /* Widget.swift */, ); @@ -341,22 +339,22 @@ name = Frameworks; sourceTree = ""; }; - 9AA28DBF243774DD00D2B196 /* Temperature */ = { + 9AA28DBF243774DD00D2B196 /* Sensors */ = { isa = PBXGroup; children = ( - 9AA28DC0243774ED00D2B196 /* Temperature.swift */, - 9AA28DC22437752D00D2B196 /* TemperatureMenu.swift */, - 9AA28DC42437762C00D2B196 /* TemperatureReader.swift */, + 9AA28DC0243774ED00D2B196 /* Sensors.swift */, + 9AA28DC22437752D00D2B196 /* SensorsMenu.swift */, + 9AA28DDA243B4AF500D2B196 /* SensorsType.swift */, ); - path = Temperature; + path = Sensors; sourceTree = ""; }; - 9AA28DD224379F8700D2B196 /* Temperature */ = { + 9AA28DD224379F8700D2B196 /* Sensors */ = { isa = PBXGroup; children = ( - 9AA28DD0243799E500D2B196 /* TemperatureWidget.swift */, + 9AA28DD0243799E500D2B196 /* SensorsWidget.swift */, ); - path = Temperature; + path = Sensors; sourceTree = ""; }; 9AF0F31822DA922800026AE6 /* Charts */ = { @@ -518,10 +516,10 @@ 9A2D15E623CE291600C4C417 /* RAM.swift in Sources */, 9A09C8A222B3D94D0018426F /* BatteryWidget.swift in Sources */, 9A5349C723D8535900C23824 /* NetworkPopup.swift in Sources */, - 9AA28DC32437752D00D2B196 /* TemperatureMenu.swift in Sources */, + 9AA28DC32437752D00D2B196 /* SensorsMenu.swift in Sources */, 9A426DB822C2B5EE00C064C4 /* MacAppUpdater.swift in Sources */, 9A606B4C232157BA00642F51 /* AboutViewController.swift in Sources */, - 9AA28DC1243774ED00D2B196 /* Temperature.swift in Sources */, + 9AA28DC1243774ED00D2B196 /* Sensors.swift in Sources */, 9AF0F32522DA92C400026AE6 /* NetworkText.swift in Sources */, 9AF0F32322DA92B900026AE6 /* NetworkArrows.swift in Sources */, 9A2D15D223CCEC7600C4C417 /* Module.swift in Sources */, @@ -530,11 +528,10 @@ 9A606B4A2321577400642F51 /* UpdatesViewController.swift in Sources */, 9AF0F31D22DA925000026AE6 /* LineChartWithValue.swift in Sources */, 9A2D160723CE462400C4C417 /* NetworkReader.swift in Sources */, - 9AA28DD1243799E500D2B196 /* TemperatureWidget.swift in Sources */, + 9AA28DD6243A8A3D00D2B196 /* SMC.swift in Sources */, + 9AA28DD1243799E500D2B196 /* SensorsWidget.swift in Sources */, 9A2D15FA23CE3BE600C4C417 /* Battery.swift in Sources */, 9A54EF67232AB81800F7DC20 /* BatteryPercentageWidget.swift in Sources */, - 9AA28DCF2437884200D2B196 /* SMC.c in Sources */, - 9AA28DC52437762C00D2B196 /* TemperatureReader.swift in Sources */, 9A57A18522A1D26D0033E318 /* MenuBar.swift in Sources */, 9A2D15D923CD036400C4C417 /* CPUMenu.swift in Sources */, 9AF6F1FE231D732600B8E1E4 /* PopupViewController.swift in Sources */, @@ -558,6 +555,7 @@ 9A74D59722B44498004FE1FA /* Mini.swift in Sources */, 9A5B1CC5229E7B40008B9D3C /* Extensions.swift in Sources */, 9A2D15E123CD133300C4C417 /* CPUUsageReader.swift in Sources */, + 9AA28DDB243B4AF500D2B196 /* SensorsType.swift in Sources */, 9A2D15D523CCEFF700C4C417 /* CPU.swift in Sources */, 9A2D15E323CD1E4B00C4C417 /* CPUProcessReader.swift in Sources */, 9A2D15EA23CE2C1100C4C417 /* RAMPopup.swift in Sources */, diff --git a/Stats/AppDelegate.swift b/Stats/AppDelegate.swift index ccb5d55c..ff51aa9c 100755 --- a/Stats/AppDelegate.swift +++ b/Stats/AppDelegate.swift @@ -12,6 +12,7 @@ import LaunchAtLogin let updater = macAppUpdater(user: "exelban", repo: "stats") var menuBar: MenuBar? +let smc = SMCService() @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { @@ -20,7 +21,12 @@ class AppDelegate: NSObject, NSApplicationDelegate { private let popover = NSPopover() func applicationDidFinishLaunching(_ aNotification: Notification) { - SMCOpen(); + let res = smc.open() + if res != kIOReturnSuccess { + print("ERROR open SMC") + NSApp.terminate(nil) + return + } guard let menuBarButton = self.menuBarItem.button else { NSApp.terminate(nil) @@ -42,7 +48,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { } func applicationWillTerminate(_ aNotification: Notification) { - SMCClose() +// SMCClose() menuBar?.destroy() } diff --git a/Stats/MenuBar.swift b/Stats/MenuBar.swift index 9b5af8a0..be6bd376 100644 --- a/Stats/MenuBar.swift +++ b/Stats/MenuBar.swift @@ -13,7 +13,7 @@ import ServiceManagement Class keeps a status bar item and has the main function for updating widgets. */ class MenuBar { - public let modules: [Module] = [CPU(), RAM(), Temperature(), Disk(), Battery(), Network()] + public let modules: [Module] = [CPU(), RAM(), Sensors(), Disk(), Battery(), Network()] private let menuBarItem: NSStatusItem private var menuBarButton: NSButton = NSButton() diff --git a/Stats/Modules/Disk/DiskCapacityReader.swift b/Stats/Modules/Disk/DiskCapacityReader.swift index 47453834..ee9f49d1 100644 --- a/Stats/Modules/Disk/DiskCapacityReader.swift +++ b/Stats/Modules/Disk/DiskCapacityReader.swift @@ -96,7 +96,9 @@ class DiskCapacityReader: Reader { continue } - self.disks.list.append(getDisk(disk)) + if let d = getDisk(disk) { + self.disks.list.append(d) + } } } } @@ -111,7 +113,7 @@ class DiskCapacityReader: Reader { self.enabled = value } - private func getDisk(_ disk: DADisk) -> diskInfo { + private func getDisk(_ disk: DADisk) -> diskInfo? { var d: diskInfo = diskInfo() if let bsdName = DADiskGetBSDName(disk) { @@ -120,6 +122,12 @@ class DiskCapacityReader: Reader { if let diskDescription = DADiskCopyDescription(disk) { if let dict = diskDescription as? [String: AnyObject] { + if let removable = dict[kDADiskDescriptionMediaRemovableKey as String] { + if removable as! Bool { + return nil + } + } + if let mediaName = dict[kDADiskDescriptionMediaNameKey as String] { d.name = mediaName as! String } diff --git a/Stats/Modules/Disk/DiskMenu.swift b/Stats/Modules/Disk/DiskMenu.swift index 2c61ae57..42ac543d 100644 --- a/Stats/Modules/Disk/DiskMenu.swift +++ b/Stats/Modules/Disk/DiskMenu.swift @@ -20,16 +20,18 @@ extension Disk { } menu.target = self - self.disks.list.forEach { (d: diskInfo) in - let disk = NSMenuItem(title: d.name, action: #selector(toggleDisk), keyEquivalent: "") - if self.selectedDisk == "" && d.root { - disk.state = NSControl.StateValue.on - } else { - disk.state = self.selectedDisk == d.mediaBSDName ? NSControl.StateValue.on : NSControl.StateValue.off + if self.disks.list.count > 1 { + self.disks.list.forEach { (d: diskInfo) in + let disk = NSMenuItem(title: d.name, action: #selector(toggleDisk), keyEquivalent: "") + if self.selectedDisk == "" && d.root { + disk.state = NSControl.StateValue.on + } else { + disk.state = self.selectedDisk == d.mediaBSDName ? NSControl.StateValue.on : NSControl.StateValue.off + } + disk.target = self + + submenu.addItem(disk) } - disk.target = self - - submenu.addItem(disk) } let mini = NSMenuItem(title: "Mini", action: #selector(toggleWidget), keyEquivalent: "") diff --git a/Stats/Modules/Module.swift b/Stats/Modules/Module.swift index 07d76885..822aabe5 100644 --- a/Stats/Modules/Module.swift +++ b/Stats/Modules/Module.swift @@ -74,8 +74,8 @@ extension Module { switch self.widget.type { case Widgets.Mini: widget = Mini() - case Widgets.Temperature: - widget = TemperatureWidget() + case Widgets.Sensors: + widget = SensorsWidget() case Widgets.Chart: widget = Chart() case Widgets.ChartWithValue: diff --git a/Stats/Modules/Network/NetworkPopup.swift b/Stats/Modules/Network/NetworkPopup.swift index 1a7b66fc..44ffd5a6 100644 --- a/Stats/Modules/Network/NetworkPopup.swift +++ b/Stats/Modules/Network/NetworkPopup.swift @@ -59,7 +59,9 @@ extension Network { marker.chartView = self.chart self.chart.marker = marker - let download = LineChartDataSet(label: "Download") + var downloadLineChartEntry = [ChartDataEntry]() + downloadLineChartEntry.append(ChartDataEntry(x: 0, y: 0)) + let download = LineChartDataSet(entries: downloadLineChartEntry, label: "Download") download.drawCirclesEnabled = false download.mode = .cubicBezier download.cubicIntensity = 0.1 @@ -67,7 +69,9 @@ extension Network { download.fillColor = downloadGradientColor download.drawFilledEnabled = true - let upload = LineChartDataSet(label: "Upload") + var uploadLineChartEntry = [ChartDataEntry]() + uploadLineChartEntry.append(ChartDataEntry(x: 0, y: 0)) + let upload = LineChartDataSet(entries: uploadLineChartEntry, label: "Upload") upload.drawCirclesEnabled = false upload.mode = .cubicBezier upload.cubicIntensity = 0.1 diff --git a/Stats/Modules/Temperature/Temperature.swift b/Stats/Modules/Sensors/Sensors.swift similarity index 59% rename from Stats/Modules/Temperature/Temperature.swift rename to Stats/Modules/Sensors/Sensors.swift index 57ba6473..5e3c2057 100644 --- a/Stats/Modules/Temperature/Temperature.swift +++ b/Stats/Modules/Sensors/Sensors.swift @@ -1,5 +1,5 @@ // -// Temperature.swift +// Sensors.swift // Stats // // Created by Serhiy Mytrovtsiy on 03/04/2020. @@ -8,8 +8,8 @@ import Cocoa -class Temperature: Module { - public var name: String = "Temperature" +class Sensors: Module { + public var name: String = "Sensors" public var updateInterval: Double = 1 public var enabled: Bool = true @@ -25,66 +25,73 @@ class Temperature: Module { internal let defaults = UserDefaults.standard internal var submenu: NSMenu = NSMenu() - internal var value_1: String = "cpu_1_diode" - internal var value_2: String = "gpu_diode" + internal var value_1: String = "TC0P" + internal var value_2: String = "TG0D" internal var once: Int = 0 + internal var sensors: Sensors_t = Sensors_t() + init() { if !self.available { return } self.enabled = defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true - self.widget.type = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Temperature + self.widget.type = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Sensors self.value_1 = (defaults.object(forKey: "\(name)_value_1") != nil ? defaults.string(forKey: "\(name)_value_1")! : value_1) self.value_2 = (defaults.object(forKey: "\(name)_value_2") != nil ? defaults.string(forKey: "\(name)_value_2")! : value_2) - self.initGroups() self.initWidget() self.initMenu() - - readers.append(TemperatureReader(self.usageUpdater)) + + if self.enabled { + self.update() + } self.task = Repeater.init(interval: .seconds(self.updateInterval), observer: { _ in - self.readers.forEach { reader in - reader.read() + if self.enabled { + self.update() } }) } - func start() { + public func start() { if self.task != nil && self.task!.state.isRunning == false { self.task!.start() } } - func stop() { + public func stop() { if self.task!.state.isRunning { self.task?.pause() } } - func restart() { + public func restart() { self.stop() self.start() } - private func usageUpdater(value: Temperatures) { - if self.widget.view is Widget { - DispatchQueue.main.async(execute: { - var value_1: Double = 0 - var value_2: Double = 0 - - let v1 = value.asDictionary.first { $0.key == self.value_1 } - let v2 = value.asDictionary.first { $0.key == self.value_2 } - - if v1 != nil { - value_1 = v1!.value as! Double - } - if v2 != nil { - value_2 = v2!.value as! Double - } - - (self.widget.view as! Widget).setValue(data: [value_1, value_2]) - }) + private func update() { + var value_1: Double = 0 + var value_2: Double = 0 + + var sensor_1: Sensor_t? = self.sensors.find(byKey: self.value_1) + var sensor_2: Sensor_t? = self.sensors.find(byKey: self.value_2) + + if sensor_1 != nil { + sensor_1!.update() + if sensor_1!.value != nil { + value_1 = sensor_1!.value! + } } + if sensor_2 != nil { + sensor_2!.update() + if sensor_2!.value != nil { + value_2 = sensor_2!.value! + } + } + + DispatchQueue.main.async(execute: { + (self.widget.view as! Widget).setValue(data: [value_1, value_2]) + }) } } diff --git a/Stats/Modules/Sensors/SensorsMenu.swift b/Stats/Modules/Sensors/SensorsMenu.swift new file mode 100644 index 00000000..20c31601 --- /dev/null +++ b/Stats/Modules/Sensors/SensorsMenu.swift @@ -0,0 +1,151 @@ +// +// SensorsMenu.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 03/04/2020. +// Copyright © 2020 Serhiy Mytrovtsiy. All rights reserved. +// + +extension Sensors { + public func initMenu() { + menu = NSMenuItem(title: name, action: #selector(toggle), keyEquivalent: "") + submenu = NSMenu() + + if defaults.object(forKey: name) != nil { + menu.state = defaults.bool(forKey: name) ? NSControl.StateValue.on : NSControl.StateValue.off + } else { + menu.state = NSControl.StateValue.on + } + menu.target = self + + let sensor_1: NSMenuItem = NSMenuItem(title: "Sensor #1", action: nil, keyEquivalent: "") + sensor_1.target = self + sensor_1.submenu = NSMenu() + addSensorsMennu(sensor_1.submenu!, value: self.value_1, action: #selector(toggleValue1)) + + let sensor_2: NSMenuItem = NSMenuItem(title: "Sensor #2", action: nil, keyEquivalent: "") + sensor_2.target = self + sensor_2.submenu = NSMenu() + addSensorsMennu(sensor_2.submenu!, value: self.value_2, action: #selector(toggleValue2)) + + submenu.addItem(sensor_1) + submenu.addItem(sensor_2) + + submenu.addItem(NSMenuItem.separator()) + + if let view = self.widget.view as? Widget { + for widgetMenu in view.menus { + submenu.addItem(widgetMenu) + } + } + + if self.enabled { + menu.submenu = submenu + } + } + + private func addSensorsMennu(_ menu: NSMenu, value: String, action: Selector?) { + var sensorsMenu: NSMenuItem? = generateSensorsMenu(type: SensorType.Temperature, value: value, action: action) + if sensorsMenu != nil { + menu.addItem(sensorsMenu!) + } + sensorsMenu = generateSensorsMenu(type: SensorType.Voltage, value: value, action: action) + if sensorsMenu != nil { + menu.addItem(sensorsMenu!) + } + sensorsMenu = generateSensorsMenu(type: SensorType.Power, value: value, action: action) + if sensorsMenu != nil { + menu.addItem(sensorsMenu!) + } + } + + private func generateSensorsMenu(type: SensorType, value: String, action: Selector?) -> NSMenuItem? { + let list: [Sensor_t] = self.sensors.list.filter{ $0.type == type.rawValue } + if list.isEmpty { + return nil + } + + let mainItem: NSMenuItem = NSMenuItem(title: type.rawValue, action: nil, keyEquivalent: "") + mainItem.target = self + mainItem.submenu = NSMenu() + + var groups: [SensorGroup_t] = [] + list.forEach { (s: Sensor_t) in + if !groups.contains(s.group) { + groups.append(s.group) + } + } + groups.sort() + + groups.forEach { (g: SensorGroup_t) in + mainItem.submenu!.addItem(NSMenuItem(title: g, action: nil, keyEquivalent: "")) + + list.filter{ $0.group == g }.forEach { (s: Sensor_t) in + let menuPoint: NSMenuItem = NSMenuItem(title: s.name, action: action, keyEquivalent: "") + menuPoint.state = s.key == value ? NSControl.StateValue.on : NSControl.StateValue.off + menuPoint.target = self + menuPoint.extraString = s.key + + mainItem.submenu!.addItem(menuPoint) + } + + mainItem.submenu!.addItem(NSMenuItem.separator()) + } + + return mainItem + } + + @objc func toggle(_ sender: NSMenuItem) { + let state = sender.state != NSControl.StateValue.on + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(state, forKey: name) + self.enabled = state + menuBar!.reload(name: self.name) + + if !state { + menu.submenu = nil + } else { + menu.submenu = submenu + } + + self.restart() + } + + @objc func toggleValue1(_ sender: NSMenuItem) { + let val: String = sender.extraString + if self.value_1 == val { + return + } + + let state = sender.state == NSControl.StateValue.on + for item in self.submenu.items { + item.state = NSControl.StateValue.off + } + + sender.state = state ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(val, forKey: "\(name)_value_1") + self.value_1 = val + self.initWidget() + self.initMenu() + menuBar!.reload(name: self.name) + } + + @objc func toggleValue2(_ sender: NSMenuItem) { + let val: String = sender.extraString + if self.value_2 == val { + return + } + + let state = sender.state == NSControl.StateValue.on + for item in self.submenu.items { + item.state = NSControl.StateValue.off + } + + sender.state = state ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(val, forKey: "\(name)_value_2") + self.value_2 = val + self.initWidget() + self.initMenu() + menuBar!.reload(name: self.name) + } +} diff --git a/Stats/Modules/Sensors/SensorsType.swift b/Stats/Modules/Sensors/SensorsType.swift new file mode 100644 index 00000000..036827d2 --- /dev/null +++ b/Stats/Modules/Sensors/SensorsType.swift @@ -0,0 +1,151 @@ +// +// SensorsType.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 06/04/2020. +// Copyright © 2020 Serhiy Mytrovtsiy. All rights reserved. +// + +typealias SensorGroup_t = String +enum SensorGroup: SensorGroup_t { + case CPU = "CPU" + case GPU = "GPU" + case System = "Systems" + case Sensor = "Sensors" +} + +typealias SensorType_t = String +enum SensorType: SensorType_t { + case Temperature = "Temperature" + case Voltage = "Voltage" + case Power = "Power" +} + +struct Sensor_t { + var name: String + var key: String = "" + + var group: SensorGroup_t + var type: SensorType_t + + var value: Double? = nil + + public mutating func update() { + self.value = smc.getValue(self.key) + } +} + +struct Sensors_t { + var list: [Sensor_t] = [] + + init() { + var available: [String] = smc.getAllKeys() + var sensor: Sensor_t? = nil + + available = available.filter({ (key: String) -> Bool in + switch key.prefix(1) { + case "T", "V", "P": return SensorsDict[key] != nil + default: return false + } + }) + + available.forEach { (key: String) in + sensor = SensorsDict[key] + if sensor != nil { + sensor!.value = smc.getValue(key) + if sensor!.value != nil { + sensor!.key = key + self.list.append(sensor!) + } + } + } + } + + public func find(byKey key: String) -> Sensor_t? { + return self.list.first{ $0.key == key} + } +} + +// List of keys: https://github.com/acidanthera/VirtualSMC/blob/master/Docs/SMCSensorKeys.txt +let SensorsDict: [String: Sensor_t] = [ + /// Temperature + "TA0P": Sensor_t(name: "Ambient 1", group: SensorGroup.Sensor.rawValue, type: SensorType.Temperature.rawValue), + "TA1P": Sensor_t(name: "Ambient 2", group: SensorGroup.Sensor.rawValue, type: SensorType.Temperature.rawValue), + "Th0H": Sensor_t(name: "Heatpipe 1", group: SensorGroup.Sensor.rawValue, type: SensorType.Temperature.rawValue), + "Th1H": Sensor_t(name: "Heatpipe 2", group: SensorGroup.Sensor.rawValue, type: SensorType.Temperature.rawValue), + "Th2H": Sensor_t(name: "Heatpipe 3", group: SensorGroup.Sensor.rawValue, type: SensorType.Temperature.rawValue), + "Th3H": Sensor_t(name: "Heatpipe 4", group: SensorGroup.Sensor.rawValue, type: SensorType.Temperature.rawValue), + "TZ0C": Sensor_t(name: "Termal zone 1", group: SensorGroup.Sensor.rawValue, type: SensorType.Temperature.rawValue), + "TZ1C": Sensor_t(name: "Termal zone 2", group: SensorGroup.Sensor.rawValue, type: SensorType.Temperature.rawValue), + + "TC0F": Sensor_t(name: "CPU die", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC0H": Sensor_t(name: "CPU heatsink", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC0P": Sensor_t(name: "CPU proximity", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC1C": Sensor_t(name: "CPU core 1", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC2C": Sensor_t(name: "CPU core 2", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC3C": Sensor_t(name: "CPU core 3", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC4C": Sensor_t(name: "CPU core 4", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC5C": Sensor_t(name: "CPU core 5", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC6C": Sensor_t(name: "CPU core 6", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC7C": Sensor_t(name: "CPU core 7", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + "TC8C": Sensor_t(name: "CPU core 8", group: SensorGroup.CPU.rawValue, type: SensorType.Temperature.rawValue), + + "TCGC": Sensor_t(name: "GPU Intel Graphics", group: SensorGroup.GPU.rawValue, type: SensorType.Temperature.rawValue), + "TG0D": Sensor_t(name: "GPU die", group: SensorGroup.GPU.rawValue, type: SensorType.Temperature.rawValue), + "TG0H": Sensor_t(name: "GPU heatsink", group: SensorGroup.GPU.rawValue, type: SensorType.Temperature.rawValue), + "TG0P": Sensor_t(name: "GPU proximity", group: SensorGroup.GPU.rawValue, type: SensorType.Temperature.rawValue), + + "Tm0P": Sensor_t(name: "Mainboard", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "Tp0P": Sensor_t(name: "Powerboard", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "TB1T": Sensor_t(name: "Battery", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "TW0P": Sensor_t(name: "Airport", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "TL0P": Sensor_t(name: "Display", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "TI0P": Sensor_t(name: "Thunderbold 1", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "TI1P": Sensor_t(name: "Thunderbold 2", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "TI2P": Sensor_t(name: "Thunderbold 3", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "TI3P": Sensor_t(name: "Thunderbold 4", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + + "TN0D": Sensor_t(name: "Northbridge die", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "TN0H": Sensor_t(name: "Northbridge heatsink", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + "TN0P": Sensor_t(name: "Northbridge proximity", group: SensorGroup.System.rawValue, type: SensorType.Temperature.rawValue), + + /// Voltage + "VCAC": Sensor_t(name: "CPU IA", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + "VCSC": Sensor_t(name: "CPU System Agent", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + "VC0C": Sensor_t(name: "CPU Core 1", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + "VC1C": Sensor_t(name: "CPU Core 2", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + "VC2C": Sensor_t(name: "CPU Core 3", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + "VC3C": Sensor_t(name: "CPU Core 4", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + "VC4C": Sensor_t(name: "CPU Core 5", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + "VC5C": Sensor_t(name: "CPU Core 6", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + "VC6C": Sensor_t(name: "CPU Core 7", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + "VC7C": Sensor_t(name: "CPU Core 8", group: SensorGroup.CPU.rawValue, type: SensorType.Voltage.rawValue), + + "VCTC": Sensor_t(name: "GPU Intel Graphics", group: SensorGroup.GPU.rawValue, type: SensorType.Voltage.rawValue), + "VG0C": Sensor_t(name: "GPU", group: SensorGroup.GPU.rawValue, type: SensorType.Voltage.rawValue), + + "VM0R": Sensor_t(name: "Memory", group: SensorGroup.System.rawValue, type: SensorType.Voltage.rawValue), + "VBAT": Sensor_t(name: "Battery", group: SensorGroup.System.rawValue, type: SensorType.Voltage.rawValue), + "Vb0R": Sensor_t(name: "CMOS", group: SensorGroup.System.rawValue, type: SensorType.Voltage.rawValue), + + "VD0R": Sensor_t(name: "DC In", group: SensorGroup.Sensor.rawValue, type: SensorType.Voltage.rawValue), + "VP0R": Sensor_t(name: "12V rail", group: SensorGroup.Sensor.rawValue, type: SensorType.Voltage.rawValue), + "Vp0C": Sensor_t(name: "12V vcc", group: SensorGroup.Sensor.rawValue, type: SensorType.Voltage.rawValue), + "VV2S": Sensor_t(name: "3V", group: SensorGroup.Sensor.rawValue, type: SensorType.Voltage.rawValue), + "VR3R": Sensor_t(name: "3.3V", group: SensorGroup.Sensor.rawValue, type: SensorType.Voltage.rawValue), + "VV1S": Sensor_t(name: "5V", group: SensorGroup.Sensor.rawValue, type: SensorType.Voltage.rawValue), + "VV9S": Sensor_t(name: "12V", group: SensorGroup.Sensor.rawValue, type: SensorType.Voltage.rawValue), + "VeES": Sensor_t(name: "PCI 12V", group: SensorGroup.Sensor.rawValue, type: SensorType.Voltage.rawValue), + + /// Power + "PCPC": Sensor_t(name: "CPU Package", group: SensorGroup.CPU.rawValue, type: SensorType.Power.rawValue), + "PCPT": Sensor_t(name: "CPU Package total", group: SensorGroup.CPU.rawValue, type: SensorType.Power.rawValue), + "PC0R": Sensor_t(name: "CPU Computing high side", group: SensorGroup.CPU.rawValue, type: SensorType.Power.rawValue), + + "PCPG": Sensor_t(name: "GPU Intel Graphics", group: SensorGroup.GPU.rawValue, type: SensorType.Power.rawValue), + "PG0R": Sensor_t(name: "GPU", group: SensorGroup.GPU.rawValue, type: SensorType.Power.rawValue), + + "PPBR": Sensor_t(name: "Battery", group: SensorGroup.Sensor.rawValue, type: SensorType.Power.rawValue), + "PDTR": Sensor_t(name: "DC In", group: SensorGroup.Sensor.rawValue, type: SensorType.Power.rawValue), + "PSTR": Sensor_t(name: "System total", group: SensorGroup.Sensor.rawValue, type: SensorType.Power.rawValue), +] diff --git a/Stats/Modules/Temperature/TemperatureMenu.swift b/Stats/Modules/Temperature/TemperatureMenu.swift deleted file mode 100644 index 570c2188..00000000 --- a/Stats/Modules/Temperature/TemperatureMenu.swift +++ /dev/null @@ -1,208 +0,0 @@ -// -// TemperatureMenu.swift -// Stats -// -// Created by Serhiy Mytrovtsiy on 03/04/2020. -// Copyright © 2020 Serhiy Mytrovtsiy. All rights reserved. -// - -import Cocoa - -struct temperatureMenu { - let name: String - let originalName: String -} - -struct temperatureGroup { - let name: String - var value: String - var menus: [temperatureMenu] - - mutating func addMenu(menu: temperatureMenu) { - self.menus.append(menu) - } - - func findBy(name: String) -> String { - let menu = self.menus.first{ $0.name == name } - if menu != nil { - return menu!.originalName - } - return "" - } -} - -struct temperatureGroupsStruct { - var list: [Int : temperatureGroup] - - mutating func addMenuToGroup(group: String, menu: temperatureMenu) { - let index = self.list.firstIndex{ $0.value.value == group} - if index != nil { - let (k, _) = self.list[index!] - self.list[k]!.menus.append(menu) - } - } - - func getOriginalNameOfSensor(name: String) -> String { - var originalName: String = "" - - self.list.forEach{ (key: Int, value: temperatureGroup) in - if value.findBy(name: name) != "" { - originalName = value.findBy(name: name) - return - } - } - - return originalName - } -} - -var temperatureGroups: temperatureGroupsStruct = temperatureGroupsStruct(list: [ - 0: temperatureGroup(name: "CPU", value: "cpu", menus: []), - 1: temperatureGroup(name: "GPU", value: "gpu", menus: []), - 2: temperatureGroup(name: "Memory", value: "mem", menus: []), - 3: temperatureGroup(name: "Termal zones", value: "termal", menus: []), - 4: temperatureGroup(name: "Sensors", value: "sensor", menus: []), - 5: temperatureGroup(name: "PCI", value: "pci", menus: []), - 6: temperatureGroup(name: "Northbridge", value: "northbridge", menus: []), - 7: temperatureGroup(name: "HDD", value: "hdd", menus: []), - 8: temperatureGroup(name: "Thunderbolt", value: "thunderbolt", menus: []), -]) - -extension Temperature { - internal func initGroups() { - var temperatures: Temperatures = Temperatures() - GetTemperatures(&temperatures) - - temperatures.asDictionary.forEach { (arg0) in - let (key, value) = arg0 - if value as! Double != 0 { - let group: String = String(key.split(separator: "_")[0]) - - var name = key.replacingOccurrences(of: "_", with: " ") - if group == "sensor" || group == "termal" { - name = name.replacingOccurrences(of: "\(group) ", with: "") - } - - temperatureGroups.addMenuToGroup(group: group, menu: temperatureMenu(name: name.toUpperCase(), originalName: key)) - } - } - } - - public func initMenu() { - menu = NSMenuItem(title: name, action: #selector(toggle), keyEquivalent: "") - submenu = NSMenu() - - if defaults.object(forKey: name) != nil { - menu.state = defaults.bool(forKey: name) ? NSControl.StateValue.on : NSControl.StateValue.off - } else { - menu.state = NSControl.StateValue.on - } - menu.target = self - - let sensor_1: NSMenuItem = NSMenuItem(title: "Sensor #1", action: nil, keyEquivalent: "") - sensor_1.target = self - sensor_1.submenu = NSMenu() - - let sensor_2: NSMenuItem = NSMenuItem(title: "Sensor #2", action: nil, keyEquivalent: "") - sensor_2.target = self - sensor_2.submenu = NSMenu() - - for i in 0...temperatureGroups.list.count-1 { - let group = temperatureGroups.list[i]! - - if group.menus.count != 0 { - sensor_1.submenu!.addItem(NSMenuItem(title: group.name, action: nil, keyEquivalent: "")) - group.menus.forEach { (m: temperatureMenu) in - let menuPoint: NSMenuItem = NSMenuItem(title: m.name, action: #selector(toggleValue1), keyEquivalent: "") - menuPoint.state = m.originalName == self.value_1 ? NSControl.StateValue.on : NSControl.StateValue.off - menuPoint.target = self - sensor_1.submenu!.addItem(menuPoint) - } - sensor_1.submenu!.addItem(NSMenuItem.separator()) - - sensor_2.submenu!.addItem(NSMenuItem(title: group.name, action: nil, keyEquivalent: "")) - group.menus.forEach { (m: temperatureMenu) in - let menuPoint: NSMenuItem = NSMenuItem(title: m.name, action: #selector(toggleValue2), keyEquivalent: "") - menuPoint.state = m.originalName == self.value_2 ? NSControl.StateValue.on : NSControl.StateValue.off - menuPoint.target = self - sensor_2.submenu!.addItem(menuPoint) - } - sensor_2.submenu!.addItem(NSMenuItem.separator()) - } - } - - if sensor_1.submenu?.items.count != 0 { - submenu.addItem(sensor_1) - } - if sensor_2.submenu?.items.count != 0 { - submenu.addItem(sensor_2) - } - submenu.addItem(NSMenuItem.separator()) - - if let view = self.widget.view as? Widget { - for widgetMenu in view.menus { - submenu.addItem(widgetMenu) - } - } - - if self.enabled { - menu.submenu = submenu - } - } - - @objc func toggle(_ sender: NSMenuItem) { - let state = sender.state != NSControl.StateValue.on - sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(state, forKey: name) - self.enabled = state - menuBar!.reload(name: self.name) - - if !state { - menu.submenu = nil - } else { - menu.submenu = submenu - } - - self.restart() - } - - @objc func toggleValue1(_ sender: NSMenuItem) { - let val: String = sender.title - let originalName = temperatureGroups.getOriginalNameOfSensor(name: val) - if self.value_1 == originalName { - return - } - - let state = sender.state == NSControl.StateValue.on - for item in self.submenu.items { - item.state = NSControl.StateValue.off - } - - sender.state = state ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(originalName, forKey: "\(name)_value_1") - self.value_1 = originalName - self.initWidget() - self.initMenu() - menuBar!.reload(name: self.name) - } - - @objc func toggleValue2(_ sender: NSMenuItem) { - let val: String = sender.title - let originalName = temperatureGroups.getOriginalNameOfSensor(name: val) - if self.value_2 == originalName { - return - } - - let state = sender.state == NSControl.StateValue.on - for item in self.submenu.items { - item.state = NSControl.StateValue.off - } - - sender.state = state ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(originalName, forKey: "\(name)_value_2") - self.value_2 = originalName - self.initWidget() - self.initMenu() - menuBar!.reload(name: self.name) - } -} diff --git a/Stats/Modules/Temperature/TemperatureReader.swift b/Stats/Modules/Temperature/TemperatureReader.swift deleted file mode 100644 index 27fe23aa..00000000 --- a/Stats/Modules/Temperature/TemperatureReader.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// TemperatureReader.swift -// Stats -// -// Created by Serhiy Mytrovtsiy on 03/04/2020. -// Copyright © 2020 Serhiy Mytrovtsiy. All rights reserved. -// - -import IOKit -import Foundation - -class TemperatureReader: Reader { - public var name: String = "Temperature" - public var enabled: Bool = true - public var available: Bool = true - public var optional: Bool = false - public var initialized: Bool = false - - public var callback: (Temperatures) -> Void = {_ in} - - init(_ updater: @escaping (Temperatures) -> Void) { - self.callback = updater - - if self.available { - DispatchQueue.global(qos: .default).async { - self.read() - } - } - } - - func read() { - if !self.enabled && self.initialized { return } - self.initialized = true - - var temperatures: Temperatures = Temperatures() - GetTemperatures(&temperatures) - - self.callback(temperatures) - } - - func toggleEnable(_ value: Bool) { - self.enabled = value - } -} diff --git a/Stats/Widgets/Temperature/TemperatureWidget.swift b/Stats/Widgets/Sensors/SensorsWidget.swift similarity index 96% rename from Stats/Widgets/Temperature/TemperatureWidget.swift rename to Stats/Widgets/Sensors/SensorsWidget.swift index 570850a5..e2d23272 100644 --- a/Stats/Widgets/Temperature/TemperatureWidget.swift +++ b/Stats/Widgets/Sensors/SensorsWidget.swift @@ -1,5 +1,5 @@ // -// DoubleRow.swift +// Sensors.swift // Stats // // Created by Serhiy Mytrovtsiy on 03/04/2020. @@ -8,8 +8,8 @@ import Foundation -class TemperatureWidget: NSView, Widget { - public var name: String = "Temperature" +class SensorsWidget: NSView, Widget { + public var name: String = "Sensors" public var menus: [NSMenuItem] = [] private var value: [Double] = [] @@ -84,10 +84,10 @@ class TemperatureWidget: NSView, Widget { func setValue(data: [Double]) { if self.value != data && data.count == 2 { self.value = data - + self.topValueView.stringValue = "\(Int(self.value[0]))°" self.bottomValueView.stringValue = "\(Int(self.value[1]))°" - + self.topValueView.textColor = self.value[0].temperatureColor(color: self.color) self.bottomValueView.textColor = self.value[1].temperatureColor(color: self.color) } diff --git a/Stats/Widgets/Widget.swift b/Stats/Widgets/Widget.swift index 5c51461f..c537a243 100644 --- a/Stats/Widgets/Widget.swift +++ b/Stats/Widgets/Widget.swift @@ -23,7 +23,7 @@ protocol Widget { typealias WidgetType = Float struct Widgets { static let Mini: WidgetType = 0.0 - static let Temperature: WidgetType = 0.1 + static let Sensors: WidgetType = 0.1 static let Chart: WidgetType = 1.0 static let ChartWithValue: WidgetType = 1.1 diff --git a/Stats/libs/Extensions.swift b/Stats/libs/Extensions.swift index d2517649..1c60a171 100755 --- a/Stats/libs/Extensions.swift +++ b/Stats/libs/Extensions.swift @@ -295,15 +295,48 @@ class ChartsNetworkAxisFormatter: IAxisValueFormatter { } } -extension Temperatures { - var asDictionary : [String: Any] { - let mirror = Mirror(reflecting: self) - - var dict: Dictionary = [:] - for (_, element) in mirror.children.enumerated() { - dict[element.label!] = element.value +public extension FourCharCode { + init(fromString str: String) { + precondition(str.count == 4) + + self = str.utf8.reduce(0) { sum, character in + return sum << 8 | UInt32(character) + } + } + + func toString() -> String { + return String(describing: UnicodeScalar(self >> 24 & 0xff)!) + + String(describing: UnicodeScalar(self >> 16 & 0xff)!) + + String(describing: UnicodeScalar(self >> 8 & 0xff)!) + + String(describing: UnicodeScalar(self & 0xff)!) + } +} + +extension UInt32 { + init(bytes: (UInt8, UInt8, UInt8, UInt8)) { + self = UInt32(bytes.0) << 24 | UInt32(bytes.1) << 16 | UInt32(bytes.2) << 8 | UInt32(bytes.3) + } +} + +extension FloatingPoint { + init?(_ bytes: [UInt8]) { + self = bytes.withUnsafeBytes { + return $0.load(fromByteOffset: 0, as: Self.self) + } + } +} + +extension NSMenuItem { + private static var _extraString = [String:String]() + + var extraString: String { + get { + let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) + return NSMenuItem._extraString[tmpAddress] ?? "" + } + set(newValue) { + let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self)) + NSMenuItem._extraString[tmpAddress] = newValue } - - return dict } } diff --git a/Stats/libs/SMC.c b/Stats/libs/SMC.c deleted file mode 100644 index 5114aba9..00000000 --- a/Stats/libs/SMC.c +++ /dev/null @@ -1,255 +0,0 @@ -// -// SMC.c -// Stats -// -// SMC code borrowed from https://github.com/lavoiesl/osx-cpu-temp. -// -// Created by Serhiy Mytrovtsiy on 03/04/2020. -// Copyright © 2020 Serhiy Mytrovtsiy. All rights reserved. -// - -#include -#include -#include - -#include -#include - -#include "SMC.h" - -static io_connect_t conn; - -UInt32 _strtoul(char* str, int size, int base) { - UInt32 total = 0; - int i; - - for (i = 0; i < size; i++) { - if (base == 16) - total += str[i] << (size - 1 - i) * 8; - else - total += (unsigned char)(str[i] << (size - 1 - i) * 8); - } - return total; -} - -void _ultostr(char* str, UInt32 val) { - str[0] = '\0'; - sprintf(str, "%c%c%c%c", - (unsigned int)val >> 24, - (unsigned int)val >> 16, - (unsigned int)val >> 8, - (unsigned int)val); -} - -void t(void * refcon, -io_service_t service, -uint32_t messageType, -void * messageArgument) { - printf("Hmmmm"); -} - -kern_return_t SMCOpen(void) { - kern_return_t result; - io_iterator_t iterator; - io_object_t device; - - CFMutableDictionaryRef matchingDictionary = IOServiceMatching("AppleSMC"); - result = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &iterator); - if (result != kIOReturnSuccess) { - printf("Error: IOServiceGetMatchingServices() = %08x\n", result); - return 1; - } - - device = IOIteratorNext(iterator); - IOObjectRelease(iterator); - if (device == 0) { - printf("Error: no SMC found\n"); - return 1; - } - - result = IOServiceOpen(device, mach_task_self(), 0, &conn); - IOObjectRelease(device); - if (result != kIOReturnSuccess) { - printf("Error: IOServiceOpen() = %08x\n", result); - return 1; - } - - return kIOReturnSuccess; -} - -kern_return_t SMCClose(void) { - return IOServiceClose(conn); -} - -kern_return_t SMCCall(int index, SMCKeyData_t* inputStructure, SMCKeyData_t* outputStructure) { - size_t structureInputSize; - size_t structureOutputSize; - - structureInputSize = sizeof(SMCKeyData_t); - structureOutputSize = sizeof(SMCKeyData_t); - -#if MAC_OS_X_VERSION_10_5 - return IOConnectCallStructMethod(conn, index, - // inputStructure - inputStructure, structureInputSize, - // ouputStructure - outputStructure, &structureOutputSize); -#else - return IOConnectMethodStructureIStructureO(conn, index, - structureInputSize, /* structureInputSize */ - &structureOutputSize, /* structureOutputSize */ - inputStructure, /* inputStructure */ - outputStructure); /* ouputStructure */ -#endif -} - -kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t* val) { - kern_return_t result; - SMCKeyData_t inputStructure; - SMCKeyData_t outputStructure; - - memset(&inputStructure, 0, sizeof(SMCKeyData_t)); - memset(&outputStructure, 0, sizeof(SMCKeyData_t)); - memset(val, 0, sizeof(SMCVal_t)); - - inputStructure.key = _strtoul(key, 4, 16); - inputStructure.data8 = SMC_CMD_READ_KEYINFO; - - result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); - if (result != kIOReturnSuccess) - return result; - - val->dataSize = outputStructure.keyInfo.dataSize; - _ultostr(val->dataType, outputStructure.keyInfo.dataType); - inputStructure.keyInfo.dataSize = val->dataSize; - inputStructure.data8 = SMC_CMD_READ_BYTES; - - result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); - if (result != kIOReturnSuccess) - return result; - - memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes)); - - return kIOReturnSuccess; -} - -double GetTemperature(char* key) { - SMCVal_t val; - kern_return_t result; - - result = SMCReadKey(key, &val); - if (result == kIOReturnSuccess) { - if (val.dataSize > 0) { - if (strcmp(val.dataType, DATATYPE_SP78) == 0) { - int intValue = val.bytes[0] * 256 + (unsigned char)val.bytes[1]; - return intValue / 256.0; - } - } - } else { - printf("Error: SMCReadKey() = %08x\n", result); - } - - return 0.0; -} - -void GetTemperatures(Temperatures *list) { - list->termal_zone_0 = GetTemperature(SMC_TEMP_TERMALZONE_0); - list->termal_zone_1 = GetTemperature(SMC_TEMP_TERMALZONE_1); - list->termal_ambient_0 = GetTemperature(SMC_TEMP_AMBIENT_AIR_0); - list->termal_ambient_1 = GetTemperature(SMC_TEMP_AMBIENT_AIR_1); - list->termal_heatpipe_0 = GetTemperature(SMC_TEMP_HEATPIPE_0); - list->termal_heatpipe_1 = GetTemperature(SMC_TEMP_HEATPIPE_1); - list->termal_heatpipe_2 = GetTemperature(SMC_TEMP_HEATPIPE_2); - list->termal_heatpipe_3 = GetTemperature(SMC_TEMP_HEATPIPE_3); - - list->cpu_0_die = GetTemperature(SMC_TEMP_CPU_0_DIE); - list->cpu_0_diode = GetTemperature(SMC_TEMP_CPU_0_DIODE); - list->cpu_0_heatsink = GetTemperature(SMC_TEMP_CPU_0_HEATSINK); - list->cpu_0_proximity = GetTemperature(SMC_TEMP_CPU_0_PROXIMITY); - list->cpu_1_die = GetTemperature(SMC_TEMP_CPU_1_DIE); - list->cpu_1_diode = GetTemperature(SMC_TEMP_CPU_1_DIODE); - list->cpu_1_heatsink = GetTemperature(SMC_TEMP_CPU_1_HEATSINK); - list->cpu_1_proximity = GetTemperature(SMC_TEMP_CPU_1_PROXIMITY); - - list->cpu_1 = GetTemperature(SMC_TEMP_CPU_CORE_1); - list->cpu_2 = GetTemperature(SMC_TEMP_CPU_CORE_2); - list->cpu_3 = GetTemperature(SMC_TEMP_CPU_CORE_3); - list->cpu_4 = GetTemperature(SMC_TEMP_CPU_CORE_4); - list->cpu_5 = GetTemperature(SMC_TEMP_CPU_CORE_5); - list->cpu_6 = GetTemperature(SMC_TEMP_CPU_CORE_6); - list->cpu_7 = GetTemperature(SMC_TEMP_CPU_CORE_7); - list->cpu_8 = GetTemperature(SMC_TEMP_CPU_CORE_8); - - list->gpu_diode = GetTemperature(SMC_TEMP_GPU_0_DIODE); - list->gpu_heatsink = GetTemperature(SMC_TEMP_GPU_0_HEATSINK); - list->gpu_proximity = GetTemperature(SMC_TEMP_GPU_0_PROXIMITY); - - list->mem_proximity = GetTemperature(SMC_TEMP_MEM_SLOTS); - list->mem_0 = GetTemperature(SMC_TEMP_MEM_SLOT_0); - list->mem_1 = GetTemperature(SMC_TEMP_MEM_SLOT_1); - list->mem_2 = GetTemperature(SMC_TEMP_MEM_SLOT_2); - list->mem_3 = GetTemperature(SMC_TEMP_MEM_SLOT_3); - - list->pci_proximity = GetTemperature(SMC_TEMP_PCI_SLOTS); - list->pci_0 = GetTemperature(SMC_TEMP_PCI_SLOT_0); - list->pci_1 = GetTemperature(SMC_TEMP_PCI_SLOT_1); - list->pci_2 = GetTemperature(SMC_TEMP_PCI_SLOT_2); - list->pci_3 = GetTemperature(SMC_TEMP_PCI_SLOT_3); - - list->sensor_mainboard = GetTemperature(SMC_TEMP_MAINBOARD_PROXIMITY); - list->sensor_powerboard = GetTemperature(SMC_TEMP_POWERBOARD_PROXIMITY); - list->sensor_battery = GetTemperature(SMC_TEMP_BATTERY_PROXIMITY); - list->sensor_airport = GetTemperature(SMC_TEMP_AIRPORT_PROXIMITY); - list->sensor_lcd = GetTemperature(SMC_TEMP_LCD_PROXIMITY); - list->sensor_odd = GetTemperature(SMC_TEMP_ODD_PROXIMITY); - - list->northbridge_die = GetTemperature(SMC_TEMP_NORTHBRIDGE_DIE); - list->northbridge_proximity = GetTemperature(SMC_TEMP_NORTHBRIDGE_PROXIMITY); - - list->hdd_0 = GetTemperature(SMC_TEMP_HDD_0); - list->hdd_1 = GetTemperature(SMC_TEMP_HDD_1); - list->hdd_2 = GetTemperature(SMC_TEMP_HDD_2); - list->hdd_3 = GetTemperature(SMC_TEMP_HDD_3); - - list->thunderbolt_0 = GetTemperature(SMC_TEMP_THUNDERBOLT_0); - list->thunderbolt_1 = GetTemperature(SMC_TEMP_THUNDERBOLT_1); - list->thunderbolt_2 = GetTemperature(SMC_TEMP_THUNDERBOLT_2); - list->thunderbolt_3 = GetTemperature(SMC_TEMP_THUNDERBOLT_3); -} - -void GetVoltages(Voltages *list) { - -} - -void GetPowers(Powers *list) { - -} - -float GetFanRPM(char* key) { - SMCVal_t val; - kern_return_t result; - - result = SMCReadKey(key, &val); - if (result == kIOReturnSuccess) { - if (val.dataSize > 0) { - if (strcmp(val.dataType, DATATYPE_FPE2) == 0) { - return ntohs(*(UInt16*)val.bytes) / 4.0; - } - } - } - return -1.f; -} - - -int64_t GetCPUFrequency() { - int mib[2]; - unsigned int freq; - size_t len; - - mib[0] = CTL_HW; - mib[1] = HW_CPU_FREQ; - len = sizeof(freq); - sysctl(mib, 2, &freq, &len, NULL, 0); - - return freq; -} diff --git a/Stats/libs/SMC.h b/Stats/libs/SMC.h deleted file mode 100644 index 59295989..00000000 --- a/Stats/libs/SMC.h +++ /dev/null @@ -1,273 +0,0 @@ -// -// SMC.h -// Stats -// -// Created by Serhiy Mytrovtsiy on 03/04/2020. -// Copyright © 2020 Serhiy Mytrovtsiy. All rights reserved. -// - -typedef struct { - double termal_zone_0; - double termal_zone_1; - double termal_ambient_0; - double termal_ambient_1; - double termal_heatpipe_0; - double termal_heatpipe_1; - double termal_heatpipe_2; - double termal_heatpipe_3; - - double cpu_0_die; - double cpu_0_diode; - double cpu_0_heatsink; - double cpu_0_proximity; - double cpu_1_die; - double cpu_1_diode; - double cpu_1_heatsink; - double cpu_1_proximity; - - double cpu_1; - double cpu_2; - double cpu_3; - double cpu_4; - double cpu_5; - double cpu_6; - double cpu_7; - double cpu_8; - - double gpu_diode; - double gpu_heatsink; - double gpu_proximity; - - double mem_proximity; - double mem_0; - double mem_1; - double mem_2; - double mem_3; - - double pci_proximity; - double pci_0; - double pci_1; - double pci_2; - double pci_3; - - double sensor_mainboard; - double sensor_powerboard; - double sensor_battery; - double sensor_airport; - double sensor_lcd; - double sensor_misc; - double sensor_odd; - - double northbridge_die; - double northbridge_proximity; - - double hdd_0; - double hdd_1; - double hdd_2; - double hdd_3; - - double thunderbolt_0; - double thunderbolt_1; - double thunderbolt_2; - double thunderbolt_3; -} Temperatures; - -typedef struct { -} Voltages; - -typedef struct { -} Powers; - -kern_return_t SMCOpen(void); -kern_return_t SMCClose(void); - -double GetTemperature(char* key); -float GetFanRPM(char* key); - -void GetTemperatures(Temperatures* list); -void GetVoltages(Voltages* list); -void GetPowers(Powers* list); - -int64_t GetCPUFrequency(void); - -#define SMC_TEMP_AMBIENT_AIR_0 "TA0P" -#define SMC_TEMP_AMBIENT_AIR_1 "TA1P" -#define SMC_TEMP_HEATPIPE_0 "Th0H" -#define SMC_TEMP_HEATPIPE_1 "Th1H" -#define SMC_TEMP_HEATPIPE_2 "Th2H" -#define SMC_TEMP_HEATPIPE_3 "Th3H" -#define SMC_TEMP_TERMALZONE_0 "TZ0C" -#define SMC_TEMP_TERMALZONE_1 "TZ1C" - -#define SMC_TEMP_CPU_0_DIE "TC0F" -#define SMC_TEMP_CPU_0_DIODE "TC0D" -#define SMC_TEMP_CPU_0_HEATSINK "TC0H" -#define SMC_TEMP_CPU_0_PROXIMITY "TC0P" -#define SMC_TEMP_CPU_1_DIE "TCAD" -#define SMC_TEMP_CPU_1_DIODE "TC1D" -#define SMC_TEMP_CPU_1_HEATSINK "TC1H" -#define SMC_TEMP_CPU_1_PROXIMITY "TC1P" - -#define SMC_TEMP_CPU_CORE_1 "TC1C" -#define SMC_TEMP_CPU_CORE_2 "TC2C" -#define SMC_TEMP_CPU_CORE_3 "TC3C" -#define SMC_TEMP_CPU_CORE_4 "TC4C" -#define SMC_TEMP_CPU_CORE_5 "TC5C" -#define SMC_TEMP_CPU_CORE_6 "TC6C" -#define SMC_TEMP_CPU_CORE_7 "TC7C" -#define SMC_TEMP_CPU_CORE_8 "TC8C" - -#define SMC_TEMP_GPU_0_DIODE "TG0D" -#define SMC_TEMP_GPU_0_HEATSINK "TG0H" -#define SMC_TEMP_GPU_0_PROXIMITY "TG0P" - -#define SMC_TEMP_MEM_SLOTS "Ts0S" -#define SMC_TEMP_MEM_SLOT_0 "TM0S" -#define SMC_TEMP_MEM_SLOT_1 "TM1S" -#define SMC_TEMP_MEM_SLOT_2 "TM2S" -#define SMC_TEMP_MEM_SLOT_3 "TM3S" - -#define SMC_TEMP_PCI_SLOTS "TS0C" -#define SMC_TEMP_PCI_SLOT_0 "TA0S" -#define SMC_TEMP_PCI_SLOT_1 "TA1S" -#define SMC_TEMP_PCI_SLOT_2 "TA2S" -#define SMC_TEMP_PCI_SLOT_3 "TA3S" - -#define SMC_TEMP_MAINBOARD_PROXIMITY "Tm0P" -#define SMC_TEMP_POWERBOARD_PROXIMITY "Tp0P" -#define SMC_TEMP_BATTERY_PROXIMITY "TB1T" - -#define SMC_TEMP_AIRPORT_PROXIMITY "TW0P" -#define SMC_TEMP_LCD_PROXIMITY "TL0P" -#define SMC_TEMP_ODD_PROXIMITY "TO0P" - -#define SMC_TEMP_NORTHBRIDGE_DIE "TN0D" -#define SMC_TEMP_NORTHBRIDGE_PROXIMITY "TN0P" - -#define SMC_TEMP_HDD_0 "TH0P" -#define SMC_TEMP_HDD_1 "TH1P" -#define SMC_TEMP_HDD_2 "TH2P" -#define SMC_TEMP_HDD_3 "TH3P" - -#define SMC_TEMP_THUNDERBOLT_0 "TI0P" -#define SMC_TEMP_THUNDERBOLT_1 "TI1P" -#define SMC_TEMP_THUNDERBOLT_2 "TI2P" -#define SMC_TEMP_THUNDERBOLT_3 "TI3P" - -#define SMC_VOLTAGE_CPU_VRM "VS0C" -#define SMC_VOLTAGE_CPU_CORE_0 "VC0C" -#define SMC_VOLTAGE_CPU_CORE_1 "VC1C" -#define SMC_VOLTAGE_CPU_CORE_2 "VC2C" -#define SMC_VOLTAGE_CPU_CORE_3 "VC3C" -#define SMC_VOLTAGE_CPU_CORE_4 "VC4C" -#define SMC_VOLTAGE_CPU_CORE_5 "VC5C" -#define SMC_VOLTAGE_CPU_CORE_6 "VC6C" -#define SMC_VOLTAGE_CPU_CORE_7 "VC7C" -#define SMC_VOLTAGE_CPU_CORE_8 "VC8C" - -#define SMC_VOLTAGE_GPU "VG0C" -#define SMC_VOLTAGE_MEMORY "VM0R" -#define SMC_VOLTAGE_BATTERY "VBAT" -#define SMC_VOLTAGE_CMOS "Vb0R" - -#define SMC_VOLTAGE_MAINBOARD "VD0R" -#define SMC_VOLTAGE_12V_RAIL "VP0R" -#define SMC_VOLTAGE_12V_VCC "Vp0C" -#define SMC_VOLTAGE_3V "VV2S" -#define SMC_VOLTAGE_3_3V "VR3R" -#define SMC_VOLTAGE_5V "VV1S" -#define SMC_VOLTAGE_12V "VV9S" -#define SMC_VOLTAGE_PCI_12V "VeES" - -#define SMC_VOLTAGE_BATT0_VOLT "B0AV" -#define SMC_CURRENT_BATT0 "B0AC" - -#define SMC_WATT_CPU_PACKAGE_CORE "PCPC" -#define SMC_WATT_CPU_PACKAGE_TOTAL "PCPT" -#define SMC_WATT_IGPU_PACKAGE "PCPG" - -#define SMC_FREQUENCY_CPU_PACKAGE_MULTI "MPkC" -#define SMC_FREQUENCY_CPU_CORE_0_MULTI "MC0C" -#define SMC_FREQUENCY_CPU_CORE_1_MULTI "MC1C" -#define SMC_FREQUENCY_CPU_CORE_2_MULTI "MC2C" -#define SMC_FREQUENCY_CPU_CORE_3_MULTI "MC3C" -#define SMC_FREQUENCY_CPU_CORE_4_MULTI "MC4C" -#define SMC_FREQUENCY_CPU_CORE_5_MULTI "MC5C" -#define SMC_FREQUENCY_CPU_CORE_6_MULTI "MC6C" -#define SMC_FREQUENCY_CPU_CORE_7_MULTI "MC7C" -#define SMC_FREQUENCY_CPU_CORE_0 "FRC0" -#define SMC_FREQUENCY_CPU_CORE_1 "FRC1" -#define SMC_FREQUENCY_CPU_CORE_2 "FRC2" -#define SMC_FREQUENCY_CPU_CORE_3 "FRC3" -#define SMC_FREQUENCY_CPU_CORE_4 "FRC4" -#define SMC_FREQUENCY_CPU_CORE_5 "FRC5" -#define SMC_FREQUENCY_CPU_CORE_6 "FRC6" -#define SMC_FREQUENCY_CPU_CORE_7 "FRC7" - -#define SMC_FREQUENCY_GPU_0 "CG0C" -#define SMC_FREQUENCY_GPU_1 "CG1C" -#define SMC_FREQUENCY_GPU_0_SHADER "CG0S" -#define SMC_FREQUENCY_GPU_1_SHADER "CG1S" -#define SMC_FREQUENCY_GPU_0_MEMORY "CG1M" -#define SMC_FREQUENCY_GPU_1_MEMORY "CG0M" - -#define SMC_FAN0_RPM "F0Ac" - -#define KERNEL_INDEX_SMC 2 - -#define SMC_CMD_READ_BYTES 5 -#define SMC_CMD_WRITE_BYTES 6 -#define SMC_CMD_READ_INDEX 8 -#define SMC_CMD_READ_KEYINFO 9 -#define SMC_CMD_READ_PLIMIT 11 -#define SMC_CMD_READ_VERS 12 - -#define DATATYPE_FPE2 "fpe2" -#define DATATYPE_UINT8 "ui8 " -#define DATATYPE_UINT16 "ui16" -#define DATATYPE_UINT32 "ui32" -#define DATATYPE_SP78 "sp78" - -typedef char UInt32Char_t[5]; -typedef char SMCBytes_t[32]; - -typedef struct { - UInt32Char_t key; - UInt32 dataSize; - UInt32Char_t dataType; - SMCBytes_t bytes; -} SMCVal_t; - -typedef struct { - char major; - char minor; - char build; - char reserved[1]; - UInt16 release; -} SMCKeyData_vers_t; - -typedef struct { - UInt16 version; - UInt16 length; - UInt32 cpuPLimit; - UInt32 gpuPLimit; - UInt32 memPLimit; -} SMCKeyData_pLimitData_t; - -typedef struct { - UInt32 dataSize; - UInt32 dataType; - char dataAttributes; -} SMCKeyData_keyInfo_t; - -typedef struct { - UInt32 key; - SMCKeyData_vers_t vers; - SMCKeyData_pLimitData_t pLimitData; - SMCKeyData_keyInfo_t keyInfo; - char result; - char status; - char data8; - UInt32 data32; - SMCBytes_t bytes; -} SMCKeyData_t; diff --git a/Stats/libs/SMC.swift b/Stats/libs/SMC.swift new file mode 100644 index 00000000..1d93b38b --- /dev/null +++ b/Stats/libs/SMC.swift @@ -0,0 +1,254 @@ +// +// SMC.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 05/04/2020. +// Copyright © 2020 Serhiy Mytrovtsiy. All rights reserved. +// + +import IOKit + +enum SMCDataType: String { + case UI32 = "ui32" + case SP78 = "sp78" + case SP87 = "sp87" + case FLT = "flt " + case FPE2 = "fpe2" +} + +enum SMCKeys: UInt8 { + case KERNEL_INDEX = 2 + case READ_BYTES = 5 + case WRITE_BYTES = 6 + case READ_INDEX = 8 + case READ_KEYINFO = 9 + case READ_PLIMIT = 11 + case READ_VERS = 12 +} + +struct SMCKeyData_t { + typealias SMCBytes_t = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, + UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, + UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, + UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, + UInt8, UInt8, UInt8, UInt8) + + struct vers_t { + var major: CUnsignedChar = 0 + var minor: CUnsignedChar = 0 + var build: CUnsignedChar = 0 + var reserved: CUnsignedChar = 0 + var release: CUnsignedShort = 0 + } + + struct LimitData_t { + var version: UInt16 = 0 + var length: UInt16 = 0 + var cpuPLimit: UInt32 = 0 + var gpuPLimit: UInt32 = 0 + var memPLimit: UInt32 = 0 + } + + struct keyInfo_t { + var dataSize: IOByteCount = 0 + var dataType: UInt32 = 0 + var dataAttributes: UInt8 = 0 + } + + var key: UInt32 = 0 + var vers = vers_t() + var pLimitData = LimitData_t() + var keyInfo = keyInfo_t() + var padding: UInt16 = 0 + var result: UInt8 = 0 + var status: UInt8 = 0 + var data8: UInt8 = 0 + var data32: UInt32 = 0 + + var bytes: SMCBytes_t = (UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), + UInt8(0), UInt8(0)) +} + +struct SMCVal_t { + var key: String + var dataSize: UInt32 = 0 + var dataType: String = "" + var bytes: [UInt8] = Array(repeating: 0, count: 32) + + init(_ key: String) { + self.key = key + } +} + +class SMCService { + private var conn: io_connect_t = 0; + + init() { + + } + + public func open() -> kern_return_t { + var result: kern_return_t + var iterator: io_iterator_t = 0 + let device: io_object_t + + let matchingDictionary: CFMutableDictionary = IOServiceMatching("AppleSMC") + result = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &iterator) + if (result != kIOReturnSuccess) { + print("Error IOServiceGetMatchingServices(): " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error")) + return result + } + + device = IOIteratorNext(iterator) + IOObjectRelease(iterator) + if (device == 0) { + print("Error IOIteratorNext(): " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error")) + return kIOReturnError + } + + result = IOServiceOpen(device, mach_task_self_, 0, &conn) + IOObjectRelease(device) + if (result != kIOReturnSuccess) { + print("Error IOServiceOpen(): " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error")) + return result + } + + return kIOReturnSuccess + } + + public func close() -> kern_return_t{ + return IOServiceClose(conn) + } + + public func getValue(_ key: String) -> Double? { + var result: kern_return_t = 0 + var val: SMCVal_t = SMCVal_t(key) + + result = read(&val) + if result != kIOReturnSuccess { + print("Error read(): " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error")) + return nil + } + + if (val.dataSize > 0) { + if val.bytes.first(where: { $0 != 0}) == nil { + return nil + } + + switch val.dataType { + case SMCDataType.UI32.rawValue: + return Double(UInt32(bytes: (val.bytes[0], val.bytes[1], val.bytes[2], val.bytes[3]))) + case SMCDataType.SP78.rawValue, SMCDataType.SP87.rawValue: + let intValue: Double = Double(Int(val.bytes[0]) * 256 + Int(val.bytes[1])) + return Double(intValue / 256.0) + case SMCDataType.FLT.rawValue: + let value: Float? = Float(val.bytes) + if value != nil { + return Double(value!) + } + return nil + case SMCDataType.FPE2.rawValue: + // ntohs(*(UInt16*)val.bytes) / 4.0; + print("FPE2") + break + default: + print("unsupported data type \(val.dataType)") + return nil + } + } + + return nil + } + + private func read(_ value: UnsafeMutablePointer) -> kern_return_t { + var result: kern_return_t = 0 + var input = SMCKeyData_t() + var output = SMCKeyData_t() + + input.key = FourCharCode(fromString: value.pointee.key) + input.data8 = SMCKeys.READ_KEYINFO.rawValue + + result = call(SMCKeys.KERNEL_INDEX.rawValue, input: &input, output: &output) + if result != kIOReturnSuccess { + print("Error call(READ_KEYINFO): " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error")) + return result + } + + value.pointee.dataSize = output.keyInfo.dataSize + value.pointee.dataType = output.keyInfo.dataType.toString() + input.keyInfo.dataSize = output.keyInfo.dataSize + input.data8 = SMCKeys.READ_BYTES.rawValue + + result = call(SMCKeys.KERNEL_INDEX.rawValue, input: &input, output: &output) + if result != kIOReturnSuccess { + print("Error call(READ_BYTES): " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error")) + return result + } + + memcpy(&value.pointee.bytes, &output.bytes, Int(value.pointee.dataSize)) + + return kIOReturnSuccess; + } + + private func call(_ index: UInt8, input: inout SMCKeyData_t, output: inout SMCKeyData_t) -> kern_return_t { + let inputSize = MemoryLayout.stride + var outputSize = MemoryLayout.stride + + return IOConnectCallStructMethod( + conn, + UInt32(index), + &input, + inputSize, + &output, + &outputSize + ) + } + + public func getAllKeys() -> [String] { + var list: [String] = [] + + let keysNum: Double? = smc.getValue("#KEY") + if keysNum == nil { + print("ERROR no keys count found") + return list + } + + var result: kern_return_t = 0 + var input: SMCKeyData_t = SMCKeyData_t() + var output: SMCKeyData_t = SMCKeyData_t() + + for i in 0...Int(keysNum!) { + input = SMCKeyData_t() + output = SMCKeyData_t() + + input.data8 = SMCKeys.READ_INDEX.rawValue + input.data32 = UInt32(i) + + result = call(SMCKeys.KERNEL_INDEX.rawValue, input: &input, output: &output) + if result != kIOReturnSuccess { + continue + } + + list.append(output.key.toString()) + } + + return list + } +} + +//int64_t GetCPUFrequency() { +// int mib[2]; +// unsigned int freq; +// size_t len; +// +// mib[0] = CTL_HW; +// mib[1] = HW_CPU_FREQ; +// len = sizeof(freq); +// sysctl(mib, 2, &freq, &len, NULL, 0); +// +// return freq; +//} diff --git a/Stats/libs/Stats.h b/Stats/libs/Stats.h index aaf9f7de..8ebd5625 100644 --- a/Stats/libs/Stats.h +++ b/Stats/libs/Stats.h @@ -8,8 +8,6 @@ #import -#import "SMC.h" - //! Project version number for SMCKit. FOUNDATION_EXPORT double SMCKitVersionNumber;