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