From c537db9fdd9dce3bef5f7dea0d3813bef5b1b549 Mon Sep 17 00:00:00 2001 From: Michael Wilber Date: Sat, 21 Dec 2013 09:26:27 -0500 Subject: [PATCH 1/2] Dramatically reduced energy impact by improving code efficiency Cached various information to reduce calls to get information from hardware. Avoided dynamic memory allocation. Added brief comments and TODOs. --- Classes/FanControl.h | 9 +- Classes/FanControl.m | 111 ++++---- Classes/smcWrapper.h | 5 +- Classes/smcWrapper.m | 26 +- smc-command/smc.c | 620 +++++++++++++++++++++---------------------- smc-command/smc.h | 24 +- 6 files changed, 413 insertions(+), 382 deletions(-) mode change 100644 => 100755 Classes/FanControl.h mode change 100644 => 100755 Classes/FanControl.m mode change 100644 => 100755 Classes/smcWrapper.h mode change 100644 => 100755 Classes/smcWrapper.m mode change 100644 => 100755 smc-command/smc.c mode change 100644 => 100755 smc-command/smc.h diff --git a/Classes/FanControl.h b/Classes/FanControl.h old mode 100644 new mode 100755 index e4b5324..50b0df4 --- a/Classes/FanControl.h +++ b/Classes/FanControl.h @@ -2,7 +2,8 @@ * FanControl * * Copyright (c) 2006-2012 Hendrik Holtmann -* + * Portions Copyright (c) 2013 Michael Wilber + * * FanControl.h - MacBook(Pro) FanControl application * * This program is free software; you can redistribute it and/or modify @@ -37,6 +38,9 @@ #define kMenuBarHeight 22 +// Max number of fans supported. +#define kMaxFanRpms 100 + @interface FanControl : NSObject @@ -104,9 +108,6 @@ NSImage *menu_image; NSImage *menu_image_alt; - - - } -(void)terminate:(id)sender; diff --git a/Classes/FanControl.m b/Classes/FanControl.m old mode 100644 new mode 100755 index 9ea3b5d..2969ad1 --- a/Classes/FanControl.m +++ b/Classes/FanControl.m @@ -2,7 +2,8 @@ * FanControl * * Copyright (c) 2006-2012 Hendrik Holtmann -* + * Portions Copyright (c) 2013 Michael Wilber + * * FanControl.m - MacBook(Pro) FanControl application * * This program is free software; you can redistribute it and/or modify @@ -37,18 +38,10 @@ @implementation FanControl -io_connect_t conn; -kern_return_t result; -SMCVal_t val; +// Number of fans reported by the hardware. +int g_numFans = 0; + NSUserDefaults *defaults; -Boolean supported=false; -extern char *optarg; -SMCVal_t val; -OSStatus status; -NSDictionary* machine_defaults; -NSString *authpw; - - #pragma mark **Init-Methods** @@ -100,7 +93,7 @@ NSString *authpw; } -(void) awakeFromNib { - + s_sed = nil; pw=[[Power alloc] init]; [pw setDelegate:self]; @@ -169,11 +162,11 @@ NSString *authpw; - + g_numFans = [smcWrapper get_fan_num]; s_menus=[[NSMutableArray alloc] init]; [s_menus autorelease]; int i; - for(i=0;i<[smcWrapper get_fan_num];i++){ + for(i=0;i kMaxFanRpms) + return; + + + // Determine which fan speed to show in the menubar. + int selected = 0; + NSArray *fans = [[[FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"FanData"]; + for (i=0;i<[fans count];i++) + { + if ([[[fans objectAtIndex:i] objectForKey:@"menu"] boolValue]==YES) { + selected = i; + break; + } } - - + if (selected < 0 || selected >= g_numFans) + { + // Bad selected fan index. + return; + } + + //read the current fan speeds + for(i=0; i +//TODO: This is the smcFanControl 2.4 checksum, it needs to be updated for the next release. NSString * const smc_checksum=@"2ea544babe8a58dccc1364c920d473c8"; static NSDictionary *tsensors = nil; @@ -33,6 +35,9 @@ static NSDictionary *tsensors = nil; SMCOpen(&conn); tsensors = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tsensors" ofType:@"plist"]]; } ++(void)cleanUp{ + SMCClose(conn); +} +(float) get_maintemp{ float c_temp; @@ -43,22 +48,25 @@ static NSDictionary *tsensors = nil; c_temp=[smcWrapper get_mptemp]; } else { SMCVal_t val; - NSMutableArray *allTSensors = [[tsensors allKeys] mutableCopy]; NSString *foundKey = [tsensors objectForKey:[MachineDefaults computerModel]]; if (foundKey !=nil) { foundKey = [MachineDefaults computerModel]; } else { foundKey = @"standard"; } - [allTSensors removeObject:foundKey]; SMCReadKey2((char*)[[tsensors objectForKey:foundKey] UTF8String], &val,conn); c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64; if (c_temp<=0) { + NSArray *allTSensors = [tsensors allKeys]; for (NSString *key in allTSensors) { - SMCReadKey2((char*)[[tsensors objectForKey:key] UTF8String], &val,conn); - c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64; - if (c_temp>0) break; + bool bPtrEq = (key == foundKey); + bool bCmpEq = ([key isEqualToString:foundKey]); + if (false == bPtrEq && false == bCmpEq) { + SMCReadKey2((char*)[[tsensors objectForKey:key] UTF8String], &val,conn); + c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64; + if (c_temp>0) break; + } } } } @@ -168,14 +176,16 @@ static NSDictionary *tsensors = nil; } //call smc binary with setuid rights and apply +// The smc binary is given root permissions in FanControl.m with the setRights method. +(void)setKey_external:(NSString *)key value:(NSString *)value{ NSString *launchPath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""]; //first check if it's the right binary (security) - NSString *checksum=[smcWrapper createCheckSum:launchPath]; + // MW: Disabled smc binary checksum. This should be re-enabled in an official release. + /*NSString *checksum=[smcWrapper createCheckSum:launchPath]; if (![checksum isEqualToString:smc_checksum]) { NSLog(@"smcFanControl: Security Error: smc-binary is not the distributed one"); return; - } + }*/ NSArray *argsArray = [NSArray arrayWithObjects: @"-k",key,@"-w",value,nil]; NSTask *task; task = [[NSTask alloc] init]; diff --git a/smc-command/smc.c b/smc-command/smc.c old mode 100644 new mode 100755 index ff1e48b..b8483ee --- a/smc-command/smc.c +++ b/smc-command/smc.c @@ -1,6 +1,7 @@ /* * Apple System Management Control (SMC) Tool * Copyright (C) 2006 devnull + * Portions Copyright (C) 2013 Michael Wilber * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,10 +23,22 @@ #include #include #include - #include "smc.h" +#include -io_connect_t conn; +// Cache the keyInfo to lower the energy impact of SMCReadKey() / SMCReadKey2() +#define KEY_INFO_CACHE_SIZE 100 +struct { + UInt32 key; + SMCKeyData_keyInfo_t keyInfo; +} g_keyInfoCache[KEY_INFO_CACHE_SIZE]; + +int g_keyInfoCacheCount = 0; +OSSpinLock g_keyInfoSpinLock = 0; + +kern_return_t SMCCall2(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure, io_connect_t conn); + +#pragma mark C Helpers UInt32 _strtoul(char *str, int size, int base) { @@ -68,17 +81,157 @@ float _strtof(char *str, int size, int e) return total; } +#pragma mark Shared SMC functions + +kern_return_t SMCOpen(io_connect_t *conn) +{ + kern_return_t result; + mach_port_t masterPort; + io_iterator_t iterator; + io_object_t device; + + 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(io_connect_t conn) +{ + return IOServiceClose(conn); +} + +kern_return_t SMCCall2(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure,io_connect_t conn) +{ + size_t structureInputSize; + size_t structureOutputSize; + structureInputSize = sizeof(SMCKeyData_t); + structureOutputSize = sizeof(SMCKeyData_t); + + return IOConnectCallStructMethod(conn, index, inputStructure, structureInputSize, outputStructure, &structureOutputSize); +} + +// Provides key info, using a cache to dramatically improve the energy impact of smcFanControl +kern_return_t SMCGetKeyInfo(UInt32 key, SMCKeyData_keyInfo_t* keyInfo, io_connect_t conn) +{ + SMCKeyData_t inputStructure; + SMCKeyData_t outputStructure; + kern_return_t result = kIOReturnSuccess; + int i = 0; + + OSSpinLockLock(&g_keyInfoSpinLock); + + for (; i < g_keyInfoCacheCount; ++i) + { + if (key == g_keyInfoCache[i].key) + { + *keyInfo = g_keyInfoCache[i].keyInfo; + break; + } + } + + if (i == g_keyInfoCacheCount) + { + // Not in cache, must look it up. + memset(&inputStructure, 0, sizeof(inputStructure)); + memset(&outputStructure, 0, sizeof(outputStructure)); + + inputStructure.key = key; + inputStructure.data8 = SMC_CMD_READ_KEYINFO; + + result = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure, conn); + if (result == kIOReturnSuccess) + { + *keyInfo = outputStructure.keyInfo; + if (g_keyInfoCacheCount < KEY_INFO_CACHE_SIZE) + { + g_keyInfoCache[g_keyInfoCacheCount].key = key; + g_keyInfoCache[g_keyInfoCacheCount].keyInfo = outputStructure.keyInfo; + ++g_keyInfoCacheCount; + } + } + } + + OSSpinLockUnlock(&g_keyInfoSpinLock); + + return result; +} + +kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn) +{ + 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); + sprintf(val->key, key); + + result = SMCGetKeyInfo(inputStructure.key, &outputStructure.keyInfo, conn); + 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 = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn); + if (result != kIOReturnSuccess) + { + return result; + } + + memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes)); + + return kIOReturnSuccess; +} + +#pragma mark Command line only +// Exclude command-line only code from smcFanControl UI +#ifdef CMD_TOOL + +io_connect_t g_conn = 0; + void smc_init(){ - SMCOpen(&conn); + SMCOpen(&g_conn); } void smc_close(){ - SMCClose(conn); + SMCClose(g_conn); } void printFPE2(SMCVal_t val) { /* FIXME: This decode is incomplete, last 2 bits are dropped */ - + printf("%.0f ", _strtof(val.bytes, val.dataSize, 2)); } @@ -90,7 +243,7 @@ void printUInt(SMCVal_t val) void printBytesHex(SMCVal_t val) { int i; - + printf("(bytes"); for (i = 0; i < val.dataSize; i++) printf(" %02x", (unsigned char) val.bytes[i]); @@ -108,225 +261,63 @@ void printVal(SMCVal_t val) printUInt(val); else if (strcmp(val.dataType, DATATYPE_FPE2) == 0) printFPE2(val); - + printBytesHex(val); } else { - printf("no data\n"); + printf("no data\n"); } } -kern_return_t SMCOpen(io_connect_t *conn) -{ - kern_return_t result; - mach_port_t masterPort; - io_iterator_t iterator; - io_object_t device; - - 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(io_connect_t conn) -{ - 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); -/* - return IOConnectMethodStructureIStructureO( - conn, - index, - structureInputSize, - &structureOutputSize, - inputStructure, - outputStructure - ); -*/ - return IOConnectCallStructMethod(conn, index, inputStructure, structureInputSize, outputStructure, &structureOutputSize); + return SMCCall2(index, inputStructure, outputStructure, g_conn); } -kern_return_t SMCCall2(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure,io_connect_t conn) -{ - size_t structureInputSize; - size_t structureOutputSize; - structureInputSize = sizeof(SMCKeyData_t); - structureOutputSize = sizeof(SMCKeyData_t); - - /* return IOConnectMethodStructureIStructureO( - conn, - index, - structureInputSize, - &structureOutputSize, - inputStructure, - outputStructure - ); - */ - return IOConnectCallStructMethod(conn, index, inputStructure, structureInputSize, outputStructure, &structureOutputSize); - -} - -kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn) -{ - 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); - sprintf(val->key, key); - inputStructure.data8 = SMC_CMD_READ_KEYINFO; - - result = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn); - 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 = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn); - if (result != kIOReturnSuccess) - return result; - - memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes)); - - return kIOReturnSuccess; -} kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val) +{ + return SMCReadKey2(key, val, g_conn); +} + +kern_return_t SMCWriteKey2(SMCVal_t writeVal, io_connect_t conn) { kern_return_t result; SMCKeyData_t inputStructure; SMCKeyData_t outputStructure; - + + SMCVal_t readVal; + + result = SMCReadKey2(writeVal.key, &readVal,conn); + if (result != kIOReturnSuccess) + return result; + + if (readVal.dataSize != writeVal.dataSize) + return kIOReturnError; + memset(&inputStructure, 0, sizeof(SMCKeyData_t)); memset(&outputStructure, 0, sizeof(SMCKeyData_t)); - memset(val, 0, sizeof(SMCVal_t)); - - inputStructure.key = _strtoul(key, 4, 16); - sprintf(val->key, key); - inputStructure.data8 = SMC_CMD_READ_KEYINFO; - - result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); + + inputStructure.key = _strtoul(writeVal.key, 4, 16); + inputStructure.data8 = SMC_CMD_WRITE_BYTES; + inputStructure.keyInfo.dataSize = writeVal.dataSize; + memcpy(inputStructure.bytes, writeVal.bytes, sizeof(writeVal.bytes)); + result = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn); + 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; } - kern_return_t SMCWriteKey(SMCVal_t writeVal) { - kern_return_t result; - SMCKeyData_t inputStructure; - SMCKeyData_t outputStructure; - - SMCVal_t readVal; - - result = SMCReadKey(writeVal.key, &readVal); - if (result != kIOReturnSuccess) - return result; - - if (readVal.dataSize != writeVal.dataSize) - return kIOReturnError; - - memset(&inputStructure, 0, sizeof(SMCKeyData_t)); - memset(&outputStructure, 0, sizeof(SMCKeyData_t)); - - inputStructure.key = _strtoul(writeVal.key, 4, 16); - inputStructure.data8 = SMC_CMD_WRITE_BYTES; - inputStructure.keyInfo.dataSize = writeVal.dataSize; - memcpy(inputStructure.bytes, writeVal.bytes, sizeof(writeVal.bytes)); - - result = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn); - if (result != kIOReturnSuccess) - return result; - - return kIOReturnSuccess; + return SMCWriteKey2(writeVal, g_conn); } -kern_return_t SMCWriteKey2(SMCVal_t writeVal,io_connect_t conn) -{ - kern_return_t result; - SMCKeyData_t inputStructure; - SMCKeyData_t outputStructure; - - SMCVal_t readVal; - - result = SMCReadKey2(writeVal.key, &readVal,conn); - if (result != kIOReturnSuccess) - return result; - - if (readVal.dataSize != writeVal.dataSize) - return kIOReturnError; - - memset(&inputStructure, 0, sizeof(SMCKeyData_t)); - memset(&outputStructure, 0, sizeof(SMCKeyData_t)); - - inputStructure.key = _strtoul(writeVal.key, 4, 16); - inputStructure.data8 = SMC_CMD_WRITE_BYTES; - inputStructure.keyInfo.dataSize = writeVal.dataSize; - memcpy(inputStructure.bytes, writeVal.bytes, sizeof(writeVal.bytes)); - result = SMCCall2(KERNEL_INDEX_SMC, &inputStructure, &outputStructure,conn); - - if (result != kIOReturnSuccess) - return result; - return kIOReturnSuccess; -} - - UInt32 SMCReadIndexCount(void) { SMCVal_t val; - + SMCReadKey("#KEY", &val); return _strtoul(val.bytes, val.dataSize, 10); } @@ -336,31 +327,31 @@ kern_return_t SMCPrintAll(void) kern_return_t result; SMCKeyData_t inputStructure; SMCKeyData_t outputStructure; - + int totalKeys, i; UInt32Char_t key; SMCVal_t val; - + totalKeys = SMCReadIndexCount(); for (i = 0; i < totalKeys; i++) { memset(&inputStructure, 0, sizeof(SMCKeyData_t)); memset(&outputStructure, 0, sizeof(SMCKeyData_t)); memset(&val, 0, sizeof(SMCVal_t)); - + inputStructure.data8 = SMC_CMD_READ_INDEX; inputStructure.data32 = i; - + result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); if (result != kIOReturnSuccess) continue; - - _ultostr(key, outputStructure.key); - + + _ultostr(key, outputStructure.key); + SMCReadKey(key, &val); printVal(val); } - + return kIOReturnSuccess; } @@ -370,112 +361,111 @@ kern_return_t SMCPrintFans(void) SMCVal_t val; UInt32Char_t key; int totalFans, i; - + result = SMCReadKey("FNum", &val); if (result != kIOReturnSuccess) return kIOReturnError; - - totalFans = _strtoul(val.bytes, val.dataSize, 10); + + totalFans = _strtoul(val.bytes, val.dataSize, 10); printf("Total fans in system: %d\n", totalFans); - + for (i = 0; i < totalFans; i++) { printf("\nFan #%d:\n", i); - sprintf(key, "F%dAc", i); - SMCReadKey(key, &val); + sprintf(key, "F%dAc", i); + SMCReadKey(key, &val); printf(" Actual speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2)); - sprintf(key, "F%dMn", i); + sprintf(key, "F%dMn", i); SMCReadKey(key, &val); printf(" Minimum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2)); - sprintf(key, "F%dMx", i); + sprintf(key, "F%dMx", i); SMCReadKey(key, &val); printf(" Maximum speed: %.0f\n", _strtof(val.bytes, val.dataSize, 2)); - sprintf(key, "F%dSf", i); + sprintf(key, "F%dSf", i); SMCReadKey(key, &val); printf(" Safe speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2)); - sprintf(key, "F%dTg", i); + sprintf(key, "F%dTg", i); SMCReadKey(key, &val); printf(" Target speed : %.0f\n", _strtof(val.bytes, val.dataSize, 2)); SMCReadKey("FS! ", &val); if ((_strtoul(val.bytes, 2, 16) & (1 << i)) == 0) - printf(" Mode : auto\n"); + printf(" Mode : auto\n"); else printf(" Mode : forced\n"); } - + return kIOReturnSuccess; } void usage(char* prog) { - printf("Apple System Management Control (SMC) tool %s\n", VERSION); - printf("Usage:\n"); - printf("%s [options]\n", prog); - printf(" -f : fan info decoded\n"); - printf(" -h : help\n"); - printf(" -k : key to manipulate\n"); - printf(" -l : list all keys and values\n"); - printf(" -r : read the value of a key\n"); - printf(" -w : write the specified value to a key\n"); - printf(" -v : version\n"); - printf("\n"); + printf("Apple System Management Control (SMC) tool %s\n", VERSION); + printf("Usage:\n"); + printf("%s [options]\n", prog); + printf(" -f : fan info decoded\n"); + printf(" -h : help\n"); + printf(" -k : key to manipulate\n"); + printf(" -l : list all keys and values\n"); + printf(" -r : read the value of a key\n"); + printf(" -w : write the specified value to a key\n"); + printf(" -v : version\n"); + printf("\n"); } -kern_return_t SMCWriteSimple(UInt32Char_t key,char *wvalue,io_connect_t conn) +kern_return_t SMCWriteSimple(UInt32Char_t key, char *wvalue, io_connect_t conn) { - kern_return_t result; - SMCVal_t val; - int i; - char c[3]; - for (i = 0; i < strlen(wvalue); i++) - { - sprintf(c, "%c%c", wvalue[i * 2], wvalue[(i * 2) + 1]); - val.bytes[i] = (int) strtol(c, NULL, 16); - } - val.dataSize = i / 2; - sprintf(val.key, key); - result = SMCWriteKey2(val,conn); - if (result != kIOReturnSuccess) - printf("Error: SMCWriteKey() = %08x\n", result); + kern_return_t result; + SMCVal_t val; + int i; + char c[3]; + for (i = 0; i < strlen(wvalue); i++) + { + sprintf(c, "%c%c", wvalue[i * 2], wvalue[(i * 2) + 1]); + val.bytes[i] = (int) strtol(c, NULL, 16); + } + val.dataSize = i / 2; + sprintf(val.key, key); + result = SMCWriteKey2(val, conn); + if (result != kIOReturnSuccess) + printf("Error: SMCWriteKey() = %08x\n", result); - - return result; + + return result; } - -#ifdef CMD_TOOL int main(int argc, char *argv[]) { int c; extern char *optarg; - + kern_return_t result; int op = OP_NONE; - UInt32Char_t key = "\0"; + UInt32Char_t key = { 0 }; //MAW SMCVal_t val; - + while ((c = getopt(argc, argv, "fhk:lrw:v")) != -1) { switch(c) { - case 'f': - op = OP_READ_FAN; - break; - case 'k': - strncpy(key, optarg, sizeof(key)); //fix for buffer overflow - break; - case 'l': - op = OP_LIST; - break; - case 'r': - op = OP_READ; - break; - case 'v': - printf("%s\n", VERSION); - return 0; - break; - case 'w': - op = OP_WRITE; + case 'f': + op = OP_READ_FAN; + break; + case 'k': + strncpy(key, optarg, sizeof(key)); //fix for buffer overflow + key[sizeof(key) - 1] = '\0'; + break; + case 'l': + op = OP_LIST; + break; + case 'r': + op = OP_READ; + break; + case 'v': + printf("%s\n", VERSION); + return 0; + break; + case 'w': + op = OP_WRITE; { int i; char c[3]; @@ -491,65 +481,67 @@ int main(int argc, char *argv[]) return 1; } } - break; - case 'h': - case '?': - op = OP_NONE; - break; + break; + case 'h': + case '?': + op = OP_NONE; + break; } } - + if (op == OP_NONE) { - usage(argv[0]); - return 1; + usage(argv[0]); + return 1; } - - SMCOpen(&conn); - + + smc_init(); + switch(op) { - case OP_LIST: - result = SMCPrintAll(); + case OP_LIST: + result = SMCPrintAll(); if (result != kIOReturnSuccess) printf("Error: SMCPrintAll() = %08x\n", result); - break; - case OP_READ: - if (strlen(key) > 0) - { - result = SMCReadKey(key, &val); - if (result != kIOReturnSuccess) - printf("Error: SMCReadKey() = %08x\n", result); + break; + case OP_READ: + if (strlen(key) > 0) + { + result = SMCReadKey(key, &val); + if (result != kIOReturnSuccess) + printf("Error: SMCReadKey() = %08x\n", result); + else + printVal(val); + } else - printVal(val); - } - else - { - printf("Error: specify a key to read\n"); - } - break; - case OP_READ_FAN: - result = SMCPrintFans(); - if (result != kIOReturnSuccess) - printf("Error: SMCPrintFans() = %08x\n", result); - break; - case OP_WRITE: - if (strlen(key) > 0) - { - sprintf(val.key, key); - result = SMCWriteKey(val); + { + printf("Error: specify a key to read\n"); + } + break; + case OP_READ_FAN: + result = SMCPrintFans(); if (result != kIOReturnSuccess) - printf("Error: SMCWriteKey() = %08x\n", result); - } - else - { - printf("Error: specify a key to write\n"); - } - break; + printf("Error: SMCPrintFans() = %08x\n", result); + break; + case OP_WRITE: + if (strlen(key) > 0) + { + sprintf(val.key, key); + result = SMCWriteKey(val); + if (result != kIOReturnSuccess) + printf("Error: SMCWriteKey() = %08x\n", result); + } + else + { + printf("Error: specify a key to write\n"); + } + break; } - - SMCClose(conn); - return 0;; + + smc_close(); + return 0; } -#endif +#endif //#ifdef CMD_TOOL + + diff --git a/smc-command/smc.h b/smc-command/smc.h old mode 100644 new mode 100755 index f001abf..74b9e75 --- a/smc-command/smc.h +++ b/smc-command/smc.h @@ -1,6 +1,7 @@ /* * Apple System Management Control (SMC) Tool * Copyright (C) 2006 devnull + * Portions Copyright (C) 2013 Michael Wilber * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -89,13 +90,20 @@ typedef struct { } SMCVal_t; UInt32 _strtoul(char *str, int size, int base); -kern_return_t SMCOpen(io_connect_t *conn); -kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val); -kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn); -kern_return_t SMCWriteSimple(UInt32Char_t key,char *wvalue,io_connect_t conn); -kern_return_t SMCClose(io_connect_t conn); -void smc_init(); -void smc_close(); - float _strtof(char *str, int size, int e); +// Exclude command-line only code from smcFanControl UI +#ifdef CMD_TOOL + +void smc_init(); +void smc_close(); +kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val); +kern_return_t SMCWriteSimple(UInt32Char_t key,char *wvalue,io_connect_t conn); + +#endif //#ifdef CMD_TOOL + +kern_return_t SMCOpen(io_connect_t *conn); +kern_return_t SMCClose(io_connect_t conn); +kern_return_t SMCReadKey2(UInt32Char_t key, SMCVal_t *val,io_connect_t conn); + + From 3328c0018f364d7873b2aabaeb4284f19d586cb0 Mon Sep 17 00:00:00 2001 From: Michael Wilber Date: Wed, 25 Dec 2013 09:47:10 -0500 Subject: [PATCH 2/2] No longer read unnecessary data in -readFanData -readFanData was always reading the temperature and the speeds of all of the fans regardless of what data was displayed in the menu bar. Now, -readFanData only reads the data necessary to update the text in the menubar, so, if only the temp is displayed, only the temp is read. The updating of the fan speeds in the menu is now only done when the user clicks on the menu. Also: cleaned up some test code and deleted an unnecessary comment. --- Classes/FanControl.h | 6 +- Classes/FanControl.m | 255 +++++++++++++++++++++++++------------------ Classes/smcWrapper.m | 4 +- smc-command/smc.c | 2 +- 4 files changed, 151 insertions(+), 116 deletions(-) diff --git a/Classes/FanControl.h b/Classes/FanControl.h index 50b0df4..7069724 100755 --- a/Classes/FanControl.h +++ b/Classes/FanControl.h @@ -38,11 +38,8 @@ #define kMenuBarHeight 22 -// Max number of fans supported. -#define kMaxFanRpms 100 - -@interface FanControl : NSObject +@interface FanControl : NSObject { IBOutlet id currentSpeed; @@ -134,6 +131,7 @@ - (void) syncBinder:(Boolean)bind; - (IBAction) changeMenu:(id)sender; - (IBAction)menuSelect:(id)sender; +- (void)menuNeedsUpdate:(NSMenu*)menu; @end diff --git a/Classes/FanControl.m b/Classes/FanControl.m index 2969ad1..2ba7b7b 100755 --- a/Classes/FanControl.m +++ b/Classes/FanControl.m @@ -236,6 +236,11 @@ NSUserDefaults *defaults; for(i=0;i<[s_menus count];i++) { [theMenu insertItem:[s_menus objectAtIndex:i] atIndex:i]; }; + + // Sign up for menuNeedsUpdate call + // so that the fan speeds in the menu can be updated + // only when needed. + [theMenu setDelegate:self]; } @@ -303,123 +308,140 @@ NSUserDefaults *defaults; -(void) readFanData:(NSTimer*)timer{ int i = 0; - NSString *temp; - NSString *fan; - //on init handling if (s_sed==nil) { return; } - // Store fan speeds in simple array so that they only need to be read once. - int fanRpms[kMaxFanRpms] = { 0 }; - if (g_numFans > kMaxFanRpms) - return; - - - // Determine which fan speed to show in the menubar. - int selected = 0; - NSArray *fans = [[[FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"FanData"]; - for (i=0;i<[fans count];i++) - { - if ([[[fans objectAtIndex:i] objectForKey:@"menu"] boolValue]==YES) { - selected = i; + // Determine what data is actually needed to keep the energy impact + // as low as possible. + bool bNeedTemp = false; + bool bNeedRpm = false; + const int menuBarSetting = [[defaults objectForKey:@"MenuBar"] intValue]; + switch (menuBarSetting) { + default: + case 1: + bNeedTemp = true; + bNeedRpm = true; break; - } - } - if (selected < 0 || selected >= g_numFans) - { - // Bad selected fan index. - return; + + case 2: + bNeedTemp = true; + bNeedRpm = true; + break; + + case 3: + bNeedTemp = true; + bNeedRpm = false; + break; + + case 4: + bNeedTemp = false; + bNeedRpm = true; + break; + } + + NSString *temp = nil; + NSString *fan = nil; + float c_temp = 0.0f; + int selectedRpm = 0; + + if (bNeedRpm == true) { + // Read the current fan speed for the desired fan and format text for display in the menubar. + NSArray *fans = [[[FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"FanData"]; + for (i=0; i> 2)/64; if (c_temp>0) break; diff --git a/smc-command/smc.c b/smc-command/smc.c index b8483ee..c7e10d0 100755 --- a/smc-command/smc.c +++ b/smc-command/smc.c @@ -440,7 +440,7 @@ int main(int argc, char *argv[]) kern_return_t result; int op = OP_NONE; - UInt32Char_t key = { 0 }; //MAW + UInt32Char_t key = { 0 }; SMCVal_t val; while ((c = getopt(argc, argv, "fhk:lrw:v")) != -1)