// This code is originally from https://github.com/freedomtan/sensors/blob/master/sensors/sensors.m // Here is the original code's license // 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. #include #include #include // Declarations from other IOKit source code typedef struct __IOHIDEvent *IOHIDEventRef; typedef struct __IOHIDServiceClient *IOHIDServiceClientRef; #ifdef __LP64__ typedef double IOHIDFloat; #else typedef float IOHIDFloat; #endif 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, @"noname"); // @ gives a Ref like in "CFStringRef name" } } return array; } // from IOHIDFamily/IOHIDEventTypes.h // e.g., https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-701.60.2/IOHIDFamily/IOHIDEventTypes.h.auto.html #define IOHIDEventFieldBase(type) (type << 16) #define kIOHIDEventTypeTemperature 15 #define kIOHIDEventTypePower 25 CFArrayRef getPowerValues(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, kIOHIDEventTypePower, 0, 0); CFNumberRef value; if (event != 0) { double temp = IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(kIOHIDEventTypePower)); value = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &temp); } else { double temp = 0; value = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &temp); } CFArrayAppendValue(array, value); } 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; } double getTempValue(CFArrayRef values, int index) { CFNumberRef value = CFArrayGetValueAtIndex(values, index); double temp = 0.0; CFNumberGetValue(value, kCFNumberDoubleType, &temp); return temp; } void printCPUGPUTemps(CFArrayRef values) { printf("CPU %0.1lf GPU %0.1lf, ", getTempValue(values,0), getTempValue(values,2)); } void dumpValues(CFArrayRef values) { long count = CFArrayGetCount(values); double accumTemp = 0.0; for (int i = 0; i < count; i++) { CFNumberRef value = CFArrayGetValueAtIndex(values, i); double temp = 0.0; CFNumberGetValue(value, kCFNumberDoubleType, &temp); // NSLog(@"value = %lf\n", temp); //printf("%0.1lf, ", temp); if(temp > 0) accumTemp+=temp; } printf("%0.0lf", accumTemp/count); } void dumpNames(CFArrayRef names, char *cat) { long count = CFArrayGetCount(names); for (int i = 0; i < count; i++) { NSString *name = (NSString *)CFArrayGetValueAtIndex(names, i); // NSLog(@"value = %lf\n", temp); // printf("%s (%s), ", [name UTF8String], cat); printf("%s, ", [name UTF8String]); } } NSArray* currentArray() { CFDictionaryRef currentSensors = matching(0xff08, 2); return CFBridgingRelease(getProductNames(currentSensors)); } NSArray* voltageArray() { CFDictionaryRef currentSensors = matching(0xff08, 3); return CFBridgingRelease(getProductNames(currentSensors)); } NSArray* thermalArray() { CFDictionaryRef currentSensors = matching(0xff00, 5); return CFBridgingRelease(getProductNames(currentSensors)); } NSArray* returnCurrentValues() { CFDictionaryRef currentSensors = matching(0xff08, 2); return CFBridgingRelease(getPowerValues(currentSensors)); } NSArray* returnVoltageValues() { CFDictionaryRef voltageSensors = matching(0xff08, 3); return CFBridgingRelease(getPowerValues(voltageSensors)); } NSArray* returnThermalValues() { CFDictionaryRef currentSensors = matching(0xff00, 5); return CFBridgingRelease(getThermalValues(currentSensors)); } //extern uint64_t my_mhz(void); //extern void mybat(void); #if 1 int main () { // Primary Usage Page: // kHIDPage_AppleVendor = 0xff00, // kHIDPage_AppleVendorTemperatureSensor = 0xff05, // kHIDPage_AppleVendorPowerSensor = 0xff08, // // Primary Usage: // kHIDUsage_AppleVendor_TemperatureSensor = 0x0005, // kHIDUsage_AppleVendorPowerSensor_Current = 0x0002, // kHIDUsage_AppleVendorPowerSensor_Voltage = 0x0003, // See IOHIDFamily/AppleHIDUsageTables.h for more information // https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-701.60.2/IOHIDFamily/AppleHIDUsageTables.h.auto.html CFDictionaryRef currentSensors = matching(0xff08, 2); CFDictionaryRef voltageSensors = matching(0xff08, 3); 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 currentNames = getProductNames(currentSensors); CFArrayRef voltageNames = getProductNames(voltageSensors); CFArrayRef thermalNames = getProductNames(thermalSensors); // printf("freq, v_bat, a_bat, temp_bat"); // dumpNames(voltageNames, "V"); // dumpNames(currentNames, "A"); //dumpNames(thermalNames, "C"); //printf("\n"); fflush(stdout); //while (1) { CFArrayRef currentValues = getPowerValues(currentSensors); CFArrayRef voltageValues = getPowerValues(voltageSensors); CFArrayRef thermalValues = getThermalValues(thermalSensors); // printf("%lld, ", my_mhz()); // mybat(); // dumpValues(voltageValues); // dumpValues(currentValues); dumpValues(thermalValues); printf("\n"); fflush(stdout); usleep(500000); // usleep - suspend execution for microsecond intervals CFRelease(currentValues); CFRelease(voltageValues); CFRelease(thermalValues); //} #if 0 NSLog(@"%@\n", CFArrayGetValueAtIndex(currentNames, 0)); NSLog(@"%@\n", CFArrayGetValueAtIndex(currentNames, 1)); NSLog(@"%@\n", CFArrayGetValueAtIndex(voltageNames, 0)); NSLog(@"%@\n", CFArrayGetValueAtIndex(voltageNames, 1)); NSLog(@"%@\n", CFArrayGetValueAtIndex(thermalNames, 0)); NSLog(@"%@\n", CFArrayGetValueAtIndex(thermalNames, 1)); #endif // IOHIDEventRef event = IOHIDServiceClientCopyEvent(alssc, 25, 0, 0); return 0; } #endif