avoid config in the psensor struct
[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_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
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         struct psensor **result;
163
164         size = psensor_list_size(sensors);
165
166         result = 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 (v > s->alarm_high_threshold || v < s->alarm_low_threshold) {
268                 if (!s->alarm_raised && s->cb_alarm_raised) {
269                         s->alarm_raised = true;
270                         s->cb_alarm_raised(s, s->cb_alarm_raised_data);
271                 }
272         } else {
273                 s->alarm_raised = false;
274         }
275 }
276
277 double psensor_get_current_value(const struct psensor *sensor)
278 {
279         return sensor->measures[sensor->values_max_length - 1].value;
280 }
281
282 struct measure *psensor_get_current_measure(struct psensor *sensor)
283 {
284         return &sensor->measures[sensor->values_max_length - 1];
285 }
286
287 /*
288   Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or
289   SENSOR_TYPE_FAN)
290  */
291 static double get_min_value(struct psensor **sensors, int type)
292 {
293         double m = UNKNOWN_DBL_VALUE;
294         struct psensor **s = sensors;
295
296         while (*s) {
297                 struct psensor *sensor = *s;
298
299                 if (sensor->type & type) {
300                         int i;
301                         double t;
302
303                         for (i = 0; i < sensor->values_max_length; i++) {
304                                 t = sensor->measures[i].value;
305
306                                 if (t == UNKNOWN_DBL_VALUE)
307                                         continue;
308
309                                 if (m == UNKNOWN_DBL_VALUE || t < m)
310                                         m = t;
311                         }
312                 }
313                 s++;
314         }
315
316         return m;
317 }
318
319 /*
320   Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or
321   SENSOR_TYPE_FAN)
322  */
323 double get_max_value(struct psensor **sensors, int type)
324 {
325         double m = UNKNOWN_DBL_VALUE;
326         struct psensor **s = sensors;
327
328         while (*s) {
329                 struct psensor *sensor = *s;
330
331                 if (sensor->type & type) {
332                         int i;
333                         double t;
334
335                         for (i = 0; i < sensor->values_max_length; i++) {
336                                 t = sensor->measures[i].value;
337
338                                 if (t == UNKNOWN_DBL_VALUE)
339                                         continue;
340
341                                 if (m == UNKNOWN_DBL_VALUE || t > m)
342                                         m = t;
343                         }
344                 }
345                 s++;
346         }
347
348         return m;
349 }
350
351 double
352 psensor_get_max_current_value(struct psensor **sensors, unsigned int type)
353 {
354         double m = UNKNOWN_DBL_VALUE;
355         struct psensor **s_cur = sensors;
356
357         while (*s_cur) {
358                 struct psensor *s = *s_cur;
359
360                 if (s->graph_enabled && (s->type & type)) {
361                         double v = psensor_get_current_value(s);
362
363                         if (m == UNKNOWN_DBL_VALUE || v > m)
364                                 m = v;
365                 }
366
367                 s_cur++;
368         }
369
370         return m;
371 }
372
373 double get_min_temp(struct psensor **sensors)
374 {
375         return get_min_value(sensors, SENSOR_TYPE_TEMP);
376 }
377
378 double get_min_rpm(struct psensor **sensors)
379 {
380         return get_min_value(sensors, SENSOR_TYPE_FAN);
381 }
382
383 double get_max_rpm(struct psensor **sensors)
384 {
385         return get_max_value(sensors, SENSOR_TYPE_FAN);
386 }
387
388 double get_max_temp(struct psensor **sensors)
389 {
390         return get_max_value(sensors, SENSOR_TYPE_TEMP);
391 }
392
393 const char *psensor_type_to_str(unsigned int type)
394 {
395         if (type & SENSOR_TYPE_NVCTRL) {
396                 if (type & SENSOR_TYPE_TEMP)
397                         return "Temperature";
398                 else if (type & SENSOR_TYPE_GRAPHICS)
399                         return "Graphics usage";
400                 else if (type & SENSOR_TYPE_VIDEO)
401                         return "Video usage";
402                 else if (type & SENSOR_TYPE_MEMORY)
403                         return "Memory usage";
404                 else if (type & SENSOR_TYPE_PCIE)
405                         return "PCIe usage";
406
407                 return "NVIDIA GPU";
408         }
409
410         if (type & SENSOR_TYPE_ATIADL) {
411                 if (type & SENSOR_TYPE_TEMP)
412                         return "AMD GPU Temperature";
413                 else if (type & SENSOR_TYPE_RPM)
414                         return "AMD GPU Fan Speed";
415                 /*else type & SENSOR_TYPE_USAGE */
416                 return "AMD GPU Usage";
417         }
418
419         if ((type & SENSOR_TYPE_HDD_TEMP) == SENSOR_TYPE_HDD_TEMP)
420                 return "HDD Temperature";
421
422         if ((type & SENSOR_TYPE_CPU_USAGE) == SENSOR_TYPE_CPU_USAGE)
423                 return "CPU Usage";
424
425         if (type & SENSOR_TYPE_TEMP)
426                 return "Temperature";
427
428         if (type & SENSOR_TYPE_RPM)
429                 return "Fan";
430
431         if (type & SENSOR_TYPE_CPU)
432                 return "CPU";
433
434         if (type & SENSOR_TYPE_REMOTE)
435                 return "Remote";
436
437         if (type & SENSOR_TYPE_MEMORY)
438                 return "Memory";
439
440         return "N/A";
441 }
442
443
444 const char *psensor_type_to_unit_str(unsigned int type, int use_celsius)
445 {
446         if (is_temp_type(type)) {
447                 if (use_celsius)
448                         return "\302\260C";
449                 return "\302\260F";
450         } else if (type & SENSOR_TYPE_RPM) {
451                 return _("RPM");
452         } else if (type & SENSOR_TYPE_PERCENT) {
453                 return _("%");
454         }
455         return _("N/A");
456 }
457
458 void psensor_log_measures(struct psensor **sensors)
459 {
460         if (log_level == LOG_DEBUG)
461                 while (*sensors) {
462                         log_debug("Measure: %s %.2f",
463                                    (*sensors)->name,
464                                    psensor_get_current_value(*sensors));
465
466                         sensors++;
467                 }
468 }
469
470 struct psensor **psensor_list_copy(struct psensor **sensors)
471 {
472         struct psensor **result;
473         int n, i;
474
475         n = psensor_list_size(sensors);
476         result = malloc((n+1) * sizeof(struct psensor *));
477         for (i = 0; i < n; i++)
478                 result[i] = sensors[i];
479         result[n] = NULL;
480
481         return result;
482 }
483
484 char *
485 psensor_current_value_to_str(const struct psensor *s, unsigned int use_celsius)
486 {
487         return psensor_value_to_str(s->type,
488                                     psensor_get_current_value(s),
489                                     use_celsius);
490 }
491
492 struct psensor **psensor_list_filter_graph_enabled(struct psensor **sensors)
493 {
494         int n, i;
495         struct psensor **result, **cur, *s;
496
497         if (!sensors)
498                 return NULL;
499
500         n = psensor_list_size(sensors);
501         result = malloc((n+1) * sizeof(struct psensor *));
502
503         for (cur = sensors, i = 0; *cur; cur++) {
504                 s = *cur;
505
506                 if (s->graph_enabled)
507                         result[i++] = s;
508         }
509
510         result[i] = NULL;
511
512         return result;
513 }