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