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