[osx] talk to SMC to get CPU and GPU temp for System Info page
authoramet <amet.nospam@gmail.com>
Fri, 30 Aug 2013 09:18:58 +0000 (13:18 +0400)
committeramet <amet.nospam@gmail.com>
Fri, 30 Aug 2013 16:22:31 +0000 (20:22 +0400)
XBMC.xcodeproj/project.pbxproj
xbmc/GUIInfoManager.cpp
xbmc/osx/smc.c [new file with mode: 0644]
xbmc/osx/smc.h [new file with mode: 0644]
xbmc/utils/CPUInfo.cpp

index 60972e9..12a73fa 100644 (file)
@@ -28,6 +28,9 @@
                0E3036EC1760F68A00D93596 /* FavouritesDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E3036EA1760F68A00D93596 /* FavouritesDirectory.cpp */; };
                0E3036ED1760F68A00D93596 /* FavouritesDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E3036EA1760F68A00D93596 /* FavouritesDirectory.cpp */; };
                0E3036EE1760F68A00D93596 /* FavouritesDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E3036EA1760F68A00D93596 /* FavouritesDirectory.cpp */; };
+               180F6C8117CE9A5700127892 /* smc.c in Sources */ = {isa = PBXBuildFile; fileRef = 180F6C8017CE9A5700127892 /* smc.c */; };
+               180F6C8217CE9A5700127892 /* smc.c in Sources */ = {isa = PBXBuildFile; fileRef = 180F6C8017CE9A5700127892 /* smc.c */; };
+               180F6C8317CE9A5700127892 /* smc.c in Sources */ = {isa = PBXBuildFile; fileRef = 180F6C8017CE9A5700127892 /* smc.c */; };
                183FDF8A11AF0B0500B81E9C /* PluginSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 183FDF8811AF0B0500B81E9C /* PluginSource.cpp */; };
                18404DA61396C31B00863BBA /* SlingboxLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 18404DA51396C31B00863BBA /* SlingboxLib.a */; };
                1840B74D13993D8A007C848B /* JSONVariantParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1840B74B13993D8A007C848B /* JSONVariantParser.cpp */; };
                0E30286C1759FCC200D93596 /* SettingsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsManager.h; sourceTree = "<group>"; };
                0E3036EA1760F68A00D93596 /* FavouritesDirectory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FavouritesDirectory.cpp; sourceTree = "<group>"; };
                0E3036EB1760F68A00D93596 /* FavouritesDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FavouritesDirectory.h; sourceTree = "<group>"; };
+               180F6C7F17CE9A5700127892 /* smc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = smc.h; sourceTree = "<group>"; };
+               180F6C8017CE9A5700127892 /* smc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smc.c; sourceTree = "<group>"; };
                18308CB41303370800AA309E /* stat_utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stat_utf8.h; sourceTree = "<group>"; };
                18308CB51303370800AA309E /* stdio_utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdio_utf8.h; sourceTree = "<group>"; };
                183FDF8811AF0B0500B81E9C /* PluginSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginSource.cpp; sourceTree = "<group>"; };
                                6E2FACD20E26E92800DF79EA /* Info.plist */,
                                F51CEEEE0F5C5D20004F4602 /* OSXGNUReplacements.c */,
                                F51CEEF00F5C5D28004F4602 /* OSXGNUReplacements.h */,
+                               180F6C7F17CE9A5700127892 /* smc.h */,
+                               180F6C8017CE9A5700127892 /* smc.c */,
                                E306D12C0DDF7B590052C2AD /* XBMCHelper.cpp */,
                                E306D12D0DDF7B590052C2AD /* XBMCHelper.h */,
                                820023D9171A28A300667D1C /* OSXTextInputResponder.h */,
                                F59EED7E17AD5174005BB7C6 /* ApplicationPlayer.cpp in Sources */,
                                DF29668017B2B04300DF10F9 /* SettingRequirement.cpp in Sources */,
                                DF28DF4D17B8379E0077F41A /* ProfilesOperations.cpp in Sources */,
+                               180F6C8117CE9A5700127892 /* smc.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                F59EED8017AD5174005BB7C6 /* ApplicationPlayer.cpp in Sources */,
                                DF29668217B2B04300DF10F9 /* SettingRequirement.cpp in Sources */,
                                DF28DF4F17B8379E0077F41A /* ProfilesOperations.cpp in Sources */,
+                               180F6C8317CE9A5700127892 /* smc.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                F59EED7F17AD5174005BB7C6 /* ApplicationPlayer.cpp in Sources */,
                                DF29668117B2B04300DF10F9 /* SettingRequirement.cpp in Sources */,
                                DF28DF4E17B8379E0077F41A /* ProfilesOperations.cpp in Sources */,
