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