badd6d632a80f9266a64968a86f9f7ec2137b696
[psensor.git] / src / lib / psensor.c
1 /*
2  * Copyright (C) 2010-2014 jeanfi@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA
18  */
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include <locale.h>
23 #include <libintl.h>
24 #define _(str) gettext(str)
25
26 #include <hdd.h>
27 #include <psensor.h>
28 #include <lmsensor.h>
29 #include <temperature.h>
30
31 #ifdef HAVE_GTOP
32 #include <cpu.h>
33 #include <pmem.h>
34 #endif
35
36 struct psensor *psensor_create(char *id,
37                                char *name,
38                                char *chip,
39                                unsigned int type,
40                                int values_max_length)
41 {
42         struct psensor *psensor;
43
44         psensor = (struct psensor *)malloc(sizeof(struct psensor));
45
46         psensor->id = id;
47         psensor->name = name;
48         psensor->chip = chip;
49         psensor->min = UNKNOWN_DBL_VALUE;
50         psensor->max = UNKNOWN_DBL_VALUE;
51
52         psensor->type = type;
53
54         psensor->values_max_length = values_max_length;
55         psensor->measures = measures_dbl_create(values_max_length);
56
57         psensor->alarm_enabled = 0;
58         psensor->alarm_high_threshold = 0;
59         psensor->alarm_low_threshold = 0;
60
61         psensor->cb_alarm_raised = NULL;
62         psensor->cb_alarm_raised_data = NULL;
63         psensor->alarm_raised = 0;
64
65         psensor->url = NULL;
66
67         psensor->color = NULL;
68
69         psensor->graph_enabled = 1;
70         psensor->appindicator_enabled = 0;
71
72         return psensor;
73 }
74
75 void psensor_values_resize(struct psensor *s, int new_size)
76 {
77         struct measure *new_ms, *cur_ms;
78         int cur_size;
79
80         cur_size = s->values_max_length;
81         cur_ms = s->measures;
82         new_ms = measures_dbl_create(new_size);
83
84         if (cur_ms) {
85                 int i;
86                 for (i = 0; i < new_size - 1 && i < cur_size - 1; i++)
87                         measure_copy(&cur_ms[cur_size - i - 1],
88                                      &new_ms[new_size - i - 1]);
89
90                 measures_free(s->measures);
91         }
92
93         s->values_max_length = new_size;
94         s->measures = new_ms;
95 }
96
97 void psensor_free(struct psensor *sensor)
98 {
99         if (sensor) {
100                 log_debug("Cleanup %s", sensor->id);
101
102                 free(sensor->name);
103                 free(sensor->id);
104
105                 if (sensor->chip)
106                         free(sensor->chip);
107
108                 if (sensor->color)
109                         free(sensor->color);
110
111                 measures_free(sensor->measures);
112
113                 free(sensor->url);
114
115                 free(sensor);
116         }
117 }
118
119 void psensor_list_free(struct psensor **sensors)
120 {
121         struct psensor **sensor_cur;
122
123         if (sensors) {
124                 sensor_cur = sensors;
125
126                 while (*sensor_cur) {
127                         psensor_free(*sensor_cur);
128
129                         sensor_cur++;
130                 }
131
132                 free(sensors);
133
134                 sensors = NULL;
135         }
136 }
137
138 int psensor_list_size(struct psensor **sensors)
139 {
140         int size;
141         struct psensor **sensor_cur;
142
143         if (!sensors)
144                 return 0;
145
146         size = 0;
147         sensor_cur = sensors;
148
149         while (*sensor_cur) {
150                 size++;
151                 sensor_cur++;
152         }
153         return size;
154 }
155
156 int psensor_list_contains_type(struct psensor **sensors, unsigned int type)
157 {
158         struct psensor **s;
159
160         if (!sensors)
161                 return 0;
162
163         s = sensors;
164         while (*s) {
165                 if ((*s)->type & type)
166                         return 1;
167                 s++;
168         }
169
170         return 0;
171 }
172
173 struct psensor **psensor_list_add(struct psensor **sensors,
174                                   struct psensor *sensor)
175 {
176         int size;
177
178         size = psensor_list_size(sensors);
179
180         struct psensor **result
181             = malloc((size + 1 + 1) * sizeof(struct psensor *));
182
183         if (sensors)
184                 memcpy(result, sensors, size * sizeof(struct psensor *));
185
186         result[size] = sensor;
187         result[size + 1] = NULL;
188
189         return result;
190 }
191
192 void psensor_list_append(struct psensor ***sensors, struct psensor *sensor)
193 {
194         struct psensor **tmp;
195
196         if (!sensor)
197                 return ;
198
199         tmp = psensor_list_add(*sensors, sensor);
200
201         if (tmp != *sensors) {
202                 free(*sensors);
203                 *sensors = tmp;
204         }
205 }
206
207
208 struct psensor *psensor_list_get_by_id(struct psensor **sensors, const char *id)
209 {
210         struct psensor **sensors_cur = sensors;
211
212         while (*sensors_cur) {
213                 if (!strcmp((*sensors_cur)->id, id))
214                         return *sensors_cur;
215
216                 sensors_cur++;
217         }
218
219         return NULL;
220 }
221
222 int is_temp_type(unsigned int type)
223 {
224         return type & SENSOR_TYPE_TEMP;
225 }
226
227 int is_fan_type(unsigned int type)
228 {
229         return type & SENSOR_TYPE_FAN;
230 }
231
232 char *
233 psensor_value_to_str(unsigned int type, double value, int use_celsius)
234 {
235         char *str;
236         const char *unit;
237
238         /*
239          * should not be possible to exceed 20 characters with temp or
240          * rpm values the .x part is never displayed
241          */
242         str = malloc(20);
243
244         unit = psensor_type_to_unit_str(type, use_celsius);
245
246         if (is_temp_type(type) && !use_celsius)
247                 value = celsius_to_fahrenheit(value);
248
249         sprintf(str, "%.0f%s", value, unit);
250
251         return str;
252 }
253
254 char *
255 psensor_measure_to_str(const struct measure *m,
256                        unsigned int type,
257                        unsigned int use_celsius)
258 {
259         return psensor_value_to_str(type, m->value, use_celsius);
260 }
261
262 void psensor_set_current_value(struct psensor *sensor, double value)
263 {
264         struct timeval tv;
265
266         if (gettimeofday(&tv, NULL) != 0)
267                 timerclear(&tv);
268
269         psensor_set_current_measure(sensor, value, tv);
270 }
271
272 void psensor_set_current_measure(struct psensor *s, double v, struct timeval tv)
273 {
274         memmove(s->measures,
275                 &s->measures[1],
276                 (s->values_max_length - 1) * sizeof(struct measure));
277
278         s->measures[s->values_max_length - 1].value = v;
279         s->measures[s->values_max_length - 1].time = tv;
280
281         if (s->min == UNKNOWN_DBL_VALUE || v < s->min)
282                 s->min = v;
283
284         if (s->max == UNKNOWN_DBL_VALUE || v > s->max)
285                 s->max = v;
286
287         if (s->alarm_enabled) {
288                 if (v > s->alarm_high_threshold || v < s->alarm_low_threshold) {
289                         if (!s->alarm_raised && s->cb_alarm_raised)
290                                 s->cb_alarm_raised(s, s->cb_alarm_raised_data);
291
292                         s->alarm_raised = 1;
293                 } else {
294                         s->alarm_raised = 0;
295                 }
296         }
297 }
298
299 double psensor_get_current_value(const struct psensor *sensor)
300 {
301         return sensor->measures[sensor->values_max_length - 1].value;
302 }
303
304 struct measure *psensor_get_current_measure(struct psensor *sensor)
305 {
306         return &sensor->measures[sensor->values_max_length - 1];
307 }
308
309 /*
310   Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or
311   SENSOR_TYPE_FAN)
312  */
313 static double get_min_value(struct psensor **sensors, int type)
314 {
315         double m = UNKNOWN_DBL_VALUE;
316         struct psensor **s = sensors;
317
318         while (*s) {
319                 struct psensor *sensor = *s;
320
321                 if (sensor->type & type) {
322                         int i;
323                         double t;
324
325                         for (i = 0; i < sensor->values_max_length; i++) {
326                                 t = sensor->measures[i].value;
327
328                                 if (t == UNKNOWN_DBL_VALUE)
329                                         continue;
330
331                                 if (m == UNKNOWN_DBL_VALUE || t < m)
332                                         m = t;
333                         }
334                 }
335                 s++;
336         }
337
338         return m;
339 }
340
341 /*
342   Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or
343   SENSOR_TYPE_FAN)
344  */
345 double get_max_value(struct psensor **sensors, int type)
346 {
347         double m = UNKNOWN_DBL_VALUE;
348         struct psensor **s = sensors;
349
350         while (*s) {
351                 struct psensor *sensor = *s;
352
353                 if (sensor->type & type) {
354                         int i;
355                         double t;
356                         for (i = 0; i < sensor->values_max_length; i++) {
357                                 t = sensor->measures[i].value;
358
359                                 if (t == UNKNOWN_DBL_VALUE)
360                                         continue;
361
362                                 if (m == UNKNOWN_DBL_VALUE || t > m)
363                                         m = t;
364                         }
365                 }
366                 s++;
367         }
368
369         return m;
370 }
371
372 double
373 psensor_get_max_current_value(struct psensor **sensors, unsigned int type)
374 {
375         double m = UNKNOWN_DBL_VALUE;
376         struct psensor **s_cur = sensors;
377
378         while (*s_cur) {
379                 struct psensor *s = *s_cur;
380
381                 if (s->graph_enabled && (s->type & type)) {
382                         double v = psensor_get_current_value(s);
383
384                         if (m == UNKNOWN_DBL_VALUE || v > m)
385                                 m = v;
386                 }
387
388                 s_cur++;
389         }
390
391         return m;
392 }
393
394 double get_min_temp(struct psensor **sensors)
395 {
396         return get_min_value(sensors, SENSOR_TYPE_TEMP);
397 }
398
399 double get_min_rpm(struct psensor **sensors)
400 {
401         return get_min_value(sensors, SENSOR_TYPE_FAN);
402 }
403
404 double get_max_rpm(struct psensor **sensors)
405 {
406         return get_max_value(sensors, SENSOR_TYPE_FAN);
407 }
408
409 double get_max_temp(struct psensor **sensors)
410 {
411         return get_max_value(sensors, SENSOR_TYPE_TEMP);
412 }
413
414 struct psensor **get_all_sensors(int use_libatasmart, int values_max_length)
415 {
416         struct psensor **psensors;
417         struct psensor **tmp_psensors;
418
419         psensors = lmsensor_psensor_list_add(NULL, values_max_length);
420
421         if (!use_libatasmart) {
422                 tmp_psensors = hddtemp_psensor_list_add(psensors,
423                                                         values_max_length);
424                 if (tmp_psensors != psensors) {
425                         free(psensors);
426                         psensors = tmp_psensors;
427                 }
428         }
429 #ifdef HAVE_ATASMART
430                 else {
431                         tmp_psensors = hdd_psensor_list_add(psensors,
432                                                             values_max_length);
433                         if (tmp_psensors != psensors) {
434                                 free(psensors);
435                                 psensors = tmp_psensors;
436                         }
437                 }
438 #endif
439
440 #ifdef HAVE_GTOP
441         mem_psensor_list_add(&psensors, values_max_length);
442 #endif
443
444         if (!psensors) {        /* there is no detected sensors */
445                 psensors = malloc(sizeof(struct psensor *));
446                 *psensors = NULL;
447         }
448
449         return psensors;
450 }
451
452 const char *psensor_type_to_str(unsigned int type)
453 {
454         if (type & SENSOR_TYPE_NVCTRL) {
455                 if (type & SENSOR_TYPE_TEMP)
456                         return "Temperature";
457                 else if (type & SENSOR_TYPE_GRAPHICS)
458                         return "Graphics usage";
459                 else if (type & SENSOR_TYPE_VIDEO)
460                         return "Video usage";
461                 else if (type & SENSOR_TYPE_MEMORY)
462                         return "Memory usage";
463                 else if (type & SENSOR_TYPE_PCIE)
464                         return "PCIe usage";
465                 else
466                         return "NVIDIA GPU";
467         }
468
469         if (type & SENSOR_TYPE_ATIADL) {
470                 if (type & SENSOR_TYPE_TEMP)
471                         return "AMD GPU Temperature";
472                 else if (type & SENSOR_TYPE_RPM)
473                         return "AMD GPU Fan Speed";
474                 else /* type & SENSOR_TYPE_USAGE */
475                         return "AMD GPU Usage";
476         }
477
478         if ((type & SENSOR_TYPE_HDD_TEMP) == SENSOR_TYPE_HDD_TEMP)
479                 return "HDD Temperature";
480
481         if ((type & SENSOR_TYPE_CPU_USAGE) == SENSOR_TYPE_CPU_USAGE)
482                 return "CPU Usage";
483
484         if (type & SENSOR_TYPE_TEMP)
485                 return "Temperature";
486
487         if (type & SENSOR_TYPE_RPM)
488                 return "Fan";
489
490         if (type & SENSOR_TYPE_CPU)
491                 return "CPU";
492
493         if (type & SENSOR_TYPE_REMOTE)
494                 return "Remote";
495
496         if (type & SENSOR_TYPE_MEMORY)
497                 return "Memory";
498
499         return "N/A";
500 }
501
502
503 const char *psensor_type_to_unit_str(unsigned int type, int use_celsius)
504 {
505         if (is_temp_type(type)) {
506                 if (use_celsius)
507                         return "\302\260C";
508                 else
509                         return "\302\260F";
510         } else if (is_fan_type(type)) {
511                 return _("RPM");
512         } else if (type & SENSOR_TYPE_CPU_USAGE) {
513                 return _("%");
514         } else {
515                 return _("N/A");
516         }
517 }
518
519 void psensor_list_update_measures(struct psensor **sensors)
520 {
521         lmsensor_psensor_list_update(sensors);
522
523 #ifdef HAVE_GTOP
524         cpu_psensor_list_update(sensors);
525         mem_psensor_list_update(sensors);
526 #endif
527
528         if (psensor_list_contains_type(sensors, SENSOR_TYPE_HDDTEMP))
529                 hddtemp_psensor_list_update(sensors);
530
531 #ifdef HAVE_ATASMART
532         if (psensor_list_contains_type(sensors, SENSOR_TYPE_ATASMART))
533                 hdd_psensor_list_update(sensors);
534 #endif
535 }
536
537 void psensor_log_measures(struct psensor **sensors)
538 {
539         if (log_level == LOG_DEBUG)
540                 while (*sensors) {
541                         log_debug("Measure: %s %.2f",
542                                    (*sensors)->name,
543                                    psensor_get_current_value(*sensors));
544
545                         sensors++;
546                 }
547 }
548
549 void psensor_init()
550 {
551         lmsensor_init();
552 }
553
554 void psensor_cleanup()
555 {
556         lmsensor_cleanup();
557 }
558
559 struct psensor **psensor_list_copy(struct psensor **sensors)
560 {
561         struct psensor **result;
562         int n, i;
563
564         n = psensor_list_size(sensors);
565         result = malloc((n+1) * sizeof(struct psensor *));
566         for (i = 0; i < n; i++)
567                 result[i] = sensors[i];
568         result[n] = NULL;
569
570         return result;
571 }
572
573 char *
574 psensor_current_value_to_str(const struct psensor *s, unsigned int use_celsius)
575 {
576         return psensor_value_to_str(s->type,
577                                     psensor_get_current_value(s),
578                                     use_celsius);
579 }
580
581 struct psensor **psensor_list_filter_graph_enabled(struct psensor **sensors)
582 {
583         int n, i;
584         struct psensor **result, **cur, *s;
585
586         if (!sensors)
587                 return NULL;
588
589         n = psensor_list_size(sensors);
590         result = malloc((n+1) * sizeof(struct psensor *));
591
592         for (cur = sensors, i = 0; *cur; cur++) {
593                 s = *cur;
594
595                 if (s->graph_enabled)
596                         result[i++] = s;
597         }
598
599         result[i] = NULL;
600
601         return result;
602 }