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