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