+                               180F6C8217CE9A5700127892 /* smc.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 56dc58d..a70afca 100644 (file)
@@ -58,6 +58,9 @@
 #include "utils/SeekHandler.h"
 #include "URL.h"
 #include "addons/Skin.h"
+#if defined(TARGET_DARWIN)
+#include "osx/smc.h"
+#endif
 
 // stuff for current song
 #include "music/MusicInfoLoader.h"
@@ -4021,10 +4024,15 @@ string CGUIInfoManager::GetSystemHeatInfo(int info)
 
 CTemperature CGUIInfoManager::GetGPUTemperature()
 {
+  int  value = 0;
+  char scale = 0;
+
+#if defined(TARGET_DARWIN)
+  value = SMCGetTemperature(SMC_KEY_GPU_TEMP);
+  return CTemperature::CreateFromCelsius(value);
+#else
   CStdString  cmd   = g_advancedSettings.m_gpuTempCmd;
-  int         value = 0,
-              ret   = 0;
-  char        scale = 0;
+  int         ret   = 0;
   FILE        *p    = NULL;
 
   if (cmd.IsEmpty() || !(p = popen(cmd.c_str(), "r")))
@@ -4035,6 +4043,7 @@ CTemperature CGUIInfoManager::GetGPUTemperature()
 
   if (ret != 2)
     return CTemperature();
+#endif
 
   if (scale == 'C' || scale == 'c')
     return CTemperature::CreateFromCelsius(value);
diff --git a/xbmc/osx/smc.c b/xbmc/osx/smc.c
new file mode 100644 (file)
index 0000000..9bee2d7
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Apple System Management Control (SMC) Tool
+ * Copyright (C) 2006 devnull
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <IOKit/IOKitLib.h>
+
+#include "smc.h"
+
+static io_connect_t conn;
+
+UInt32 _strtoul(char *str, int size, int base)
+{
+  UInt32 total = 0;
+  int i;
+  
+  for (i = 0; i < size; i++)
+  {
+    if (base == 16)
+      total += str[i] << (size - 1 - i) * 8;
+    else
+      total += (unsigned char) (str[i] << (size - 1 - i) * 8);
+  }
+  return total;
+}
+
+void _ultostr(char *str, UInt32 val)
+{
+  str[0] = '\0';
+  sprintf(str, "%c%c%c%c",
+          (unsigned int) val >> 24,
+          (unsigned int) val >> 16,
+          (unsigned int) val >> 8,
+          (unsigned int) val);
+}
+
+kern_return_t SMCOpen(void)
+{
+  kern_return_t result;
+  mach_port_t   masterPort;
+  io_iterator_t iterator;
+  io_object_t   device;
+  
+  result = IOMasterPort(MACH_PORT_NULL, &masterPort);
+  
+  CFMutableDictionaryRef matchingDictionary = IOServiceMatching("AppleSMC");
+  result = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator);
+  if (result != kIOReturnSuccess)
+  {
+    printf("Error: IOServiceGetMatchingServices() = %08x\n", result);
+    return 1;
+  }
+  
+  device = IOIteratorNext(iterator);
+  IOObjectRelease(iterator);
+  if (device == 0)
+  {
+    printf("Error: no SMC found\n");
+    return 1;
+  }
+  
+  result = IOServiceOpen(device, mach_task_self(), 0, &conn);
+  IOObjectRelease(device);
+  if (result != kIOReturnSuccess)
+  {
+    printf("Error: IOServiceOpen() = %08x\n", result);
+    return 1;
+  }
+  
+  return kIOReturnSuccess;
+}
+
+kern_return_t SMCClose()
+{
+  return IOServiceClose(conn);
+}
+
+
+kern_return_t SMCCall(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure)
+{
+  size_t   structureInputSize;
+  size_t   structureOutputSize;
+  
+  structureInputSize = sizeof(SMCKeyData_t);
+  structureOutputSize = sizeof(SMCKeyData_t);
+  
+#if MAC_OS_X_VERSION_10_5
+  return IOConnectCallStructMethod( conn, index,
+                                   // inputStructure
+                                   inputStructure, structureInputSize,
+                                   // ouputStructure
+                                   outputStructure, &structureOutputSize );
+#else
+  return IOConnectMethodStructureIStructureO( conn, index,
+                                             structureInputSize, /* structureInputSize */
+                                             &structureOutputSize,   /* structureOutputSize */
+                                             inputStructure,        /* inputStructure */
+                                             outputStructure);       /* ouputStructure */
+#endif
+  
+}
+
+kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val)
+{
+  kern_return_t result;
+  SMCKeyData_t  inputStructure;
+  SMCKeyData_t  outputStructure;
+  
+  memset(&inputStructure, 0, sizeof(SMCKeyData_t));
+  memset(&outputStructure, 0, sizeof(SMCKeyData_t));
+  memset(val, 0, sizeof(SMCVal_t));
+  
+  inputStructure.key = _strtoul(key, 4, 16);
+  inputStructure.data8 = SMC_CMD_READ_KEYINFO;
+  
+  result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
+  if (result != kIOReturnSuccess)
+    return result;
+  
+  val->dataSize = outputStructure.keyInfo.dataSize;
+  _ultostr(val->dataType, outputStructure.keyInfo.dataType);
+  inputStructure.keyInfo.dataSize = val->dataSize;
+  inputStructure.data8 = SMC_CMD_READ_BYTES;
+  
+  result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
+  if (result != kIOReturnSuccess)
+    return result;
+  
+  memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes));
+  
+  return kIOReturnSuccess;
+}
+
+double SMCGetTemperature(char *key)
+{
+  SMCVal_t val;
+  kern_return_t result;
+  SMCOpen();
+  result = SMCReadKey(key, &val);
+  SMCClose();
+  if (result == kIOReturnSuccess) {
+    // read succeeded - check returned value
+    if (val.dataSize > 0) {
+      if (strcmp(val.dataType, DATATYPE_SP78) == 0) {
+        // convert fp78 value to temperature
+        int intValue = (val.bytes[0] * 256 + val.bytes[1]) >> 2;
+        return intValue / 64.0;
+      }
+    }
+  }
+  // read failed
+  return 0.0;
+}
+
diff --git a/xbmc/osx/smc.h b/xbmc/osx/smc.h
new file mode 100644 (file)
index 0000000..1a3f014
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Apple System Management Control (SMC) Tool
+ * Copyright (C) 2006 devnull
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __SMC_H__
+#define __SMC_H__
+#endif
+
+#define SMC_VERSION               "0.01"
+
+#define OP_NONE               0
+#define OP_LIST               1
+#define OP_READ               2
+#define OP_READ_FAN           3
+#define OP_WRITE              4
+
+#define KERNEL_INDEX_SMC      2
+
+#define SMC_CMD_READ_BYTES    5
+#define SMC_CMD_WRITE_BYTES   6
+#define SMC_CMD_READ_INDEX    8
+#define SMC_CMD_READ_KEYINFO  9
+#define SMC_CMD_READ_PLIMIT   11
+#define SMC_CMD_READ_VERS     12
+
+#define DATATYPE_FPE2         "fpe2"
+#define DATATYPE_UINT8        "ui8 "
+#define DATATYPE_UINT16       "ui16"
+#define DATATYPE_UINT32       "ui32"
+#define DATATYPE_SP78         "sp78"
+
+// key values
+#define SMC_KEY_CPU_TEMP      "TC0D"
+#define SMC_KEY_GPU_TEMP      "TG0D"
+#define SMC_KEY_FAN0_RPM_MIN  "F0Mn"
+#define SMC_KEY_FAN1_RPM_MIN  "F1Mn"
+#define SMC_KEY_FAN0_RPM_CUR  "F0Ac"
+#define SMC_KEY_FAN1_RPM_CUR  "F1Ac"
+
+
+typedef struct {
+  char                  major;
+  char                  minor;
+  char                  build;
+  char                  reserved[1];
+  UInt16                release;
+} SMCKeyData_vers_t;
+
+typedef struct {
+  UInt16                version;
+  UInt16                length;
+  UInt32                cpuPLimit;
+  UInt32                gpuPLimit;
+  UInt32                memPLimit;
+} SMCKeyData_pLimitData_t;
+
+typedef struct {
+  UInt32                dataSize;
+  UInt32                dataType;
+  char                  dataAttributes;
+} SMCKeyData_keyInfo_t;
+
+typedef char              SMCBytes_t[32];
+
+typedef struct {
+  UInt32                  key;
+  SMCKeyData_vers_t       vers;
+  SMCKeyData_pLimitData_t pLimitData;
+  SMCKeyData_keyInfo_t    keyInfo;
+  char                    result;
+  char                    status;
+  char                    data8;
+  UInt32                  data32;
+  SMCBytes_t              bytes;
+} SMCKeyData_t;
+
+typedef char              UInt32Char_t[5];
+
+typedef struct {
+  UInt32Char_t            key;
+  UInt32                  dataSize;
+  UInt32Char_t            dataType;
+  SMCBytes_t              bytes;
+} SMCVal_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+// prototypes
+double SMCGetTemperature(char *key);
+
+#ifdef __cplusplus
+}
+#endif
index 2a09d07..efbeb53 100644 (file)
@@ -26,6 +26,7 @@
 #if defined(TARGET_DARWIN)
 #include <sys/types.h>
 #include <sys/sysctl.h>
+#include "osx/smc.h"
 #ifdef __ppc__
 #include <mach-o/arch.h>
 #endif
@@ -504,9 +505,14 @@ float CCPUInfo::getCPUFrequency()
 
 bool CCPUInfo::getTemperature(CTemperature& temperature)
 {
-  int         value = 0,
-              ret   = 0;
+  int         value = 0;
   char        scale = 0;
+  
+#if defined(TARGET_DARWIN)
+  value = SMCGetTemperature(SMC_KEY_CPU_TEMP);
+  scale = 'c';
+#else
+  int         ret   = 0;
   FILE        *p    = NULL;
   CStdString  cmd   = g_advancedSettings.m_cpuTempCmd;
 
@@ -546,6 +552,7 @@ bool CCPUInfo::getTemperature(CTemperature& temperature)
 
   if (ret != 2)
     return false; 
+#endif
 
   if (scale == 'C' || scale == 'c')
     temperature = CTemperature::CreateFromCelsius(value);