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