moko-specific battery handling
[gregoa/zavai.git] / src / power.vala
1 /*
2  * power - zavai power event handling
3  *
4  * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 using GLib;
22
23 namespace zavai {
24 namespace power {
25
26 class Power : Service
27 {
28     public enum State
29     {
30         UNKNOWN,
31         CHARGING,
32         DISCHARGING,
33         FULLY_CHARGED,
34     }
35
36     protected string battery_device;
37     protected uint timeout;
38     public signal void changed();
39     public State state;
40     public int percentage;
41
42     public Power()
43     {
44         battery_device = "/sys/class/power_supply/battery/";
45         if (Posix.access(battery_device, Posix.R_OK) != 0)
46             battery_device = null;
47         timeout = 0;
48         state = State.UNKNOWN;
49         percentage = 0;
50     }
51
52     /// Activate the service
53     protected override void start()
54     {
55         if (started) return;
56
57         uint poll_time;
58         if (uevent.uevent != null)
59         {
60             uevent.uevent.event += on_uevent;
61             uevent.uevent.request("zavai.power");
62             // If we can get plug/unplug notifications, it's ok to just poll
63             // every 5 minutes
64             poll_time = 300 * 1000;
65         } else {
66             if (battery_device == null)
67             {
68                 zavai.log.warning("No battery device found that I know how to read: try building with devkit-power");
69                 poll_time = 0;
70             } else {
71                 // Else poll every 30 seconds to be somehow reactive to plug/unplug
72                 // events
73                 poll_time = 30 * 1000;
74             }
75         }
76
77         poll();
78
79         // Poll battery every minute
80         if (poll_time != 0)
81             timeout = Timeout.add(poll_time, on_timeout);
82
83         base.start();
84     }
85
86     /// Deactivate the service
87     protected override void stop()
88     {
89         if (!started) return;
90
91         // Stop polling
92         if (timeout != 0)
93             Source.remove(timeout);
94
95         if (uevent.uevent != null)
96         {
97             uevent.uevent.release("zavai.power");
98             uevent.uevent.event -= on_uevent;
99         }
100
101         base.stop();
102     }
103
104     protected void poll()
105     {
106         if (battery_device == null)
107             return;
108
109         char buf[200];
110         State new_state = State.UNKNOWN;
111         int new_percentage = 0;
112
113         FileStream state_fd = FileStream.open(battery_device + "/status", "r");
114         string val = state_fd.gets(buf);
115         if (val == "Charging")
116             new_state = State.CHARGING;
117         else if (val == "Discharging")
118             new_state = State.DISCHARGING;
119         else if (val == "Not charging")
120             new_state = State.FULLY_CHARGED;
121
122         FileStream cap_fd = FileStream.open(battery_device + "/capacity", "r");
123         val = cap_fd.gets(buf);
124         new_percentage = val.to_int();
125
126         if (new_state != state || new_percentage != percentage)
127         {
128             state = new_state;
129             percentage = new_percentage;
130             changed();
131         }
132     }
133
134     protected bool on_timeout()
135     {
136         poll();
137         return true;
138     }
139
140     protected void on_uevent()
141     {
142         /* if (uevent.uevent.event_data.buffer.has_prefix("change@/class/power_supply/ac"))
143         {
144             changed();
145         }
146         else */
147         if (uevent.uevent.event_data.buffer.has_prefix("change@/class/power_supply/battery"))
148         {
149             State new_state = State.UNKNOWN;
150             int new_percentage = 0;
151
152             Omhacks.UEvent.parse(ref uevent.uevent.event_data);
153             for (int i = 0; uevent.uevent.event_data.envp[i] != null; ++i)
154             {
155                 if (uevent.uevent.event_data.envp[i].has_prefix("POWER_SUPPLY_STATUS="))
156                 {
157                     var val = uevent.uevent.event_data.envp[i].offset(20);
158                     if (val == "Charging")
159                         new_state = State.CHARGING;
160                     else if (val == "Discharging")
161                         new_state = State.DISCHARGING;
162                     else if (val == "Not charging")
163                         new_state = State.FULLY_CHARGED;
164                     else
165                         zavai.log.warning("Unknown state: " + uevent.uevent.event_data.envp[i]);
166                 }
167                 else if (uevent.uevent.event_data.envp[i].has_prefix("POWER_SUPPLY_CAPACITY="))
168                 {
169                     new_percentage = uevent.uevent.event_data.envp[i].offset(22).to_int();
170                 }
171             }
172             if (new_state != state || new_percentage != percentage)
173             {
174                 state = new_state;
175                 percentage = new_percentage;
176                 changed();
177             }
178         }
179     }
180 }
181
182 Power power;
183
184 public void init()
185 {
186     power = new Power();
187 }
188
189 }
190 }