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