updated copyright to 2013
[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
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             = (struct psensor *)malloc(sizeof(struct psensor));
43
44         psensor->id = id;
45         psensor->name = name;
46         psensor->chip = chip;
47         psensor->enabled = 1;
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->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 (!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
263 psensor_set_current_measure(struct psensor *s,
264                             double v, struct timeval tv)
265 {
266         memmove(s->measures,
267                 &s->measures[1],
268                 (s->values_max_length - 1) * sizeof(struct measure));
269
270         s->measures[s->values_max_length - 1].value = v;
271         s->measures[s->values_max_length - 1].time = tv;
272
273         if (s->min == UNKNOWN_DBL_VALUE || v < s->min)
274                 s->min = v;
275
276         if (s->max == UNKNOWN_DBL_VALUE || v > s->max)
277                 s->max = v;
278
279         if (s->alarm_enabled) {
280                 if (v > s->alarm_high_threshold || v < s->alarm_low_threshold) {
281                         if (!s->alarm_raised && s->cb_alarm_raised)
282                                 s->cb_alarm_raised(s, s->cb_alarm_raised_data);
283
284                         s->alarm_raised = 1;
285                 } else {
286                         s->alarm_raised = 0;
287                 }
288         }
289 }
290
291 double psensor_get_current_value(struct psensor *sensor)
292 {
293         return sensor->measures[sensor->values_max_length - 1].value;
294 }
295
296 struct measure *psensor_get_current_measure(struct psensor *sensor)
297 {
298         return &sensor->measures[sensor->values_max_length - 1];
299 }
300
301 /*
302   Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or
303   SENSOR_TYPE_FAN)
304  */
305 double get_min_value(struct psensor **sensors, int type)
306 {
307         double m = UNKNOWN_DBL_VALUE;
308         struct psensor **s = sensors;
309
310         while (*s) {
311                 struct psensor *sensor = *s;
312
313                 if (sensor->enabled && (sensor->type & type)) {
314                         int i;
315                         double t;
316
317                         for (i = 0; i < sensor->values_max_length; i++) {
318                                 t = sensor->measures[i].value;
319
320                                 if (t == UNKNOWN_DBL_VALUE)
321                                         continue;
322
323                                 if (m == UNKNOWN_DBL_VALUE || t < m)
324                                         m = t;
325                         }
326                 }
327                 s++;
328         }
329
330         return m;
331 }
332
333 /*
334   Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or
335   SENSOR_TYPE_FAN)
336  */
337 double get_max_value(struct psensor **sensors, int type)
338 {
339         double m = UNKNOWN_DBL_VALUE;
340         struct psensor **s = sensors;
341
342         while (*s) {
343                 struct psensor *sensor = *s;
344
345                 if (sensor->enabled && (sensor->type & type)) {
346                         int i;
347                         double t;
348                         for (i = 0; i < sensor->values_max_length; i++) {
349                                 t = sensor->measures[i].value;
350
351                                 if (t == UNKNOWN_DBL_VALUE)
352                                         continue;
353
354                                 if (m == UNKNOWN_DBL_VALUE || t > m)
355                                         m = t;
356                         }
357                 }
358                 s++;
359         }
360
361         return m;
362 }
363
364 double
365 psensor_get_max_current_value(struct psensor **sensors, unsigned int type)
366 {
367         double m = UNKNOWN_DBL_VALUE;
368         struct psensor **s_cur = sensors;
369
370         while (*s_cur) {
371                 struct psensor *s = *s_cur;
372
373                 if (s->enabled && (s->type & type)) {
374                         double v = psensor_get_current_value(s);
375
376                         if (m == UNKNOWN_DBL_VALUE || v > m)
377                                 m = v;
378                 }
379
380                 s_cur++;
381         }
382
383         return m;
384 }
385
386 double get_min_temp(struct psensor **sensors)
387 {
388         return get_min_value(sensors, SENSOR_TYPE_TEMP);
389 }
390
391 double get_min_rpm(struct psensor **sensors)
392 {
393         return get_min_value(sensors, SENSOR_TYPE_FAN);
394 }
395
396 double get_max_rpm(struct psensor **sensors)
397 {
398         return get_max_value(sensors, SENSOR_TYPE_FAN);
399 }
400
401 double get_max_temp(struct psensor **sensors)
402 {
403         return get_max_value(sensors, SENSOR_TYPE_TEMP);
404 }
405
406 struct psensor **get_all_sensors(int use_libatasmart, int values_max_length)
407 {
408         struct psensor **psensors;
409         struct psensor **tmp_psensors;
410
411         psensors = lmsensor_psensor_list_add(NULL, values_max_length);
412
413         if (!use_libatasmart) {
414                 tmp_psensors = hddtemp_psensor_list_add(psensors,
415                                                         values_max_length);
416                 if (tmp_psensors != psensors) {
417                         free(psensors);
418                         psensors = tmp_psensors;
419                 }
420         }
421 #ifdef HAVE_ATASMART
422                 else {
423                         tmp_psensors = hdd_psensor_list_add(psensors,
424                                                             values_max_length);
425                         if (tmp_psensors != psensors) {
426                                 free(psensors);
427                                 psensors = tmp_psensors;
428                         }
429                 }
430 #endif
431
432         if (!psensors) {        /* there is no detected sensors */
433                 psensors = malloc(sizeof(struct psensor *));
434                 *psensors = NULL;
435         }
436
437         return psensors;
438 }
439
440 const char *psensor_type_to_str(unsigned int type)
441 {
442         if (type & SENSOR_TYPE_NVCTRL)
443                 return "NVidia GPU";
444
445         if (type & SENSOR_TYPE_ATIADL) {
446                 if (type & SENSOR_TYPE_TEMP)
447                         return "AMD GPU Temperature";
448                 else if (type & SENSOR_TYPE_RPM)
449                         return "AMD GPU Fan Speed";
450                 else /* type & SENSOR_TYPE_USAGE */
451                         return "AMD GPU Usage";
452         }
453
454         if ((type & SENSOR_TYPE_HDD_TEMP) == SENSOR_TYPE_HDD_TEMP)
455                 return "HDD Temperature";
456
457         if ((type & SENSOR_TYPE_CPU_USAGE) == SENSOR_TYPE_CPU_USAGE)
458                 return "CPU Usage";
459
460         if (type & SENSOR_TYPE_TEMP)
461                 return "Temperature";
462
463         if (type & SENSOR_TYPE_FAN)
464                 return "Fan";
465
466         if (type & SENSOR_TYPE_CPU)
467                 return "CPU";
468
469         if (type & SENSOR_TYPE_REMOTE)
470                 return "Remote";
471
472         return "N/A";
473 }
474
475
476 const char *psensor_type_to_unit_str(unsigned int type, int use_celcius)
477 {
478         if (is_temp_type(type)) {
479                 if (use_celcius)
480                         return "\302\260C";
481                 else
482                         return "\302\260F";
483         } else if (is_fan_type(type)) {
484                 return _("RPM");
485         } else if (type & SENSOR_TYPE_CPU_USAGE) {
486                 return _("%");
487         } else {
488                 return _("N/A");
489         }
490 }
491
492 void psensor_list_update_measures(struct psensor **sensors)
493 {
494         lmsensor_psensor_list_update(sensors);
495
496 #ifdef HAVE_GTOP
497         cpu_psensor_list_update(sensors);
498 #endif
499
500         if (psensor_list_contains_type(sensors, SENSOR_TYPE_HDDTEMP))
501                 hddtemp_psensor_list_update(sensors);
502
503 #ifdef HAVE_ATASMART
504         if (psensor_list_contains_type(sensors, SENSOR_TYPE_ATASMART))
505                 hdd_psensor_list_update(sensors);
506 #endif
507 }
508
509 void psensor_log_measures(struct psensor **sensors)
510 {
511         if (log_level == LOG_DEBUG)
512                 while (*sensors) {
513                         log_debug("Measure: %s %.2f",
514                                    (*sensors)->name,
515                                    psensor_get_current_value(*sensors));
516
517                         sensors++;
518                 }
519 }
520
521 void psensor_init()
522 {
523         lmsensor_init();
524 }
525
526 void psensor_cleanup()
527 {
528         lmsensor_cleanup();
529 }