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