diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/powermgmt.h | 10 | ||||
-rw-r--r-- | firmware/powermgmt.c | 750 |
2 files changed, 398 insertions, 362 deletions
diff --git a/firmware/export/powermgmt.h b/firmware/export/powermgmt.h index 3bccb0f59f..ccfdede9f9 100644 --- a/firmware/export/powermgmt.h +++ b/firmware/export/powermgmt.h | |||
@@ -57,12 +57,13 @@ | |||
57 | #ifndef SIMULATOR | 57 | #ifndef SIMULATOR |
58 | 58 | ||
59 | #ifdef HAVE_CHARGE_CTRL | 59 | #ifdef HAVE_CHARGE_CTRL |
60 | #define START_TOPOFF_CHG 85 /* Battery % to start at top-off */ | ||
61 | #define START_TRICKLE_CHG 95 /* Battery % to start at trickle */ | ||
62 | |||
60 | #define POWER_MESSAGE_LEN 32 /* power thread status message */ | 63 | #define POWER_MESSAGE_LEN 32 /* power thread status message */ |
61 | #define CHARGE_MAX_TIME_1500 450 /* minutes: maximum charging time for 1500 mAh batteries */ | 64 | #define CHARGE_MAX_TIME_1500 450 /* minutes: maximum charging time for 1500 mAh batteries */ |
62 | /* actual max time depends also on BATTERY_CAPACITY! */ | 65 | /* actual max time depends also on BATTERY_CAPACITY! */ |
63 | #define CHARGE_MIN_TIME 10 /* minutes: minimum charging time */ | 66 | #define CHARGE_MIN_TIME 10 /* minutes: minimum charging time */ |
64 | #define CHARGE_RESTART 85 /* %: when to restart charging in 'charge' mode */ | ||
65 | /* attention: if set too high, normal charging is started in trickle mode */ | ||
66 | #define TOPOFF_MAX_TIME 90 /* After charging, go to top off charge. How long should top off charge be? */ | 67 | #define TOPOFF_MAX_TIME 90 /* After charging, go to top off charge. How long should top off charge be? */ |
67 | #define TOPOFF_VOLTAGE 565 /* which voltage is best? (centivolts) */ | 68 | #define TOPOFF_VOLTAGE 565 /* which voltage is best? (centivolts) */ |
68 | #define TRICKLE_MAX_TIME 12*60 /* After top off charge, go to trickle charge. How long should trickle charge be? */ | 69 | #define TRICKLE_MAX_TIME 12*60 /* After top off charge, go to trickle charge. How long should trickle charge be? */ |
@@ -71,6 +72,9 @@ | |||
71 | #define START_TOPOFF_SEC 25 /* initial trickle_sec for topoff */ | 72 | #define START_TOPOFF_SEC 25 /* initial trickle_sec for topoff */ |
72 | #define START_TRICKLE_SEC 15 /* initial trickle_sec for trickle */ | 73 | #define START_TRICKLE_SEC 15 /* initial trickle_sec for trickle */ |
73 | 74 | ||
75 | #define PID_PCONST 2 /* PID proportional constant */ | ||
76 | #define PID_DEADZONE 2 /* PID proportional deadzone */ | ||
77 | |||
74 | extern char power_message[POWER_MESSAGE_LEN]; | 78 | extern char power_message[POWER_MESSAGE_LEN]; |
75 | 79 | ||
76 | extern int long_delta; /* long term delta battery voltage */ | 80 | extern int long_delta; /* long term delta battery voltage */ |
@@ -79,6 +83,8 @@ extern int short_delta; /* short term delta battery voltage */ | |||
79 | extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was the charging started or stopped? */ | 83 | extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was the charging started or stopped? */ |
80 | extern int powermgmt_last_cycle_level; /* which level had the batteries at this time? */ | 84 | extern int powermgmt_last_cycle_level; /* which level had the batteries at this time? */ |
81 | 85 | ||
86 | extern int pid_p; /* PID proportional term */ | ||
87 | extern int pid_i; /* PID integral term */ | ||
82 | extern int trickle_sec; /* trickle charge: How many seconds per minute are we charging actually? */ | 88 | extern int trickle_sec; /* trickle charge: How many seconds per minute are we charging actually? */ |
83 | 89 | ||
84 | #endif /* HAVE_CHARGE_CTRL */ | 90 | #endif /* HAVE_CHARGE_CTRL */ |
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index dd2233efb1..0366896bb4 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c | |||
@@ -57,17 +57,11 @@ | |||
57 | static char debug_message[DEBUG_MESSAGE_LEN]; | 57 | static char debug_message[DEBUG_MESSAGE_LEN]; |
58 | #define DEBUG_STACK ((0x1000)/sizeof(long)) | 58 | #define DEBUG_STACK ((0x1000)/sizeof(long)) |
59 | static int fd; /* write debug information to this file */ | 59 | static int fd; /* write debug information to this file */ |
60 | static int wrcount; | ||
60 | #else | 61 | #else |
61 | #define DEBUG_STACK 0 | 62 | #define DEBUG_STACK 0 |
62 | #endif | 63 | #endif |
63 | 64 | ||
64 | long last_event_tick; | ||
65 | |||
66 | void reset_poweroff_timer(void) | ||
67 | { | ||
68 | last_event_tick = current_tick; | ||
69 | } | ||
70 | |||
71 | #ifdef SIMULATOR /***********************************************************/ | 65 | #ifdef SIMULATOR /***********************************************************/ |
72 | 66 | ||
73 | int battery_level(void) | 67 | int battery_level(void) |
@@ -125,24 +119,38 @@ static const short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = | |||
125 | #endif | 119 | #endif |
126 | }; | 120 | }; |
127 | 121 | ||
128 | static int battery_type = 0; | 122 | #ifdef HAVE_CHARGING |
123 | /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ | ||
124 | static const short percent_to_volt_charge[11] = | ||
125 | { | ||
126 | /* values guessed, see | ||
127 | http://www.seattlerobotics.org/encoder/200210/LiIon2.pdf until someone | ||
128 | measures voltages over a charging cycle */ | ||
129 | 476, 544, 551, 556, 561, 564, 566, 576, 582, 584, 585 /* NiMH */ | ||
130 | }; | ||
131 | #endif /* HAVE_CHARGING */ | ||
129 | 132 | ||
130 | #if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200 | 133 | #if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200 |
131 | charge_state_type charge_state; /* charging mode */ | 134 | charge_state_type charge_state; /* charging mode */ |
132 | int charge_timer; /* charge timer (minutes, dec to zero) */ | ||
133 | #endif | 135 | #endif |
134 | 136 | ||
135 | #ifdef HAVE_CHARGING | 137 | #ifdef HAVE_CHARGING |
136 | /* Flag that the charger has been plugged in */ | 138 | /* |
137 | static bool charger_was_inserted = false; /* for power off logic */ | 139 | * Flag that the charger has been plugged in/removed: this is set for exactly |
138 | static bool charger_power_is_on; /* for car adapter mode */ | 140 | * one time through the power loop when the charger has been plugged in. |
139 | #endif | 141 | */ |
142 | static enum { | ||
143 | NO_CHARGER, | ||
144 | CHARGER_UNPLUGGED, /* transient state */ | ||
145 | CHARGER_PLUGGED, /* transient state */ | ||
146 | CHARGER | ||
147 | } charger_input_state; | ||
140 | 148 | ||
141 | /* Power history: power_history[0] is the newest sample */ | 149 | static bool waiting_to_resume_play = false; |
142 | unsigned short power_history[POWER_HISTORY_LEN]; | 150 | static long play_resume_time; |
151 | #endif | ||
143 | 152 | ||
144 | #ifdef HAVE_CHARGE_CTRL | 153 | #ifdef HAVE_CHARGE_CTRL |
145 | |||
146 | int long_delta; /* long term delta battery voltage */ | 154 | int long_delta; /* long term delta battery voltage */ |
147 | int short_delta; /* short term delta battery voltage */ | 155 | int short_delta; /* short term delta battery voltage */ |
148 | 156 | ||
@@ -155,52 +163,56 @@ int powermgmt_last_cycle_startstop_min = 0; /* how many minutes ago was the | |||
155 | stopped? */ | 163 | stopped? */ |
156 | int powermgmt_last_cycle_level = 0; /* which level had the | 164 | int powermgmt_last_cycle_level = 0; /* which level had the |
157 | batteries at this time? */ | 165 | batteries at this time? */ |
158 | int trickle_sec = 0; /* how many seconds should the | 166 | int trickle_sec = 0; /* how many seconds should the |
159 | charger be enabled per | 167 | charger be enabled per |
160 | minute for trickle | 168 | minute for trickle |
161 | charging? */ | 169 | charging? */ |
162 | /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ | 170 | int pid_p = 0; /* PID proportional term */ |
163 | static const short percent_to_volt_charge[11] = | 171 | int pid_i = 0; /* PID integral term */ |
164 | { | 172 | #endif /* HAVE_CHARGE_CTRL */ |
165 | /* values guessed, see | ||
166 | http://www.seattlerobotics.org/encoder/200210/LiIon2.pdf until someone | ||
167 | measures voltages over a charging cycle */ | ||
168 | 476, 544, 551, 556, 561, 564, 566, 576, 582, 584, 585 /* NiMH */ | ||
169 | }; | ||
170 | |||
171 | #endif /* HAVE_CHARGE_CTRL || CONFIG_BATTERY == BATT_LIION2200 */ | ||
172 | 173 | ||
173 | /* | 174 | /* |
174 | * Average battery voltage and charger voltage, filtered via a digital | 175 | * Average battery voltage and charger voltage, filtered via a digital |
175 | * exponential filter. | 176 | * exponential filter. |
176 | */ | 177 | */ |
177 | unsigned int battery_centivolts;/* filtered battery voltage, centvolts */ | 178 | static unsigned int battery_centivolts;/* filtered battery voltage, centvolts */ |
178 | static unsigned int avgbat; /* average battery voltage */ | 179 | static unsigned int avgbat; /* average battery voltage (filtering) */ |
179 | #define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */ | 180 | #define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */ |
180 | 181 | ||
181 | int battery_capacity = BATTERY_CAPACITY_MIN; /* only a default value */ | ||
182 | |||
183 | /* battery level (0-100%) of this minute, updated once per minute */ | 182 | /* battery level (0-100%) of this minute, updated once per minute */ |
184 | static int battery_percent = -1; | 183 | static int battery_percent = -1; |
184 | static int battery_capacity = BATTERY_CAPACITY_MIN; /* default value, mAH */ | ||
185 | static int battery_type = 0; | ||
186 | |||
187 | /* Power history: power_history[0] is the newest sample */ | ||
188 | unsigned short power_history[POWER_HISTORY_LEN]; | ||
185 | 189 | ||
186 | static bool car_adapter_mode_enabled = false; | 190 | static bool car_adapter_mode_enabled = false; |
187 | 191 | ||
188 | static char power_stack[DEFAULT_STACK_SIZE + DEBUG_STACK]; | 192 | static char power_stack[DEFAULT_STACK_SIZE + DEBUG_STACK]; |
189 | static const char power_thread_name[] = "power"; | 193 | static const char power_thread_name[] = "power"; |
190 | 194 | ||
191 | static int poweroff_timeout = 0; | 195 | static int poweroff_timeout = 0; |
192 | static long last_charge_time = 0; | 196 | static int powermgmt_est_runningtime_min = -1; |
193 | int powermgmt_est_runningtime_min = -1; | ||
194 | 197 | ||
195 | static bool sleeptimer_active = false; | 198 | static bool sleeptimer_active = false; |
196 | static unsigned long sleeptimer_endtick; | 199 | static long sleeptimer_endtick; |
200 | |||
201 | static long last_event_tick; | ||
202 | |||
203 | static void battery_level_update(void); /* forward declaration */ | ||
204 | |||
205 | void reset_poweroff_timer(void) | ||
206 | { | ||
207 | last_event_tick = current_tick; | ||
208 | } | ||
197 | 209 | ||
198 | #if BATTERY_TYPES_COUNT > 1 | 210 | #if BATTERY_TYPES_COUNT > 1 |
199 | void set_battery_type(int type) | 211 | void set_battery_type(int type) |
200 | { | 212 | { |
201 | if (type != battery_type) { | 213 | if (type != battery_type) { |
202 | battery_type = type; | 214 | battery_type = type; |
203 | battery_percent = -1; /* reset on type change */ | 215 | battery_level_update(); /* recalculate the battery level */ |
204 | } | 216 | } |
205 | } | 217 | } |
206 | #endif | 218 | #endif |
@@ -219,79 +231,6 @@ int battery_time(void) | |||
219 | return powermgmt_est_runningtime_min; | 231 | return powermgmt_est_runningtime_min; |
220 | } | 232 | } |
221 | 233 | ||
222 | /* look into the percent_to_volt_* table and get a realistic battery level | ||
223 | percentage */ | ||
224 | int voltage_to_percent(int voltage, const short* table) | ||
225 | { | ||
226 | if (voltage <= table[0]) | ||
227 | return 0; | ||
228 | else | ||
229 | if (voltage >= table[10]) | ||
230 | return 100; | ||
231 | else { | ||
232 | /* search nearest value */ | ||
233 | int i = 0; | ||
234 | while ((i < 10) && (table[i+1] < voltage)) | ||
235 | i++; | ||
236 | /* interpolate linear between the smaller and greater value */ | ||
237 | return i * 10 /* 10th */ | ||
238 | + (voltage - table[i]) * | ||
239 | 10 / (table[i+1] - table[i]); /* 1th */ | ||
240 | } | ||
241 | } | ||
242 | |||
243 | /* update battery level, called only once per minute */ | ||
244 | void battery_level_update(void) | ||
245 | { | ||
246 | int level; | ||
247 | |||
248 | level = battery_centivolts; | ||
249 | if(level > BATTERY_LEVEL_FULL) | ||
250 | level = BATTERY_LEVEL_FULL; | ||
251 | |||
252 | if(level < BATTERY_LEVEL_EMPTY) | ||
253 | level = BATTERY_LEVEL_EMPTY; | ||
254 | |||
255 | #ifdef HAVE_CHARGE_CTRL | ||
256 | if (charge_state == DISCHARGING) { | ||
257 | level = voltage_to_percent(level, | ||
258 | percent_to_volt_discharge[battery_type]); | ||
259 | } | ||
260 | else if (charge_state == CHARGING) { | ||
261 | level = voltage_to_percent(level, percent_to_volt_charge); | ||
262 | } | ||
263 | else {/* in trickle charge, the battery is by definition 100% full */ | ||
264 | battery_percent = level = 100; | ||
265 | } | ||
266 | #else | ||
267 | /* always use the discharge table */ | ||
268 | level = voltage_to_percent(level, | ||
269 | percent_to_volt_discharge[battery_type]); | ||
270 | #endif | ||
271 | |||
272 | #ifndef HAVE_MMC /* this adjustment is only needed for HD based */ | ||
273 | if (battery_percent == -1) { /* first run of this procedure */ | ||
274 | /* The battery voltage is usually a little lower directly after | ||
275 | turning on, because the disk was used heavily. Raise it by 5. % */ | ||
276 | battery_percent = (level > 95) ? 100 : level + 5; | ||
277 | } | ||
278 | else | ||
279 | #endif | ||
280 | { | ||
281 | /* the level is allowed to be -1 of the last value when usb not | ||
282 | connected and to be -3 of the last value when usb is connected */ | ||
283 | if (usb_inserted()) { | ||
284 | if (level < battery_percent - 3) | ||
285 | level = battery_percent - 3; | ||
286 | } | ||
287 | else { | ||
288 | if (level < battery_percent - 1) | ||
289 | level = battery_percent - 1; | ||
290 | } | ||
291 | battery_percent = level; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /* Returns battery level in percent */ | 234 | /* Returns battery level in percent */ |
296 | int battery_level(void) | 235 | int battery_level(void) |
297 | { | 236 | { |
@@ -316,11 +255,11 @@ void set_poweroff_timeout(int timeout) | |||
316 | void set_sleep_timer(int seconds) | 255 | void set_sleep_timer(int seconds) |
317 | { | 256 | { |
318 | if(seconds) { | 257 | if(seconds) { |
319 | sleeptimer_active = true; | 258 | sleeptimer_active = true; |
320 | sleeptimer_endtick = current_tick + seconds * HZ; | 259 | sleeptimer_endtick = current_tick + seconds * HZ; |
321 | } | 260 | } |
322 | else { | 261 | else { |
323 | sleeptimer_active = false; | 262 | sleeptimer_active = false; |
324 | sleeptimer_endtick = 0; | 263 | sleeptimer_endtick = 0; |
325 | } | 264 | } |
326 | } | 265 | } |
@@ -333,31 +272,82 @@ int get_sleep_timer(void) | |||
333 | return 0; | 272 | return 0; |
334 | } | 273 | } |
335 | 274 | ||
336 | /* We shut off in the following cases: | 275 | /* look into the percent_to_volt_* table and get a realistic battery level |
337 | 1) The unit is idle, not playing music | 276 | percentage */ |
338 | 2) The unit is playing music, but is paused | 277 | static int voltage_to_percent(int voltage, const short* table) |
278 | { | ||
279 | if (voltage <= table[0]) | ||
280 | return 0; | ||
281 | else | ||
282 | if (voltage >= table[10]) | ||
283 | return 100; | ||
284 | else { | ||
285 | /* search nearest value */ | ||
286 | int i = 0; | ||
287 | while ((i < 10) && (table[i+1] < voltage)) | ||
288 | i++; | ||
289 | /* interpolate linear between the smaller and greater value */ | ||
290 | return (i * 10) /* Tens digit, 10% per entry */ | ||
291 | + (((voltage - table[i]) * 10) | ||
292 | / (table[i+1] - table[i])); /* Ones digit: interpolated */ | ||
293 | } | ||
294 | } | ||
339 | 295 | ||
340 | We do not shut off in the following cases: | 296 | /* update battery level, called once per minute */ |
341 | 1) The USB is connected | 297 | static void battery_level_update(void) |
342 | 2) The charger is connected | 298 | { |
343 | 3) We are recording, or recording with pause | 299 | int level; |
344 | */ | 300 | |
301 | #ifdef HAVE_CHARGE_CTRL | ||
302 | if (charge_state == DISCHARGING) { | ||
303 | level = voltage_to_percent(battery_centivolts, | ||
304 | percent_to_volt_discharge[battery_type]); | ||
305 | } | ||
306 | else if (charge_state == CHARGING) { | ||
307 | level = voltage_to_percent(battery_centivolts, percent_to_volt_charge); | ||
308 | } | ||
309 | else { /* in trickle charge, the battery is by definition 100% full */ | ||
310 | level = 100; | ||
311 | } | ||
312 | #else | ||
313 | /* always use the discharge table */ | ||
314 | level = voltage_to_percent(battery_centivolts, | ||
315 | percent_to_volt_discharge[battery_type]); | ||
316 | #endif | ||
317 | |||
318 | #ifndef HAVE_MMC /* this adjustment is only needed for HD based */ | ||
319 | if (battery_percent == -1) { /* first run of this procedure */ | ||
320 | /* The battery voltage is usually a little lower directly after | ||
321 | turning on, because the disk was used heavily. Raise it by 5. % */ | ||
322 | level = (level > 95) ? 100 : level + 5; | ||
323 | } | ||
324 | #endif | ||
325 | battery_percent = level; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * We shut off in the following cases: | ||
330 | * 1) The unit is idle, not playing music | ||
331 | * 2) The unit is playing music, but is paused | ||
332 | * | ||
333 | * We do not shut off in the following cases: | ||
334 | * 1) The USB is connected | ||
335 | * 2) The charger is connected | ||
336 | * 3) We are recording, or recording with pause | ||
337 | */ | ||
345 | static void handle_auto_poweroff(void) | 338 | static void handle_auto_poweroff(void) |
346 | { | 339 | { |
347 | long timeout = poweroff_idle_timeout_value[poweroff_timeout]*60*HZ; | 340 | long timeout = poweroff_idle_timeout_value[poweroff_timeout]*60*HZ; |
348 | int mpeg_stat = mpeg_status(); | 341 | int mpeg_stat = mpeg_status(); |
349 | #ifdef HAVE_CHARGING | ||
350 | bool charger_is_inserted = charger_inserted(); | ||
351 | #endif | ||
352 | 342 | ||
353 | #ifdef HAVE_CHARGING | 343 | #ifdef HAVE_CHARGING |
354 | /* The was_inserted thing prevents the unit to shut down immediately | 344 | /* |
355 | when the charger is extracted */ | 345 | * Inhibit shutdown as long as the charger is plugged in. If it is |
356 | if(charger_is_inserted || charger_was_inserted) | 346 | * unplugged, wait for a timeout period and then shut down. |
357 | { | 347 | */ |
358 | last_charge_time = current_tick; | 348 | if(charger_input_state == CHARGER) { |
349 | last_event_tick = current_tick; | ||
359 | } | 350 | } |
360 | charger_was_inserted = charger_is_inserted; | ||
361 | #endif | 351 | #endif |
362 | 352 | ||
363 | if(timeout && | 353 | if(timeout && |
@@ -369,9 +359,8 @@ static void handle_auto_poweroff(void) | |||
369 | ((mpeg_stat == (MPEG_STATUS_PLAY | MPEG_STATUS_PAUSE)) && | 359 | ((mpeg_stat == (MPEG_STATUS_PLAY | MPEG_STATUS_PAUSE)) && |
370 | !sleeptimer_active))) | 360 | !sleeptimer_active))) |
371 | { | 361 | { |
372 | if(TIME_AFTER(current_tick, last_event_tick + timeout) && | 362 | if(TIME_AFTER(current_tick, last_event_tick + timeout) && |
373 | TIME_AFTER(current_tick, last_disk_activity + timeout) && | 363 | TIME_AFTER(current_tick, last_disk_activity + timeout)) |
374 | TIME_AFTER(current_tick, last_charge_time + timeout)) | ||
375 | { | 364 | { |
376 | shutdown_hw(); | 365 | shutdown_hw(); |
377 | } | 366 | } |
@@ -385,7 +374,8 @@ static void handle_auto_poweroff(void) | |||
385 | { | 374 | { |
386 | mpeg_stop(); | 375 | mpeg_stop(); |
387 | #ifdef HAVE_CHARGING | 376 | #ifdef HAVE_CHARGING |
388 | if(charger_is_inserted) | 377 | if((charger_input_state == CHARGER) || |
378 | (charger_input_state == CHARGER_PLUGGED)) | ||
389 | { | 379 | { |
390 | DEBUGF("Sleep timer timeout. Stopping...\n"); | 380 | DEBUGF("Sleep timer timeout. Stopping...\n"); |
391 | set_sleep_timer(0); | 381 | set_sleep_timer(0); |
@@ -413,10 +403,7 @@ void set_car_adapter_mode(bool setting) | |||
413 | 403 | ||
414 | #ifdef HAVE_CHARGING | 404 | #ifdef HAVE_CHARGING |
415 | static void car_adapter_mode_processing(void) | 405 | static void car_adapter_mode_processing(void) |
416 | { | 406 | { |
417 | static bool waiting_to_resume_play = false; | ||
418 | static long play_resume_time; | ||
419 | |||
420 | if (car_adapter_mode_enabled) { | 407 | if (car_adapter_mode_enabled) { |
421 | 408 | ||
422 | if (waiting_to_resume_play) { | 409 | if (waiting_to_resume_play) { |
@@ -426,34 +413,23 @@ static void car_adapter_mode_processing(void) | |||
426 | } | 413 | } |
427 | waiting_to_resume_play = false; | 414 | waiting_to_resume_play = false; |
428 | } | 415 | } |
429 | } | 416 | } else { |
430 | else { | 417 | if (charger_input_state == CHARGER_UNPLUGGED) { |
431 | if (charger_power_is_on) { | 418 | /* |
432 | 419 | * Just got unplugged, pause if playing | |
433 | /* if external power was turned off */ | 420 | */ |
434 | if (!charger_inserted()) { | 421 | if ((mpeg_status() & MPEG_STATUS_PLAY) && |
435 | 422 | !(mpeg_status() & MPEG_STATUS_PAUSE)) { | |
436 | charger_power_is_on = false; | 423 | mpeg_pause(); |
437 | |||
438 | /* if playing */ | ||
439 | if ((mpeg_status() & MPEG_STATUS_PLAY) && | ||
440 | !(mpeg_status() & MPEG_STATUS_PAUSE)) { | ||
441 | mpeg_pause(); | ||
442 | } | ||
443 | } | 424 | } |
444 | } | 425 | } else if(charger_input_state == CHARGER_PLUGGED) { |
445 | else { | 426 | /* |
446 | /* if external power was turned on */ | 427 | * Just got plugged in, delay & resume if we were playing |
447 | if (charger_inserted()) { | 428 | */ |
448 | 429 | if (mpeg_status() & MPEG_STATUS_PAUSE) { | |
449 | charger_power_is_on = true; | 430 | /* delay resume a bit while the engine is cranking */ |
450 | 431 | play_resume_time = current_tick + HZ*5; | |
451 | /* if paused */ | 432 | waiting_to_resume_play = true; |
452 | if (mpeg_status() & MPEG_STATUS_PAUSE) { | ||
453 | /* delay resume a bit while the engine is cranking */ | ||
454 | play_resume_time = current_tick + HZ*5; | ||
455 | waiting_to_resume_play = true; | ||
456 | } | ||
457 | } | 433 | } |
458 | } | 434 | } |
459 | } | 435 | } |
@@ -509,14 +485,43 @@ static void power_thread_rtc_process(void) | |||
509 | static void power_thread_sleep(int ticks) | 485 | static void power_thread_sleep(int ticks) |
510 | { | 486 | { |
511 | int small_ticks; | 487 | int small_ticks; |
512 | #ifdef HAVE_CHARGING | 488 | |
513 | bool charger_plugged; | 489 | while (ticks > 0) { |
514 | #endif | ||
515 | 490 | ||
516 | #ifdef HAVE_CHARGING | 491 | #ifdef HAVE_CHARGING |
517 | charger_plugged = charger_inserted(); | 492 | /* |
493 | * Detect charger plugged/unplugged transitions. On a plugged or | ||
494 | * unplugged event, we return immediately, run once through the main | ||
495 | * loop (including the subroutines), and end up back here where we | ||
496 | * transition to the appropriate steady state charger on/off state. | ||
497 | */ | ||
498 | if(charger_inserted()) { | ||
499 | switch(charger_input_state) { | ||
500 | case NO_CHARGER: | ||
501 | case CHARGER_UNPLUGGED: | ||
502 | charger_input_state = CHARGER_PLUGGED; | ||
503 | return; | ||
504 | case CHARGER_PLUGGED: | ||
505 | charger_input_state = CHARGER; | ||
506 | break; | ||
507 | case CHARGER: | ||
508 | break; | ||
509 | } | ||
510 | } else { /* charger not inserted */ | ||
511 | switch(charger_input_state) { | ||
512 | case NO_CHARGER: | ||
513 | break; | ||
514 | case CHARGER_UNPLUGGED: | ||
515 | charger_input_state = NO_CHARGER; | ||
516 | break; | ||
517 | case CHARGER_PLUGGED: | ||
518 | case CHARGER: | ||
519 | charger_input_state = CHARGER_UNPLUGGED; | ||
520 | return; | ||
521 | } | ||
522 | } | ||
518 | #endif | 523 | #endif |
519 | while (ticks > 0) { | 524 | |
520 | small_ticks = MIN(HZ/2, ticks); | 525 | small_ticks = MIN(HZ/2, ticks); |
521 | sleep(small_ticks); | 526 | sleep(small_ticks); |
522 | ticks -= small_ticks; | 527 | ticks -= small_ticks; |
@@ -532,8 +537,6 @@ static void power_thread_sleep(int ticks) | |||
532 | * Do a digital exponential filter. We don't sample the battery if | 537 | * Do a digital exponential filter. We don't sample the battery if |
533 | * the disk is spinning unless we are in USB mode (the disk will most | 538 | * the disk is spinning unless we are in USB mode (the disk will most |
534 | * likely always be spinning in USB mode). | 539 | * likely always be spinning in USB mode). |
535 | * If the charging voltage is greater than 0x3F0 charging isn't active | ||
536 | * and that voltage isn't valid. | ||
537 | */ | 540 | */ |
538 | if (!ata_disk_is_active() || usb_inserted()) { | 541 | if (!ata_disk_is_active() || usb_inserted()) { |
539 | avgbat = avgbat - (avgbat / BATT_AVE_SAMPLES) + | 542 | avgbat = avgbat - (avgbat / BATT_AVE_SAMPLES) + |
@@ -541,13 +544,19 @@ static void power_thread_sleep(int ticks) | |||
541 | /* | 544 | /* |
542 | * battery_centivolts is the centivolt-scaled filtered battery value. | 545 | * battery_centivolts is the centivolt-scaled filtered battery value. |
543 | */ | 546 | */ |
544 | battery_centivolts = ((avgbat / BATT_AVE_SAMPLES) * BATTERY_SCALE_FACTOR) / 10000; | 547 | battery_centivolts = ((avgbat / BATT_AVE_SAMPLES) * |
548 | BATTERY_SCALE_FACTOR) / 10000; | ||
549 | } | ||
550 | #if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL) | ||
551 | /* | ||
552 | * If we have a lot of pending writes or if the disk is spining, | ||
553 | * fsync the debug log file. | ||
554 | */ | ||
555 | if((wrcount > 10) || | ||
556 | ((wrcount > 0) && ata_disk_is_active())) { | ||
557 | fsync(fd); | ||
558 | wrcount = 0; | ||
545 | } | 559 | } |
546 | |||
547 | #ifdef HAVE_CHARGING | ||
548 | /* If the charger was plugged in, exit now so we can start charging */ | ||
549 | if(!charger_plugged && charger_inserted()) | ||
550 | return; | ||
551 | #endif | 560 | #endif |
552 | } | 561 | } |
553 | } | 562 | } |
@@ -568,17 +577,19 @@ static void power_thread(void) | |||
568 | int charging_current; | 577 | int charging_current; |
569 | #endif | 578 | #endif |
570 | #ifdef HAVE_CHARGE_CTRL | 579 | #ifdef HAVE_CHARGE_CTRL |
571 | int charge_max_time_now = 0; /* max. charging duration, calculated at | 580 | unsigned int target_voltage; /* desired topoff/trickle voltage level */ |
572 | beginning of charging */ | 581 | int charge_max_time_now = 0; /* max. charging duration, calculated at |
582 | beginning of charging */ | ||
573 | #endif | 583 | #endif |
574 | 584 | ||
575 | /* initialize the voltages for the exponential filter */ | 585 | /* initialize the voltages for the exponential filter */ |
576 | 586 | ||
577 | avgbat = adc_read(ADC_UNREG_POWER) * BATT_AVE_SAMPLES; | 587 | avgbat = adc_read(ADC_UNREG_POWER) * BATT_AVE_SAMPLES; |
578 | battery_centivolts = ((avgbat / BATT_AVE_SAMPLES) * BATTERY_SCALE_FACTOR) / 10000; | 588 | battery_centivolts = ((avgbat / BATT_AVE_SAMPLES) * BATTERY_SCALE_FACTOR) / 10000; |
579 | 589 | ||
580 | #if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL) | 590 | #if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL) |
581 | fd = -1; | 591 | fd = -1; |
592 | wrcount = 0; | ||
582 | #endif | 593 | #endif |
583 | 594 | ||
584 | while (1) | 595 | while (1) |
@@ -611,7 +622,6 @@ static void power_thread(void) | |||
611 | * If we are charging, the "runtime" is estimated time till the battery | 622 | * If we are charging, the "runtime" is estimated time till the battery |
612 | * is recharged. | 623 | * is recharged. |
613 | */ | 624 | */ |
614 | // TBD: use real charging current estimate | ||
615 | if (charge_state == CHARGING) { | 625 | if (charge_state == CHARGING) { |
616 | powermgmt_est_runningtime_min = (100 - battery_level()) * | 626 | powermgmt_est_runningtime_min = (100 - battery_level()) * |
617 | battery_capacity / 100 * 60 / (CURRENT_MAX_CHG - runcurrent()); | 627 | battery_capacity / 100 * 60 / (CURRENT_MAX_CHG - runcurrent()); |
@@ -638,185 +648,200 @@ static void power_thread(void) | |||
638 | #endif /* # if CONFIG_BATTERY == BATT_LIION2200 */ | 648 | #endif /* # if CONFIG_BATTERY == BATT_LIION2200 */ |
639 | 649 | ||
640 | #ifdef HAVE_CHARGE_CTRL | 650 | #ifdef HAVE_CHARGE_CTRL |
641 | 651 | if (charger_input_state == CHARGER_PLUGGED) { | |
642 | if (charger_inserted()) { | 652 | pid_p = 0; |
653 | pid_i = 0; | ||
654 | snprintf(power_message, POWER_MESSAGE_LEN, "Charger plugged in"); | ||
643 | /* | 655 | /* |
644 | * Time to start charging again? | 656 | * The charger was just plugged in. If the battery level is |
645 | * 1) If we are currently discharging but trickle is enabled, | 657 | * nearly charged, just trickle. If the battery is low, start |
646 | * the charger must have just been plugged in. | 658 | * a full charge cycle. If the battery level is in between, |
647 | * 2) If our battery level falls below the restart level, charge! | 659 | * top-off and then trickle. |
648 | */ | 660 | */ |
649 | if ((charge_state == DISCHARGING) || | 661 | if(battery_percent > START_TOPOFF_CHG) { |
650 | (battery_level() < CHARGE_RESTART)) { | 662 | powermgmt_last_cycle_level = battery_percent; |
651 | 663 | powermgmt_last_cycle_startstop_min = 0; | |
664 | if(battery_percent >= START_TRICKLE_CHG) { | ||
665 | charge_state = TRICKLE; | ||
666 | } else { | ||
667 | charge_state = TOPOFF; | ||
668 | } | ||
669 | } else { | ||
652 | /* | 670 | /* |
653 | * If the battery level is nearly charged, just trickle. | 671 | * Start the charger full strength |
654 | * If the battery is in between, top-off and then trickle. | ||
655 | */ | 672 | */ |
656 | if(battery_percent > CHARGE_RESTART) { | 673 | i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500; |
657 | powermgmt_last_cycle_level = battery_percent; | 674 | charge_max_time_now = |
658 | powermgmt_last_cycle_startstop_min = 0; | 675 | i * (100 + 35 - battery_percent) / 100; |
659 | if(battery_percent >= 95) { | 676 | if (charge_max_time_now > i) { |
660 | trickle_sec = START_TRICKLE_SEC; | 677 | charge_max_time_now = i; |
661 | charge_state = TRICKLE; | ||
662 | } else { | ||
663 | trickle_sec = START_TOPOFF_SEC; | ||
664 | charge_state = TOPOFF; | ||
665 | } | ||
666 | } else { | ||
667 | /* | ||
668 | * Start the charger full strength | ||
669 | */ | ||
670 | i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500; | ||
671 | charge_max_time_now = | ||
672 | i * (100 + 35 - battery_percent) / 100; | ||
673 | if (charge_max_time_now > i) { | ||
674 | charge_max_time_now = i; | ||
675 | } | ||
676 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
677 | "ChgAt %d%% max %dm", battery_level(), | ||
678 | charge_max_time_now); | ||
679 | |||
680 | /* enable the charger after the max time calc is done, | ||
681 | because battery_level depends on if the charger is | ||
682 | on */ | ||
683 | DEBUGF("power: charger inserted and battery" | ||
684 | " not full, enabling\n"); | ||
685 | powermgmt_last_cycle_level = battery_percent; | ||
686 | powermgmt_last_cycle_startstop_min = 0; | ||
687 | trickle_sec = 60; | ||
688 | charge_state = CHARGING; | ||
689 | } | 678 | } |
690 | } | ||
691 | if (charge_state == CHARGING) { | ||
692 | /* charger inserted and enabled 100% of the time */ | ||
693 | trickle_sec = 60; /* 100% on */ | ||
694 | |||
695 | snprintf(power_message, POWER_MESSAGE_LEN, | 679 | snprintf(power_message, POWER_MESSAGE_LEN, |
696 | "Chg %dm, max %dm", powermgmt_last_cycle_startstop_min, | 680 | "ChgAt %d%% max %dm", battery_level(), |
697 | charge_max_time_now); | 681 | charge_max_time_now); |
698 | /* | 682 | |
699 | * Sum the deltas over the last X minutes so we can do our | 683 | /* enable the charger after the max time calc is done, |
700 | * end-of-charge logic based on the battery level change. | 684 | because battery_level depends on if the charger is |
701 | */ | 685 | on */ |
702 | long_delta = short_delta = 999999; | 686 | DEBUGF("power: charger inserted and battery" |
703 | if (powermgmt_last_cycle_startstop_min > CHARGE_MIN_TIME) { | 687 | " not full, charging\n"); |
704 | short_delta = power_history[0] - | 688 | powermgmt_last_cycle_level = battery_percent; |
705 | power_history[CHARGE_END_NEGD - 1]; | 689 | powermgmt_last_cycle_startstop_min = 0; |
706 | } | 690 | trickle_sec = 60; |
707 | if (powermgmt_last_cycle_startstop_min > CHARGE_END_ZEROD) { | 691 | long_delta = short_delta = 999999; |
708 | /* | 692 | charge_state = CHARGING; |
709 | * Scan the history: if we have a big delta in the middle of | 693 | } |
710 | * our history, the long term delta isn't a valid end-of-charge | 694 | } |
711 | * indicator. | 695 | if (charge_state == CHARGING) { |
712 | */ | 696 | snprintf(power_message, POWER_MESSAGE_LEN, |
713 | long_delta = power_history[0] - | 697 | "Chg %dm, max %dm", powermgmt_last_cycle_startstop_min, |
714 | power_history[CHARGE_END_ZEROD - 1]; | 698 | charge_max_time_now); |
715 | for(i = 0; i < CHARGE_END_ZEROD; i++) { | 699 | /* |
716 | if(((power_history[i] - power_history[i+1]) > 5) || | 700 | * Check the delta voltage over the last X minutes so we can do |
717 | ((power_history[i] - power_history[i+1]) < -5)) { | 701 | * our end-of-charge logic based on the battery level change. |
718 | long_delta = 888888; | 702 | */ |
719 | break; | 703 | if (powermgmt_last_cycle_startstop_min > CHARGE_MIN_TIME) { |
720 | } | 704 | short_delta = power_history[0] - |
705 | power_history[CHARGE_END_NEGD - 1]; | ||
706 | } | ||
707 | if (powermgmt_last_cycle_startstop_min > CHARGE_END_ZEROD) { | ||
708 | /* | ||
709 | * Scan the history: if we have a big delta in the middle of | ||
710 | * our history, the long term delta isn't a valid end-of-charge | ||
711 | * indicator. | ||
712 | */ | ||
713 | long_delta = power_history[0] - | ||
714 | power_history[CHARGE_END_ZEROD - 1]; | ||
715 | for(i = 0; i < CHARGE_END_ZEROD; i++) { | ||
716 | if(((power_history[i] - power_history[i+1]) > 5) || | ||
717 | ((power_history[i] - power_history[i+1]) < -5)) { | ||
718 | long_delta = 888888; | ||
719 | break; | ||
721 | } | 720 | } |
722 | } | 721 | } |
722 | } | ||
723 | 723 | ||
724 | /* | 724 | /* |
725 | * End of charge criteria (any qualify): | 725 | * End of charge criteria (any qualify): |
726 | * 1) Charged a long time | 726 | * 1) Charged a long time |
727 | * 2) DeltaV went negative for a short time | 727 | * 2) DeltaV went negative for a short time |
728 | * 3) DeltaV was close to zero for a long time | 728 | * 3) DeltaV was close to zero for a long time |
729 | * Note: short_delta and long_delta are centivolts | 729 | * Note: short_delta and long_delta are centivolts |
730 | */ | 730 | */ |
731 | if ((powermgmt_last_cycle_startstop_min > charge_max_time_now) || | 731 | if ((powermgmt_last_cycle_startstop_min > charge_max_time_now) || |
732 | (short_delta < -5) || (long_delta < 5)) | 732 | (short_delta <= -5) || (long_delta < 5)) |
733 | { | 733 | { |
734 | if (powermgmt_last_cycle_startstop_min > charge_max_time_now) { | 734 | if (powermgmt_last_cycle_startstop_min > charge_max_time_now) { |
735 | DEBUGF("power: powermgmt_last_cycle_startstop_min > charge_max_time_now, " | 735 | DEBUGF("power: powermgmt_last_cycle_startstop_min > charge_max_time_now, " |
736 | "enough!\n"); | 736 | "enough!\n"); |
737 | /* have charged too long and deltaV detection did not | 737 | /* have charged too long and deltaV detection did not |
738 | work! */ | 738 | work! */ |
739 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
740 | "Chg tmout %d min", charge_max_time_now); | ||
741 | /* | ||
742 | * Switch to trickle charging. We skip the top-off | ||
743 | * since we've effectively done the top-off operation | ||
744 | * already since we charged for the maximum full | ||
745 | * charge time. | ||
746 | */ | ||
747 | powermgmt_last_cycle_level = battery_percent; | ||
748 | powermgmt_last_cycle_startstop_min = 0; | ||
749 | charge_state = TRICKLE; | ||
750 | } else { | ||
751 | if(short_delta <= -5) { | ||
752 | DEBUGF("power: short-term negative" | ||
753 | " delta, enough!\n"); | ||
739 | snprintf(power_message, POWER_MESSAGE_LEN, | 754 | snprintf(power_message, POWER_MESSAGE_LEN, |
740 | "Chg tmout %d min", charge_max_time_now); | 755 | "end negd %d %dmin", short_delta, |
756 | powermgmt_last_cycle_startstop_min); | ||
741 | } else { | 757 | } else { |
742 | if(short_delta < -5) { | 758 | DEBUGF("power: long-term small " |
743 | DEBUGF("power: short-term negative" | 759 | "positive delta, enough!\n"); |
744 | " delta, enough!\n"); | 760 | snprintf(power_message, POWER_MESSAGE_LEN, |
745 | snprintf(power_message, POWER_MESSAGE_LEN, | 761 | "end lowd %d %dmin", long_delta, |
746 | "end negd %d %dmin", short_delta, | 762 | powermgmt_last_cycle_startstop_min); |
747 | powermgmt_last_cycle_startstop_min); | ||
748 | } else { | ||
749 | DEBUGF("power: long-term small " | ||
750 | "positive delta, enough!\n"); | ||
751 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
752 | "end lowd %d %dmin", long_delta, | ||
753 | powermgmt_last_cycle_startstop_min); | ||
754 | } | ||
755 | } | 763 | } |
756 | /* Switch to trickle charging. We skip the top-off | 764 | /* |
757 | since we've effectively done the top-off operation | 765 | * Switch to top-off charging. |
758 | already since we charged for the maximum full | 766 | */ |
759 | charge time. For trickle charging, we use 0.05C */ | ||
760 | powermgmt_last_cycle_level = battery_percent; | 767 | powermgmt_last_cycle_level = battery_percent; |
761 | powermgmt_last_cycle_startstop_min = 0; | 768 | powermgmt_last_cycle_startstop_min = 0; |
762 | 769 | charge_state = TOPOFF; | |
763 | trickle_sec = START_TRICKLE_SEC; | ||
764 | charge_state = TRICKLE; | ||
765 | } | 770 | } |
766 | } | 771 | } |
767 | else if (charge_state > CHARGING) /* top off or trickle */ | 772 | } |
773 | else if (charge_state > CHARGING) /* top off or trickle */ | ||
774 | { | ||
775 | /* Time to switch from topoff to trickle? | ||
776 | */ | ||
777 | if ((charge_state == TOPOFF) && | ||
778 | (powermgmt_last_cycle_startstop_min > TOPOFF_MAX_TIME)) | ||
768 | { | 779 | { |
769 | /* Time to switch from topoff to trickle? Note that we don't | 780 | powermgmt_last_cycle_level = battery_percent; |
770 | * adjust trickle_sec: it will get adjusted down by the | 781 | powermgmt_last_cycle_startstop_min = 0; |
771 | * charge level adjustment in the loop and will drift down | 782 | charge_state = TRICKLE; |
772 | * from the topoff level to the trickle level. | 783 | } |
773 | */ | 784 | /* |
774 | if ((charge_state == TOPOFF) && | 785 | * Adjust trickle charge time (proportional and integral terms). |
775 | (powermgmt_last_cycle_startstop_min > TOPOFF_MAX_TIME)) | 786 | * Note: I considered setting the level higher if the USB is |
776 | { | 787 | * plugged in, but it doesn't appear to be necessary and will |
777 | powermgmt_last_cycle_level = battery_percent; | 788 | * generate more heat [gvb]. |
778 | powermgmt_last_cycle_startstop_min = 0; | 789 | */ |
779 | charge_state = TRICKLE; | 790 | if(charge_state == TOPOFF) |
780 | } | 791 | target_voltage = TOPOFF_VOLTAGE; |
781 | 792 | else | |
782 | /* Adjust trickle charge time. I considered setting the level | 793 | target_voltage = TRICKLE_VOLTAGE; |
783 | * higher if the USB is plugged in, but it doesn't appear to | 794 | |
784 | * be necessary and will generate more heat [gvb]. | 795 | pid_p = target_voltage - battery_centivolts; |
785 | */ | 796 | if((pid_p > PID_DEADZONE) || (pid_p < -PID_DEADZONE)) |
786 | if(((charge_state == TOPOFF) && (battery_centivolts > TOPOFF_VOLTAGE)) || | 797 | pid_p = pid_p * PID_PCONST; |
787 | ((charge_state == TRICKLE) && (battery_centivolts > TRICKLE_VOLTAGE))) | 798 | else |
788 | { /* charging too much */ | 799 | pid_p = 0; |
789 | if(trickle_sec > 0) | 800 | if(battery_centivolts < target_voltage) { |
790 | trickle_sec--; | 801 | if(pid_i < 60) { |
802 | pid_i++; /* limit so it doesn't "wind up" */ | ||
791 | } | 803 | } |
792 | else { /* charging too little */ | 804 | } else { |
793 | if(trickle_sec < 60) | 805 | if(pid_i > 0) { |
794 | trickle_sec++; | 806 | pid_i--; /* limit so it doesn't "wind up" */ |
795 | } | 807 | } |
808 | } | ||
809 | |||
810 | trickle_sec = pid_p + pid_i; | ||
796 | 811 | ||
797 | } else if (charge_state == DISCHARGING) { | 812 | if(trickle_sec > 60) { |
813 | trickle_sec = 60; | ||
814 | } | ||
815 | if(trickle_sec < 0) { | ||
798 | trickle_sec = 0; | 816 | trickle_sec = 0; |
799 | /* the charger is enabled here only in one case: if it was | ||
800 | turned on at boot time (power_init) */ | ||
801 | /* turn it off now */ | ||
802 | if (charger_enabled) | ||
803 | charger_enable(false); | ||
804 | } | 817 | } |
805 | } else { | ||
806 | if (charge_state != DISCHARGING) { | ||
807 | /* charger not inserted but was enabled */ | ||
808 | DEBUGF("power: charger disconnected, disabling\n"); | ||
809 | 818 | ||
819 | } else if (charge_state == DISCHARGING) { | ||
820 | trickle_sec = 0; | ||
821 | /* | ||
822 | * The charger is enabled here only in one case: if it was | ||
823 | * turned on at boot time (power_init). Turn it off now. | ||
824 | */ | ||
825 | if (charger_enabled) | ||
810 | charger_enable(false); | 826 | charger_enable(false); |
811 | powermgmt_last_cycle_level = battery_percent; | ||
812 | powermgmt_last_cycle_startstop_min = 0; | ||
813 | trickle_sec = 0; | ||
814 | charge_state = DISCHARGING; | ||
815 | snprintf(power_message, POWER_MESSAGE_LEN, "Charger: discharge"); | ||
816 | } | ||
817 | } | 827 | } |
818 | powermgmt_last_cycle_startstop_min++; | 828 | |
819 | 829 | if (charger_input_state == CHARGER_UNPLUGGED) { | |
830 | /* | ||
831 | * The charger was just unplugged. | ||
832 | */ | ||
833 | DEBUGF("power: charger disconnected, disabling\n"); | ||
834 | |||
835 | charger_enable(false); | ||
836 | powermgmt_last_cycle_level = battery_percent; | ||
837 | powermgmt_last_cycle_startstop_min = 0; | ||
838 | trickle_sec = 0; | ||
839 | pid_p = 0; | ||
840 | pid_i = 0; | ||
841 | charge_state = DISCHARGING; | ||
842 | snprintf(power_message, POWER_MESSAGE_LEN, "Charger: discharge"); | ||
843 | } | ||
844 | |||
820 | #endif /* HAVE_CHARGE_CTRL*/ | 845 | #endif /* HAVE_CHARGE_CTRL*/ |
821 | 846 | ||
822 | /* sleep for a minute */ | 847 | /* sleep for a minute */ |
@@ -834,25 +859,36 @@ static void power_thread(void) | |||
834 | #endif | 859 | #endif |
835 | 860 | ||
836 | #if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL) | 861 | #if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL) |
837 | if((fd < 0) && !usb_inserted()) { | 862 | if(usb_inserted()) { |
838 | fd = open(DEBUG_FILE_NAME, O_WRONLY | O_APPEND | O_CREAT); | 863 | if(fd >= 0) { |
839 | snprintf(debug_message, DEBUG_MESSAGE_LEN, | 864 | /* It is probably too late to close the file but we can try... */ |
840 | "cycle_min, bat_centivolts, bat_percent, chgr, chg_state, trickle_sec\n"); | 865 | close(fd); |
841 | write(fd, debug_message, strlen(debug_message)); | 866 | fd = -1; |
842 | fsync(fd); | 867 | } |
843 | } else if((fd >= 0) && !usb_inserted()) { | 868 | } else { |
844 | snprintf(debug_message, DEBUG_MESSAGE_LEN, "%d, %d, %d, %d, %d, %d\n", | 869 | if(fd < 0) { |
845 | powermgmt_last_cycle_startstop_min, battery_centivolts, | 870 | fd = open(DEBUG_FILE_NAME, O_WRONLY | O_APPEND | O_CREAT); |
846 | battery_percent, charger_inserted(), charge_state, trickle_sec); | 871 | if(fd >= 0) { |
847 | write(fd, debug_message, strlen(debug_message)); | 872 | snprintf(debug_message, DEBUG_MESSAGE_LEN, |
848 | fsync(fd); | 873 | "cycle_min, bat_centivolts, bat_percent, chgr_state, charge_state, pid_p, pid_i, trickle_sec\n"); |
849 | } else if((fd >= 0) && usb_inserted()) { | 874 | write(fd, debug_message, strlen(debug_message)); |
850 | /* NOTE: It is probably already TOO LATE to close the file */ | 875 | wrcount = 99; /* force a flush */ |
851 | close(fd); | 876 | } |
852 | fd = -1; | 877 | } |
878 | if(fd >= 0) { | ||
879 | snprintf(debug_message, DEBUG_MESSAGE_LEN, "%d, %d, %d, %d, %d, %d, %d, %d\n", | ||
880 | powermgmt_last_cycle_startstop_min, battery_centivolts, | ||
881 | battery_percent, charger_input_state, charge_state, pid_p, pid_i, trickle_sec); | ||
882 | write(fd, debug_message, strlen(debug_message)); | ||
883 | wrcount++; | ||
884 | } | ||
853 | } | 885 | } |
854 | #endif | 886 | #endif |
855 | handle_auto_poweroff(); | 887 | handle_auto_poweroff(); |
888 | |||
889 | #ifdef HAVE_CHARGE_CTRL | ||
890 | powermgmt_last_cycle_startstop_min++; | ||
891 | #endif | ||
856 | } | 892 | } |
857 | } | 893 | } |
858 | 894 | ||
@@ -862,10 +898,6 @@ void powermgmt_init(void) | |||
862 | 898 | ||
863 | /* init history to 0 */ | 899 | /* init history to 0 */ |
864 | memset(power_history, 0x00, sizeof(power_history)); | 900 | memset(power_history, 0x00, sizeof(power_history)); |
865 | |||
866 | #ifdef HAVE_CHARGING | ||
867 | charger_power_is_on = charger_inserted(); | ||
868 | #endif | ||
869 | 901 | ||
870 | create_thread(power_thread, power_stack, sizeof(power_stack), | 902 | create_thread(power_thread, power_stack, sizeof(power_stack), |
871 | power_thread_name); | 903 | power_thread_name); |
@@ -876,11 +908,10 @@ void powermgmt_init(void) | |||
876 | /* Various hardware housekeeping tasks relating to shutting down the jukebox */ | 908 | /* Various hardware housekeeping tasks relating to shutting down the jukebox */ |
877 | void shutdown_hw(void) | 909 | void shutdown_hw(void) |
878 | { | 910 | { |
879 | #ifndef SIMULATOR | ||
880 | #if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL) | 911 | #if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL) |
881 | if(fd > 0) { | 912 | if(fd >= 0) { |
882 | close(fd); | 913 | close(fd); |
883 | fd = 0; | 914 | fd = -1; |
884 | } | 915 | } |
885 | #endif | 916 | #endif |
886 | mpeg_stop(); | 917 | mpeg_stop(); |
@@ -899,5 +930,4 @@ void shutdown_hw(void) | |||
899 | lcd_set_contrast(0); | 930 | lcd_set_contrast(0); |
900 | #endif | 931 | #endif |
901 | power_off(); | 932 | power_off(); |
902 | #endif | ||
903 | } | 933 | } |