- 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;
This commit is contained in:
Serhiy Mytrovtsiy
2020-04-06 18:22:12 +02:00
parent a2ae1421aa
commit 413674db32
19 changed files with 707 additions and 875 deletions

View File

@@ -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()
}

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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: "")

View File

@@ -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:

View File

@@ -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

View File

@@ -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])
})
}
}

View File

@@ -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)
}
}

View File

@@ -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),
]

View File

@@ -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)
}
}

View File

@@ -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
}
}

View File

@@ -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)
}

View File

@@ -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

View File

@@ -295,15 +295,48 @@ class ChartsNetworkAxisFormatter: IAxisValueFormatter {
}
}
extension Temperatures {
var asDictionary : [String: Any] {
let mirror = Mirror(reflecting: self)
var dict: Dictionary<String, Any> = [:]
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
}
}

View File

@@ -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 <IOKit/IOKitLib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#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;
}

View File

@@ -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;

254
Stats/libs/SMC.swift Normal file
View File

@@ -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<SMCVal_t>) -> 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<SMCKeyData_t>.stride
var outputSize = MemoryLayout<SMCKeyData_t>.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;
//}

View File

@@ -8,8 +8,6 @@
#import <Cocoa/Cocoa.h>
#import "SMC.h"
//! Project version number for SMCKit.
FOUNDATION_EXPORT double SMCKitVersionNumber;