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