added support of cpu usage monitoring
[psensor.git] / src / lib / psensor.c
1 /*
2     Copyright (C) 2010-2011 jeanfi@gmail.com
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU 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
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <locale.h>
24 #include <libintl.h>
25 #define _(str) gettext(str)
26
27 #include "hdd.h"
28 #include "psensor.h"
29 #include "lmsensor.h"
30
31 #ifdef HAVE_GTOP
32 #include "cpu.h"
33 #endif
34
35
36 struct psensor *psensor_create(char *id, char *name,
37                                unsigned int type, int values_max_length)
38 {
39         struct psensor *psensor
40             = (struct psensor *)malloc(sizeof(struct psensor));
41
42         psensor->id = id;
43         psensor->name = name;
44         psensor->enabled = 1;
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_limit = 0;
54
55         psensor->cb_alarm_raised = NULL;
56         psensor->cb_alarm_raised_data = NULL;
57         psensor->alarm_raised = 0;
58
59         psensor->alarm_enabled = 0;
60
61         psensor->url = NULL;
62
63         psensor->color = NULL;
64
65         return psensor;
66 }
67
68 void psensor_values_resize(struct psensor *s, int new_size)
69 {
70         struct measure *new_ms, *cur_ms;
71         int cur_size;
72
73         cur_size = s->values_max_length;
74         cur_ms = s->measures;
75         new_ms = measures_dbl_create(new_size);
76
77         if (cur_ms) {
78                 int i;
79                 for (i = 0; i < new_size - 1 && i < cur_size - 1; i++)
80                         measure_copy(&cur_ms[cur_size - i - 1],
81                                      &new_ms[new_size - i - 1]);
82
83                 measures_free(s->measures);
84         }
85
86         s->values_max_length = new_size;
87         s->measures = new_ms;
88 }
89
90 void psensor_free(struct psensor *sensor)
91 {
92         if (sensor) {
93                 free(sensor->name);
94                 free(sensor->id);
95
96                 if (sensor->color)
97                         free(sensor->color);
98
99                 measures_free(sensor->measures);
100
101                 free(sensor->url);
102
103                 free(sensor);
104         }
105 }
106
107 void psensor_list_free(struct psensor **sensors)
108 {
109         struct psensor **sensor_cur;
110
111         if (sensors) {
112                 sensor_cur = sensors;
113
114                 while (*sensor_cur) {
115                         psensor_free(*sensor_cur);
116
117                         sensor_cur++;
118                 }
119
120                 free(sensors);
121
122                 sensors = NULL;
123         }
124 }
125
126 int psensor_list_size(struct psensor **sensors)
127 {
128         int size;
129         struct psensor **sensor_cur;
130
131         if (!sensors)
132                 return 0;
133
134         size = 0;
135         sensor_cur = sensors;
136
137         while (*sensor_cur) {
138                 size++;
139                 sensor_cur++;
140         }
141         return size;
142 }
143
144 int psensor_list_contains_type(struct psensor **sensors, unsigned int type)
145 {
146         struct psensor **s;
147
148         if (!sensors)
149                 return 0;
150
151         s = sensors;
152         while (*s) {
153                 if ((*s)->type == type)
154                         return 1;
155                 s++;
156         }
157
158         return 0;
159 }
160
161 struct psensor **psensor_list_add(struct psensor **sensors,
162                                   struct psensor *sensor)
163 {
164         int size = psensor_list_size(sensors);
165
166         struct psensor **result
167             = 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 struct psensor *psensor_list_get_by_id(struct psensor **sensors, const char *id)
179 {
180         struct psensor **sensors_cur = sensors;
181
182         while (*sensors_cur) {
183                 if (!strcmp((*sensors_cur)->id, id))
184                         return *sensors_cur;
185
186                 sensors_cur++;
187         }
188
189         return NULL;
190 }
191
192 int is_temp_type(unsigned int type)
193 {
194         return type & SENSOR_TYPE_TEMP;
195 }
196
197 int is_fan_type(unsigned int type)
198 {
199         return type & SENSOR_TYPE_FAN;
200 }
201
202 char *psensor_value_to_string(unsigned int type, double value)
203 {
204         /* should not be possible to exceed 20 characters with temp or
205            rpm values the .x part is never displayed */
206         char *str = malloc(20);
207
208         char *unit;
209
210         if (is_temp_type(type))
211                 unit = "C";
212         else if (type & SENSOR_TYPE_CPU_USAGE)
213                 unit = "%";
214         else
215                 unit = "";
216
217         sprintf(str, "%.0f%s", value, unit);
218
219         return str;
220 }
221
222 void psensor_set_current_value(struct psensor *sensor, double value)
223 {
224         struct timeval tv;
225
226         if (gettimeofday(&tv, NULL) != 0)
227                 timerclear(&tv);
228
229         psensor_set_current_measure(sensor, value, tv);
230 }
231
232 void
233 psensor_set_current_measure(struct psensor *s,
234                             double v, struct timeval tv)
235 {
236         memmove(s->measures,
237                 &s->measures[1],
238                 (s->values_max_length - 1) * sizeof(struct measure));
239
240         s->measures[s->values_max_length - 1].value.d_num = v;
241         s->measures[s->values_max_length - 1].time = tv;
242
243         if (s->min == UNKNOWN_DBL_VALUE || v < s->min)
244                 s->min = v;
245
246         if (s->max == UNKNOWN_DBL_VALUE || v > s->max)
247                 s->max = v;
248
249         if (s->alarm_limit && s->alarm_enabled) {
250                 if (v > s->alarm_limit) {
251                         if (!s->alarm_raised && s->cb_alarm_raised)
252                                 s->cb_alarm_raised(s,
253                                                    s->cb_alarm_raised_data);
254
255                         s->alarm_raised = 1;
256                 } else {
257                         s->alarm_raised = 0;
258                 }
259         }
260 }
261
262 double psensor_get_current_value(struct psensor *sensor)
263 {
264         return sensor->measures[sensor->values_max_length - 1].value.d_num;
265 }
266
267 struct measure *psensor_get_current_measure(struct psensor *sensor)
268 {
269         return &sensor->measures[sensor->values_max_length - 1];
270 }
271
272 /*
273   Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or
274   SENSOR_TYPE_FAN)
275  */
276 double get_min_value(struct psensor **sensors, int type)
277 {
278         double m = UNKNOWN_DBL_VALUE;
279         struct psensor **s = sensors;
280
281         while (*s) {
282                 struct psensor *sensor = *s;
283
284                 if (sensor->enabled && (sensor->type & type)) {
285                         int i;
286                         double t;
287
288                         for (i = 0; i < sensor->values_max_length; i++) {
289                                 t = sensor->measures[i].value.d_num;
290
291                                 if (t == UNKNOWN_DBL_VALUE)
292                                         continue;
293
294                                 if (m == UNKNOWN_DBL_VALUE || t < m)
295                                         m = t;
296                         }
297                 }
298                 s++;
299         }
300
301         return m;
302 }
303
304 /*
305   Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or
306   SENSOR_TYPE_FAN)
307  */
308 double get_max_value(struct psensor **sensors, int type)
309 {
310         double m = UNKNOWN_DBL_VALUE;
311         struct psensor **s = sensors;
312
313         while (*s) {
314                 struct psensor *sensor = *s;
315
316                 if (sensor->enabled && (sensor->type & type)) {
317                         int i;
318                         double t;
319                         for (i = 0; i < sensor->values_max_length; i++) {
320                                 t = sensor->measures[i].value.d_num;
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 double
336 psensor_get_max_current_value(struct psensor **sensors, unsigned int type)
337 {
338         double m = UNKNOWN_DBL_VALUE;
339         struct psensor **s_cur = sensors;
340
341         while (*s_cur) {
342                 struct psensor *s = *s_cur;
343
344                 if (s->enabled && (s->type & type)) {
345                         double v = psensor_get_current_value(s);
346
347                         if (m == UNKNOWN_DBL_VALUE || v > m)
348                                 m = v;
349                 }
350
351                 s_cur++;
352         }
353
354         return m;
355 }
356
357 double get_min_temp(struct psensor **sensors)
358 {
359         return get_min_value(sensors, SENSOR_TYPE_TEMP);
360 }
361
362 double get_min_rpm(struct psensor **sensors)
363 {
364         return get_min_value(sensors, SENSOR_TYPE_FAN);
365 }
366
367 double get_max_rpm(struct psensor **sensors)
368 {
369         return get_max_value(sensors, SENSOR_TYPE_FAN);
370 }
371
372 double get_max_temp(struct psensor **sensors)
373 {
374         return get_max_value(sensors, SENSOR_TYPE_TEMP);
375 }
376
377 struct psensor **get_all_sensors(int values_max_length)
378 {
379         struct psensor **psensors = NULL;
380         struct psensor **tmp_psensors;
381
382         psensors = lmsensor_psensor_list_add(NULL, values_max_length);
383
384         tmp_psensors = hdd_psensor_list_add(psensors, values_max_length);
385         if (tmp_psensors != psensors) {
386                 free(psensors);
387                 psensors = tmp_psensors;
388         }
389
390         if (!psensors) {        /* there is no detected sensors */
391                 psensors = malloc(sizeof(struct psensor *));
392                 *psensors = NULL;
393         }
394
395         return psensors;
396 }
397
398 const char *psensor_type_to_str(unsigned int type)
399 {
400         if (type & SENSOR_TYPE_REMOTE)
401                 return "Remote";
402
403         if (type & SENSOR_TYPE_LMSENSOR_TEMP)
404                 return "Temperature";
405
406         if (type & SENSOR_TYPE_LMSENSOR_FAN)
407                 return "Fan";
408
409         if (type & SENSOR_TYPE_NVIDIA_TEMP)
410                 return "NVidia GPU Temperature";
411
412         if (type & SENSOR_TYPE_AMD_TEMP)
413                 return "AMD GPU Temperature";
414
415         if (type & SENSOR_TYPE_AMD_FAN)
416                 return "AMD GPU Fan Speed";
417
418         if (type & SENSOR_TYPE_HDD_TEMP)
419                 return "HDD Temperature";
420
421         if (type & SENSOR_TYPE_CPU_USAGE)
422                 return "CPU Usage";
423
424         return "N/A";           /* should not be possible */
425 }
426
427
428 const char *psensor_type_to_unit_str(unsigned int type)
429 {
430         if (type & SENSOR_TYPE_TEMP)
431                 return _("C");
432
433         if (type & SENSOR_TYPE_FAN)
434                 return _("RPM");
435
436         if (type & SENSOR_TYPE_CPU_USAGE)
437                 return _("%");
438
439         return "N/A";
440 }
441
442 void psensor_list_update_measures(struct psensor **sensors)
443 {
444         lmsensor_psensor_list_update(sensors);
445
446 #ifdef HAVE_GTOP
447         cpu_psensor_list_update(sensors);
448 #endif
449
450         if (psensor_list_contains_type(sensors, SENSOR_TYPE_HDD_TEMP))
451                 hdd_psensor_list_update(sensors);
452 }
453
454 void psensor_init()
455 {
456         lmsensor_init();
457 }
458
459 void psensor_cleanup()
460 {
461         lmsensor_cleanup();
462 }