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