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