Replaced the IOHID and SMC interfaces. Replaced the sensors window.

This commit is contained in:
macmade
2023-02-06 09:58:33 +01:00
parent 860f4c0ea8
commit ecf7028a88
32 changed files with 1264 additions and 746 deletions

View File

@@ -7,27 +7,43 @@
objects = {
/* Begin PBXBuildFile section */
05221E62266FD5BD007246FF /* AppleSilicon.m in Sources */ = {isa = PBXBuildFile; fileRef = 05221E61266FD5BD007246FF /* AppleSilicon.m */; };
05221E8626700772007246FF /* DictionaryIsEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05221E8526700772007246FF /* DictionaryIsEmpty.swift */; };
05221E88267009A8007246FF /* SensorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05221E87267009A8007246FF /* SensorViewController.swift */; };
05221E8B26700A57007246FF /* SensorViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 05221E8926700A57007246FF /* SensorViewController.xib */; };
052FBC34251ECA8600C4322E /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 052FBC33251ECA8600C4322E /* IOKit.framework */; };
052FBC38251ECB8B00C4322E /* SMC.c in Sources */ = {isa = PBXBuildFile; fileRef = 052FBC37251ECB8B00C4322E /* SMC.c */; };
052FBCA3251EE43B00C4322E /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 052FBCA2251EE43B00C4322E /* PreferencesWindowController.swift */; };
052FBCA7251EE46700C4322E /* PreferencesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 052FBCA5251EE46700C4322E /* PreferencesWindowController.xib */; };
052FBCD4251F842C00C4322E /* SpeedTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 052FBCCF251F842C00C4322E /* SpeedTemplate.pdf */; };
052FBCD5251F842C00C4322E /* CPUTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 052FBCD1251F842C00C4322E /* CPUTemplate.pdf */; };
052FBCD6251F842C00C4322E /* TemperatureTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 052FBCD2251F842C00C4322E /* TemperatureTemplate.pdf */; };
052FBCD7251F842C00C4322E /* SchedulerTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 052FBCD3251F842C00C4322E /* SchedulerTemplate.pdf */; };
05566A082990F85200E7A5F1 /* SensorIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669EA2990F85200E7A5F1 /* SensorIcon.swift */; };
05566A092990F85200E7A5F1 /* SensorsWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669EB2990F85200E7A5F1 /* SensorsWindowController.swift */; };
05566A0A2990F85200E7A5F1 /* VoltageTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 055669ED2990F85200E7A5F1 /* VoltageTemplate.pdf */; };
05566A0B2990F85200E7A5F1 /* CurrentTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 055669EE2990F85200E7A5F1 /* CurrentTemplate.pdf */; };
05566A0C2990F85200E7A5F1 /* ThermalTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 055669EF2990F85200E7A5F1 /* ThermalTemplate.pdf */; };
05566A0D2990F85200E7A5F1 /* SensorValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F02990F85200E7A5F1 /* SensorValue.swift */; };
05566A0E2990F85200E7A5F1 /* SensorHistoryData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F12990F85200E7A5F1 /* SensorHistoryData.swift */; };
05566A0F2990F85200E7A5F1 /* ArrayIsNotEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F22990F85200E7A5F1 /* ArrayIsNotEmpty.swift */; };
05566A102990F85200E7A5F1 /* SensorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F32990F85200E7A5F1 /* SensorItem.swift */; };
05566A112990F85200E7A5F1 /* SensorItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = 055669F42990F85200E7A5F1 /* SensorItem.xib */; };
05566A122990F85200E7A5F1 /* SensorsWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 055669F62990F85200E7A5F1 /* SensorsWindowController.xib */; };
05566A132990F85200E7A5F1 /* ArrayIsEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F82990F85200E7A5F1 /* ArrayIsEmpty.swift */; };
05566A142990F85200E7A5F1 /* SensorGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669F92990F85200E7A5F1 /* SensorGraphView.swift */; };
05566A152990F85200E7A5F1 /* NSImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669FA2990F85200E7A5F1 /* NSImage.swift */; };
05566A162990F85200E7A5F1 /* Sensors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669FB2990F85200E7A5F1 /* Sensors.swift */; };
05566A172990F85200E7A5F1 /* Synchronizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669FC2990F85200E7A5F1 /* Synchronizable.swift */; };
05566A182990F85200E7A5F1 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055669FD2990F85200E7A5F1 /* Colors.swift */; };
05566A192990F85200E7A5F1 /* IOHIDData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05566A012990F85200E7A5F1 /* IOHIDData.swift */; };
05566A1A2990F85200E7A5F1 /* IOHID.m in Sources */ = {isa = PBXBuildFile; fileRef = 05566A022990F85200E7A5F1 /* IOHID.m */; };
05566A1B2990F85200E7A5F1 /* SMC.m in Sources */ = {isa = PBXBuildFile; fileRef = 05566A042990F85200E7A5F1 /* SMC.m */; };
05566A1C2990F85200E7A5F1 /* SMCData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05566A052990F85200E7A5F1 /* SMCData.swift */; };
055A9320252778C10070F771 /* InfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055A931F252778C10070F771 /* InfoViewController.swift */; };
055A9323252778D00070F771 /* InfoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 055A9321252778D00070F771 /* InfoViewController.xib */; };
055A932525277E9E0070F771 /* IntegerToString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055A932425277E9E0070F771 /* IntegerToString.swift */; };
055A932725277F6E0070F771 /* TemperatureToString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055A932625277F6E0070F771 /* TemperatureToString.swift */; };
055A932925277F990070F771 /* PercentToString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055A932825277F990070F771 /* PercentToString.swift */; };
055A932B252780FD0070F771 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055A932A252780FD0070F771 /* GraphView.swift */; };
057BA11728884BCD00324D16 /* CurrentTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 057BA11328884BCD00324D16 /* CurrentTemplate.pdf */; };
057BA11828884BCD00324D16 /* ThermalTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 057BA11528884BCD00324D16 /* ThermalTemplate.pdf */; };
057BA11928884BCD00324D16 /* VoltageTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 057BA11628884BCD00324D16 /* VoltageTemplate.pdf */; };
057F8B00251D22360048F1E1 /* StatusIconTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 057F8AFF251D22360048F1E1 /* StatusIconTemplate.pdf */; };
057F8B0C251D273E0048F1E1 /* AboutWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057F8B0B251D273E0048F1E1 /* AboutWindowController.swift */; };
057F8B11251D274C0048F1E1 /* NSApplication+LaunchServices.m in Sources */ = {isa = PBXBuildFile; fileRef = 057F8B10251D274C0048F1E1 /* NSApplication+LaunchServices.m */; };
@@ -35,20 +51,6 @@
057F8B1B251D2A970048F1E1 /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 057F8B1A251D2A970048F1E1 /* Icon.icns */; };
057F8B65251D2D5F0048F1E1 /* GitHubUpdates.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 057F8B5C251D2D510048F1E1 /* GitHubUpdates.framework */; };
057F8B67251D2D680048F1E1 /* GitHubUpdates.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 057F8B5C251D2D510048F1E1 /* GitHubUpdates.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
05A012C226FB9AEB00D3F6B6 /* SensorIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012B026FB9AEB00D3F6B6 /* SensorIcon.swift */; };
05A012C326FB9AEB00D3F6B6 /* SensorData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012B126FB9AEB00D3F6B6 /* SensorData.swift */; };
05A012C426FB9AEB00D3F6B6 /* SensorsWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012B226FB9AEB00D3F6B6 /* SensorsWindowController.swift */; };
05A012C626FB9AEB00D3F6B6 /* SensorValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012B526FB9AEB00D3F6B6 /* SensorValue.swift */; };
05A012C826FB9AEB00D3F6B6 /* ArrayIsNotEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012B726FB9AEB00D3F6B6 /* ArrayIsNotEmpty.swift */; };
05A012C926FB9AEB00D3F6B6 /* SensorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012B826FB9AEB00D3F6B6 /* SensorItem.swift */; };
05A012CA26FB9AEB00D3F6B6 /* ArrayIsEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012BA26FB9AEB00D3F6B6 /* ArrayIsEmpty.swift */; };
05A012CB26FB9AEB00D3F6B6 /* SensorGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012BB26FB9AEB00D3F6B6 /* SensorGraphView.swift */; };
05A012CC26FB9AEB00D3F6B6 /* NSImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012BC26FB9AEB00D3F6B6 /* NSImage.swift */; };
05A012CD26FB9AEB00D3F6B6 /* Synchronizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012BD26FB9AEB00D3F6B6 /* Synchronizable.swift */; };
05A012CE26FB9AEB00D3F6B6 /* Sensors.m in Sources */ = {isa = PBXBuildFile; fileRef = 05A012BE26FB9AEB00D3F6B6 /* Sensors.m */; };
05A012CF26FB9AEB00D3F6B6 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A012BF26FB9AEB00D3F6B6 /* Colors.swift */; };
05A012D626FB9B8B00D3F6B6 /* SensorItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = 05A012D226FB9B8B00D3F6B6 /* SensorItem.xib */; };
05A012D726FB9B8B00D3F6B6 /* SensorsWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 05A012D426FB9B8B00D3F6B6 /* SensorsWindowController.xib */; };
05AA407A251CF3D200106CEA /* ApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AA4079251CF3D200106CEA /* ApplicationDelegate.swift */; };
05AA407F251CF3D600106CEA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 05AA407D251CF3D600106CEA /* MainMenu.xib */; };
05AA408D251CFA0600106CEA /* ThermalLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AA408C251CFA0600106CEA /* ThermalLog.swift */; };
@@ -102,29 +104,47 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
05221E60266FD5BD007246FF /* AppleSilicon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleSilicon.h; sourceTree = "<group>"; };
05221E61266FD5BD007246FF /* AppleSilicon.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppleSilicon.m; sourceTree = "<group>"; };
05221E8526700772007246FF /* DictionaryIsEmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryIsEmpty.swift; sourceTree = "<group>"; };
05221E87267009A8007246FF /* SensorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorViewController.swift; sourceTree = "<group>"; };
05221E8A26700A57007246FF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SensorViewController.xib; sourceTree = "<group>"; };
052FBC32251EC69B00C4322E /* SMC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SMC.h; sourceTree = "<group>"; };
052FBC33251ECA8600C4322E /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
052FBC37251ECB8B00C4322E /* SMC.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SMC.c; sourceTree = "<group>"; };
052FBCA2251EE43B00C4322E /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
052FBCA6251EE46700C4322E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PreferencesWindowController.xib; sourceTree = "<group>"; };
052FBCCF251F842C00C4322E /* SpeedTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = SpeedTemplate.pdf; sourceTree = "<group>"; };
052FBCD1251F842C00C4322E /* CPUTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = CPUTemplate.pdf; sourceTree = "<group>"; };
052FBCD2251F842C00C4322E /* TemperatureTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = TemperatureTemplate.pdf; sourceTree = "<group>"; };
052FBCD3251F842C00C4322E /* SchedulerTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = SchedulerTemplate.pdf; sourceTree = "<group>"; };
055669EA2990F85200E7A5F1 /* SensorIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorIcon.swift; sourceTree = "<group>"; };
055669EB2990F85200E7A5F1 /* SensorsWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorsWindowController.swift; sourceTree = "<group>"; };
055669ED2990F85200E7A5F1 /* VoltageTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = VoltageTemplate.pdf; sourceTree = "<group>"; };
055669EE2990F85200E7A5F1 /* CurrentTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = CurrentTemplate.pdf; sourceTree = "<group>"; };
055669EF2990F85200E7A5F1 /* ThermalTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = ThermalTemplate.pdf; sourceTree = "<group>"; };
055669F02990F85200E7A5F1 /* SensorValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorValue.swift; sourceTree = "<group>"; };
055669F12990F85200E7A5F1 /* SensorHistoryData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorHistoryData.swift; sourceTree = "<group>"; };
055669F22990F85200E7A5F1 /* ArrayIsNotEmpty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayIsNotEmpty.swift; sourceTree = "<group>"; };
055669F32990F85200E7A5F1 /* SensorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorItem.swift; sourceTree = "<group>"; };
055669F52990F85200E7A5F1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SensorItem.xib; sourceTree = "<group>"; };
055669F72990F85200E7A5F1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SensorsWindowController.xib; sourceTree = "<group>"; };
055669F82990F85200E7A5F1 /* ArrayIsEmpty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayIsEmpty.swift; sourceTree = "<group>"; };
055669F92990F85200E7A5F1 /* SensorGraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorGraphView.swift; sourceTree = "<group>"; };
055669FA2990F85200E7A5F1 /* NSImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSImage.swift; sourceTree = "<group>"; };
055669FB2990F85200E7A5F1 /* Sensors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sensors.swift; sourceTree = "<group>"; };
055669FC2990F85200E7A5F1 /* Synchronizable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Synchronizable.swift; sourceTree = "<group>"; };
055669FD2990F85200E7A5F1 /* Colors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
055669FF2990F85200E7A5F1 /* IOHID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOHID.h; sourceTree = "<group>"; };
05566A002990F85200E7A5F1 /* IOHID-Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IOHID-Internal.h"; sourceTree = "<group>"; };
05566A012990F85200E7A5F1 /* IOHIDData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IOHIDData.swift; sourceTree = "<group>"; };
05566A022990F85200E7A5F1 /* IOHID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IOHID.m; sourceTree = "<group>"; };
05566A042990F85200E7A5F1 /* SMC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMC.m; sourceTree = "<group>"; };
05566A052990F85200E7A5F1 /* SMCData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMCData.swift; sourceTree = "<group>"; };
05566A062990F85200E7A5F1 /* SMC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMC.h; sourceTree = "<group>"; };
05566A072990F85200E7A5F1 /* SMC-Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SMC-Internal.h"; sourceTree = "<group>"; };
055A931F252778C10070F771 /* InfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoViewController.swift; sourceTree = "<group>"; };
055A9322252778D00070F771 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/InfoViewController.xib; sourceTree = "<group>"; };
055A932425277E9E0070F771 /* IntegerToString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegerToString.swift; sourceTree = "<group>"; };
055A932625277F6E0070F771 /* TemperatureToString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemperatureToString.swift; sourceTree = "<group>"; };
055A932825277F990070F771 /* PercentToString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PercentToString.swift; sourceTree = "<group>"; };
055A932A252780FD0070F771 /* GraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphView.swift; sourceTree = "<group>"; };
057BA11328884BCD00324D16 /* CurrentTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = CurrentTemplate.pdf; sourceTree = "<group>"; };
057BA11528884BCD00324D16 /* ThermalTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = ThermalTemplate.pdf; sourceTree = "<group>"; };
057BA11628884BCD00324D16 /* VoltageTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = VoltageTemplate.pdf; sourceTree = "<group>"; };
057F8AFF251D22360048F1E1 /* StatusIconTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = StatusIconTemplate.pdf; sourceTree = "<group>"; };
057F8B0B251D273E0048F1E1 /* AboutWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutWindowController.swift; sourceTree = "<group>"; };
057F8B0E251D274C0048F1E1 /* Hot-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Hot-Bridging-Header.h"; sourceTree = "<group>"; };
@@ -179,22 +199,6 @@
057F8B53251D2C840048F1E1 /* ccache.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ccache.sh; sourceTree = "<group>"; };
057F8B54251D2C840048F1E1 /* Debug - zld.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Debug - zld.xcconfig"; sourceTree = "<group>"; };
057F8B56251D2D510048F1E1 /* GitHubUpdates.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GitHubUpdates.xcodeproj; path = Submodules/GitHubUpdates/GitHubUpdates.xcodeproj; sourceTree = "<group>"; };
05A012B026FB9AEB00D3F6B6 /* SensorIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorIcon.swift; sourceTree = "<group>"; };
05A012B126FB9AEB00D3F6B6 /* SensorData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorData.swift; sourceTree = "<group>"; };
05A012B226FB9AEB00D3F6B6 /* SensorsWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorsWindowController.swift; sourceTree = "<group>"; };
05A012B426FB9AEB00D3F6B6 /* Sensors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sensors.h; sourceTree = "<group>"; };
05A012B526FB9AEB00D3F6B6 /* SensorValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorValue.swift; sourceTree = "<group>"; };
05A012B726FB9AEB00D3F6B6 /* ArrayIsNotEmpty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayIsNotEmpty.swift; sourceTree = "<group>"; };
05A012B826FB9AEB00D3F6B6 /* SensorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorItem.swift; sourceTree = "<group>"; };
05A012B926FB9AEB00D3F6B6 /* IOHID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOHID.h; sourceTree = "<group>"; };
05A012BA26FB9AEB00D3F6B6 /* ArrayIsEmpty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayIsEmpty.swift; sourceTree = "<group>"; };
05A012BB26FB9AEB00D3F6B6 /* SensorGraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorGraphView.swift; sourceTree = "<group>"; };
05A012BC26FB9AEB00D3F6B6 /* NSImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSImage.swift; sourceTree = "<group>"; };
05A012BD26FB9AEB00D3F6B6 /* Synchronizable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Synchronizable.swift; sourceTree = "<group>"; };
05A012BE26FB9AEB00D3F6B6 /* Sensors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Sensors.m; sourceTree = "<group>"; };
05A012BF26FB9AEB00D3F6B6 /* Colors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
05A012D326FB9B8B00D3F6B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SensorItem.xib; sourceTree = "<group>"; };
05A012D526FB9B8B00D3F6B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SensorsWindowController.xib; sourceTree = "<group>"; };
05AA4076251CF3D200106CEA /* Hot.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Hot.app; sourceTree = BUILT_PRODUCTS_DIR; };
05AA4079251CF3D200106CEA /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = "<group>"; };
05AA407E251CF3D600106CEA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
@@ -226,13 +230,64 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
055669E92990F85200E7A5F1 /* SensorsWindow */ = {
isa = PBXGroup;
children = (
055669EA2990F85200E7A5F1 /* SensorIcon.swift */,
055669EB2990F85200E7A5F1 /* SensorsWindowController.swift */,
055669EC2990F85200E7A5F1 /* Images */,
055669F02990F85200E7A5F1 /* SensorValue.swift */,
055669F12990F85200E7A5F1 /* SensorHistoryData.swift */,
055669F22990F85200E7A5F1 /* ArrayIsNotEmpty.swift */,
055669F32990F85200E7A5F1 /* SensorItem.swift */,
055669F42990F85200E7A5F1 /* SensorItem.xib */,
055669F62990F85200E7A5F1 /* SensorsWindowController.xib */,
055669F82990F85200E7A5F1 /* ArrayIsEmpty.swift */,
055669F92990F85200E7A5F1 /* SensorGraphView.swift */,
055669FA2990F85200E7A5F1 /* NSImage.swift */,
055669FB2990F85200E7A5F1 /* Sensors.swift */,
055669FC2990F85200E7A5F1 /* Synchronizable.swift */,
055669FD2990F85200E7A5F1 /* Colors.swift */,
);
path = SensorsWindow;
sourceTree = "<group>";
};
055669EC2990F85200E7A5F1 /* Images */ = {
isa = PBXGroup;
children = (
055669ED2990F85200E7A5F1 /* VoltageTemplate.pdf */,
055669EE2990F85200E7A5F1 /* CurrentTemplate.pdf */,
055669EF2990F85200E7A5F1 /* ThermalTemplate.pdf */,
);
path = Images;
sourceTree = "<group>";
};
055669FE2990F85200E7A5F1 /* IOHID */ = {
isa = PBXGroup;
children = (
055669FF2990F85200E7A5F1 /* IOHID.h */,
05566A002990F85200E7A5F1 /* IOHID-Internal.h */,
05566A012990F85200E7A5F1 /* IOHIDData.swift */,
05566A022990F85200E7A5F1 /* IOHID.m */,
);
path = IOHID;
sourceTree = "<group>";
};
05566A032990F85200E7A5F1 /* SMC */ = {
isa = PBXGroup;
children = (
05566A042990F85200E7A5F1 /* SMC.m */,
05566A052990F85200E7A5F1 /* SMCData.swift */,
05566A062990F85200E7A5F1 /* SMC.h */,
05566A072990F85200E7A5F1 /* SMC-Internal.h */,
);
path = SMC;
sourceTree = "<group>";
};
057F8AFE251D22360048F1E1 /* Images */ = {
isa = PBXGroup;
children = (
05AD458F29092B8400A791C8 /* BatteryTemplate.pdf */,
057BA11328884BCD00324D16 /* CurrentTemplate.pdf */,
057BA11528884BCD00324D16 /* ThermalTemplate.pdf */,
057BA11628884BCD00324D16 /* VoltageTemplate.pdf */,
05AD459129092CEB00A791C8 /* TCalTemplate.pdf */,
05B0DFA8267150F40068FF9B /* TCXCTemplate.pdf */,
05B0DFA326714A830068FF9B /* eAccTemplate.pdf */,
@@ -382,36 +437,6 @@
name = Frameworks;
sourceTree = "<group>";
};
05A012AF26FB9AEB00D3F6B6 /* Sensors */ = {
isa = PBXGroup;
children = (
05A012BA26FB9AEB00D3F6B6 /* ArrayIsEmpty.swift */,
05A012B726FB9AEB00D3F6B6 /* ArrayIsNotEmpty.swift */,
05A012BF26FB9AEB00D3F6B6 /* Colors.swift */,
05A012B926FB9AEB00D3F6B6 /* IOHID.h */,
05A012B226FB9AEB00D3F6B6 /* SensorsWindowController.swift */,
05A012BC26FB9AEB00D3F6B6 /* NSImage.swift */,
05A012B126FB9AEB00D3F6B6 /* SensorData.swift */,
05A012BB26FB9AEB00D3F6B6 /* SensorGraphView.swift */,
05A012B026FB9AEB00D3F6B6 /* SensorIcon.swift */,
05A012B826FB9AEB00D3F6B6 /* SensorItem.swift */,
05A012B426FB9AEB00D3F6B6 /* Sensors.h */,
05A012BE26FB9AEB00D3F6B6 /* Sensors.m */,
05A012B526FB9AEB00D3F6B6 /* SensorValue.swift */,
05A012BD26FB9AEB00D3F6B6 /* Synchronizable.swift */,
);
path = Sensors;
sourceTree = "<group>";
};
05A012D126FB9B8B00D3F6B6 /* Sensors */ = {
isa = PBXGroup;
children = (
05A012D226FB9B8B00D3F6B6 /* SensorItem.xib */,
05A012D426FB9B8B00D3F6B6 /* SensorsWindowController.xib */,
);
path = Sensors;
sourceTree = "<group>";
};
05AA406D251CF3D200106CEA = {
isa = PBXGroup;
children = (
@@ -447,7 +472,9 @@
05AA4088251CF3F400106CEA /* Classes */ = {
isa = PBXGroup;
children = (
05A012AF26FB9AEB00D3F6B6 /* Sensors */,
055669FE2990F85200E7A5F1 /* IOHID */,
055669E92990F85200E7A5F1 /* SensorsWindow */,
05566A032990F85200E7A5F1 /* SMC */,
057F8B0B251D273E0048F1E1 /* AboutWindowController.swift */,
05AA4079251CF3D200106CEA /* ApplicationDelegate.swift */,
05221E87267009A8007246FF /* SensorViewController.swift */,
@@ -460,10 +487,6 @@
057F8B10251D274C0048F1E1 /* NSApplication+LaunchServices.m */,
055A932825277F990070F771 /* PercentToString.swift */,
052FBCA2251EE43B00C4322E /* PreferencesWindowController.swift */,
052FBC37251ECB8B00C4322E /* SMC.c */,
052FBC32251EC69B00C4322E /* SMC.h */,
05221E60266FD5BD007246FF /* AppleSilicon.h */,
05221E61266FD5BD007246FF /* AppleSilicon.m */,
055A932625277F6E0070F771 /* TemperatureToString.swift */,
05BA0BA926F342DA00AA7BFC /* PressureToString.swift */,
05AA408C251CFA0600106CEA /* ThermalLog.swift */,
@@ -475,7 +498,6 @@
05AA4089251CF3FC00106CEA /* UI */ = {
isa = PBXGroup;
children = (
05A012D126FB9B8B00D3F6B6 /* Sensors */,
057F8B13251D27650048F1E1 /* AboutWindowController.xib */,
057F8AFE251D22360048F1E1 /* Images */,
055A9321252778D00070F771 /* InfoViewController.xib */,
@@ -571,28 +593,28 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
057BA11728884BCD00324D16 /* CurrentTemplate.pdf in Resources */,
052FBCD4251F842C00C4322E /* SpeedTemplate.pdf in Resources */,
05BA0BAD26F347A500AA7BFC /* PressureTemplate.pdf in Resources */,
052FBCD6251F842C00C4322E /* TemperatureTemplate.pdf in Resources */,
057F8B00251D22360048F1E1 /* StatusIconTemplate.pdf in Resources */,
057F8B1B251D2A970048F1E1 /* Icon.icns in Resources */,
052FBCD5251F842C00C4322E /* CPUTemplate.pdf in Resources */,
05566A0C2990F85200E7A5F1 /* ThermalTemplate.pdf in Resources */,
05221E8B26700A57007246FF /* SensorViewController.xib in Resources */,
05AD459229092CEB00A791C8 /* TCalTemplate.pdf in Resources */,
05A012D626FB9B8B00D3F6B6 /* SensorItem.xib in Resources */,
05AD458C2908505900A791C8 /* SelectSensorsWindowController.xib in Resources */,
055A9323252778D00070F771 /* InfoViewController.xib in Resources */,
05B0DFA526714A830068FF9B /* UnknownTemplate.pdf in Resources */,
05A012D726FB9B8B00D3F6B6 /* SensorsWindowController.xib in Resources */,
05566A112990F85200E7A5F1 /* SensorItem.xib in Resources */,
05566A0B2990F85200E7A5F1 /* CurrentTemplate.pdf in Resources */,
05AD459029092B8400A791C8 /* BatteryTemplate.pdf in Resources */,
057BA11828884BCD00324D16 /* ThermalTemplate.pdf in Resources */,
057BA11928884BCD00324D16 /* VoltageTemplate.pdf in Resources */,
057F8B15251D27650048F1E1 /* AboutWindowController.xib in Resources */,
052FBCA7251EE46700C4322E /* PreferencesWindowController.xib in Resources */,
05AA407F251CF3D600106CEA /* MainMenu.xib in Resources */,
052FBCD7251F842C00C4322E /* SchedulerTemplate.pdf in Resources */,
05B0DFA626714A830068FF9B /* eAccTemplate.pdf in Resources */,
05566A0A2990F85200E7A5F1 /* VoltageTemplate.pdf in Resources */,
05566A122990F85200E7A5F1 /* SensorsWindowController.xib in Resources */,
05B0DFAA267150F40068FF9B /* TCXCTemplate.pdf in Resources */,
05B0DFA426714A830068FF9B /* pAccTemplate.pdf in Resources */,
);
@@ -626,34 +648,36 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
05566A0E2990F85200E7A5F1 /* SensorHistoryData.swift in Sources */,
055A932525277E9E0070F771 /* IntegerToString.swift in Sources */,
05566A172990F85200E7A5F1 /* Synchronizable.swift in Sources */,
055A932725277F6E0070F771 /* TemperatureToString.swift in Sources */,
05A012CD26FB9AEB00D3F6B6 /* Synchronizable.swift in Sources */,
05566A0D2990F85200E7A5F1 /* SensorValue.swift in Sources */,
05566A1C2990F85200E7A5F1 /* SMCData.swift in Sources */,
05566A192990F85200E7A5F1 /* IOHIDData.swift in Sources */,
05566A152990F85200E7A5F1 /* NSImage.swift in Sources */,
05221E8626700772007246FF /* DictionaryIsEmpty.swift in Sources */,
05A012C626FB9AEB00D3F6B6 /* SensorValue.swift in Sources */,
05A012C326FB9AEB00D3F6B6 /* SensorData.swift in Sources */,
052FBCA3251EE43B00C4322E /* PreferencesWindowController.swift in Sources */,
055A932B252780FD0070F771 /* GraphView.swift in Sources */,
05A012CC26FB9AEB00D3F6B6 /* NSImage.swift in Sources */,
05221E62266FD5BD007246FF /* AppleSilicon.m in Sources */,
05221E88267009A8007246FF /* SensorViewController.swift in Sources */,
05A012C426FB9AEB00D3F6B6 /* SensorsWindowController.swift in Sources */,
057F8B11251D274C0048F1E1 /* NSApplication+LaunchServices.m in Sources */,
05A012C926FB9AEB00D3F6B6 /* SensorItem.swift in Sources */,
057F8B0C251D273E0048F1E1 /* AboutWindowController.swift in Sources */,
05A012CA26FB9AEB00D3F6B6 /* ArrayIsEmpty.swift in Sources */,
055A9320252778C10070F771 /* InfoViewController.swift in Sources */,
05A012CB26FB9AEB00D3F6B6 /* SensorGraphView.swift in Sources */,
05A012CF26FB9AEB00D3F6B6 /* Colors.swift in Sources */,
05566A162990F85200E7A5F1 /* Sensors.swift in Sources */,
05566A102990F85200E7A5F1 /* SensorItem.swift in Sources */,
05566A082990F85200E7A5F1 /* SensorIcon.swift in Sources */,
05566A182990F85200E7A5F1 /* Colors.swift in Sources */,
05566A092990F85200E7A5F1 /* SensorsWindowController.swift in Sources */,
05AD458829084FEF00A791C8 /* SelectSensorsWindowController.swift in Sources */,
05566A1A2990F85200E7A5F1 /* IOHID.m in Sources */,
05566A0F2990F85200E7A5F1 /* ArrayIsNotEmpty.swift in Sources */,
05AA408D251CFA0600106CEA /* ThermalLog.swift in Sources */,
055A932925277F990070F771 /* PercentToString.swift in Sources */,
05566A132990F85200E7A5F1 /* ArrayIsEmpty.swift in Sources */,
05AA407A251CF3D200106CEA /* ApplicationDelegate.swift in Sources */,
05BA0BAA26F342DA00AA7BFC /* PressureToString.swift in Sources */,
05A012C226FB9AEB00D3F6B6 /* SensorIcon.swift in Sources */,
05A012CE26FB9AEB00D3F6B6 /* Sensors.m in Sources */,
052FBC38251ECB8B00C4322E /* SMC.c in Sources */,
05A012C826FB9AEB00D3F6B6 /* ArrayIsNotEmpty.swift in Sources */,
05566A1B2990F85200E7A5F1 /* SMC.m in Sources */,
05566A142990F85200E7A5F1 /* SensorGraphView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -684,6 +708,22 @@
name = PreferencesWindowController.xib;
sourceTree = "<group>";
};
055669F42990F85200E7A5F1 /* SensorItem.xib */ = {
isa = PBXVariantGroup;
children = (
055669F52990F85200E7A5F1 /* Base */,
);
name = SensorItem.xib;
sourceTree = "<group>";
};
055669F62990F85200E7A5F1 /* SensorsWindowController.xib */ = {
isa = PBXVariantGroup;
children = (
055669F72990F85200E7A5F1 /* Base */,
);
name = SensorsWindowController.xib;
sourceTree = "<group>";
};
055A9321252778D00070F771 /* InfoViewController.xib */ = {
isa = PBXVariantGroup;
children = (
@@ -700,22 +740,6 @@
name = AboutWindowController.xib;
sourceTree = "<group>";
};
05A012D226FB9B8B00D3F6B6 /* SensorItem.xib */ = {
isa = PBXVariantGroup;
children = (
05A012D326FB9B8B00D3F6B6 /* Base */,
);
name = SensorItem.xib;
sourceTree = "<group>";
};
05A012D426FB9B8B00D3F6B6 /* SensorsWindowController.xib */ = {
isa = PBXVariantGroup;
children = (
05A012D526FB9B8B00D3F6B6 /* Base */,
);
name = SensorsWindowController.xib;
sourceTree = "<group>";
};
05AA407D251CF3D600106CEA /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (

View File

@@ -1,113 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2021 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
/*!
* @file AppleSilicon.m
* @copyright (c) 2021, Jean-David Gadina - www.xs-labs.com
*/
/*******************************************************************************
* LICENSE NOTICE
*
* The private IOKit calls used in the following code have been derived
* from the https://github.com/fermion-star/apple_sensors project, which itself
* has been derived from the https://github.com/freedomtan/sensors project,
* by Koan-Sin Tan. As this might be considered as a derivative work, here are
* the original license terms:
*
* BSD 3-Clause License
*
* Copyright (c) 2016-2018, "freedom" Koan-Sin Tan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#import "AppleSilicon.h"
#import "IOHID.h"
#import <IOKit/hidsystem/IOHIDEventSystemClient.h>
#import <IOKit/hidsystem/IOHIDServiceClient.h>
static IOHIDEventSystemClientRef client = nil;
NSDictionary< NSString *, NSNumber * > * ReadAppleSiliconSensors( void )
{
if( client == nil )
{
client = IOHIDEventSystemClientCreate( kCFAllocatorDefault );
NSDictionary * filter =
@{
@"PrimaryUsagePage" : [ NSNumber numberWithLongLong: IOHIDPageAppleVendor ],
@"PrimaryUsage" : [ NSNumber numberWithLongLong: IOHIDUsageAppleVendorTemperatureSensor ]
};
IOHIDEventSystemClientSetMatching( client, ( __bridge CFDictionaryRef )filter );
}
NSArray * services = CFBridgingRelease( IOHIDEventSystemClientCopyServices( client ) );
NSMutableDictionary< NSString *, NSNumber * > * values = [ NSMutableDictionary new ];
for( id o in services )
{
IOHIDServiceClientRef service = ( __bridge IOHIDServiceClientRef )o;
NSString * name = CFBridgingRelease( IOHIDServiceClientCopyProperty( service, CFSTR( "Product" ) ) );
CFTypeRef event = IOHIDServiceClientCopyEvent( service, IOHIDEventTypeTemperature, 0, 0 );
if( name != nil && event != nil )
{
values[ name ] = [ NSNumber numberWithDouble: IOHIDEventGetFloatValue( event, 0x000F0000 ) ];
}
if( event != nil )
{
CFRelease( event );
}
}
return [ values copy ];
}

View File

@@ -407,7 +407,7 @@ class ApplicationDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate
func windowWillClose( _ notification: Notification )
{
self.sensorsWindowController?.stop()
self.sensorsWindowController?.stop( completion: nil )
self.sensorsWindowController = nil
}

View File

@@ -24,5 +24,4 @@
#import "NSApplication+LaunchServices.h"
#import "SMC.h"
#import "AppleSilicon.h"
#import "Sensors.h"
#import "IOHID.h"

View File

@@ -120,6 +120,14 @@ typedef NS_ENUM( int64_t, IOHIDEvent )
IOHIDEventTypeReset = 0x1D
};
#define IOHIDEventFieldBase( _type_ ) ( _type_ << 16 )
typedef NS_ENUM( int64_t, IOHIDEventField )
{
IOHIDEventFieldTemperatureLevel = IOHIDEventFieldBase( IOHIDEventTypeTemperature ),
IOHIDEventFieldPowerMeasurement = IOHIDEventFieldBase( IOHIDEventTypePower )
};
extern IOHIDEventSystemClientRef IOHIDEventSystemClientCreate( CFAllocatorRef );
extern void IOHIDEventSystemClientSetMatching( IOHIDEventSystemClientRef, CFDictionaryRef );
extern CFTypeRef IOHIDServiceClientCopyEvent( IOHIDServiceClientRef, IOHIDEvent, int64_t, int64_t );

View File

@@ -1,18 +1,18 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2021 Jean-David Gadina - www.xs-labs.com
*
*
* Copyright (c) 2022 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -24,15 +24,18 @@
@import Foundation;
@class IOHIDData;
NS_ASSUME_NONNULL_BEGIN
@class SensorData;
@interface IOHID: NSObject
@interface Sensors: NSObject
@property( class, nonatomic, readonly ) IOHID * shared;
@property( atomic, readwrite, strong ) NSArray< SensorData * > * data;
- ( void )stop: ( void ( ^ _Nullable )( void ) )completion;
- ( instancetype )init;
- ( NSArray< IOHIDData * > * )readTemperatureSensors;
- ( NSArray< IOHIDData * > * )readVoltageSensors;
- ( NSArray< IOHIDData * > * )readCurrentSensors;
@end

132
Hot/Classes/IOHID/IOHID.m Normal file
View File

@@ -0,0 +1,132 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2021 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#import "IOHID.h"
#import "IOHID-Internal.h"
#import "Hot-Swift.h"
#import <IOKit/hidsystem/IOHIDEventSystemClient.h>
#import <IOKit/hidsystem/IOHIDServiceClient.h>
NS_ASSUME_NONNULL_BEGIN
@interface IOHID()
@property( nonatomic, readwrite, assign, nullable ) IOHIDEventSystemClientRef client;
- ( NSArray< IOHIDData * > * )read: ( long long )page usage: ( int64_t )usage eventType: ( int64_t )eventType eventField: ( int64_t )eventField;
@end
NS_ASSUME_NONNULL_END
@implementation IOHID
+ ( IOHID * )shared
{
static dispatch_once_t once;
static IOHID * instance;
dispatch_once
(
&once,
^( void )
{
instance = [ IOHID new ];
}
);
return instance;
}
- ( instancetype )init
{
if( ( self = [ super init ] ) )
{
self.client = IOHIDEventSystemClientCreate( kCFAllocatorDefault );
}
return self;
}
- ( oneway void )dealloc
{
CFRelease( self.client );
}
- ( NSArray< IOHIDData * > * )readTemperatureSensors
{
return [ self read: IOHIDPageAppleVendor usage: IOHIDUsageAppleVendorTemperatureSensor eventType: IOHIDEventTypeTemperature eventField: IOHIDEventFieldTemperatureLevel ];
}
- ( NSArray< IOHIDData * > * )readVoltageSensors
{
return [ self read: IOHIDPageAppleVendorPowerSensor usage: IOHIDUsageAppleVendorPowerSensorVoltage eventType: IOHIDEventTypePower eventField: IOHIDEventFieldPowerMeasurement ];
}
- ( NSArray< IOHIDData * > * )readCurrentSensors
{
return [ self read: IOHIDPageAppleVendorPowerSensor usage: IOHIDUsageAppleVendorPowerSensorCurrent eventType: IOHIDEventTypePower eventField: IOHIDEventFieldPowerMeasurement ];
}
- ( NSArray< IOHIDData * > * )read: ( long long )page usage: ( int64_t )usage eventType: ( int64_t )eventType eventField: ( int64_t )eventField
{
if( self.client == nil )
{
return @[];
}
NSDictionary * filter =
@{
@"PrimaryUsagePage" : [ NSNumber numberWithLongLong: page ],
@"PrimaryUsage" : [ NSNumber numberWithLongLong: usage ]
};
IOHIDEventSystemClientSetMatching( self.client, ( __bridge CFDictionaryRef )filter );
NSArray * services = CFBridgingRelease( IOHIDEventSystemClientCopyServices( ( IOHIDEventSystemClientRef )( self.client ) ) );
NSMutableDictionary< NSString *, IOHIDData * > * values = [ NSMutableDictionary new ];
for( id o in services )
{
IOHIDServiceClientRef service = ( __bridge IOHIDServiceClientRef )o;
NSString * name = CFBridgingRelease( IOHIDServiceClientCopyProperty( service, CFSTR( "Product" ) ) );
NSArray * keys = @[ @"IOClass", @"IOProviderClass", @"IONameMatch", @"Product", @"DeviceUsagePairs" ];
NSDictionary * properties = CFBridgingRelease( IOHIDServiceClientCopyProperties( service, ( __bridge CFArrayRef )keys ) );
CFTypeRef event = IOHIDServiceClientCopyEvent( service, eventType, 0, 0 );
if( name != nil && event != nil )
{
values[ name ] = [ [ IOHIDData alloc ] initWithName: name value: IOHIDEventGetFloatValue( event, eventField ) properties: properties ];
}
if( event != nil )
{
CFRelease( event );
}
}
return [ values allValues ];
}
@end

View File

@@ -0,0 +1,41 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Foundation
@objc
public class IOHIDData: NSObject
{
@objc public dynamic var name: String
@objc public dynamic var value: Double
@objc public dynamic var properties: [ AnyHashable: Any ]
@objc
public init( name: String, value: Double, properties: [ AnyHashable: Any ] )
{
self.name = name
self.value = value
self.properties = properties
}
}

View File

@@ -1,188 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2020 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
/*!
* @file SMC.c
* @copyright (c) 2020, Jean-David Gadina - www.xs-labs.com
*/
#include "SMC.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfour-char-constants"
/* Reference: https://logi.wiki/index.php/SMC_Sensor_Codes */
uint32_t SMCKeyTCXC = 'TCXC';
uint32_t SMCKeyCUS1 = 'CUS1';
uint32_t SMCKeyTC0D = 'TC0D';
uint32_t SMCKeyTC0C = 'TC0C';
uint32_t SMCKeyTCAD = 'TCAD';
#pragma clang diagnostic pop
/*
* Reference:
* - https://opensource.apple.com/source/IOKitUser/
* - https://opensource.apple.com/source/IOKitUser/IOKitUser-647.6/pwr_mgt.subproj/IOPMLibPrivate.c
*/
IOReturn SMCReadKey( uint32_t key, uint8_t * buf, IOByteCount * maxSize )
{
SMCParamStruct input;
SMCParamStruct output;
IOReturn ret;
if( key == 0 || buf == NULL )
{
return kIOReturnCannotWire;
}
memset( buf, 0, *( maxSize ) );
memset( &input, 0, sizeof( SMCParamStruct ) );
memset( &output, 0, sizeof( SMCParamStruct ) );
input.data8 = kSMCGetKeyInfo;
input.key = key;
SMCCallFunction( kSMCHandleYPCEvent, &input, &output );
if( output.result == kSMCKeyNotFound )
{
return kIOReturnNotFound;
}
else if( output.result != kSMCSuccess )
{
return kIOReturnInternalError;
}
input.data8 = kSMCReadKey;
input.key = key;
input.keyInfo.dataSize = output.keyInfo.dataSize;
memset( &output, 0, sizeof( SMCParamStruct ) );
ret = SMCCallFunction( kSMCHandleYPCEvent, &input, &output );
if( output.result == kSMCKeyNotFound )
{
return kIOReturnNotFound;
}
else if( output.result != kSMCSuccess )
{
return kIOReturnInternalError;
}
if( *( maxSize ) > input.keyInfo.dataSize )
{
*( maxSize ) = input.keyInfo.dataSize;
}
for( IOByteCount i = 0; i < *( maxSize ); i++ )
{
buf[ i ] = output.bytes[ i ];
}
return ret;
}
IOReturn SMCCallFunction( uint32_t function, SMCParamStruct * input, SMCParamStruct * output )
{
io_connect_t connection;
io_service_t smc;
IOReturn result;
smc = IOServiceGetMatchingService( kIOMasterPortDefault, IOServiceMatching( "AppleSMC" ) );
if( smc == IO_OBJECT_NULL )
{
return kIOReturnNotFound;
}
result = IOServiceOpen( smc, mach_task_self(), 1, &connection );
if( result != kIOReturnSuccess || connection == IO_OBJECT_NULL )
{
return result;
}
result = IOConnectCallMethod( connection, kSMCUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL );
if( result != kIOReturnSuccess )
{
goto exit;
}
{
size_t outputSize;
outputSize = sizeof( SMCParamStruct );
result = IOConnectCallStructMethod( connection, function, input, sizeof( SMCParamStruct ), output, &outputSize );
}
exit:
if( connection != IO_OBJECT_NULL )
{
IOConnectCallMethod( connection, kSMCUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL );
IOServiceClose( connection );
}
return result;
}
bool SMCGetCPUTemperature( uint32_t key, double * valueOut )
{
uint8_t bytes[ 2 ];
IOByteCount size;
memset( &bytes, 0, sizeof( bytes ) );
size = sizeof( bytes );
if( SMCReadKey( key, ( uint8_t * )&bytes, &size ) != kIOReturnSuccess || size != 2 )
{
if( valueOut )
{
*( valueOut ) = 0.0;
}
return false;
}
{
double t1;
double t2;
t1 = bytes[ 0 ] & 0x7F;
t2 = bytes[ 1 ];
t2 /= 1 << 8;
if( valueOut )
{
*( valueOut ) = t1 + t2;
}
return true;
}
}

View File

@@ -1,18 +1,18 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2020 Jean-David Gadina - www.xs-labs.com
*
*
* Copyright (c) 2022 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -22,34 +22,29 @@
* THE SOFTWARE.
******************************************************************************/
/*!
* @header SMC.h
* @copyright (c) 2020, Jean-David Gadina - www.xs-labs.com
*/
#ifndef SMC_H
#define SMC_H
#include <stdint.h>
#include <IOKit/IOKitLib.h>
@import IOKit;
/*
* Reference:
* - https://github.com/apple-oss-distributions/IOKitUser
* - https://opensource.apple.com/source/IOKitUser/
* - https://opensource.apple.com/source/IOKitUser/IOKitUser-647.6/pwr_mgt.subproj/IOPMLibPrivate.c
*/
/* Do not modify - defined by AppleSMC.kext */
enum
{
kSMCKeyNotFound = 0x84
};
/* Do not modify - defined by AppleSMC.kext */
enum
{
kSMCSuccess = 0,
kSMCError = 1
kSMCSuccess = 0,
kSMCError = 1
};
/* Do not modify - defined by AppleSMC.kext */
enum
{
kSMCUserClientOpen = 0,
@@ -62,6 +57,7 @@ enum
kSMCGetKeyInfo = 9
};
/* Do not modify - defined by AppleSMC.kext */
typedef struct
{
unsigned char major;
@@ -72,6 +68,7 @@ typedef struct
}
SMCVersion;
/* Do not modify - defined by AppleSMC.kext */
typedef struct
{
uint16_t version;
@@ -82,14 +79,16 @@ typedef struct
}
SMCPLimitData;
/* Do not modify - defined by AppleSMC.kext */
typedef struct
{
IOByteCount dataSize;
uint32_t dataType;
uint8_t dataAttributes;
uint32_t dataSize;
uint32_t dataType;
uint8_t dataAttributes;
}
SMCKeyInfoData;
/* Do not modify - defined by AppleSMC.kext */
typedef struct
{
uint32_t key;
@@ -104,14 +103,5 @@ typedef struct
}
SMCParamStruct;
extern uint32_t SMCKeyTCXC;
extern uint32_t SMCKeyCUS1;
extern uint32_t SMCKeyTC0D;
extern uint32_t SMCKeyTC0C;
extern uint32_t SMCKeyTCAD;
IOReturn SMCReadKey( uint32_t key, uint8_t * buf, IOByteCount * maxSize );
IOReturn SMCCallFunction( uint32_t function, SMCParamStruct * input, SMCParamStruct * output );
bool SMCGetCPUTemperature( uint32_t key, double * valueOut );
#endif /* SMC_H */
extern const uint32_t kSMCKeyNKEY;
extern const uint32_t kSMCKeyACID;

View File

@@ -1,7 +1,7 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2021 Jean-David Gadina - www.xs-labs.com
* Copyright (c) 2022 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,15 +22,19 @@
* THE SOFTWARE.
******************************************************************************/
/*!
* @header AppleSilicon.h
* @copyright (c) 2021, Jean-David Gadina - www.xs-labs.com
*/
@import Foundation;
@class SMCData;
NS_ASSUME_NONNULL_BEGIN
NSDictionary< NSString *, NSNumber * > * ReadAppleSiliconSensors( void );
@interface SMC: NSObject
@property( class, nonatomic, readonly ) SMC * shared;
- ( instancetype )init;
- ( NSArray< SMCData * > * )readAllKeys;
@end
NS_ASSUME_NONNULL_END

405
Hot/Classes/SMC/SMC.m Normal file
View File

@@ -0,0 +1,405 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#import "SMC.h"
#import "SMC-Internal.h"
#import "Hot-Swift.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfour-char-constants"
const uint32_t kSMCKeyNKEY = '#KEY';
const uint32_t kSMCKeyACID = 'ACID';
#pragma clang diagnostic push
@import IOKit;
NS_ASSUME_NONNULL_BEGIN
@interface SMC()
@property( nonatomic, readwrite, assign ) io_connect_t connection;
@property( nonatomic, readwrite, strong ) NSMutableArray< NSNumber * > * keys;
@property( nonatomic, readwrite, strong ) NSMutableDictionary< NSNumber *, NSValue * > * keyInfoCache;
+ ( NSError * )errorWithTitle: ( NSString * )title message: ( NSString * )message code: ( NSInteger )code;
- ( BOOL )callSMCFunction: ( uint32_t )function input: ( const SMCParamStruct * )input output: ( SMCParamStruct * )output;
- ( BOOL )readSMCKeyInfo: ( SMCKeyInfoData * )info forKey: ( uint32_t )key;
- ( BOOL )readSMCKey: ( uint32_t * )key atIndex: ( uint32_t )index;
- ( BOOL )readSMCKey: ( uint32_t )key buffer: ( uint8_t * )buffer maxSize: ( uint32_t * )maxSize keyInfo: ( SMCKeyInfoData * _Nullable )keyInfo;
- ( uint32_t )readSMCKeyCount;
- ( uint32_t )readInteger: ( uint8_t * )data size: ( uint32_t )size;
@end
NS_ASSUME_NONNULL_END
@implementation SMC
+ ( SMC * )shared
{
static dispatch_once_t once;
static SMC * instance;
dispatch_once
(
&once,
^( void )
{
instance = [ SMC new ];
}
);
return instance;
}
+ ( NSError * )errorWithTitle: ( NSString * )title message: ( NSString * )message code: ( NSInteger )code
{
NSDictionary * info =
@{
NSLocalizedDescriptionKey: title,
NSLocalizedRecoverySuggestionErrorKey: message
};
return [ [ NSError alloc ] initWithDomain: NSCocoaErrorDomain code: code userInfo: info ];
}
- ( instancetype )init
{
if( ( self = [ super init ] ) )
{
self.keys = [ NSMutableArray new ];
self.keyInfoCache = [ NSMutableDictionary new ];
[ self open: nil ];
}
return self;
}
- ( oneway void )dealloc
{
[ self close ];
}
- ( NSArray< SMCData * > * )readAllKeys
{
if( self.connection == IO_OBJECT_NULL )
{
return @[];
}
if( self.keys.count == 0 )
{
uint32_t count = [ self readSMCKeyCount ];
for( uint32_t i = 0; i < count; i++ )
{
uint32_t key = 0;
if( [ self readSMCKey: &key atIndex: i ] == NO )
{
continue;
}
if( key != 0 )
{
[ self.keys addObject: [ NSNumber numberWithUnsignedInt: key ] ];
}
}
}
NSMutableArray< SMCData * > * items = [ [ NSMutableArray alloc ] initWithCapacity: self.keys.count ];
for( NSNumber * key in self.keys )
{
SMCKeyInfoData info;
uint8_t data[ 32 ];
uint32_t size = sizeof( data );
if( [ self readSMCKey: key.unsignedIntValue buffer: data maxSize: &size keyInfo: &info ] == NO )
{
continue;
}
SMCData * item = [ [ SMCData alloc ] initWithKey: key.unsignedIntValue type: info.dataType data: [ NSData dataWithBytes: data length: size ] ];
[ items addObject: item ];
}
return items;
}
- ( BOOL )open: ( NSError * _Nullable __autoreleasing * )error
{
if( self.connection != IO_OBJECT_NULL )
{
return YES;
}
io_service_t smc = IOServiceGetMatchingService( kIOMasterPortDefault, IOServiceMatching( "AppleSMC" ) );
if( smc == IO_OBJECT_NULL )
{
if( error )
{
*( error ) = [ SMC errorWithTitle: @"Cannot Open SMC" message: @"Unable to retrieve the SMC service." code: -1 ];
}
return NO;
}
io_connect_t connection = IO_OBJECT_NULL;
kern_return_t result = IOServiceOpen( smc, mach_task_self(), 0, &connection );
if( result != kIOReturnSuccess || connection == IO_OBJECT_NULL )
{
if( error )
{
*( error ) = [ SMC errorWithTitle: @"Cannot Open SMC" message: @"Unable to open the SMC service." code: -1 ];
}
return NO;
}
self.connection = connection;
return YES;
}
- ( BOOL )close
{
if( self.connection == IO_OBJECT_NULL )
{
return YES;
}
if( IOServiceClose( self.connection ) != kIOReturnSuccess )
{
return false;
}
self.connection = IO_OBJECT_NULL;
return YES;
}
- ( BOOL )callSMCFunction: ( uint32_t )function input: ( const SMCParamStruct * )input output: ( SMCParamStruct * )output
{
size_t inputSize = sizeof( SMCParamStruct );
size_t outputSize = sizeof( SMCParamStruct );
kern_return_t result = IOConnectCallMethod( self.connection, kSMCUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL );
if( result != kIOReturnSuccess )
{
return NO;
}
result = IOConnectCallStructMethod( self.connection, function, input, inputSize, output, &outputSize );
IOConnectCallMethod( self.connection, kSMCUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL );
return result == kIOReturnSuccess;
}
- ( BOOL )readSMCKeyInfo: ( SMCKeyInfoData * )info forKey: ( uint32_t )key
{
if( info == NULL || key == 0 )
{
return NO;
}
{
NSValue * cached = self.keyInfoCache[ [ NSNumber numberWithUnsignedInt: key ] ];
if( cached != nil )
{
*( info ) = *( ( SMCKeyInfoData * )( cached.pointerValue ) );
return YES;
}
}
SMCParamStruct input;
SMCParamStruct output;
bzero( &input, sizeof( SMCParamStruct ) );
bzero( &output, sizeof( SMCParamStruct ) );
input.data8 = kSMCGetKeyInfo;
input.key = key;
if( [ self callSMCFunction: kSMCHandleYPCEvent input: &input output: &output ] == NO )
{
return NO;
}
if( output.result != kSMCSuccess )
{
return NO;
}
*( info ) = output.keyInfo;
{
SMCKeyInfoData * cached = calloc( sizeof( SMCKeyInfoData ), 1 );
if( cached != NULL )
{
*( cached ) = output.keyInfo;
self.keyInfoCache[ [ NSNumber numberWithUnsignedInt: key ] ] = [ NSValue valueWithPointer: cached ];
}
}
return YES;
}
- ( BOOL )readSMCKey: ( uint32_t * )key atIndex: ( uint32_t )index
{
if( key == NULL )
{
return NO;
}
SMCParamStruct input;
SMCParamStruct output;
bzero( &input, sizeof( SMCParamStruct ) );
bzero( &output, sizeof( SMCParamStruct ) );
input.data8 = kSMCGetKeyFromIndex;
input.data32 = index;
if( [ self callSMCFunction: kSMCHandleYPCEvent input: &input output: &output ] == NO )
{
return NO;
}
if( output.result != kSMCSuccess )
{
return NO;
}
*( key ) = output.key;
return YES;
}
- ( BOOL )readSMCKey: ( uint32_t )key buffer: ( uint8_t * )buffer maxSize: ( uint32_t * )maxSize keyInfo: ( SMCKeyInfoData * _Nullable )keyInfo
{
if( key == 0 || buffer == NULL || maxSize == NULL )
{
return NO;
}
SMCKeyInfoData info;
if( [ self readSMCKeyInfo: &info forKey: key ] == NO )
{
return NO;
}
SMCParamStruct input;
SMCParamStruct output;
bzero( &input, sizeof( SMCParamStruct ) );
bzero( &output, sizeof( SMCParamStruct ) );
input.key = key;
input.data8 = kSMCReadKey;
input.keyInfo.dataSize = info.dataSize;
if( [ self callSMCFunction: kSMCHandleYPCEvent input: &input output: &output ] == NO )
{
return NO;
}
if( output.result != kSMCSuccess )
{
return NO;
}
if( *( maxSize ) < info.dataSize )
{
return NO;
}
if( keyInfo != NULL )
{
*( keyInfo ) = info;
}
*( maxSize ) = info.dataSize;
bzero( buffer, *( maxSize ) );
for( uint32_t i = 0; i < info.dataSize; i++ )
{
if( key == kSMCKeyACID )
{
buffer[ i ] = output.bytes[ i ];
}
else
{
buffer[ i ] = output.bytes[ info.dataSize - ( i + 1 ) ];
}
}
return YES;
}
- ( uint32_t )readSMCKeyCount
{
uint8_t data[ 8 ];
uint32_t size = sizeof( data );
bzero( data, size );
if( [ self readSMCKey: kSMCKeyNKEY buffer: data maxSize: &size keyInfo: NULL ] == NO )
{
return 0;
}
return [ self readInteger: data size: size ];
}
- ( uint32_t )readInteger: ( uint8_t * )data size: ( uint32_t )size
{
uint32_t n = 0;
if( size > sizeof( uint32_t ) )
{
return 0;
}
for( uint32_t i = 0; i < size; i++ )
{
n |= ( uint32_t )( data[ i ] ) << ( i * 8 );
}
return n;
}
@end

View File

@@ -0,0 +1,180 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Foundation
@objc
public class SMCData: NSObject
{
@objc public dynamic var key: UInt32
@objc public dynamic var type: UInt32
@objc public dynamic var data: Data
@objc public dynamic var value: Any?
@objc public var keyName: String
{
SMCData.fourCC( value: self.key )
}
@objc public var typeName: String
{
SMCData.fourCC( value: self.type )
}
@objc
public init( key: UInt32, type: UInt32, data: Data )
{
self.key = key
self.type = type
self.data = data
self.value = SMCData.value( for: data, type: type )
}
private class func fourCC( value: UInt32 ) -> String
{
let c1 = UInt8( ( value >> 24 ) & 0xFF )
let c2 = UInt8( ( value >> 16 ) & 0xFF )
let c3 = UInt8( ( value >> 8 ) & 0xFF )
let c4 = UInt8( ( value >> 0 ) & 0xFF )
return String( format: "%c%c%c%c", c1, c2, c3, c4 )
}
private class func value( for data: Data, type: UInt32 ) -> Any?
{
switch self.fourCC( value: type )
{
case "si8 ": return self.sint8( data: data ).byteSwapped
case "ui8 ": return self.uint8( data: data ).byteSwapped
case "si16": return self.sint16( data: data ).byteSwapped
case "ui16": return self.uint16( data: data ).byteSwapped
case "si32": return self.sint32( data: data ).byteSwapped
case "ui32": return self.uint32( data: data ).byteSwapped
case "si64": return self.sint64( data: data ).byteSwapped
case "ui64": return self.uint64( data: data ).byteSwapped
case "flt ": return self.float32( data: data )
case "ioft": return self.ioFloat( data: data )
case "sp78": return self.sp78( data: data )
case "flag": return data[ 0 ] == 1 ? "True" : "False"
case "ch8*": return String( data: Data( data.reversed() ), encoding: .utf8 )
default: return nil
}
}
private class func sint8( data: Data ) -> Int8
{
Int8( bitPattern: self.uint8( data: data ) )
}
private class func sint16( data: Data ) -> Int16
{
Int16( bitPattern: self.uint16( data: data ) )
}
private class func sint32( data: Data ) -> Int32
{
Int32( bitPattern: self.uint32( data: data ) )
}
private class func sint64( data: Data ) -> Int64
{
Int64( bitPattern: self.uint64( data: data ) )
}
private class func uint8( data: Data ) -> UInt8
{
UInt8( data[ 0 ] )
}
private class func uint16( data: Data ) -> UInt16
{
let u1 = UInt16( data[ 0 ] ) << 8
let u2 = UInt16( data[ 1 ] ) << 0
return u1 | u2
}
private class func uint32( data: Data ) -> UInt32
{
let u1 = UInt32( data[ 0 ] ) << 24
let u2 = UInt32( data[ 1 ] ) << 16
let u3 = UInt32( data[ 2 ] ) << 8
let u4 = UInt32( data[ 3 ] ) << 0
return u1 | u2 | u3 | u4
}
private class func uint64( data: Data ) -> UInt64
{
let u1 = UInt64( data[ 0 ] ) << 56
let u2 = UInt64( data[ 1 ] ) << 48
let u3 = UInt64( data[ 2 ] ) << 40
let u4 = UInt64( data[ 3 ] ) << 32
let u5 = UInt64( data[ 4 ] ) << 24
let u6 = UInt64( data[ 5 ] ) << 16
let u7 = UInt64( data[ 6 ] ) << 8
let u8 = UInt64( data[ 7 ] ) << 0
return u1 | u2 | u3 | u4 | u5 | u6 | u7 | u8
}
private class func float32( data: Data ) -> Float32
{
Float32( bitPattern: self.uint32( data: data ) )
}
private class func float64( data: Data ) -> Float64
{
Float64( bitPattern: self.uint64( data: data ) )
}
private class func ioFloat( data: Data ) -> Double
{
if data.count != 8
{
return 0
}
let u64 = self.uint64( data: data )
let integral = Double( u64 >> 16 )
let mask = pow( 2.0, 16.0 ) - 1
let fractional = Double( u64 & UInt64( mask ) ) / Double( 1 << 16 )
return integral + fractional
}
private class func sp78( data: Data ) -> Double
{
if data.count != 2
{
return 0
}
let b1 = Double( data[ 1 ] & 0x7F )
let b2 = Double( data[ 0 ] ) / Double( 1 << 8 )
return b1 + b2
}
}

View File

@@ -1,180 +0,0 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2021 Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#import "Sensors.h"
#import "Hot-Swift.h"
#import "IOHID.h"
NS_ASSUME_NONNULL_BEGIN
@interface Sensors()
@property( nonatomic, readwrite, strong ) NSMutableDictionary< NSString *, SensorData * > * sensors;
@property( atomic, readwrite, strong, nullable ) void ( ^ completion )( void );
@property( atomic, readwrite, assign ) BOOL shouldRun;
- ( void )run;
- ( void )readSensors: ( NSTimer * )timer;
- ( void )readSensors: ( SensorDataKind )kind page: ( IOHIDPage )page usage: ( NSInteger )usage event: ( IOHIDEvent )eventType client: ( IOHIDEventSystemClientRef )client;
- ( void )addSensorData: ( double )value name: ( NSString * )name kind: ( SensorDataKind )kind properties: ( nullable NSDictionary * )properties;
@end
NS_ASSUME_NONNULL_END
@implementation Sensors
- ( instancetype )init
{
if( ( self = [ super init ] ) )
{
self.sensors = [ NSMutableDictionary new ];
self.data = [ NSArray new ];
self.shouldRun = YES;
dispatch_async
(
dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ),
^( void )
{
[ self run ];
}
);
}
return self;
}
- ( void )stop: ( void ( ^ _Nullable )( void ) )completion
{
if( self.shouldRun == false )
{
return;
}
self.completion = completion;
self.shouldRun = false;
}
- ( void )run
{
IOHIDEventSystemClientRef client = IOHIDEventSystemClientCreate( kCFAllocatorDefault );
NSDictionary * info = @{ @"Client" : [ NSValue valueWithPointer: client ] };
NSTimer * timer = [ NSTimer timerWithTimeInterval: 1 target: self selector: @selector( readSensors: ) userInfo: info repeats: YES ];
[ self readSensors: timer ];
[ [ NSRunLoop currentRunLoop ] addTimer: timer forMode: NSDefaultRunLoopMode ];
while( self.shouldRun )
{
[ [ NSRunLoop currentRunLoop ] runUntilDate: [ NSDate dateWithTimeIntervalSinceNow: 5 ] ];
}
void ( ^ completion )( void ) = self.completion;
self.completion = nil;
if( completion != nil )
{
completion();
}
}
- ( void )readSensors: ( NSTimer * )timer
{
IOHIDEventSystemClientRef client = ( ( NSValue * )( timer.userInfo[ @"Client" ] ) ).pointerValue;
if( client != nil )
{
[ self readSensors: SensorDataKindThermal page: IOHIDPageAppleVendor usage: IOHIDUsageAppleVendorTemperatureSensor event: IOHIDEventTypeTemperature client: client ];
[ self readSensors: SensorDataKindVoltage page: IOHIDPageAppleVendorPowerSensor usage: IOHIDUsageAppleVendorPowerSensorVoltage event: IOHIDEventTypePower client: client ];
[ self readSensors: SensorDataKindCurrent page: IOHIDPageAppleVendorPowerSensor usage: IOHIDUsageAppleVendorPowerSensorCurrent event: IOHIDEventTypePower client: client ];
dispatch_async
(
dispatch_get_main_queue(),
^( void )
{
self.data = self.sensors.allValues;
}
);
}
}
- ( void )readSensors: ( SensorDataKind )kind page: ( IOHIDPage )page usage: ( NSInteger )usage event: ( IOHIDEvent )eventType client: ( IOHIDEventSystemClientRef )client
{
NSDictionary * filter =
@{
@"PrimaryUsagePage" : [ NSNumber numberWithLongLong: page ],
@"PrimaryUsage" : [ NSNumber numberWithLongLong: usage ]
};
IOHIDEventSystemClientSetMatching( client, ( __bridge CFDictionaryRef )filter );
{
NSArray * services = CFBridgingRelease( IOHIDEventSystemClientCopyServices( client ) );
for( id o in services )
{
IOHIDServiceClientRef service = ( __bridge IOHIDServiceClientRef )o;
CFTypeRef event = IOHIDServiceClientCopyEvent( service, eventType, 0, 0 );
NSString * name = CFBridgingRelease( IOHIDServiceClientCopyProperty( service, CFSTR( "Product" ) ) );
NSArray * keys = @[ @"IOClass", @"IOProviderClass", @"IONameMatch", @"Product", @"DeviceUsagePairs" ];
NSDictionary * properties = CFBridgingRelease( IOHIDServiceClientCopyProperties( service, ( __bridge CFArrayRef )keys ) );
if( name != nil && event != nil )
{
[ self addSensorData: IOHIDEventGetFloatValue( event, eventType << 16 ) name: name kind: kind properties: properties ];
}
if( event != nil )
{
CFRelease( event );
}
}
}
}
- ( void )addSensorData: ( double )value name: ( NSString * )name kind: ( SensorDataKind )kind properties: ( nullable NSDictionary * )properties
{
NSString * key = [ NSString stringWithFormat: @"%llu.%@", ( uint64_t )kind, name ];
SensorData * data = [ self.sensors objectForKey: key ];
if( data == nil )
{
data = [ [ SensorData alloc ] initWithKind: kind name: name properties: properties ];
[ self.sensors setObject: data forKey: key ];
}
dispatch_async
(
dispatch_get_main_queue(),
^( void )
{
[ data addValue: value ];
}
);
}
@end

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19162" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19162"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="SensorsWindowController" customModule="Hot" customModuleProvider="target">
<customObject id="-2" userLabel="File's Owner" customClass="SensorsWindowController" customModule="Sensors" customModuleProvider="target">
<connections>
<outlet property="arrayController" destination="k4f-4o-be4" id="F6X-Lo-Fc0"/>
<outlet property="collectionView" destination="d8j-id-ziA" id="tbm-Yo-sK6"/>
@@ -19,7 +19,7 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="800" height="515"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1025"/>
<rect key="screenRect" x="0.0" y="0.0" width="1710" height="1069"/>
<value key="minSize" type="size" width="800" height="515"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="515"/>
@@ -113,6 +113,26 @@
<binding destination="-2" name="value" keyPath="self.showCurrent" id="McY-1z-eLE"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="AZ7-l5-9da">
<rect key="frame" x="481" y="21" width="62" height="18"/>
<buttonCell key="cell" type="check" title="IOHID" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="B30-xT-MxH">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="-2" name="value" keyPath="self.showIOHID" id="BgH-kZ-wRG"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="wQZ-5m-sLD">
<rect key="frame" x="549" y="21" width="55" height="18"/>
<buttonCell key="cell" type="check" title="SMC" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="lBw-Xe-W5E">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="-2" name="value" keyPath="self.showSMC" id="vG2-nh-ynR"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="wh8-P7-8p4">
<rect key="frame" x="610" y="22" width="79" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Graph Style:" id="6Ty-8X-UI6">
@@ -142,12 +162,14 @@
</subviews>
<constraints>
<constraint firstItem="0b0-bM-ppa" firstAttribute="leading" secondItem="X4f-ON-Yh7" secondAttribute="leading" constant="20" symbolic="YES" id="7Hg-zM-lO0"/>
<constraint firstItem="wh8-P7-8p4" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="DL0-ry-nBa" secondAttribute="trailing" constant="8" symbolic="YES" id="AMf-YL-aMc"/>
<constraint firstItem="AZ7-l5-9da" firstAttribute="centerY" secondItem="DL0-ry-nBa" secondAttribute="centerY" id="95S-Ic-EYV"/>
<constraint firstItem="YH9-KV-isM" firstAttribute="centerY" secondItem="CWx-dr-5aC" secondAttribute="centerY" id="DiY-62-WNM"/>
<constraint firstItem="0b0-bM-ppa" firstAttribute="top" secondItem="X4f-ON-Yh7" secondAttribute="top" constant="20" symbolic="YES" id="MLt-9Q-NWw"/>
<constraint firstItem="wQZ-5m-sLD" firstAttribute="leading" secondItem="AZ7-l5-9da" secondAttribute="trailing" constant="8" symbolic="YES" id="TAj-3M-Ri4"/>
<constraint firstItem="wh8-P7-8p4" firstAttribute="centerY" secondItem="DL0-ry-nBa" secondAttribute="centerY" id="TS8-6H-T7P"/>
<constraint firstItem="DL0-ry-nBa" firstAttribute="centerY" secondItem="YH9-KV-isM" secondAttribute="centerY" id="UFB-Be-d69"/>
<constraint firstItem="b2Z-bC-lIL" firstAttribute="leading" secondItem="wh8-P7-8p4" secondAttribute="trailing" constant="8" symbolic="YES" id="V4o-Be-jIe"/>
<constraint firstItem="AZ7-l5-9da" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="DL0-ry-nBa" secondAttribute="trailing" constant="8" symbolic="YES" id="guo-9T-pSR"/>
<constraint firstItem="CWx-dr-5aC" firstAttribute="leading" secondItem="X4f-ON-Yh7" secondAttribute="leading" constant="20" symbolic="YES" id="kHN-fy-wU3"/>
<constraint firstItem="DL0-ry-nBa" firstAttribute="leading" secondItem="YH9-KV-isM" secondAttribute="trailing" constant="8" symbolic="YES" id="kXC-gz-rYd"/>
<constraint firstItem="b2Z-bC-lIL" firstAttribute="top" secondItem="0b0-bM-ppa" secondAttribute="bottom" constant="20" symbolic="YES" id="nmc-VG-jfo"/>
@@ -156,7 +178,8 @@
<constraint firstAttribute="trailing" secondItem="0b0-bM-ppa" secondAttribute="trailing" constant="20" symbolic="YES" id="vhy-3U-orM"/>
<constraint firstAttribute="trailing" secondItem="b2Z-bC-lIL" secondAttribute="trailing" constant="20" symbolic="YES" id="vmq-Sh-oFu"/>
<constraint firstItem="b2Z-bC-lIL" firstAttribute="centerY" secondItem="wh8-P7-8p4" secondAttribute="centerY" id="wRu-AK-pi5"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="DL0-ry-nBa" secondAttribute="trailing" constant="20" symbolic="YES" id="yDe-dg-UV7"/>
<constraint firstItem="wh8-P7-8p4" firstAttribute="leading" secondItem="wQZ-5m-sLD" secondAttribute="trailing" constant="8" symbolic="YES" id="ywZ-bR-CBb"/>
<constraint firstItem="wQZ-5m-sLD" firstAttribute="centerY" secondItem="AZ7-l5-9da" secondAttribute="centerY" id="zw8-PQ-uUL"/>
</constraints>
<connections>
<binding destination="-2" name="hidden" keyPath="self.sensors.data" id="oYT-Hj-xEu">

View File

@@ -26,7 +26,7 @@ import Cocoa
public class Colors
{
public class func color( for kind: SensorData.Kind ) -> NSColor
public class func color( for kind: SensorHistoryData.Kind ) -> NSColor
{
switch kind
{

View File

@@ -35,48 +35,36 @@ public class SensorGraphView: NSView
case bars
}
@objc public dynamic var sensor: SensorData?
@objc public dynamic var sensor: SensorHistoryData?
private var graphStyleObserver: NSKeyValueObservation?
private var defaultsObserver: Any?
public override init( frame: NSRect )
{
super.init( frame: frame )
UserDefaults.standard.addObserver( self, forKeyPath: "graphStyle", options: .new, context: nil )
self.defaultsObserver = NotificationCenter.default.addObserver( forName: UserDefaults.didChangeNotification, object: nil, queue: nil )
{
[ weak self ] _ in self?.needsDisplay = true
}
}
required init?( coder: NSCoder )
{
super.init( coder: coder )
UserDefaults.standard.addObserver( self, forKeyPath: "graphStyle", options: .new, context: nil )
}
deinit
{
UserDefaults.standard.removeObserver( self, forKeyPath: "graphStyle" )
}
public override func observeValue( forKeyPath keyPath: String?, of object: Any?, change: [ NSKeyValueChangeKey: Any ]?, context: UnsafeMutableRawPointer? )
{
if let keyPath = keyPath, keyPath == "graphStyle", let object = object as? UserDefaults, object == UserDefaults.standard
self.defaultsObserver = NotificationCenter.default.addObserver( forName: UserDefaults.didChangeNotification, object: nil, queue: nil )
{
self.needsDisplay = true
[ weak self ] _ in self?.needsDisplay = true
}
else
{
super.observeValue( forKeyPath: keyPath, of: object, change: change, context: context )
}
}
private var graphStyle: GraphStyle
{
GraphStyle( rawValue: UserDefaults.standard.integer( forKey: "graphStyle" ) ) ?? .gradient
}
public override func draw( _ rect: NSRect )
{
self.drawBorder( in: rect )
self.drawBackground( in: rect )
let style = GraphStyle( rawValue: UserDefaults.standard.integer( forKey: "sensorsWindowGraphStyle" ) ) ?? .bars
self.drawBorder( in: rect, style: style )
self.drawBackground( in: rect, style: style )
guard let sensor = self.sensor, sensor.values.count >= 2
else
@@ -94,7 +82,7 @@ public class SensorGraphView: NSView
max = 100
}
if self.graphStyle == .bars
if style == .bars
{
self.drawBars(
in: rect,
@@ -113,14 +101,15 @@ public class SensorGraphView: NSView
values: values,
min: min,
max: max,
color: Colors.color( for: sensor.kind )
color: Colors.color( for: sensor.kind ),
style: style
)
}
}
private func drawBorder( in rect: NSRect )
private func drawBorder( in rect: NSRect, style: GraphStyle )
{
if self.graphStyle == .bars
if style == .bars
{
return
}
@@ -132,9 +121,9 @@ public class SensorGraphView: NSView
border.stroke()
}
private func drawBackground( in rect: NSRect )
private func drawBackground( in rect: NSRect, style: GraphStyle )
{
if self.graphStyle == .bars
if style == .bars
{
let c = 15
let h = rect.size.height / CGFloat( c )
@@ -160,7 +149,7 @@ public class SensorGraphView: NSView
}
}
private func drawGraph( in rect: NSRect, kind: SensorData.Kind, values: [ CGFloat ], min: CGFloat, max: CGFloat, color: NSColor )
private func drawGraph( in rect: NSRect, kind: SensorHistoryData.Kind, values: [ CGFloat ], min: CGFloat, max: CGFloat, color: NSColor, style: GraphStyle )
{
let p1 = NSBezierPath()
let p2 = NSBezierPath()
@@ -201,13 +190,13 @@ public class SensorGraphView: NSView
p2.line( to: NSPoint( x: rect.origin.x, y: rect.origin.y - 3 ) )
p2.close()
if self.graphStyle == .gradient
if style == .gradient
{
let gradient = NSGradient( colors: [ color.withAlphaComponent( 0.25 ), color.withAlphaComponent( 0 ) ] )
gradient?.draw( in: p2, angle: -90 )
}
else if self.graphStyle == .fill
else if style == .fill
{
color.setFill()
p2.fill()
@@ -217,7 +206,7 @@ public class SensorGraphView: NSView
p1.stroke()
}
private func drawBars( in rect: NSRect, kind: SensorData.Kind, values: [ CGFloat ], min: CGFloat, max: CGFloat, color: NSColor )
private func drawBars( in rect: NSRect, kind: SensorHistoryData.Kind, values: [ CGFloat ], min: CGFloat, max: CGFloat, color: NSColor )
{
let c = 15
let h = rect.size.height / CGFloat( c )

View File

@@ -25,9 +25,9 @@
import Foundation
@objc
public class SensorData: NSObject
public class SensorHistoryData: NSObject, Synchronizable
{
@objc( SensorDataKind )
@objc( SensorHistoryDataKind )
public enum Kind: Int, CustomStringConvertible
{
case thermal
@@ -45,53 +45,83 @@ public class SensorData: NSObject
}
}
@objc( SensorHistoryDataSource )
public enum Source: Int, CustomStringConvertible
{
case hid
case smc
public var description: String
{
switch self
{
case .hid: return "IOHID"
case .smc: return "SMC"
}
}
}
@objc public private( set ) dynamic var source: Source
@objc public private( set ) dynamic var kind: Kind
@objc public private( set ) dynamic var name: String
@objc public private( set ) dynamic var properties: [ String: Any ]?
@objc public private( set ) dynamic var properties: [ AnyHashable: Any ]?
private var data: [ Double ] = []
@objc public dynamic var values: [ NSNumber ]
{
self.data.map { NSNumber( floatLiteral: $0 ) }
return self.synchronized
{
return self.data.map { NSNumber( floatLiteral: $0 ) }
}
}
@objc public dynamic var min: NSNumber?
{
guard let max = self.data.min()
else
return self.synchronized
{
return nil
}
guard let max = self.data.min()
else
{
return nil
}
return NSNumber( floatLiteral: max )
return NSNumber( floatLiteral: max )
}
}
@objc public dynamic var max: NSNumber?
{
guard let min = self.data.max()
else
return self.synchronized
{
return nil
}
guard let min = self.data.max()
else
{
return nil
}
return NSNumber( floatLiteral: min )
return NSNumber( floatLiteral: min )
}
}
@objc public dynamic var last: NSNumber?
{
guard let last = self.data.last
else
return self.synchronized
{
return nil
}
guard let last = self.data.last
else
{
return nil
}
return NSNumber( floatLiteral: last )
return NSNumber( floatLiteral: last )
}
}
@objc
public init( kind: Kind, name: String, properties: [ String: Any ]? )
public init( source: Source, kind: Kind, name: String, properties: [ AnyHashable: Any ]? )
{
self.source = source
self.kind = kind
self.name = name
self.properties = properties
@@ -100,21 +130,24 @@ public class SensorData: NSObject
@objc( addValue: )
public func add( value: Double )
{
var data = self.data
self.synchronized
{
var data = self.data
data.append( value )
data.append( value )
self.willChangeValue( for: \.values )
self.willChangeValue( for: \.min )
self.willChangeValue( for: \.max )
self.willChangeValue( for: \.last )
self.willChangeValue( for: \.values )
self.willChangeValue( for: \.min )
self.willChangeValue( for: \.max )
self.willChangeValue( for: \.last )
self.data = data.suffix( 50 )
self.data = data.suffix( 50 )
self.didChangeValue( for: \.values )
self.didChangeValue( for: \.min )
self.didChangeValue( for: \.max )
self.didChangeValue( for: \.last )
self.didChangeValue( for: \.values )
self.didChangeValue( for: \.min )
self.didChangeValue( for: \.max )
self.didChangeValue( for: \.last )
}
}
public override var description: String

View File

@@ -39,7 +39,7 @@ public class SensorIcon: ValueTransformer
public override func transformedValue( _ value: Any? ) -> Any?
{
guard let data = value as? SensorData
guard let data = value as? SensorHistoryData
else
{
return nil

View File

@@ -26,7 +26,7 @@ import Cocoa
public class SensorItem: NSCollectionViewItem
{
@objc public dynamic var sensor: SensorData?
@objc public dynamic var sensor: SensorHistoryData?
{
didSet
{

View File

@@ -0,0 +1,145 @@
/*******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2022, Jean-David Gadina - www.xs-labs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
import Cocoa
@objc
public class Sensors: NSObject
{
@objc public private( set ) dynamic var data = [ SensorHistoryData ]()
@objc private dynamic var sensors = [ String: SensorHistoryData ]()
private var shouldRun = true
private var completion: ( () -> Void )?
public override init()
{
super.init()
DispatchQueue.global( qos: .background ).async
{
self.run()
}
}
public func stop( completion: ( () -> Void )? )
{
if self.shouldRun == false
{
return
}
self.completion = completion
self.shouldRun = false
}
private func run()
{
let timer = Timer.scheduledTimer( withTimeInterval: 1, repeats: true )
{
_ in self.readSensors()
}
self.readSensors()
RunLoop.current.add( timer, forMode: .default )
while self.shouldRun
{
RunLoop.current.run( until: Date( timeIntervalSinceNow: 5 ) )
}
let completion = self.completion
self.completion = nil
completion?()
}
private func readSensors()
{
self.readIOHIDSensors()
self.readSMCSensors()
let sensors = self.sensors
DispatchQueue.main.async
{
self.data = [ SensorHistoryData ]( sensors.values )
}
}
private func readIOHIDSensors()
{
IOHID.shared.readTemperatureSensors().forEach { self.addSensorHistoryData( data: $0, kind: .thermal ) }
IOHID.shared.readVoltageSensors().forEach { self.addSensorHistoryData( data: $0, kind: .voltage ) }
IOHID.shared.readCurrentSensors().forEach { self.addSensorHistoryData( data: $0, kind: .current ) }
}
private func readSMCSensors()
{
let all = SMC.shared.readAllKeys()
all.filter { $0.keyName.hasPrefix( "T" ) }.forEach { self.addSensorHistoryData( data: $0, kind: .thermal ) }
all.filter { $0.keyName.hasPrefix( "V" ) }.forEach { self.addSensorHistoryData( data: $0, kind: .voltage ) }
all.filter { $0.keyName.hasPrefix( "I" ) }.forEach { self.addSensorHistoryData( data: $0, kind: .current ) }
}
private func addSensorHistoryData( data: IOHIDData, kind: SensorHistoryData.Kind )
{
let key = String( format: "IOHID.%llu.%@", kind.rawValue, data.name )
if self.sensors[ key ] == nil
{
self.sensors[ key ] = SensorHistoryData( source: .hid, kind: kind, name: data.name, properties: data.properties )
}
self.sensors[ key ]?.add( value: data.value )
}
private func addSensorHistoryData( data: SMCData, kind: SensorHistoryData.Kind )
{
let value: Double
if let f = data.value as? Double
{
value = f
}
else if let f = data.value as? Float32
{
value = Double( f )
}
else
{
return
}
let key = String( format: "SMC.%llu.%@", kind.rawValue, data.keyName )
if self.sensors[ key ] == nil
{
self.sensors[ key ] = SensorHistoryData( source: .smc, kind: kind, name: data.keyName, properties: [ : ] )
}
self.sensors[ key ]?.add( value: value )
}
}

View File

@@ -26,9 +26,9 @@ import Cocoa
public class SensorsWindowController: NSWindowController
{
@objc private dynamic var sensors: Sensors? = Sensors()
@objc private dynamic var sensors = Sensors()
@objc private dynamic var showTemperature = UserDefaults.standard.bool( forKey: "sensorsWindowShowTemperature" )
@objc private dynamic var showTemperature = UserDefaults.standard.object( forKey: "sensorsWindowShowTemperature" ) as? Bool ?? true
{
didSet
{
@@ -37,7 +37,7 @@ public class SensorsWindowController: NSWindowController
}
}
@objc private dynamic var showVoltage = UserDefaults.standard.bool( forKey: "sensorsWindowShowVoltage" )
@objc private dynamic var showVoltage = UserDefaults.standard.object( forKey: "sensorsWindowShowVoltage" ) as? Bool ?? true
{
didSet
{
@@ -46,7 +46,7 @@ public class SensorsWindowController: NSWindowController
}
}
@objc private dynamic var showCurrent = UserDefaults.standard.bool( forKey: "sensorsWindowShowCurrent" )
@objc private dynamic var showCurrent = UserDefaults.standard.object( forKey: "sensorsWindowShowCurrent" ) as? Bool ?? true
{
didSet
{
@@ -55,16 +55,34 @@ public class SensorsWindowController: NSWindowController
}
}
@objc private dynamic var showIOHID = UserDefaults.standard.object( forKey: "sensorsWindowShowIOHID" ) as? Bool ?? true
{
didSet
{
self.updateFilters()
UserDefaults.standard.set( self.showIOHID, forKey: "sensorsWindowShowIOHID" )
}
}
@objc private dynamic var showSMC = UserDefaults.standard.object( forKey: "sensorsWindowShowSMC" ) as? Bool ?? true
{
didSet
{
self.updateFilters()
UserDefaults.standard.set( self.showSMC, forKey: "sensorsWindowShowSMC" )
}
}
@objc private dynamic var searchText: String?
{
didSet { self.updateFilters() }
}
@objc private dynamic var graphStyle = UserDefaults.standard.integer( forKey: "graphStyle" )
@objc private dynamic var graphStyle = UserDefaults.standard.integer( forKey: "sensorsWindowGraphStyle" )
{
didSet
{
UserDefaults.standard.set( self.graphStyle, forKey: "graphStyle" )
UserDefaults.standard.set( self.graphStyle, forKey: "sensorsWindowGraphStyle" )
}
}
@@ -79,20 +97,15 @@ public class SensorsWindowController: NSWindowController
public override func windowDidLoad()
{
super.windowDidLoad()
self.updateFilters()
self.arrayController.sortDescriptors = [ NSSortDescriptor( key: "name", ascending: true, selector: #selector( NSString.localizedCaseInsensitiveCompare( _: ) ) ) ]
self.updateFilters()
}
public func stop()
public func stop( completion: ( () -> Void )? )
{
self.sensors?.stop
{
DispatchQueue.main.async
{
self.sensors = nil
}
}
self.sensors.stop( completion: completion )
}
private func updateFilters()
@@ -101,17 +114,27 @@ public class SensorsWindowController: NSWindowController
if self.showTemperature == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorData )?.kind != .thermal } )
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.kind != .thermal } )
}
if self.showVoltage == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorData )?.kind != .voltage } )
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.kind != .voltage } )
}
if self.showCurrent == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorData )?.kind != .current } )
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.kind != .current } )
}
if self.showIOHID == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.source != .hid } )
}
if self.showSMC == false
{
predicates.append( NSPredicate { o, i in ( o as? SensorHistoryData )?.source != .smc } )
}
if let search = self.searchText, search.count > 0
@@ -139,14 +162,14 @@ extension SensorsWindowController: NSCollectionViewDataSource
public func collectionView( _ collectionView: NSCollectionView, numberOfItemsInSection section: Int ) -> Int
{
( self.arrayController.arrangedObjects as? [ SensorData ] )?.count ?? 0
( self.arrayController.arrangedObjects as? [ SensorHistoryData ] )?.count ?? 0
}
public func collectionView( _ itemForRepresentedObjectAtcollectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath ) -> NSCollectionViewItem
{
let item = self.collectionView.makeItem( withIdentifier: NSUserInterfaceItemIdentifier( rawValue: "SensorItem" ), for: indexPath )
if let item = item as? SensorItem, let sensors = self.arrayController.arrangedObjects as? [ SensorData ]
if let item = item as? SensorItem, let sensors = self.arrayController.arrangedObjects as? [ SensorHistoryData ]
{
if sensors.count > indexPath.item
{

View File

@@ -47,11 +47,11 @@ public class ThermalLog: NSObject
#if arch( arm64 )
return Dictionary( uniqueKeysWithValues:
ReadAppleSiliconSensors().map
IOHID.shared.readTemperatureSensors().map
{
let isCPU = $0.key.hasPrefix( "pACC" ) || $0.key.hasPrefix( "eACC" )
let isCPU = $0.name.hasPrefix( "pACC" ) || $0.name.hasPrefix( "eACC" )
return ( $0.key, ( temperature: $0.value.doubleValue, isCPU: isCPU ) )
return ( $0.name, ( temperature: $0.value, isCPU: isCPU ) )
}
)