switched to 3.9.7 defaults
[psensor-pkg-ubuntu.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 struct psensor **psensor_list_add(struct psensor **sensors,
159                                   struct psensor *sensor)
160 {
161         int size;
162
163         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 void psensor_list_append(struct psensor ***sensors, struct psensor *sensor)
178 {
179         struct psensor **tmp;
180
181         if (!sensor)
182                 return;
183
184         tmp = psensor_list_add(*sensors, sensor);
185
186         if (tmp != *sensors) {
187                 free(*sensors);
188                 *sensors = tmp;
189         }
190 }
191
192
193 struct psensor *psensor_list_get_by_id(struct psensor **sensors, const char *id)
194 {
195         struct psensor **sensors_cur = sensors;
196
197         while (*sensors_cur) {
198                 if (!strcmp((*sensors_cur)->id, id))
199                         return *sensors_cur;
200
201                 sensors_cur++;
202         }
203
204         return NULL;
205 }
206
207 int is_temp_type(unsigned int type)
208 {
209         return type & SENSOR_TYPE_TEMP;
210 }
211
212 char *
213 psensor_value_to_str(unsigned int type, double value, int use_celsius)
214 {
215         char *str;
216         const char *unit;
217
218         /*
219          * should not be possible to exceed 20 characters with temp or
220          * rpm values the .x part is never displayed
221          */
222         str = malloc(20);
223
224         unit = psensor_type_to_unit_str(type, use_celsius);
225
226         if (is_temp_type(type) && !use_celsius)
227                 value = celsius_to_fahrenheit(value);
228
229         sprintf(str, "%.0f%s", value, unit);
230
231         return str;
232 }
233
234 char *
235 psensor_measure_to_str(const struct measure *m,
236                        unsigned int type,
237                        unsigned int use_celsius)
238 {
239         return psensor_value_to_str(type, m->value, use_celsius);
240 }
241
242 void psensor_set_current_value(struct psensor *sensor, double value)
243 {
244         struct timeval tv;
245
246         if (gettimeofday(&tv, NULL) != 0)
247                 timerclear(&tv);
248
249         psensor_set_current_measure(sensor, value, tv);
250 }
251
252 void psensor_set_current_measure(struct psensor *s, double v, struct timeval tv)
253 {
254         memmove(s->measures,
255                 &s->measures[1],
256                 (s->values_max_length - 1) * sizeof(struct measure));
257
258         s->measures[s->values_max_length - 1].value = v;
259         s->measures[s->values_max_length - 1].time = tv;
260
261         if (s->min == UNKNOWN_DBL_VALUE || v < s->min)
262                 s->min = v;
263
264         if (s->max == UNKNOWN_DBL_VALUE || v > s->max)
265                 s->max = v;
266
267         if (s->alarm_enabled) {
268                 if (v > s->alarm_high_threshold || v < s->alarm_low_threshold) {
269                         if (!s->alarm_raised && s->cb_alarm_raised)
270                                 s->cb_alarm_raised(s, s->cb_alarm_raised_data);
271
272                         s->alarm_raised = 1;
273                 } else {
274                         s->alarm_raised = 0;
275                 }
276         }
277 }
278
279 double psensor_get_current_value(const struct psensor *sensor)
280 {
281         return sensor->measures[sensor->values_max_length - 1].value;
282 }
283
284 struct measure *psensor_get_current_measure(struct psensor *sensor)
285 {
286         return &sensor->measures[sensor->values_max_length - 1];
287 }
288
289 /*
290   Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or
291   SENSOR_TYPE_FAN)
292  */
293 static double get_min_value(struct psensor **sensors, int type)
294 {
295         double m = UNKNOWN_DBL_VALUE;
296         struct psensor **s = sensors;
297
298         while (*s) {
299                 struct psensor *sensor = *s;
300
301                 if (sensor->type & type) {
302                         int i;
303                         double t;
304
305                         for (i = 0; i < sensor->values_max_length; i++) {
306                                 t = sensor->measures[i].value;
307
308                                 if (t == UNKNOWN_DBL_VALUE)
309                                         continue;
310
311                                 if (m == UNKNOWN_DBL_VALUE || t < m)
312                                         m = t;
313                         }
314                 }
315                 s++;
316         }
317
318         return m;
319 }
320
321 /*
322   Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or
323   SENSOR_TYPE_FAN)
324  */
325 double get_max_value(struct psensor **sensors, int type)
326 {
327         double m = UNKNOWN_DBL_VALUE;
328         struct psensor **s = sensors;
329
330         while (*s) {
331                 struct psensor *sensor = *s;
332
333                 if (sensor->type & type) {
334                         int i;
335                         double t;
336
337                         for (i = 0; i < sensor->values_max_length; i++) {
338                                 t = sensor->measures[i].value;
339
340                                 if (t == UNKNOWN_DBL_VALUE)
341                                         continue;
342
343                                 if (m == UNKNOWN_DBL_VALUE || t > m)
344                                         m = t;
345                         }
346                 }
347                 s++;
348         }
349
350         return m;
351 }
352
353 double
354 psensor_get_max_current_value(struct psensor **sensors, unsigned int type)
355 {
356         double m = UNKNOWN_DBL_VALUE;
357         struct psensor **s_cur = sensors;
358
359         while (*s_cur) {
360                 struct psensor *s = *s_cur;
361
362                 if (s->graph_enabled && (s->type & type)) {
363                         double v = psensor_get_current_value(s);
364
365                         if (m == UNKNOWN_DBL_VALUE || v > m)
366                                 m = v;
367                 }
368
369                 s_cur++;
370         }
371
372         return m;
373 }
374
375 double get_min_temp(struct psensor **sensors)
376 {
377         return get_min_value(sensors, SENSOR_TYPE_TEMP);
378 }
379
380 double get_min_rpm(struct psensor **sensors)
381 {
382         return get_min_value(sensors, SENSOR_TYPE_FAN);
383 }
384
385 double get_max_rpm(struct psensor **sensors)
386 {
387         return get_max_value(sensors, SENSOR_TYPE_FAN);
388 }
389
390 double get_max_temp(struct psensor **sensors)
391 {
392         return get_max_value(sensors, SENSOR_TYPE_TEMP);
393 }
394
395 const char *psensor_type_to_str(unsigned int type)
396 {
397         if (type & SENSOR_TYPE_NVCTRL) {
398                 if (type & SENSOR_TYPE_TEMP)
399                         return "Temperature";
400                 else if (type & SENSOR_TYPE_GRAPHICS)
401                         return "Graphics usage";
402                 else if (type & SENSOR_TYPE_VIDEO)
403                         return "Video usage";
404                 else if (type & SENSOR_TYPE_MEMORY)
405                         return "Memory usage";
406                 else if (type & SENSOR_TYPE_PCIE)
407                         return "PCIe usage";
408
409                 return "NVIDIA GPU";
410         }
411
412         if (type & SENSOR_TYPE_ATIADL) {
413                 if (type & SENSOR_TYPE_TEMP)
414                         return "AMD GPU Temperature";
415                 else if (type & SENSOR_TYPE_RPM)
416                         return "AMD GPU Fan Speed";
417                 /*else type & SENSOR_TYPE_USAGE */
418                 return "AMD GPU Usage";
419         }
420
421         if ((type & SENSOR_TYPE_HDD_TEMP) == SENSOR_TYPE_HDD_TEMP)
422                 return "HDD Temperature";
423
424         if ((type & SENSOR_TYPE_CPU_USAGE) == SENSOR_TYPE_CPU_USAGE)
425                 return "CPU Usage";
426
427         if (type & SENSOR_TYPE_TEMP)
428                 return "Temperature";
429
430         if (type & SENSOR_TYPE_RPM)
431                 return "Fan";
432
433         if (type & SENSOR_TYPE_CPU)
434                 return "CPU";
435
436         if (type & SENSOR_TYPE_REMOTE)
437                 return "Remote";
438
439         if (type & SENSOR_TYPE_MEMORY)
440                 return "Memory";
441
442         return "N/A";
443 }
444
445
446 const char *psensor_type_to_unit_str(unsigned int type, int use_celsius)
447 {
448         if (is_temp_type(type)) {
449                 if (use_celsius)
450                         return "\302\260C";
451                 return "\302\260F";
452         } else if (type & SENSOR_TYPE_RPM) {
453                 return _("RPM");
454         } else if (type & SENSOR_TYPE_PERCENT) {
455                 return _("%");
456         }
457         return _("N/A");
458 }
459
460 void psensor_log_measures(struct psensor **sensors)
461 {
462         if (log_level == LOG_DEBUG)
463                 while (*sensors) {
464                         log_debug("Measure: %s %.2f",
465                                    (*sensors)->name,
466                                    psensor_get_current_value(*sensors));
467
468                         sensors++;
469                 }
470 }
471
472 struct psensor **psensor_list_copy(struct psensor **sensors)
473 {
474         struct psensor **result;
475         int n, i;
476
477         n = psensor_list_size(sensors);
478         result = malloc((n+1) * sizeof(struct psensor *));
479         for (i = 0; i < n; i++)
480                 result[i] = sensors[i];
481         result[n] = NULL;
482
483         return result;
484 }
485
486 char *
487 psensor_current_value_to_str(const struct psensor *s, unsigned int use_celsius)
488 {
489         return psensor_value_to_str(s->type,
490                                     psensor_get_current_value(s),
491                                     use_celsius);
492 }
493
494 struct psensor **psensor_list_filter_graph_enabled(struct psensor **sensors)
495 {
496         int n, i;
497         struct psensor **result, **cur, *s;
498
499         if (!sensors)
500                 return NULL;
501
502         n = psensor_list_size(sensors);
503         result = malloc((n+1) * sizeof(struct psensor *));
504
505         for (cur = sensors, i = 0; *cur; cur++) {
506                 s = *cur;
507
508                 if (s->graph_enabled)
509                         result[i++] = s;
510         }
511
512         result[i] = NULL;
513
514         return result;
515 }