Imported Debian patch 0.8.0.4-1
[psensor-pkg-debian.git] / src / lib / psensor.c
1 /*
2  * Copyright (C) 2010-2013 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 celcius_to_fahrenheit(double c)
213 {
214         return c * (9.0/5.0) + 32;
215 }
216
217 double fahrenheit_to_celcius(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_celcius)
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_celcius);
235
236         if (is_temp_type(type) && !use_celcius)
237                 value = celcius_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_celcius)
248 {
249         return psensor_value_to_str(type, m->value, use_celcius);
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                 return "NVidia GPU";
442
443         if (type & SENSOR_TYPE_ATIADL) {
444                 if (type & SENSOR_TYPE_TEMP)
445                         return "AMD GPU Temperature";
446                 else if (type & SENSOR_TYPE_RPM)
447                         return "AMD GPU Fan Speed";
448                 else /* type & SENSOR_TYPE_USAGE */
449                         return "AMD GPU Usage";
450         }
451
452         if ((type & SENSOR_TYPE_HDD_TEMP) == SENSOR_TYPE_HDD_TEMP)
453                 return "HDD Temperature";
454
455         if ((type & SENSOR_TYPE_CPU_USAGE) == SENSOR_TYPE_CPU_USAGE)
456                 return "CPU Usage";
457
458         if (type & SENSOR_TYPE_TEMP)
459                 return "Temperature";
460
461         if (type & SENSOR_TYPE_FAN)
462                 return "Fan";
463
464         if (type & SENSOR_TYPE_CPU)
465                 return "CPU";
466
467         if (type & SENSOR_TYPE_REMOTE)
468                 return "Remote";
469
470         return "N/A";
471 }
472
473
474 const char *psensor_type_to_unit_str(unsigned int type, int use_celcius)
475 {
476         if (is_temp_type(type)) {
477                 if (use_celcius)
478                         return "\302\260C";
479                 else
480                         return "\302\260F";
481         } else if (is_fan_type(type)) {
482                 return _("RPM");
483         } else if (type & SENSOR_TYPE_CPU_USAGE) {
484                 return _("%");
485         } else {
486                 return _("N/A");
487         }
488 }
489
490 void psensor_list_update_measures(struct psensor **sensors)
491 {
492         lmsensor_psensor_list_update(sensors);
493
494 #ifdef HAVE_GTOP
495         cpu_psensor_list_update(sensors);
496 #endif
497
498         if (psensor_list_contains_type(sensors, SENSOR_TYPE_HDDTEMP))
499                 hddtemp_psensor_list_update(sensors);
500
501 #ifdef HAVE_ATASMART
502         if (psensor_list_contains_type(sensors, SENSOR_TYPE_ATASMART))
503                 hdd_psensor_list_update(sensors);
504 #endif
505 }
506
507 void psensor_log_measures(struct psensor **sensors)
508 {
509         if (log_level == LOG_DEBUG)
510                 while (*sensors) {
511                         log_debug("Measure: %s %.2f",
512                                    (*sensors)->name,
513                                    psensor_get_current_value(*sensors));
514
515                         sensors++;
516                 }
517 }
518
519 void psensor_init()
520 {
521         lmsensor_init();
522 }
523
524 void psensor_cleanup()
525 {
526         lmsensor_cleanup();
527 }
528
529 struct psensor **psensor_list_copy(struct psensor **sensors)
530 {
531         struct psensor **result;
532         int n, i;
533
534         n = psensor_list_size(sensors);
535         result = malloc((n+1) * sizeof(struct psensor *));
536         for (i = 0; i < n; i++)
537                 result[i] = sensors[i];
538         result[n] = NULL;
539
540         return result;
541 }
542
543 char *
544 psensor_current_value_to_str(const struct psensor *s, unsigned int celcius)
545 {
546         return psensor_value_to_str(s->type,
547                                     psensor_get_current_value(s),
548                                     celcius);
549 }
550
551 struct psensor **psensor_list_filter_graph_enabled(struct psensor **sensors)
552 {
553         int n, i;
554         struct psensor **result, **cur, *s;
555
556         if (!sensors)
557                 return NULL;
558
559         n = psensor_list_size(sensors);
560         result = malloc((n+1) * sizeof(struct psensor *));
561
562         for (cur = sensors, i = 0; *cur; cur++) {
563                 s = *cur;
564
565                 if (s->graph_enabled)
566                         result[i++] = s;
567         }
568
569         result[i] = NULL;
570
571         return result;
572 }