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