display the name of chip in sensor preferences.
[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,
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         sprintf(str, "%.0f%s", value, unit);
237
238         return str;
239 }
240
241 char *
242 psensor_measure_to_str(const struct measure *m,
243                        unsigned int type,
244                        unsigned int use_celcius)
245 {
246         return psensor_value_to_str(type, m->value, use_celcius);
247 }
248
249 void psensor_set_current_value(struct psensor *sensor, double value)
250 {
251         struct timeval tv;
252
253         if (gettimeofday(&tv, NULL) != 0)
254                 timerclear(&tv);
255
256         psensor_set_current_measure(sensor, value, tv);
257 }
258
259 void
260 psensor_set_current_measure(struct psensor *s,
261                             double v, struct timeval tv)
262 {
263         memmove(s->measures,
264                 &s->measures[1],
265                 (s->values_max_length - 1) * sizeof(struct measure));
266
267         s->measures[s->values_max_length - 1].value = v;
268         s->measures[s->values_max_length - 1].time = tv;
269
270         if (s->min == UNKNOWN_DBL_VALUE || v < s->min)
271                 s->min = v;
272
273         if (s->max == UNKNOWN_DBL_VALUE || v > s->max)
274                 s->max = v;
275
276         if (s->alarm_enabled) {
277                 if (v > s->alarm_high_threshold || v < s->alarm_low_threshold) {
278                         if (!s->alarm_raised && s->cb_alarm_raised)
279                                 s->cb_alarm_raised(s, s->cb_alarm_raised_data);
280
281                         s->alarm_raised = 1;
282                 } else {
283                         s->alarm_raised = 0;
284                 }
285         }
286 }
287
288 double psensor_get_current_value(struct psensor *sensor)
289 {
290         return sensor->measures[sensor->values_max_length - 1].value;
291 }
292
293 struct measure *psensor_get_current_measure(struct psensor *sensor)
294 {
295         return &sensor->measures[sensor->values_max_length - 1];
296 }
297
298 /*
299   Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or
300   SENSOR_TYPE_FAN)
301  */
302 double get_min_value(struct psensor **sensors, int type)
303 {
304         double m = UNKNOWN_DBL_VALUE;
305         struct psensor **s = sensors;
306
307         while (*s) {
308                 struct psensor *sensor = *s;
309
310                 if (sensor->enabled && (sensor->type & type)) {
311                         int i;
312                         double t;
313
314                         for (i = 0; i < sensor->values_max_length; i++) {
315                                 t = sensor->measures[i].value;
316
317                                 if (t == UNKNOWN_DBL_VALUE)
318                                         continue;
319
320                                 if (m == UNKNOWN_DBL_VALUE || t < m)
321                                         m = t;
322                         }
323                 }
324                 s++;
325         }
326
327         return m;
328 }
329
330 /*
331   Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or
332   SENSOR_TYPE_FAN)
333  */
334 double get_max_value(struct psensor **sensors, int type)
335 {
336         double m = UNKNOWN_DBL_VALUE;
337         struct psensor **s = sensors;
338
339         while (*s) {
340                 struct psensor *sensor = *s;
341
342                 if (sensor->enabled && (sensor->type & type)) {
343                         int i;
344                         double t;
345                         for (i = 0; i < sensor->values_max_length; i++) {
346                                 t = sensor->measures[i].value;
347
348                                 if (t == UNKNOWN_DBL_VALUE)
349                                         continue;
350
351                                 if (m == UNKNOWN_DBL_VALUE || t > m)
352                                         m = t;
353                         }
354                 }
355                 s++;
356         }
357
358         return m;
359 }
360
361 double
362 psensor_get_max_current_value(struct psensor **sensors, unsigned int type)
363 {
364         double m = UNKNOWN_DBL_VALUE;
365         struct psensor **s_cur = sensors;
366
367         while (*s_cur) {
368                 struct psensor *s = *s_cur;
369
370                 if (s->enabled && (s->type & type)) {
371                         double v = psensor_get_current_value(s);
372
373                         if (m == UNKNOWN_DBL_VALUE || v > m)
374                                 m = v;
375                 }
376
377                 s_cur++;
378         }
379
380         return m;
381 }
382
383 double get_min_temp(struct psensor **sensors)
384 {
385         return get_min_value(sensors, SENSOR_TYPE_TEMP);
386 }
387
388 double get_min_rpm(struct psensor **sensors)
389 {
390         return get_min_value(sensors, SENSOR_TYPE_FAN);
391 }
392
393 double get_max_rpm(struct psensor **sensors)
394 {
395         return get_max_value(sensors, SENSOR_TYPE_FAN);
396 }
397
398 double get_max_temp(struct psensor **sensors)
399 {
400         return get_max_value(sensors, SENSOR_TYPE_TEMP);
401 }
402
403 struct psensor **get_all_sensors(int use_libatasmart, int values_max_length)
404 {
405         struct psensor **psensors = NULL;
406         struct psensor **tmp_psensors;
407
408         psensors = lmsensor_psensor_list_add(NULL, values_max_length);
409
410         if (!use_libatasmart) {
411                 tmp_psensors = hddtemp_psensor_list_add(psensors,
412                                                         values_max_length);
413                 if (tmp_psensors != psensors) {
414                         free(psensors);
415                         psensors = tmp_psensors;
416                 }
417         }
418 #ifdef HAVE_ATASMART
419                 else {
420                         tmp_psensors = hdd_psensor_list_add(psensors,
421                                                             values_max_length);
422                         if (tmp_psensors != psensors) {
423                                 free(psensors);
424                                 psensors = tmp_psensors;
425                         }
426                 }
427 #endif
428
429         if (!psensors) {        /* there is no detected sensors */
430                 psensors = malloc(sizeof(struct psensor *));
431                 *psensors = NULL;
432         }
433
434         return psensors;
435 }
436
437 const char *psensor_type_to_str(unsigned int type)
438 {
439         if ((type & SENSOR_TYPE_NVIDIA_TEMP) == SENSOR_TYPE_NVIDIA_TEMP)
440                 return "NVidia GPU Temperature";
441
442         if ((type & SENSOR_TYPE_AMD_TEMP) == SENSOR_TYPE_AMD_TEMP)
443                 return "AMD GPU Temperature";
444
445         if ((type & SENSOR_TYPE_AMD_FAN) == SENSOR_TYPE_AMD_FAN)
446                 return "AMD GPU Fan Speed";
447
448         if ((type & SENSOR_TYPE_HDD_TEMP) == SENSOR_TYPE_HDD_TEMP)
449                 return "HDD Temperature";
450
451         if (type & SENSOR_TYPE_CPU_USAGE)
452                 return "CPU Usage";
453
454         if (type & SENSOR_TYPE_TEMP)
455                 return "Temperature";
456
457         if (type & SENSOR_TYPE_FAN)
458                 return "Fan";
459
460         if (type & SENSOR_TYPE_REMOTE)
461                 return "Remote";
462
463         return "N/A";           /* should not be possible */
464 }
465
466
467 const char *psensor_type_to_unit_str(unsigned int type, int use_celcius)
468 {
469         if (is_temp_type(type)) {
470                 if (use_celcius)
471                         return "\302\260C";
472                 else
473                         return "\302\260F";
474         } else if (is_fan_type(type)) {
475                 return _("RPM");
476         } else if (type & SENSOR_TYPE_CPU_USAGE) {
477                 return _("%");
478         } else {
479                 return _("N/A");
480         }
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 }