#include "sensors.hpp" #include #include #include #include #include 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); CFRelease(keys); return dict; } double getValue(IOHIDServiceClientRef sc) { IOHIDEventRef event = IOHIDServiceClientCopyEvent(sc, kIOHIDEventTypeTemperature, 0, 0); // here we use ...CopyEvent IOHIDFloat temp = 0.0; if (event != 0) { temp = IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(kIOHIDEventTypeTemperature)); CFRelease(event); } return temp; } } // extern C long long Cpu::ThermalSensors::getSensors() { 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 IOHIDEventSystemClientRef system = IOHIDEventSystemClientCreate(kCFAllocatorDefault); IOHIDEventSystemClientSetMatching(system, thermalSensors); CFArrayRef matchingsrvs = IOHIDEventSystemClientCopyServices(system); std::vector temps; if (matchingsrvs) { long count = CFArrayGetCount(matchingsrvs); for (int i = 0; i < count; i++) { IOHIDServiceClientRef sc = (IOHIDServiceClientRef)CFArrayGetValueAtIndex(matchingsrvs, i); if (sc) { CFStringRef name = IOHIDServiceClientCopyProperty(sc, CFSTR("Product")); // here we use ...CopyProperty if (name) { char buf[200]; CFStringGetCString(name, buf, 200, kCFStringEncodingASCII); std::string n(buf); // this is just a guess, nobody knows which sensors mean what // on my system PMU tdie 3 and 9 are missing... // there is also PMU tdev1-8 but it has negative values?? // there is also eACC for efficiency package but it only has 2 entries // and pACC for performance but it has 7 entries (2 - 9) WTF if (n.starts_with("eACC") or n.starts_with("pACC")) { temps.push_back(getValue(sc)); } CFRelease(name); } } } CFRelease(matchingsrvs); } CFRelease(system); CFRelease(thermalSensors); if (temps.empty()) return 0ll; return round(std::accumulate(temps.begin(), temps.end(), 0ll) / temps.size()); }