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