xref: /dflybsd-src/usr.bin/systat/sensors.c (revision 23832f75edc9855492226d612851679a00de2f9c)
1 /* $OpenBSD: sensors.c,v 1.11 2007/03/23 14:48:22 ckuethe Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Deanna Phillips <deanna@openbsd.org>
5  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
6  * Copyright (c) 2006 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/param.h>
22 #include <sys/sysctl.h>
23 #include <sys/sensors.h>
24 
25 #include <err.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 
30 #include "systat.h"
31 #include "extern.h"
32 
33 struct sensor sensor;
34 struct sensordev sensordev;
35 int row, sensor_cnt;
36 void printline(void);
37 static char * fmttime(double);
38 
39 WINDOW *
40 opensensors(void)
41 {
42 	return (subwin(stdscr, LINES-5-1, 0, 5, 0));
43 }
44 
45 void
46 closesensors(WINDOW *w)
47 {
48 	if (w == NULL)
49 		return;
50 	wclear(w);
51 	wrefresh(w);
52 	delwin(w);
53 }
54 
55 void
56 labelsensors(void)
57 {
58 	wmove(wnd, 0, 0);
59 	wclrtobot(wnd);
60 	mvwaddstr(wnd, 0, 0, "Sensor");
61 	mvwaddstr(wnd, 0, 34, "Value");
62 	mvwaddstr(wnd, 0, 45, "Status");
63 	mvwaddstr(wnd, 0, 58, "Description");
64 }
65 
66 void
67 fetchsensors(void)
68 {
69 	enum sensor_type type;
70 	size_t		 slen, sdlen, idmax_len;
71 	int		 mib[5], dev, numt, idmax;
72 	int		 maxsensordevices;
73 
74 	maxsensordevices = MAXSENSORDEVICES;
75 	idmax_len = sizeof(idmax);
76 	if (sysctlbyname("hw.sensors.dev_idmax", &idmax, &idmax_len,
77 	    NULL, 0) == 0)
78 		maxsensordevices = idmax;
79 
80 	mib[0] = CTL_HW;
81 	mib[1] = HW_SENSORS;
82 	slen = sizeof(struct sensor);
83 	sdlen = sizeof(struct sensordev);
84 
85 	row = 1;
86 	sensor_cnt = 0;
87 
88 	wmove(wnd, row, 0);
89 	wclrtobot(wnd);
90 
91 	for (dev = 0; dev < maxsensordevices; dev++) {
92 		mib[2] = dev;
93 		if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
94 			if (errno != ENOENT)
95 				warn("sysctl");
96 			continue;
97 		}
98 		for (type = 0; type < SENSOR_MAX_TYPES; type++) {
99 			mib[3] = type;
100 			for (numt = 0; numt < sensordev.maxnumt[type]; numt++) {
101 				mib[4] = numt;
102 				if (sysctl(mib, 5, &sensor, &slen, NULL, 0)
103 				    == -1) {
104 					if (errno != ENOENT)
105 						warn("sysctl");
106 					continue;
107 				}
108 				if (sensor.flags & SENSOR_FINVALID)
109 					continue;
110 				sensor_cnt++;
111 				printline();
112 			}
113 		}
114 	}
115 }
116 
117 const char *drvstat[] = {
118 	NULL,
119 	"empty", "ready", "powerup", "online", "idle", "active",
120 	"rebuild", "powerdown", "fail", "pfail"
121 };
122 
123 void
124 showsensors(void)
125 {
126 	if (sensor_cnt == 0)
127 		mvwaddstr(wnd, row, 0, "No sensors found.");
128 }
129 
130 int
131 initsensors(void)
132 {
133 	return (1);
134 }
135 
136 void
137 printline(void)
138 {
139 	mvwprintw(wnd, row, 0, "%s.%s%d", sensordev.xname,
140 	    sensor_type_s[sensor.type], sensor.numt);
141 	switch (sensor.type) {
142 	case SENSOR_TEMP:
143 		mvwprintw(wnd, row, 24, "%10.2f degC",
144 		    (sensor.value - 273150000) / 1000000.0);
145 		break;
146 	case SENSOR_FANRPM:
147 		mvwprintw(wnd, row, 24, "%11lld RPM", sensor.value);
148 		break;
149 	case SENSOR_VOLTS_DC:
150 		mvwprintw(wnd, row, 24, "%10.2f V DC",
151 		    sensor.value / 1000000.0);
152 		break;
153 	case SENSOR_AMPS:
154 		mvwprintw(wnd, row, 24, "%10.2f A", sensor.value / 1000000.0);
155 		break;
156 	case SENSOR_INDICATOR:
157 		mvwprintw(wnd, row, 24, "%15s", sensor.value? "On" : "Off");
158 		break;
159 	case SENSOR_INTEGER:
160 		mvwprintw(wnd, row, 24, "%11lld raw", sensor.value);
161 		break;
162 	case SENSOR_PERCENT:
163 		mvwprintw(wnd, row, 24, "%14.2f%%", sensor.value / 1000.0);
164 		break;
165 	case SENSOR_LUX:
166 		mvwprintw(wnd, row, 24, "%15.2f lx", sensor.value / 1000000.0);
167 		break;
168 	case SENSOR_DRIVE:
169 		if (0 < sensor.value &&
170 		    (size_t)sensor.value < sizeof(drvstat)/sizeof(drvstat[0])) {
171 			mvwprintw(wnd, row, 24, "%15s", drvstat[sensor.value]);
172 			break;
173 		}
174 		break;
175 	case SENSOR_TIMEDELTA:
176 		mvwprintw(wnd, row, 24, "%15s", fmttime(sensor.value / 1000000000.0));
177 		break;
178 	case SENSOR_WATTHOUR:
179 		mvwprintw(wnd, row, 24, "%12.2f Wh", sensor.value / 1000000.0);
180 		break;
181 	case SENSOR_AMPHOUR:
182 		mvwprintw(wnd, row, 24, "%10.2f Ah", sensor.value / 1000000.0);
183 		break;
184 	default:
185 		mvwprintw(wnd, row, 24, "%10lld", sensor.value);
186 		break;
187 	}
188 	if (sensor.desc[0] != '\0')
189 		mvwprintw(wnd, row, 58, "(%s)", sensor.desc);
190 
191 	switch (sensor.status) {
192 	case SENSOR_S_UNSPEC:
193 		break;
194 	case SENSOR_S_UNKNOWN:
195 		mvwaddstr(wnd, row, 45, "unknown");
196 		break;
197 	case SENSOR_S_WARN:
198 		mvwaddstr(wnd, row, 45, "WARNING");
199 		break;
200 	case SENSOR_S_CRIT:
201 		mvwaddstr(wnd, row, 45, "CRITICAL");
202 		break;
203 	case SENSOR_S_OK:
204 		mvwaddstr(wnd, row, 45, "OK");
205 		break;
206 	}
207 	row++;
208 }
209 
210 #define SECS_PER_DAY 86400
211 #define SECS_PER_HOUR 3600
212 #define SECS_PER_MIN 60
213 
214 static char *
215 fmttime(double in)
216 {
217 	int signbit = 1;
218 	int tiny = 0;
219 	const char *unit;
220 #define LEN 32
221 	static char outbuf[LEN];
222 
223 	if (in < 0){
224 		signbit = -1;
225 		in *= -1;
226 	}
227 
228 	if (in >= SECS_PER_DAY ){
229 		unit = "days";
230 		in /= SECS_PER_DAY;
231 	} else if (in >= SECS_PER_HOUR ){
232 		unit = "hr";
233 		in /= SECS_PER_HOUR;
234 	} else if (in >= SECS_PER_MIN ){
235 		unit = "min";
236 		in /= SECS_PER_MIN;
237 	} else if (in >= 1 ){
238 		unit = "s";
239 		/* in *= 1; */ /* no op */
240 	} else if (in == 0 ){ /* direct comparisons to floats are scary */
241 		unit = "s";
242 	} else if (in >= 1e-3 ){
243 		unit = "ms";
244 		in *= 1e3;
245 	} else if (in >= 1e-6 ){
246 		unit = "us";
247 		in *= 1e6;
248 	} else if (in >= 1e-9 ){
249 		unit = "ns";
250 		in *= 1e9;
251 	} else {
252 		unit = "ps";
253 		if (in < 1e-13)
254 			tiny = 1;
255 		in *= 1e12;
256 	}
257 
258 	snprintf(outbuf, LEN,
259 	    tiny ? "%s%lf %s" : "%s%.3lf %s",
260 	    signbit == -1 ? "-" : "", in, unit);
261 
262 	return outbuf;
263 }
264