Skip to content

Commit 2a4d8d2

Browse files
committed
store cmdline cpu temp
1 parent 5e72da9 commit 2a4d8d2

File tree

3 files changed

+477
-0
lines changed

3 files changed

+477
-0
lines changed

temperature/intel/Makefile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
CC = cc
3+
CFLAGS = -O2 -Wall
4+
INC = -framework IOKit
5+
PREFIX = /usr/local
6+
EXEC = osx-cpu-temp
7+
SOURCES := $(shell find . -name '*.c')
8+
9+
build : $(EXEC)
10+
11+
clean :
12+
rm $(EXEC)
13+
14+
$(EXEC) : smc.c
15+
$(CC) $(CFLAGS) $(INC) -o $@ $?
16+
17+
install : $(EXEC)
18+
@install -v $(EXEC) $(PREFIX)/bin/$(EXEC)
19+
20+
lint: bin/lint.sh $(SOURCES)
21+
@$<
22+
23+
lint-fix: bin/lint-fix.sh $(SOURCES)
24+
@$<
25+
26+
.PHONY: lint lint-fix clean install build

temperature/intel/smc.c

Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
/*
2+
* Apple System Management Control (SMC) Tool
3+
* Copyright (C) 2006 devnull
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License
7+
* as published by the Free Software Foundation; either version 2
8+
* of the License, or (at your option) any later version.
9+
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18+
*/
19+
20+
#include <IOKit/IOKitLib.h>
21+
#include <stdio.h>
22+
#include <string.h>
23+
24+
#include "smc.h"
25+
26+
static io_connect_t conn;
27+
28+
UInt32 _strtoul(char* str, int size, int base)
29+
{
30+
UInt32 total = 0;
31+
int i;
32+
33+
for (i = 0; i < size; i++) {
34+
if (base == 16)
35+
total += str[i] << (size - 1 - i) * 8;
36+
else
37+
total += (unsigned char)(str[i] << (size - 1 - i) * 8);
38+
}
39+
return total;
40+
}
41+
42+
void _ultostr(char* str, UInt32 val)
43+
{
44+
str[0] = '\0';
45+
sprintf(str, "%c%c%c%c",
46+
(unsigned int)val >> 24,
47+
(unsigned int)val >> 16,
48+
(unsigned int)val >> 8,
49+
(unsigned int)val);
50+
}
51+
52+
kern_return_t SMCOpen(void)
53+
{
54+
kern_return_t result;
55+
io_iterator_t iterator;
56+
io_object_t device;
57+
58+
CFMutableDictionaryRef matchingDictionary = IOServiceMatching("AppleSMC");
59+
result = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &iterator);
60+
if (result != kIOReturnSuccess) {
61+
printf("Error: IOServiceGetMatchingServices() = %08x\n", result);
62+
return 1;
63+
}
64+
65+
device = IOIteratorNext(iterator);
66+
IOObjectRelease(iterator);
67+
if (device == 0) {
68+
printf("Error: no SMC found\n");
69+
return 1;
70+
}
71+
72+
result = IOServiceOpen(device, mach_task_self(), 0, &conn);
73+
IOObjectRelease(device);
74+
if (result != kIOReturnSuccess) {
75+
printf("Error: IOServiceOpen() = %08x\n", result);
76+
return 1;
77+
}
78+
79+
return kIOReturnSuccess;
80+
}
81+
82+
kern_return_t SMCClose()
83+
{
84+
return IOServiceClose(conn);
85+
}
86+
87+
kern_return_t SMCCall(int index, SMCKeyData_t* inputStructure, SMCKeyData_t* outputStructure)
88+
{
89+
size_t structureInputSize;
90+
size_t structureOutputSize;
91+
92+
structureInputSize = sizeof(SMCKeyData_t);
93+
structureOutputSize = sizeof(SMCKeyData_t);
94+
95+
#if MAC_OS_X_VERSION_10_5
96+
return IOConnectCallStructMethod(conn, index,
97+
// inputStructure
98+
inputStructure, structureInputSize,
99+
// ouputStructure
100+
outputStructure, &structureOutputSize);
101+
#else
102+
return IOConnectMethodStructureIStructureO(conn, index,
103+
structureInputSize, /* structureInputSize */
104+
&structureOutputSize, /* structureOutputSize */
105+
inputStructure, /* inputStructure */
106+
outputStructure); /* ouputStructure */
107+
#endif
108+
}
109+
110+
kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t* val)
111+
{
112+
kern_return_t result;
113+
SMCKeyData_t inputStructure;
114+
SMCKeyData_t outputStructure;
115+
116+
memset(&inputStructure, 0, sizeof(SMCKeyData_t));
117+
memset(&outputStructure, 0, sizeof(SMCKeyData_t));
118+
memset(val, 0, sizeof(SMCVal_t));
119+
120+
inputStructure.key = _strtoul(key, 4, 16);
121+
inputStructure.data8 = SMC_CMD_READ_KEYINFO;
122+
123+
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
124+
if (result != kIOReturnSuccess)
125+
return result;
126+
127+
val->dataSize = outputStructure.keyInfo.dataSize;
128+
_ultostr(val->dataType, outputStructure.keyInfo.dataType);
129+
inputStructure.keyInfo.dataSize = val->dataSize;
130+
inputStructure.data8 = SMC_CMD_READ_BYTES;
131+
132+
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
133+
if (result != kIOReturnSuccess)
134+
return result;
135+
136+
memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes));
137+
138+
return kIOReturnSuccess;
139+
}
140+
141+
double SMCGetTemperature(char* key)
142+
{
143+
SMCVal_t val;
144+
kern_return_t result;
145+
146+
result = SMCReadKey(key, &val);
147+
if (result == kIOReturnSuccess) {
148+
// read succeeded - check returned value
149+
if (val.dataSize > 0) {
150+
if (strcmp(val.dataType, DATATYPE_SP78) == 0) {
151+
// convert sp78 value to temperature
152+
int intValue = val.bytes[0] * 256 + (unsigned char)val.bytes[1];
153+
return intValue / 256.0;
154+
}
155+
}
156+
}
157+
// read failed
158+
return 0.0;
159+
}
160+
161+
double SMCGetFanSpeed(char* key)
162+
{
163+
SMCVal_t val;
164+
kern_return_t result;
165+
166+
result = SMCReadKey(key, &val);
167+
if (result == kIOReturnSuccess) {
168+
// read succeeded - check returned value
169+
if (val.dataSize > 0) {
170+
if (strcmp(val.dataType, DATATYPE_FPE2) == 0) {
171+
// convert fpe2 value to rpm
172+
int intValue = (unsigned char)val.bytes[0] * 256 + (unsigned char)val.bytes[1];
173+
return intValue / 4.0;
174+
}
175+
}
176+
}
177+
// read failed
178+
return 0.0;
179+
}
180+
181+
double convertToFahrenheit(double celsius)
182+
{
183+
return (celsius * (9.0 / 5.0)) + 32.0;
184+
}
185+
186+
// Requires SMCOpen()
187+
void readAndPrintCpuTemp(int show_title, char scale)
188+
{
189+
double temperature = SMCGetTemperature(SMC_KEY_CPU_TEMP);
190+
if (scale == 'F') {
191+
temperature = convertToFahrenheit(temperature);
192+
}
193+
194+
char* title = "";
195+
if (show_title) {
196+
title = "CPU: ";
197+
}
198+
printf("%s%5.1f°%c\n", title, temperature, scale);
199+
}
200+
201+
// Requires SMCOpen()
202+
void readAndPrintGpuTemp(int show_title, char scale)
203+
{
204+
double temperature = SMCGetTemperature(SMC_KEY_GPU_TEMP);
205+
if (scale == 'F') {
206+
temperature = convertToFahrenheit(temperature);
207+
}
208+
209+
char* title = "";
210+
if (show_title) {
211+
title = "GPU: ";
212+
}
213+
printf("%s%0.1f °%c\n", title, temperature, scale);
214+
}
215+
216+
float SMCGetFanRPM(char* key)
217+
{
218+
SMCVal_t val;
219+
kern_return_t result;
220+
221+
result = SMCReadKey(key, &val);
222+
if (result == kIOReturnSuccess) {
223+
// read succeeded - check returned value
224+
if (val.dataSize > 0) {
225+
if (strcmp(val.dataType, DATATYPE_FPE2) == 0) {
226+
// convert fpe2 value to RPM
227+
return ntohs(*(UInt16*)val.bytes) / 4.0;
228+
}
229+
}
230+
}
231+
// read failed
232+
return -1.f;
233+
}
234+
235+
// Requires SMCOpen()
236+
void readAndPrintFanRPMs(void)
237+
{
238+
kern_return_t result;
239+
SMCVal_t val;
240+
UInt32Char_t key;
241+
int totalFans, i;
242+
243+
result = SMCReadKey("FNum", &val);
244+
245+
if (result == kIOReturnSuccess) {
246+
totalFans = _strtoul((char*)val.bytes, val.dataSize, 10);
247+
248+
printf("Num fans: %d\n", totalFans);
249+
for (i = 0; i < totalFans; i++) {
250+
sprintf(key, "F%dID", i);
251+
result = SMCReadKey(key, &val);
252+
if (result != kIOReturnSuccess) {
253+
continue;
254+
}
255+
char* name = val.bytes + 4;
256+
257+
sprintf(key, "F%dAc", i);
258+
float actual_speed = SMCGetFanRPM(key);
259+
if (actual_speed < 0.f) {
260+
continue;
261+
}
262+
263+
sprintf(key, "F%dMn", i);
264+
float minimum_speed = SMCGetFanRPM(key);
265+
if (minimum_speed < 0.f) {
266+
continue;
267+
}
268+
269+
sprintf(key, "F%dMx", i);
270+
float maximum_speed = SMCGetFanRPM(key);
271+
if (maximum_speed < 0.f) {
272+
continue;
273+
}
274+
275+
float rpm = actual_speed - minimum_speed;
276+
if (rpm < 0.f) {
277+
rpm = 0.f;
278+
}
279+
float pct = rpm / (maximum_speed - minimum_speed);
280+
281+
pct *= 100.f;
282+
printf("Fan %d - %s at %.0f RPM (%.0f%%)\n", i, name, rpm, pct);
283+
284+
//sprintf(key, "F%dSf", i);
285+
//SMCReadKey(key, &val);
286+
//printf(" Safe speed : %.0f\n", strtof(val.bytes, val.dataSize, 2));
287+
//sprintf(key, "F%dTg", i);
288+
//SMCReadKey(key, &val);
289+
//printf(" Target speed : %.0f\n", strtof(val.bytes, val.dataSize, 2));
290+
//SMCReadKey("FS! ", &val);
291+
//if ((_strtoul((char *)val.bytes, 2, 16) & (1 << i)) == 0)
292+
// printf(" Mode : auto\n");
293+
//else
294+
// printf(" Mode : forced\n");
295+
}
296+
}
297+
}
298+
299+
int main(int argc, char* argv[])
300+
{
301+
char scale = 'C';
302+
int cpu = 0;
303+
int fan = 0;
304+
int gpu = 0;
305+
306+
int c;
307+
while ((c = getopt(argc, argv, "CFcfgh?")) != -1) {
308+
switch (c) {
309+
case 'F':
310+
case 'C':
311+
scale = c;
312+
break;
313+
case 'c':
314+
cpu = 1;
315+
break;
316+
case 'f':
317+
fan = 1;
318+
break;
319+
case 'g':
320+
gpu = 1;
321+
break;
322+
case 'h':
323+
case '?':
324+
printf("usage: osx-cpu-temp <options>\n");
325+
printf("Options:\n");
326+
printf(" -F Display temperatures in degrees Fahrenheit.\n");
327+
printf(" -C Display temperatures in degrees Celsius (Default).\n");
328+
printf(" -c Display CPU temperature (Default).\n");
329+
printf(" -g Display GPU temperature.\n");
330+
printf(" -f Display fan speeds.\n");
331+
printf(" -h Display this help.\n");
332+
printf("\nIf more than one of -c, -f, or -g are specified, titles will be added\n");
333+
return -1;
334+
}
335+
}
336+
337+
if (!fan && !gpu) {
338+
cpu = 1;
339+
}
340+
341+
int show_title = fan + gpu + cpu > 1;
342+
343+
SMCOpen();
344+
345+
if (cpu) {
346+
readAndPrintCpuTemp(show_title, scale);
347+
}
348+
if (gpu) {
349+
readAndPrintGpuTemp(show_title, scale);
350+
}
351+
if (fan) {
352+
readAndPrintFanRPMs();
353+
}
354+
355+
SMCClose();
356+
return 0;
357+
}

0 commit comments

Comments
 (0)