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