a385ddac5211e1a2f37aa932ad610f05e187fee7
[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 <sensors/sensors.h>
24 #include <sensors/error.h>
25
26 #include "hdd.h"
27 #include "psensor.h"
28 #include "lmsensor.h"
29
30 struct psensor *psensor_create(char *id, char *name,
31                                unsigned int type, int values_max_length)
32 {
33         struct psensor *psensor
34             = (struct psensor *)malloc(sizeof(struct psensor));
35
36         psensor->id = id;
37         psensor->name = name;
38         psensor->enabled = 1;
39         psensor->min = UNKNOWN_VALUE;
40         psensor->max = UNKNOWN_VALUE;
41
42         psensor->type = type;
43
44         psensor->values_max_length = values_max_length;
45         psensor->measures = measures_create(values_max_length);
46
47         psensor->alarm_limit = 0;
48
49         psensor->cb_alarm_raised = NULL;
50         psensor->cb_alarm_raised_data = NULL;
51         psensor->alarm_raised = 0;
52
53         psensor->alarm_enabled = 0;
54
55         psensor->url = NULL;
56
57         psensor->color = NULL;
58
59         return psensor;
60 }
61
62 void psensor_values_resize(struct psensor *s, int new_size)
63 {
64         struct measure *new_ms, *cur_ms;
65         int cur_size;
66
67         cur_size = s->values_max_length;
68         cur_ms = s->measures;
69         new_ms = measures_create(new_size);
70
71         if (cur_ms) {
72                 int i;
73                 for (i = 0; i < new_size - 1 && i < cur_size - 1; i++)
74                         measure_copy(&cur_ms[cur_size - i - 1],
75                                      &new_ms[new_size - i - 1]);
76
77                 measures_free(s->measures);
78         }
79
80         s->values_max_length = new_size;
81         s->measures = new_ms;
82 }
83
84 void psensor_free(struct psensor *sensor)
85 {
86         if (sensor) {
87                 free(sensor->name);
88                 free(sensor->id);
89
90                 if (sensor->color)
91                         free(sensor->color);
92
93                 measures_free(sensor->measures);
94
95                 free(sensor->url);
96
97                 free(sensor);
98         }
99 }
100
101 void psensor_list_free(struct psensor **sensors)
102 {
103         struct psensor **sensor_cur;
104
105         if (sensors) {
106                 sensor_cur = sensors;
107
108                 while (*sensor_cur) {
109                         psensor_free(*sensor_cur);
110
111                         sensor_cur++;
112                 }
113
114                 free(sensors);
115
116                 sensors = NULL;
117         }
118 }
119
120 int psensor_list_size(struct psensor **sensors)
121 {
122         int size;
123         struct psensor **sensor_cur;
124
125         if (!sensors)
126                 return 0;
127
128         size = 0;
129         sensor_cur = sensors;
130
131         while (*sensor_cur) {
132                 size++;
133                 sensor_cur++;
134         }
135         return size;
136 }
137
138 int psensor_list_contains_type(struct psensor **sensors, unsigned int type)
139 {
140         struct psensor **s;
141
142         if (!sensors)
143                 return 0;
144
145         s = sensors;
146         while (*s) {
147                 if ((*s)->type == type)
148                         return 1;
149                 s++;
150         }
151
152         return 0;
153 }
154
155 struct psensor **psensor_list_add(struct psensor **sensors,
156                                   struct psensor *sensor)
157 {
158         int size = psensor_list_size(sensors);
159
160         struct psensor **result
161             = malloc((size + 1 + 1) * sizeof(struct psensor *));
162
163         if (sensors)
164                 memcpy(result, sensors, size * sizeof(struct psensor *));
165
166         result[size] = sensor;
167         result[size + 1] = NULL;
168
169         return result;
170 }
171
172 struct psensor *psensor_list_get_by_id(struct psensor **sensors, const char *id)
173 {
174         struct psensor **sensors_cur = sensors;
175
176         while (*sensors_cur) {
177                 if (!strcmp((*sensors_cur)->id, id))
178                         return *sensors_cur;
179
180                 sensors_cur++;
181         }
182
183         return NULL;
184 }
185
186 int is_temp_type(unsigned int type)
187 {
188         return type & SENSOR_TYPE_TEMP;
189 }
190
191 int is_fan_type(unsigned int type)
192 {
193         return type & SENSOR_TYPE_FAN;
194 }
195
196 char *psensor_value_to_string(unsigned int type, double value)
197 {
198         /* should not be possible to exceed 20 characters with temp or
199            rpm values the .x part is never displayed */
200         char *str = malloc(20);
201
202         char *unit;
203
204         if (is_temp_type(type))
205                 unit = "C";
206         else
207                 unit = "";
208
209         sprintf(str, "%.0f%s", value, unit);
210
211         return str;
212 }
213
214 void psensor_set_current_value(struct psensor *sensor, double value)
215 {
216         struct timeval tv;
217
218         if (gettimeofday(&tv, NULL) != 0)
219                 timerclear(&tv);
220
221         psensor_set_current_measure(sensor, value, tv);
222 }
223
224 void
225 psensor_set_current_measure(struct psensor *s,
226                             double v, struct timeval tv)
227 {
228         memmove(s->measures,
229                 &s->measures[1],
230                 (s->values_max_length - 1) * sizeof(struct measure));
231
232         s->measures[s->values_max_length - 1].value = v;
233         s->measures[s->values_max_length - 1].time = tv;
234
235         if (s->min == UNKNOWN_VALUE || v < s->min)
236                 s->min = v;
237
238         if (s->max == UNKNOWN_VALUE || v > s->max)
239                 s->max = v;
240
241         if (s->alarm_limit && s->alarm_enabled) {
242                 if (v > s->alarm_limit) {
243                         if (!s->alarm_raised && s->cb_alarm_raised)
244                                 s->cb_alarm_raised(s,
245                                                    s->cb_alarm_raised_data);
246
247                         s->alarm_raised = 1;
248                 } else {
249                         s->alarm_raised = 0;
250                 }
251         }
252 }
253
254 double psensor_get_current_value(struct psensor *sensor)
255 {
256         return sensor->measures[sensor->values_max_length - 1].value;
257 }
258
259 struct measure *psensor_get_current_measure(struct psensor *sensor)
260 {
261         return &sensor->measures[sensor->values_max_length - 1];
262 }
263
264 /*
265   Returns the minimal value of a given 'type' (SENSOR_TYPE_TEMP or
266   SENSOR_TYPE_FAN)
267  */
268 double get_min_value(struct psensor **sensors, int type)
269 {
270         double m = UNKNOWN_VALUE;
271         struct psensor **s = sensors;
272
273         while (*s) {
274                 struct psensor *sensor = *s;
275
276                 if (sensor->enabled && (sensor->type & type)) {
277                         int i;
278                         double t;
279
280                         for (i = 0; i < sensor->values_max_length; i++) {
281                                 t = sensor->measures[i].value;
282
283                                 if (t == UNKNOWN_VALUE)
284                                         continue;
285
286                                 if (m == UNKNOWN_VALUE || t < m)
287                                         m = t;
288                         }
289                 }
290                 s++;
291         }
292
293         return m;
294 }
295
296 /*
297   Returns the maximal value of a given 'type' (SENSOR_TYPE_TEMP or
298   SENSOR_TYPE_FAN)
299  */
300 static double get_max_value(struct psensor **sensors, int type)
301 {
302         double m = UNKNOWN_VALUE;
303         struct psensor **s = sensors;
304
305         while (*s) {
306                 struct psensor *sensor = *s;
307
308                 if (sensor->enabled && (sensor->type & type)) {
309                         int i;
310                         double t;
311                         for (i = 0; i < sensor->values_max_length; i++) {
312                                 t = sensor->measures[i].value;
313
314                                 if (t == UNKNOWN_VALUE)
315                                         continue;
316
317                                 if (m == UNKNOWN_VALUE || t > m)
318                                         m = t;
319                         }
320                 }
321                 s++;
322         }
323
324         return m;
325 }
326
327 double
328 psensor_get_max_current_value(struct psensor **sensors, unsigned int type)
329 {
330         double m = UNKNOWN_VALUE;
331         struct psensor **s_cur = sensors;
332
333         while (*s_cur) {
334                 struct psensor *s = *s_cur;
335
336                 if (s->enabled && (s->type & type)) {
337                         double v = psensor_get_current_value(s);
338
339                         if (m == UNKNOWN_VALUE || v > m)
340                                 m = v;
341                 }
342
343                 s_cur++;
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 struct psensor **get_all_sensors(int values_max_length)
370 {
371         struct psensor **psensors = NULL;
372         int count = 0;
373         const sensors_chip_name *chip;
374         int chip_nr = 0;
375         struct psensor **tmp_psensors;
376         const sensors_feature *feature;
377         struct psensor *psensor;
378         int i;
379
380         while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
381                 i = 0;
382                 while ((feature = sensors_get_features(chip, &i))) {
383
384                         if (feature->type == SENSORS_FEATURE_TEMP
385                             || feature->type == SENSORS_FEATURE_FAN) {
386
387                                 psensor = lmsensor_psensor_create
388                                         (chip, feature, values_max_length);
389
390                                 if (psensor) {
391                                         tmp_psensors
392                                                 = psensor_list_add(psensors,
393                                                                    psensor);
394
395                                         free(psensors);
396
397                                         psensors = tmp_psensors;
398
399                                         count++;
400                                 }
401                         }
402                 }
403         }
404
405         tmp_psensors = hdd_psensor_list_add(psensors, values_max_length);
406
407         if (tmp_psensors != psensors) {
408                 free(psensors);
409                 psensors = tmp_psensors;
410         }
411
412         if (!psensors) {        /* there is no detected sensors */
413                 psensors = malloc(sizeof(struct psensor *));
414                 *psensors = NULL;
415         }
416
417         return psensors;
418 }
419
420 const char *psensor_type_to_str(unsigned int type)
421 {
422         if (type & SENSOR_TYPE_REMOTE)
423                 return "Remote";
424
425         if (type & SENSOR_TYPE_LMSENSOR_TEMP)
426                 return "Temperature";
427
428         if (type & SENSOR_TYPE_LMSENSOR_FAN)
429                 return "Fan";
430
431         if (type & SENSOR_TYPE_NVIDIA)
432                 return "NVidia GPU Temperature";
433
434         if (type & SENSOR_TYPE_HDD_TEMP)
435                 return "HDD Temperature";
436
437         return "N/A";           /* should not be possible */
438 }
439
440 void psensor_list_update_measures(struct psensor **sensors)
441 {
442         lmsensor_psensor_list_update(sensors);
443
444         if (psensor_list_contains_type(sensors, SENSOR_TYPE_HDD_TEMP))
445                 hdd_psensor_list_update(sensors);
446 }