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