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