1 /**************************************************************************
3 * Copyright (C) 2016 Steven Toth <stoth@kernellabs.com>
4 * Copyright (C) 2016 Zodiac Inflight Innovations
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
30 /* Purpose: Extract lm-sensors data, expose temperature, power, voltage. */
32 #include "hud/hud_private.h"
33 #include "util/list.h"
34 #include "os/os_time.h"
35 #include "util/u_memory.h"
42 #include <sys/types.h>
45 #include <sensors/sensors.h>
49 /* TODO: We don't handle dynamic sensor discovery / arrival or removal.
50 * Static globals specific to this HUD category.
52 static int gsensors_temp_count
= 0;
53 static struct list_head gsensors_temp_list
;
55 struct sensors_temp_info
57 struct list_head list
;
59 /* Combined chip and feature name, human readable. */
62 /* The type of measurement, critical or current. */
68 char featurename
[128];
70 sensors_chip_name
*chip
;
71 const sensors_feature
*feature
;
72 double current
, min
, max
, critical
;
76 get_value(const sensors_chip_name
*name
, const sensors_subfeature
*sub
)
81 err
= sensors_get_value(name
, sub
->number
, &val
);
83 fprintf(stderr
, "ERROR: Can't get value of subfeature %s\n", sub
->name
);
90 get_sensor_values(struct sensors_temp_info
*sti
)
92 const sensors_subfeature
*sf
;
95 case SENSORS_VOLTAGE_CURRENT
:
96 sf
= sensors_get_subfeature(sti
->chip
, sti
->feature
,
97 SENSORS_SUBFEATURE_IN_INPUT
);
99 sti
->current
= get_value(sti
->chip
, sf
);
101 case SENSORS_CURRENT_CURRENT
:
102 sf
= sensors_get_subfeature(sti
->chip
, sti
->feature
,
103 SENSORS_SUBFEATURE_CURR_INPUT
);
105 /* Sensors API returns in AMPs, even though driver is reporting mA,
106 * convert back to mA */
107 sti
->current
= get_value(sti
->chip
, sf
) * 1000;
110 case SENSORS_TEMP_CURRENT
:
111 sf
= sensors_get_subfeature(sti
->chip
, sti
->feature
,
112 SENSORS_SUBFEATURE_TEMP_INPUT
);
114 sti
->current
= get_value(sti
->chip
, sf
);
116 case SENSORS_TEMP_CRITICAL
:
117 sf
= sensors_get_subfeature(sti
->chip
, sti
->feature
,
118 SENSORS_SUBFEATURE_TEMP_CRIT
);
120 sti
->critical
= get_value(sti
->chip
, sf
);
122 case SENSORS_POWER_CURRENT
:
123 sf
= sensors_get_subfeature(sti
->chip
, sti
->feature
,
124 SENSORS_SUBFEATURE_POWER_INPUT
);
126 /* Sensors API returns in WATTs, even though driver is reporting mW,
127 * convert back to mW */
128 sti
->current
= get_value(sti
->chip
, sf
) * 1000;
133 sf
= sensors_get_subfeature(sti
->chip
, sti
->feature
,
134 SENSORS_SUBFEATURE_TEMP_MIN
);
136 sti
->min
= get_value(sti
->chip
, sf
);
138 sf
= sensors_get_subfeature(sti
->chip
, sti
->feature
,
139 SENSORS_SUBFEATURE_TEMP_MAX
);
141 sti
->max
= get_value(sti
->chip
, sf
);
143 printf("%s.%s.current = %.1f\n", sti
->chipname
, sti
->featurename
,
145 printf("%s.%s.critical = %.1f\n", sti
->chipname
, sti
->featurename
,
150 static struct sensors_temp_info
*
151 find_sti_by_name(const char *n
, unsigned int mode
)
153 list_for_each_entry(struct sensors_temp_info
, sti
, &gsensors_temp_list
, list
) {
154 if (sti
->mode
!= mode
)
156 if (strcasecmp(sti
->name
, n
) == 0)
163 query_sti_load(struct hud_graph
*gr
)
165 struct sensors_temp_info
*sti
= gr
->query_data
;
166 uint64_t now
= os_time_get();
168 if (sti
->last_time
) {
169 if (sti
->last_time
+ gr
->pane
->period
<= now
) {
170 get_sensor_values(sti
);
173 case SENSORS_TEMP_CURRENT
:
174 hud_graph_add_value(gr
, (uint64_t) sti
->current
);
176 case SENSORS_TEMP_CRITICAL
:
177 hud_graph_add_value(gr
, (uint64_t) sti
->critical
);
179 case SENSORS_VOLTAGE_CURRENT
:
180 hud_graph_add_value(gr
, (uint64_t)(sti
->current
* 1000));
182 case SENSORS_CURRENT_CURRENT
:
183 hud_graph_add_value(gr
, (uint64_t) sti
->current
);
185 case SENSORS_POWER_CURRENT
:
186 hud_graph_add_value(gr
, (uint64_t) sti
->current
);
190 sti
->last_time
= now
;
195 get_sensor_values(sti
);
196 sti
->last_time
= now
;
201 free_query_data(void *p
)
203 struct sensors_temp_info
*sti
= (struct sensors_temp_info
*) p
;
204 list_del(&sti
->list
);
206 sensors_free_chip_name(sti
->chip
);
212 * Create and initialize a new object for a specific sensor interface dev.
213 * \param pane parent context.
214 * \param dev_name device name, EG. 'coretemp-isa-0000.Core 1'
215 * \param mode query type (NIC_DIRECTION_RX/WR/RSSI) statistics.
218 hud_sensors_temp_graph_install(struct hud_pane
*pane
, const char *dev_name
,
221 struct hud_graph
*gr
;
222 struct sensors_temp_info
*sti
;
224 int num_devs
= hud_get_num_sensors(0);
228 printf("%s(%s, %s) - Creating HUD object\n", __func__
, dev_name
,
229 mode
== SENSORS_VOLTAGE_CURRENT
? "VOLTS" :
230 mode
== SENSORS_CURRENT_CURRENT
? "AMPS" :
231 mode
== SENSORS_TEMP_CURRENT
? "CU" :
232 mode
== SENSORS_POWER_CURRENT
? "POWER" :
233 mode
== SENSORS_TEMP_CRITICAL
? "CR" : "UNDEFINED");
236 sti
= find_sti_by_name(dev_name
, mode
);
240 gr
= CALLOC_STRUCT(hud_graph
);
244 snprintf(gr
->name
, sizeof(gr
->name
), "%.6s..%s (%s)",
247 sti
->mode
== SENSORS_VOLTAGE_CURRENT
? "Volts" :
248 sti
->mode
== SENSORS_CURRENT_CURRENT
? "Amps" :
249 sti
->mode
== SENSORS_TEMP_CURRENT
? "Curr" :
250 sti
->mode
== SENSORS_POWER_CURRENT
? "Pow" :
251 sti
->mode
== SENSORS_TEMP_CRITICAL
? "Crit" : "Unkn");
253 gr
->query_data
= sti
;
254 gr
->query_new_value
= query_sti_load
;
256 /* Don't use free() as our callback as that messes up Gallium's
257 * memory debugger. Use simple free_query_data() wrapper.
259 gr
->free_query_data
= free_query_data
;
261 hud_pane_add_graph(pane
, gr
);
263 case SENSORS_TEMP_CURRENT
:
264 case SENSORS_TEMP_CRITICAL
:
265 hud_pane_set_max_value(pane
, 120);
267 case SENSORS_VOLTAGE_CURRENT
:
268 hud_pane_set_max_value(pane
, 12);
270 case SENSORS_CURRENT_CURRENT
:
271 hud_pane_set_max_value(pane
, 5000);
273 case SENSORS_POWER_CURRENT
:
274 hud_pane_set_max_value(pane
, 5000 /* mW */);
280 create_object(const char *chipname
, const char *featurename
,
281 const sensors_chip_name
*chip
, const sensors_feature
*feature
,
285 printf("%03d: %s.%s\n", gsensors_temp_count
, chipname
, featurename
);
287 struct sensors_temp_info
*sti
= CALLOC_STRUCT(sensors_temp_info
);
290 sti
->chip
= (sensors_chip_name
*) chip
;
291 sti
->feature
= feature
;
292 strcpy(sti
->chipname
, chipname
);
293 strcpy(sti
->featurename
, featurename
);
294 snprintf(sti
->name
, sizeof(sti
->name
), "%s.%s", sti
->chipname
,
297 list_addtail(&sti
->list
, &gsensors_temp_list
);
298 gsensors_temp_count
++;
302 build_sensor_list(void)
304 const sensors_chip_name
*chip
;
305 const sensors_chip_name
*match
= 0;
306 const sensors_feature
*feature
;
310 while ((chip
= sensors_get_detected_chips(match
, &chip_nr
))) {
311 sensors_snprintf_chip_name(name
, sizeof(name
), chip
);
313 /* Get all features and filter accordingly. */
315 while ((feature
= sensors_get_features(chip
, &fnr
))) {
316 char *featurename
= sensors_get_label(chip
, feature
);
320 /* Create a 'current' and 'critical' object pair.
321 * Ignore sensor if its not temperature based.
323 switch(feature
->type
) {
324 case SENSORS_FEATURE_TEMP
:
325 create_object(name
, featurename
, chip
, feature
,
326 SENSORS_TEMP_CURRENT
);
327 create_object(name
, featurename
, chip
, feature
,
328 SENSORS_TEMP_CRITICAL
);
330 case SENSORS_FEATURE_IN
:
331 create_object(name
, featurename
, chip
, feature
,
332 SENSORS_VOLTAGE_CURRENT
);
334 case SENSORS_FEATURE_CURR
:
335 create_object(name
, featurename
, chip
, feature
,
336 SENSORS_CURRENT_CURRENT
);
338 case SENSORS_FEATURE_POWER
:
339 create_object(name
, featurename
, chip
, feature
,
340 SENSORS_POWER_CURRENT
);
351 * Initialize internal object arrays and display lmsensors HUD help.
352 * \param displayhelp true if the list of detected devices should be
353 displayed on the console.
354 * \return number of detected lmsensor devices.
357 hud_get_num_sensors(bool displayhelp
)
359 /* Return the number of sensors detected. */
360 if (gsensors_temp_count
)
361 return gsensors_temp_count
;
363 int ret
= sensors_init(NULL
);
367 list_inithead(&gsensors_temp_list
);
369 /* Scan /sys/block, for every object type we support, create and
370 * persist an object to represent its different statistics.
375 list_for_each_entry(struct sensors_temp_info
, sti
, &gsensors_temp_list
, list
) {
378 case SENSORS_TEMP_CURRENT
:
379 snprintf(line
, sizeof(line
), " sensors_temp_cu-%s", sti
->name
);
381 case SENSORS_TEMP_CRITICAL
:
382 snprintf(line
, sizeof(line
), " sensors_temp_cr-%s", sti
->name
);
384 case SENSORS_VOLTAGE_CURRENT
:
385 snprintf(line
, sizeof(line
), " sensors_volt_cu-%s", sti
->name
);
387 case SENSORS_CURRENT_CURRENT
:
388 snprintf(line
, sizeof(line
), " sensors_curr_cu-%s", sti
->name
);
390 case SENSORS_POWER_CURRENT
:
391 snprintf(line
, sizeof(line
), " sensors_pow_cu-%s", sti
->name
);
399 return gsensors_temp_count
;
402 #endif /* HAVE_LIBSENSORS */