1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Adapted from the 'sensors' program.
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <math.h>
26
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <unistd.h>
30
31 #include <sensors/sensors.h>
32 #include <sensors/error.h>
33
34 #include "applet-struct.h"
35 #include "applet-sensors.h"
36
37 /**************************************************
38 it87-isa-0290
39 Adapter: ISA adapter
40 VCore 1: +1.57 V (min = +1.42 V, max = +1.57 V) ALARM
41 VCore 2: +2.66 V (min = +2.40 V, max = +2.61 V) ALARM
42 +3.3V: +6.59 V (min = +3.14 V, max = +3.46 V) ALARM
43 +5V: +5.11 V (min = +4.76 V, max = +5.24 V)
44 +12V: +11.78 V (min = +11.39 V, max = +12.61 V)
45 -12V: -19.14 V (min = -12.63 V, max = -11.41 V) ALARM
46 -5V: +0.77 V (min = -5.26 V, max = -4.77 V) ALARM
47 Stdby: +5.00 V (min = +4.76 V, max = +5.24 V)
48 VBat: +3.12 V
49 fan1: 3668 RPM (min = 0 RPM, div =
50 fan2: 0 RPM (min = 664 RPM, div = ALARM
51 fan3: 0 RPM (min = 2657 RPM, div = 2) ALARM
52 M/B Temp: +39°C (low = +15°C, high = +40°C) sensor = thermistor
53 CPU Temp: +36°C (low = +15°C, high = +45°C) sensor = thermistor
54 Temp3: +96°C (low = +15°C, high = +45°C) sensor = diode
55 **************************************************/
56
57 static int s_iSensorsState = 0; // on en fait une variable globale plutot qu'un parametre de myData, car la libsensors ne doit etre fermee qu'une seule fois (meme si l'applet est instancee plusieurs fois, le .so du plug-in n'est ouvert une seule fois).
58
cd_sysmonitor_clean_sensors(void)59 void cd_sysmonitor_clean_sensors (void)
60 {
61 if (s_iSensorsState == 1)
62 sensors_cleanup();
63 s_iSensorsState = 0;
64 }
65
get_value(const sensors_chip_name * name,const sensors_subfeature * sub)66 static double get_value (const sensors_chip_name *name, const sensors_subfeature *sub)
67 {
68 double val;
69 int err;
70
71 err = sensors_get_value(name, sub->number, &val);
72 if (err) {
73 fprintf(stderr, "ERROR: Can't get value of subfeature %s: %s\n",
74 sub->name, sensors_strerror(err));
75 val = 0;
76 }
77 return val;
78 }
79
_init_sensors(void)80 static inline void _init_sensors (void)
81 {
82 if (s_iSensorsState == 0)
83 {
84 int err = sensors_init (NULL);
85 if (err != 0)
86 {
87 s_iSensorsState = -1;
88 cd_warning ("couldn't initialize libsensors: %s\nTry running 'sensors-detect' as root in a terminal.", sensors_strerror (err));
89 return;
90 }
91 s_iSensorsState = 1;
92 }
93 }
94
cd_sysmonitor_get_sensors_data(GldiModuleInstance * myApplet)95 void cd_sysmonitor_get_sensors_data (GldiModuleInstance *myApplet)
96 {
97 _init_sensors ();
98 if (s_iSensorsState != 1)
99 return;
100
101 const sensors_chip_name *chip;
102 const sensors_subfeature *sf;
103 double val;
104 int chip_nr;
105
106 chip_nr = 0;
107 double fCpuTempPercentMax = 0;
108 myData.iFanSpeed = 0;
109 myData.iCPUTemp = 0;
110 myData.bCpuTempAlarm = FALSE;
111 myData.bFanAlarm = FALSE;
112 while ((chip = sensors_get_detected_chips (NULL, &chip_nr)))
113 {
114 const sensors_feature *feature;
115 int i;
116
117 i = 0;
118 while ((feature = sensors_get_features (chip, &i)))
119 {
120 switch (feature->type)
121 {
122 case SENSORS_FEATURE_TEMP: // une sonde de temperature
123 {
124 double limit1=0, limit2=100;
125
126 sf = sensors_get_subfeature (chip, feature,
127 SENSORS_SUBFEATURE_TEMP_FAULT);
128 if (sf && get_value (chip, sf)) // fault
129 break;
130
131 // valeur
132 sf = sensors_get_subfeature (chip, feature,
133 SENSORS_SUBFEATURE_TEMP_INPUT);
134 if (!sf)
135 break;
136 val = get_value(chip, sf);
137 if (val == 0)
138 break;
139
140 // alarme
141 sf = sensors_get_subfeature (chip, feature,
142 SENSORS_SUBFEATURE_TEMP_ALARM);
143 if (sf && get_value (chip, sf))
144 myData.bCpuTempAlarm = TRUE;
145
146 // min limit
147 sf = sensors_get_subfeature (chip, feature,
148 SENSORS_SUBFEATURE_TEMP_MIN);
149 if (sf)
150 {
151 limit1 = get_value(chip, sf);
152
153 sf = sensors_get_subfeature (chip, feature,
154 SENSORS_SUBFEATURE_TEMP_MIN_ALARM);
155 if (sf && get_value (chip, sf))
156 myData.bCpuTempAlarm = TRUE;
157 }
158
159 // max limit
160 sf = sensors_get_subfeature(chip, feature,
161 SENSORS_SUBFEATURE_TEMP_MAX);
162 if (sf)
163 {
164 limit2 = get_value (chip, sf);
165
166 sf = sensors_get_subfeature (chip, feature,
167 SENSORS_SUBFEATURE_TEMP_MAX_ALARM);
168 if (sf && get_value (chip, sf))
169 myData.bCpuTempAlarm = TRUE;
170 }
171 else // pas de valeur max, on regarde si une valeur critique existe.
172 {
173 sf = sensors_get_subfeature(chip, feature,
174 SENSORS_SUBFEATURE_TEMP_CRIT);
175 if (sf)
176 {
177 limit2 = get_value(chip, sf);
178
179 sf = sensors_get_subfeature(chip, feature,
180 SENSORS_SUBFEATURE_TEMP_CRIT_ALARM);
181 if (sf && get_value(chip, sf))
182 myData.bCpuTempAlarm = TRUE;
183 }
184 }
185 if (limit2 <= limit1 + 1)
186 limit2 = limit1 + 1;
187
188 double fCpuTempPercent = 100. * (val - limit1) / (limit2 - limit1);
189 if (fCpuTempPercent > fCpuTempPercentMax) // on ne va garder qu'une seule valeur : celle qui est la plus grande en valeur relative.
190 {
191 fCpuTempPercentMax = fCpuTempPercent;
192 myData.fCpuTempPercent = fCpuTempPercent;
193 myData.iCPUTemp = val;
194 myData.iCPUTempMin = limit1;
195 myData.iCPUTempMax = limit2;
196 }
197 //g_print ("CPU : %.2f %d(%d) %.2f\n", limit1, myData.iCPUTemp, myData.bCpuTempAlarm, limit2);
198 }
199 break;
200
201 case SENSORS_FEATURE_FAN: // un ventilo
202 {
203 double min = 0;
204
205 sf = sensors_get_subfeature (chip, feature,
206 SENSORS_SUBFEATURE_FAN_FAULT);
207 if (sf && get_value (chip, sf)) // fault
208 break;
209
210 // valeur
211 sf = sensors_get_subfeature (chip, feature,
212 SENSORS_SUBFEATURE_FAN_INPUT);
213 if (!sf)
214 break;
215 val = get_value (chip, sf); // rpm
216 if (val == 0)
217 break;
218
219 // alarm
220 sf = sensors_get_subfeature (chip, feature,
221 SENSORS_SUBFEATURE_FAN_MIN);
222 if (sf)
223 min = get_value(chip, sf);
224
225 sf = sensors_get_subfeature (chip, feature,
226 SENSORS_SUBFEATURE_FAN_ALARM);
227 if (sf && get_value(chip, sf) && val > min) // on elimine les cas ou le min a une valeur aberrante.
228 myData.bFanAlarm = TRUE;
229
230 // max speed
231 myData.fMaxFanSpeed = 8000.; // pour l'instant on la laisse en dur a une valeur pas trop bete, car libsensors ne fournit pas de max pour les fans (elle fournit un min, mais sans le max ca a peu d'interet).
232 if (val > myData.fMaxFanSpeed)
233 val = myData.fMaxFanSpeed;
234
235 myData.iFanSpeed = MAX (myData.iFanSpeed, val); // on ne garde qu'une valeur : la plus grande.
236
237 myData.fFanSpeedPercent = 100. * myData.iFanSpeed / myData.fMaxFanSpeed;
238 }
239 break;
240
241 default:
242 break;
243 }
244 }
245 }
246
247 if (fabs (myData.fCpuTempPercent - myData.fPrevCpuTempPercent) > 1)
248 {
249 myData.fPrevCpuTempPercent = myData.fCpuTempPercent;
250 myData.bNeedsUpdate = TRUE;
251 }
252 if (fabs (myData.fFanSpeedPercent - myData.fPrevFanSpeedPercent) > 1)
253 {
254 myData.fPrevFanSpeedPercent = myData.fFanSpeedPercent;
255 myData.bNeedsUpdate = TRUE;
256 }
257 }
258
259
cd_sysmonitor_get_sensors_info(GldiModuleInstance * myApplet,GString * pInfo)260 void cd_sysmonitor_get_sensors_info (GldiModuleInstance *myApplet, GString *pInfo)
261 {
262 _init_sensors ();
263 if (s_iSensorsState != 1)
264 return;
265
266 const sensors_chip_name *chip;
267 const sensors_subfeature *sf;
268 double val;
269 int chip_nr;
270
271 chip_nr = 0;
272 char *label;
273 gboolean alarm;
274 while ((chip = sensors_get_detected_chips (NULL, &chip_nr)))
275 {
276 const sensors_feature *feature;
277 int i;
278
279 i = 0;
280 while ((feature = sensors_get_features (chip, &i)))
281 {
282 label = NULL;
283 alarm = 0;
284 switch (feature->type)
285 {
286 case SENSORS_FEATURE_TEMP: // une sonde de temperature
287 {
288 // name
289 label = sensors_get_label(chip, feature);
290 if (!label)
291 break;
292
293 double limit1=-100, limit2=-100;
294
295 sf = sensors_get_subfeature(chip, feature,
296 SENSORS_SUBFEATURE_TEMP_FAULT);
297 if (sf && get_value(chip, sf)) // fault
298 break;
299
300 // valeur
301 sf = sensors_get_subfeature(chip, feature,
302 SENSORS_SUBFEATURE_TEMP_INPUT);
303 if (!sf)
304 break;
305 val = get_value(chip, sf);
306 if (val == 0)
307 break;
308
309 // alarme
310 sf = sensors_get_subfeature(chip, feature,
311 SENSORS_SUBFEATURE_TEMP_ALARM);
312 if (sf && get_value(chip, sf))
313 alarm = TRUE;
314
315 // min limit
316 sf = sensors_get_subfeature(chip, feature,
317 SENSORS_SUBFEATURE_TEMP_MIN);
318 if (sf)
319 {
320 limit1 = get_value(chip, sf);
321
322 sf = sensors_get_subfeature(chip, feature,
323 SENSORS_SUBFEATURE_TEMP_MIN_ALARM);
324 if (sf && get_value(chip, sf))
325 alarm = TRUE;
326 }
327
328 // max limit
329 sf = sensors_get_subfeature(chip, feature,
330 SENSORS_SUBFEATURE_TEMP_MAX);
331 if (sf)
332 {
333 limit2 = get_value(chip, sf);
334
335 sf = sensors_get_subfeature(chip, feature,
336 SENSORS_SUBFEATURE_TEMP_MAX_ALARM);
337 if (sf && get_value(chip, sf))
338 alarm = TRUE;
339 }
340 else // pas de valeur max, on regarde si une valeur critique existe.
341 {
342 sf = sensors_get_subfeature(chip, feature,
343 SENSORS_SUBFEATURE_TEMP_CRIT);
344 if (sf)
345 {
346 limit2 = get_value(chip, sf);
347
348 sf = sensors_get_subfeature(chip, feature,
349 SENSORS_SUBFEATURE_TEMP_CRIT_ALARM);
350 if (sf && get_value(chip, sf))
351 alarm = TRUE;
352 }
353 }
354
355 //g_print ("CPU : %.2f %d(%d) %.2f\n", limit1, myData.iCPUTemp, myData.bCpuTempAlarm, limit2);
356 g_string_append_printf (pInfo, "\n%s: %d°C", label, (int)val);
357 if (limit1 > -99)
358 g_string_append_printf (pInfo, ", %s: %d°C", D_("min"), (int)limit1);
359 if (limit2 > -99)
360 g_string_append_printf (pInfo, ", %s: %d°C", D_("max"), (int)limit2);
361
362 if (alarm)
363 g_string_append_printf (pInfo, " (%s)", D_("alarm"));
364 free(label);
365 }
366 break;
367
368 case SENSORS_FEATURE_FAN: // un ventilo
369 // name
370 label = sensors_get_label(chip, feature);
371 if (!label)
372 break;
373
374 sf = sensors_get_subfeature (chip, feature,
375 SENSORS_SUBFEATURE_FAN_FAULT);
376 if (sf && get_value(chip, sf)) // fault
377 break;
378
379 // valeur
380 sf = sensors_get_subfeature (chip, feature,
381 SENSORS_SUBFEATURE_FAN_INPUT);
382 if (!sf)
383 break;
384 val = get_value (chip, sf); // rpm
385 if (val == 0)
386 break;
387
388 // alarm
389 sf = sensors_get_subfeature (chip, feature,
390 SENSORS_SUBFEATURE_FAN_ALARM);
391 if (sf && get_value(chip, sf))
392 alarm = TRUE;
393
394 g_string_append_printf (pInfo, "\n%s: %d %s", label, (int)val, D_("rpm"));
395 if (alarm)
396 g_string_append_printf (pInfo, " (%s)", D_("alarm"));
397 free(label);
398 break;
399
400 default: // les autres ne nous interessent pas.
401 break;
402 }
403 }
404 }
405 }
406
cd_cpu_alert(GldiModuleInstance * myApplet)407 void cd_cpu_alert (GldiModuleInstance *myApplet)
408 {
409 if (myData.bCPUAlerted || ! myConfig.bAlert)
410 return;
411
412 gldi_dialogs_remove_on_icon (myIcon);
413 gldi_dialog_show_temporary_with_icon_printf (D_("CPU temperature has reached %d°C"), myIcon, myContainer, 4e3, MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE, myData.iCPUTemp);
414
415 if (myConfig.bAlertSound)
416 cairo_dock_play_sound (myConfig.cSoundPath);
417
418 myData.bCPUAlerted = TRUE;
419 }
420
cd_fan_alert(GldiModuleInstance * myApplet)421 void cd_fan_alert (GldiModuleInstance *myApplet)
422 {
423 if (myData.bFanAlerted || ! myConfig.bAlert)
424 return;
425
426 gldi_dialogs_remove_on_icon (myIcon);
427 gldi_dialog_show_temporary_with_icon_printf (D_("Fan speed has reached %d rpm"), myIcon, myContainer, 4e3, MY_APPLET_SHARE_DATA_DIR"/"MY_APPLET_ICON_FILE, myData.iFanSpeed);
428
429 if (myConfig.bAlertSound)
430 cairo_dock_play_sound (myConfig.cSoundPath);
431
432 myData.bFanAlerted = TRUE;
433 }
434