1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
#include "sensors.hpp"
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hidsystem/IOHIDEventSystemClient.h>
#include <iostream>
#include <map>
#include <string>
extern "C" {
typedef struct __IOHIDEvent *IOHIDEventRef;
typedef struct __IOHIDServiceClient *IOHIDServiceClientRef;
#ifdef __LP64__
typedef double IOHIDFloat;
#else
typedef float IOHIDFloat;
#endif
#define IOHIDEventFieldBase(type) (type << 16)
#define kIOHIDEventTypeTemperature 15
IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef allocator);
int IOHIDEventSystemClientSetMatching(IOHIDEventSystemClientRef client, CFDictionaryRef match);
int IOHIDEventSystemClientSetMatchingMultiple(IOHIDEventSystemClientRef client, CFArrayRef match);
IOHIDEventRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef, int64_t, int32_t, int64_t);
CFStringRef IOHIDServiceClientCopyProperty(IOHIDServiceClientRef service, CFStringRef property);
IOHIDFloat IOHIDEventGetFloatValue(IOHIDEventRef event, int32_t field);
// create a dict ref, like for temperature sensor {"PrimaryUsagePage":0xff00, "PrimaryUsage":0x5}
CFDictionaryRef matching(int page, int usage) {
CFNumberRef nums[2];
CFStringRef keys[2];
keys[0] = CFStringCreateWithCString(0, "PrimaryUsagePage", 0);
keys[1] = CFStringCreateWithCString(0, "PrimaryUsage", 0);
nums[0] = CFNumberCreate(0, kCFNumberSInt32Type, &page);
nums[1] = CFNumberCreate(0, kCFNumberSInt32Type, &usage);
CFDictionaryRef dict = CFDictionaryCreate(0, (const void **)keys, (const void **)nums, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
return dict;
}
CFArrayRef getProductNames(CFDictionaryRef sensors) {
IOHIDEventSystemClientRef system = IOHIDEventSystemClientCreate(kCFAllocatorDefault); // in CFBase.h = NULL
// ... this is the same as using kCFAllocatorDefault or the return value from CFAllocatorGetDefault()
IOHIDEventSystemClientSetMatching(system, sensors);
CFArrayRef matchingsrvs = IOHIDEventSystemClientCopyServices(system); // matchingsrvs = matching services
long count = CFArrayGetCount(matchingsrvs);
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
for (int i = 0; i < count; i++) {
IOHIDServiceClientRef sc = (IOHIDServiceClientRef)CFArrayGetValueAtIndex(matchingsrvs, i);
CFStringRef name = IOHIDServiceClientCopyProperty(sc, CFSTR("Product")); // here we use ...CopyProperty
if (name) {
CFArrayAppendValue(array, name);
} else {
CFArrayAppendValue(array, CFSTR("noname")); // @ gives a Ref like in "CFStringRef name"
}
}
return array;
}
CFArrayRef getThermalValues(CFDictionaryRef sensors) {
IOHIDEventSystemClientRef system = IOHIDEventSystemClientCreate(kCFAllocatorDefault);
IOHIDEventSystemClientSetMatching(system, sensors);
CFArrayRef matchingsrvs = IOHIDEventSystemClientCopyServices(system);
long count = CFArrayGetCount(matchingsrvs);
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
for (int i = 0; i < count; i++) {
IOHIDServiceClientRef sc = (IOHIDServiceClientRef)CFArrayGetValueAtIndex(matchingsrvs, i);
IOHIDEventRef event = IOHIDServiceClientCopyEvent(sc, kIOHIDEventTypeTemperature, 0, 0); // here we use ...CopyEvent
CFNumberRef value;
if (event != 0) {
double temp = IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(kIOHIDEventTypeTemperature));
value = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &temp);
} else {
double temp = 0;
value = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &temp);
}
CFArrayAppendValue(array, value);
}
return array;
}
}
std::map<int, double> Cpu::ThermalSensors::getSensors() {
std::map<int, double> cpuValues;
CFDictionaryRef thermalSensors = matching(0xff00, 5); // 65280_10 = FF00_16
// thermalSensors's PrimaryUsagePage should be 0xff00 for M1 chip, instead of 0xff05
// can be checked by ioreg -lfx
CFArrayRef thermalNames = getProductNames(thermalSensors);
CFArrayRef thermalValues = getThermalValues(thermalSensors);
long count = CFArrayGetCount(thermalNames);
for (int i = 0; i < count; i++) {
CFStringRef nameRef = (CFStringRef)CFArrayGetValueAtIndex(thermalNames, i);
char buf[200];
CFStringGetCString(nameRef, buf, 200, kCFStringEncodingASCII);
std::string n(buf);
CFNumberRef value = (CFNumberRef)CFArrayGetValueAtIndex(thermalValues, i);
double temp = 0.0;
CFNumberGetValue(value, kCFNumberDoubleType, &temp);
if (n.starts_with("PMU tdie")) {
// Apple Silicon
std::string indexString = n.substr(8, 1);
int index = stoi(indexString);
cpuValues[index - 1] = temp;
} else if (n.starts_with("TC") && n[3] == 'c') {
// intel mac
std::string indexString = n.substr(2, 1);
int index = stoi(indexString);
cpuValues[index] = temp;
} else if (n == "TCAD") {
cpuValues[0] = temp; // package T for intel
} else if (n == "SOC MTR Temp Sensor0") {
cpuValues[0] = temp; // package T for Apple Silicon
}
}
CFRelease(thermalValues);
return cpuValues;
}
|