d151ac1dfd86d5c88d92944e30957c723aa3495d
[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->provider_data = NULL;
65         psensor->provider_data_free_fct = &free;
66
67         return psensor;
68 }
69
70 void psensor_values_resize(struct psensor *s, int new_size)
71 {
72         struct measure *new_ms, *cur_ms;
73         int cur_size;
74
75         cur_size = s->values_max_length;
76         cur_ms = s->measures;
77         new_ms = measures_dbl_create(new_size);
78
79         if (cur_ms) {
80                 int i;
81
82                 for (i = 0; i < new_size - 1 && i < cur_size - 1; i++)
83                         measure_copy(&cur_ms[cur_size - i - 1],
84                                      &new_ms[new_size - i - 1]);
85
86                 measures_free(s->measures);
87         }
88
89         s->values_max_length = new_size;
90         s->measures = new_ms;
91 }
92
93 void psensor_free(struct psensor *s)
94 {
95         if (!s)
96                 return;
97
98         log_debug("Cleanup %s", s->id);
99
100         free(s->name);
101         free(s->id);
102
103         if (s->chip)
104                 free(s->chip);
105
106         if (s->color)
107                 free(s->color);
108
109         measures_free(s->measures);
110
111         free(s->url);
112
113         if (s->provider_data && s->provider_data_free_fct)
114                 s->provider_data_free_fct(s->provider_data);
115
116         free(s);
117 }
118
119 void psensor_list_free(struct psensor **sensors)
120 {
121         struct psensor **sensor_cur;
122
123         if (sensors) {
124                 sensor_cur = sensors;
125
126                 while (*sensor_cur) {
127                         psensor_free(*sensor_cur);
128
129                         sensor_cur++;
130                 }
131
132                 free(sensors);
133
134                 sensors = NULL;
135         }
136 }
137
138 int psensor_list_size(struct psensor **sensors)
139 {
140         int size;
141         struct psensor **sensor_cur;
142
143         if (!sensors)
144                 return 0;
145
146         size = 0;
147         sensor_cur = sensors;
148
149         while (*sensor_cur) {
150                 size++;
151                 sensor_cur++;
152         }
153         return size;
154 }
155
156 struct psensor **psensor_list_add(struct psensor **sensors,
157                                   struct psensor *sensor)
158 {
159         int size;
160         struct psensor **result;
161
162         size = psensor_list_size(sensors);
163
164         result = malloc((size + 1 + 1) * sizeof(struct psensor *));
165
166         if (sensors)
167                 memcpy(result, sensors, size * sizeof(struct psensor *));
168
169         result[size] = sensor;
170         result[size + 1] = NULL;
171
172         return result;
173 }
174
175 void psensor_list_append(struct psensor ***sensors, struct psensor *sensor)
176 {
177         struct psensor **tmp;
178
179         if (!sensor)
180                 return;
181
182         tmp = psensor_list_add(*sensors, sensor);
183
184         if (tmp != *sensors) {
185                 free(*sensors);
186                 *sensors = tmp;
187         }
188 }
189
190
191 struct psensor *psensor_list_get_by_id(struct psensor **sensors, const char *id)
192 {
193         struct psensor **sensors_cur = sensors;
194
195         while (*sensors_cur) {
196                 if (!strcmp((*sensors_cur)->id, id))
197                         return *sensors_cur;
198
199                 sensors_cur++;
200         }
201
202         return NULL;
203 }
204
205 int is_temp_type(unsigned int type)
206 {
207         return type & SENSOR_TYPE_TEMP;
208 }
209
210 char *
211 psensor_value_to_str(unsigned int type, double value, int use_celsius)
212 {
213         char *str;
214         const char *unit;
215
216         /*
217          * should not be possible to exceed 20 characters with temp or
218          * rpm values the .x part is never displayed
219          */
220         str = malloc(20);
221
222         unit = psensor_type_to_unit_str(type, use_celsius);
223
224         if (is_temp_type(type) && !use_celsius)
225                 value = celsius_to_fahrenheit(value);
226
227         sprintf(str, "%.0f%s", value, unit);
228
229         return str;
230 }
231
232 char *
233 psensor_measure_to_str(const struct measure *m,
234                        unsigned int type,
235                        unsigned int use_celsius)
236 {
237         return psensor_value_to_str(type, m->value, use_celsius);
238 }
239
240 void psensor_set_current_value(struct psensor *sensor, double value)
241 {
242         struct timeval tv;
243
244         if (gettimeofday(&tv, NULL) != 0)
245                 timerclear(&tv);
246
247         psensor_set_current_measure(sensor, value, tv);
248 }
249
250 void psensor_set_current_measure(struct psensor *s, double v, struct timeval tv)
251 {
252         memmove(s->measures,
253                 &s->measures[1],
254                 (s->values_max_length - 1) * sizeof(struct measure));
255
256         s->measures[s->values_max_length - 1].value = v;
257         s->measures[s->values_max_length - 1].time = tv;
258
259         if (s->min == UNKNOWN_DBL_VALUE || v < s->min)
260                 s->min = v;
261
262         if (s->max == UNKNOWN_DBL_VALUE || v > s->max)
263                 s->max = v;
264
265         if (v > s->alarm_high_threshold || v < s->alarm_low_threshold) {
266                 if (!s->alarm_raised && s->cb_alarm_raised) {
267                         s->alarm_raised = true;
268                         s->cb_alarm_raised(s, s->cb_alarm_raised_data);
269                 }
270         } else {
271                 s->alarm_raised = false;
272         }
273 }
274
275 double psensor_get_current_value(const struct psensor *sensor)
276 {
277         return sensor->measures[sensor->values_max_length - 1].value;
278 }
279
280 struct measure *psensor_get_current_measure(struct psensor *sensor)
281 {
282         return &sensor->measures[sensor->values_max_length - 1];
283 }
284
285 /*
286   Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or
287   SENSOR_TYPE_FAN)
288  */
289 static double get_min_value(struct psensor **sensors, int type)
290 {
291         double m = UNKNOWN_DBL_VALUE;
292         struct psensor **s = sensors;
293
294         while (*s) {
295                 struct psensor *sensor = *s;
296
297                 if (sensor->type & type) {
298                         int i;
299                         double t;
300
301                         for (i = 0; i < sensor->values_max_length; i++) {
302                                 t = sensor->measures[i].value;
303
304                                 if (t == UNKNOWN_DBL_VALUE)
305                                         continue;
306
307                                 if (m == UNKNOWN_DBL_VALUE || t < m)
308                                         m = t;
309                         }
310                 }
311                 s++;
312         }
313
314         return m;
315 }
316
317 /*
318   Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or
319   SENSOR_TYPE_FAN)
320  */
321 double get_max_value(struct psensor **sensors, int type)
322 {
323         double m = UNKNOWN_DBL_VALUE;
324         struct psensor **s = sensors;
325
326         while (*s) {
327                 struct psensor *sensor = *s;
328
329                 if (sensor->type & type) {
330                         int i;
331                         double t;
332
333                         for (i = 0; i < sensor->values_max_length; i++) {
334                                 t = sensor->measures[i].value;
335
336                                 if (t == UNKNOWN_DBL_VALUE)
337                                         continue;
338
339                                 if (m == UNKNOWN_DBL_VALUE || t > m)
340                                         m = t;
341                         }
342                 }
343                 s++;
344         }
345
346         return m;
347 }
348
349 double get_min_temp(struct psensor **sensors)
350 {
351         return get_min_value(sensors, SENSOR_TYPE_TEMP);
352 }
353
354 double get_min_rpm(struct psensor **sensors)
355 {
356         return get_min_value(sensors, SENSOR_TYPE_FAN);
357 }
358
359 double get_max_rpm(struct psensor **sensors)
360 {
361         return get_max_value(sensors, SENSOR_TYPE_FAN);
362 }
363
364 double get_max_temp(struct psensor **sensors)
365 {
366         return get_max_value(sensors, SENSOR_TYPE_TEMP);
367 }
368
369 const char *psensor_type_to_str(unsigned int type)
370 {
371         if (type & SENSOR_TYPE_NVCTRL) {
372                 if (type & SENSOR_TYPE_TEMP)
373                         return "Temperature";
374                 else if (type & SENSOR_TYPE_GRAPHICS)
375                         return "Graphics usage";
376                 else if (type & SENSOR_TYPE_VIDEO)
377                         return "Video usage";
378                 else if (type & SENSOR_TYPE_MEMORY)
379                         return "Memory usage";
380                 else if (type & SENSOR_TYPE_PCIE)
381                         return "PCIe usage";
382
383                 return "NVIDIA GPU";
384         }
385
386         if (type & SENSOR_TYPE_ATIADL) {
387                 if (type & SENSOR_TYPE_TEMP)
388                         return "AMD GPU Temperature";
389                 else if (type & SENSOR_TYPE_RPM)
390                         return "AMD GPU Fan Speed";
391                 /*else type & SENSOR_TYPE_USAGE */
392                 return "AMD GPU Usage";
393         }
394
395         if ((type & SENSOR_TYPE_HDD_TEMP) == SENSOR_TYPE_HDD_TEMP)
396                 return "HDD Temperature";
397
398         if ((type & SENSOR_TYPE_CPU_USAGE) == SENSOR_TYPE_CPU_USAGE)
399                 return "CPU Usage";
400
401         if (type & SENSOR_TYPE_TEMP)
402                 return "Temperature";
403
404         if (type & SENSOR_TYPE_RPM)
405                 return "Fan";
406
407         if (type & SENSOR_TYPE_CPU)
408                 return "CPU";
409
410         if (type & SENSOR_TYPE_REMOTE)
411                 return "Remote";
412
413         if (type & SENSOR_TYPE_MEMORY)
414                 return "Memory";
415
416         return "N/A";
417 }
418
419
420 const char *psensor_type_to_unit_str(unsigned int type, int use_celsius)
421 {
422         if (is_temp_type(type)) {
423                 if (use_celsius)
424                         return "\302\260C";
425                 return "\302\260F";
426         } else if (type & SENSOR_TYPE_RPM) {
427                 return _("RPM");
428         } else if (type & SENSOR_TYPE_PERCENT) {
429                 return _("%");
430         }
431         return _("N/A");
432 }
433
434 void psensor_log_measures(struct psensor **sensors)
435 {
436         if (log_level == LOG_DEBUG)
437                 while (*sensors) {
438                         log_debug("Measure: %s %.2f",
439                                    (*sensors)->name,
440                                    psensor_get_current_value(*sensors));
441
442                         sensors++;
443                 }
444 }
445
446 struct psensor **psensor_list_copy(struct psensor **sensors)
447 {
448         struct psensor **result;
449         int n, i;
450
451         n = psensor_list_size(sensors);
452         result = malloc((n+1) * sizeof(struct psensor *));
453         for (i = 0; i < n; i++)
454                 result[i] = sensors[i];
455         result[n] = NULL;
456
457         return result;
458 }
459
460 char *
461 psensor_current_value_to_str(const struct psensor *s, unsigned int use_celsius)
462 {
463         return psensor_value_to_str(s->type,
464                                     psensor_get_current_value(s),
465                                     use_celsius);
466 }