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