diff options
author | Barry Wardell <rockbox@barrywardell.net> | 2006-11-11 01:18:57 +0000 |
---|---|---|
committer | Barry Wardell <rockbox@barrywardell.net> | 2006-11-11 01:18:57 +0000 |
commit | 8d2711b7d2d9f19dc2375bd9395359ed725375ab (patch) | |
tree | 788f6dc4e010f7cf6eac2e3a5d3eebe2427fe06e /firmware/powermgmt.c | |
parent | b3d2017057a47b1a5863d4e18e8d3eaf6a2fb63a (diff) | |
download | rockbox-8d2711b7d2d9f19dc2375bd9395359ed725375ab.tar.gz rockbox-8d2711b7d2d9f19dc2375bd9395359ed725375ab.zip |
Improved power management (FS#3001). Shutdown rockbox when the battery gets to a level where the device doesn't function properly. Calculate remaining charging time while charging (rather than remaining running time). Show "Low Battery" and "Battery Empty" warnings. Also fixes FS#4786.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11507 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/powermgmt.c')
-rw-r--r-- | firmware/powermgmt.c | 358 |
1 files changed, 292 insertions, 66 deletions
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index 2ca176d072..d30a31897e 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c | |||
@@ -49,10 +49,15 @@ | |||
49 | #include "wm8758.h" | 49 | #include "wm8758.h" |
50 | #elif defined(HAVE_WM8975) | 50 | #elif defined(HAVE_WM8975) |
51 | #include "wm8975.h" | 51 | #include "wm8975.h" |
52 | #elif defined(HAVE_WM8731) | ||
53 | #include "wm8731l.h" | ||
52 | #endif | 54 | #endif |
53 | #ifdef HAVE_LCD_BITMAP | 55 | #ifdef HAVE_LCD_BITMAP |
54 | #include "font.h" | 56 | #include "font.h" |
55 | #endif | 57 | #endif |
58 | #if defined(HAVE_RECORDING) && (CONFIG_CODEC == SWCODEC) | ||
59 | #include "pcm_record.h" | ||
60 | #endif | ||
56 | #include "logf.h" | 61 | #include "logf.h" |
57 | #include "lcd-remote.h" | 62 | #include "lcd-remote.h" |
58 | #ifdef SIMULATOR | 63 | #ifdef SIMULATOR |
@@ -149,6 +154,11 @@ bool battery_level_safe(void) | |||
149 | return battery_level() >= 10; | 154 | return battery_level() >= 10; |
150 | } | 155 | } |
151 | 156 | ||
157 | bool battery_level_critical(void) | ||
158 | { | ||
159 | return false; | ||
160 | } | ||
161 | |||
152 | void set_poweroff_timeout(int timeout) | 162 | void set_poweroff_timeout(int timeout) |
153 | { | 163 | { |
154 | (void)timeout; | 164 | (void)timeout; |
@@ -173,41 +183,57 @@ static const int poweroff_idle_timeout_value[15] = | |||
173 | 183 | ||
174 | static const unsigned int battery_level_dangerous[BATTERY_TYPES_COUNT] = | 184 | static const unsigned int battery_level_dangerous[BATTERY_TYPES_COUNT] = |
175 | { | 185 | { |
176 | #if CONFIG_BATTERY == BATT_LIION2200 /* FM Recorder, LiIon */ | 186 | #if CONFIG_BATTERY == BATT_LIION2200 /* FM Recorder, LiIon */ |
177 | 280 | 187 | 280 |
178 | #elif CONFIG_BATTERY == BATT_3AAA /* Ondio */ | 188 | #elif CONFIG_BATTERY == BATT_3AAA /* Ondio: Alkaline, NiHM */ |
179 | 310, 345 /* alkaline, NiHM */ | 189 | 310, 345 |
180 | #elif CONFIG_BATTERY == BATT_1AA /* iRiver iFP */ | 190 | #elif CONFIG_BATTERY == BATT_1AA /* iRiver iFP: Alkaline, NiHM */ |
181 | 105, 115 /* alkaline, NiHM */ | 191 | 105, 115 |
182 | #elif CONFIG_BATTERY == BATT_LIPOL1300 /* iRiver H1x0 */ | 192 | #elif CONFIG_BATTERY == BATT_LIPOL1300 /* iRiver H1x0: LiPolymer */ |
183 | 339 | 193 | 338 |
184 | #elif CONFIG_BATTERY == BATT_IAUDIO_X5 | 194 | #elif CONFIG_BATTERY == BATT_IAUDIO_X5 /* iAudio X5 */ |
185 | 354 | 195 | 354 |
186 | #elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB */ | 196 | #elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB: LiPolymer*/ |
187 | 376 | 197 | 376 |
188 | #elif CONFIG_BATTERY == BATT_BP009 /* iriver H10 5/6GB */ | 198 | #elif CONFIG_BATTERY == BATT_BP009 /* iriver H10 5/6GB: LiPolymer */ |
189 | 372 | 199 | 372 |
190 | #else /* Player/recorder, NiMH */ | 200 | #else /* Player/recorder: NiMH */ |
191 | 475 | 201 | 475 |
192 | #endif | 202 | #endif |
193 | }; | 203 | }; |
194 | 204 | ||
195 | static const short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = | 205 | static const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = |
206 | { | ||
207 | #if CONFIG_BATTERY == BATT_LIION2200 /* FM Recorder */ | ||
208 | 258 | ||
209 | #elif CONFIG_BATTERY == BATT_3AAA /* Ondio */ | ||
210 | 270, 280 | ||
211 | #elif CONFIG_BATTERY == BATT_LIPOL1300 /* iRiver Hxxx */ | ||
212 | 299 | ||
213 | #elif CONFIG_BATTERY == BATT_IAUDIO_X5 /* iAudio X5 */ | ||
214 | 350 | ||
215 | #elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB */ | ||
216 | 365 | ||
217 | #elif CONFIG_BATTERY == BATT_BP009 /* iriver H10 5/6GB */ | ||
218 | 365 | ||
219 | #else /* Player/recorder: NiMH */ | ||
220 | 440 | ||
221 | #endif | ||
222 | }; | ||
223 | |||
196 | /* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */ | 224 | /* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */ |
225 | static const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = | ||
197 | { | 226 | { |
198 | #if CONFIG_BATTERY == BATT_LIION2200 | 227 | #if CONFIG_BATTERY == BATT_LIION2200 |
199 | /* measured values */ | 228 | /* measured values */ |
200 | { 260, 285, 295, 303, 311, 320, 330, 345, 360, 380, 400 } | 229 | { 260, 285, 295, 303, 311, 320, 330, 345, 360, 380, 400 } |
201 | #elif CONFIG_BATTERY == BATT_3AAA | 230 | #elif CONFIG_BATTERY == BATT_3AAA |
202 | /* measured values */ | 231 | /* measured values */ |
203 | { 280, 325, 341, 353, 364, 374, 385, 395, 409, 427, 475 }, /* alkaline */ | 232 | { 280, 325, 341, 353, 364, 374, 385, 395, 409, 427, 475 }, /* Alkaline */ |
204 | { 310, 355, 363, 369, 372, 374, 376, 378, 380, 386, 405 } /* NiMH */ | 233 | { 310, 355, 363, 369, 372, 374, 376, 378, 380, 386, 405 } /* NiMH */ |
205 | #elif CONFIG_BATTERY == BATT_LIPOL1300 | 234 | #elif CONFIG_BATTERY == BATT_LIPOL1300 |
206 | /* Below 337 the backlight starts flickering during HD access */ | 235 | /* Below 337 the backlight starts flickering during HD access */ |
207 | /* Calibrated for Ionity 1900 mAh battery. If necessary, re-calibrate | 236 | { 337, 365, 370, 374, 378, 382, 387, 393, 400, 408, 416 } |
208 | * for the 1300 mAh stock battery. */ | ||
209 | // { 337, 358, 365, 369, 372, 377, 383, 389, 397, 406, 413 } | ||
210 | { 337, 366, 372, 374, 378, 381, 385, 392, 399, 408, 417 } | ||
211 | #elif CONFIG_BATTERY == BATT_IAUDIO_X5 | 237 | #elif CONFIG_BATTERY == BATT_IAUDIO_X5 |
212 | /* iAudio x5 series - still experimenting with best curve */ | 238 | /* iAudio x5 series - still experimenting with best curve */ |
213 | // Lithium ion discharge curve | 239 | // Lithium ion discharge curve |
@@ -238,12 +264,11 @@ static const short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = | |||
238 | charger_input_state_type charger_input_state IDATA_ATTR; | 264 | charger_input_state_type charger_input_state IDATA_ATTR; |
239 | 265 | ||
240 | /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ | 266 | /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ |
241 | static const short percent_to_volt_charge[11] = | 267 | static const unsigned short percent_to_volt_charge[11] = |
242 | { | 268 | { |
243 | #if CONFIG_BATTERY == BATT_LIPOL1300 | 269 | #if CONFIG_BATTERY == BATT_LIPOL1300 |
244 | /* Calibrated for 1900 mAh Ionity battery (estimated 90% charge when | 270 | /* values measured over one full charging cycle */ |
245 | entering in trickle-charging). We will never reach 100%. */ | 271 | 354, 386, 393, 398, 400, 402, 404, 408, 413, 418, 423 /* LiPo */ |
246 | 340, 390, 394, 399, 400, 404, 407, 413, 417, 422, 426 | ||
247 | #elif CONFIG_BATTERY == BATT_LPCS355385 | 272 | #elif CONFIG_BATTERY == BATT_LPCS355385 |
248 | /* iriver H10 20GB */ | 273 | /* iriver H10 20GB */ |
249 | 399, 403, 406, 408, 410, 412, 415, 418, 422, 426, 431 | 274 | 399, 403, 406, 408, 410, 412, 415, 418, 422, 426, 431 |
@@ -289,9 +314,15 @@ int pid_i = 0; /* PID integral term */ | |||
289 | * Average battery voltage and charger voltage, filtered via a digital | 314 | * Average battery voltage and charger voltage, filtered via a digital |
290 | * exponential filter. | 315 | * exponential filter. |
291 | */ | 316 | */ |
292 | static unsigned int battery_centivolts;/* filtered battery voltage, centvolts */ | ||
293 | static unsigned int avgbat; /* average battery voltage (filtering) */ | 317 | static unsigned int avgbat; /* average battery voltage (filtering) */ |
294 | #define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */ | 318 | static unsigned int battery_centivolts;/* filtered battery voltage, centvolts */ |
319 | #ifdef HAVE_CHARGE_CTRL | ||
320 | #define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */ | ||
321 | #elif CONFIG_BATTERY == BATT_LIPOL1300 | ||
322 | #define BATT_AVE_SAMPLES 128 /* slow filter for iriver */ | ||
323 | #else | ||
324 | #define BATT_AVE_SAMPLES 64 /* medium filter constant for all others */ | ||
325 | #endif | ||
295 | 326 | ||
296 | /* battery level (0-100%) of this minute, updated once per minute */ | 327 | /* battery level (0-100%) of this minute, updated once per minute */ |
297 | static int battery_percent = -1; | 328 | static int battery_percent = -1; |
@@ -301,11 +332,12 @@ static int battery_type = 0; | |||
301 | /* Power history: power_history[0] is the newest sample */ | 332 | /* Power history: power_history[0] is the newest sample */ |
302 | unsigned short power_history[POWER_HISTORY_LEN]; | 333 | unsigned short power_history[POWER_HISTORY_LEN]; |
303 | 334 | ||
304 | static char power_stack[DEFAULT_STACK_SIZE + DEBUG_STACK]; | 335 | static char power_stack[DEFAULT_STACK_SIZE/2 + DEBUG_STACK]; |
305 | static const char power_thread_name[] = "power"; | 336 | static const char power_thread_name[] = "power"; |
306 | 337 | ||
307 | static int poweroff_timeout = 0; | 338 | static int poweroff_timeout = 0; |
308 | static int powermgmt_est_runningtime_min = -1; | 339 | static int powermgmt_est_runningtime_min = -1; |
340 | static bool low_battery = false; | ||
309 | 341 | ||
310 | static bool sleeptimer_active = false; | 342 | static bool sleeptimer_active = false; |
311 | static long sleeptimer_endtick; | 343 | static long sleeptimer_endtick; |
@@ -331,11 +363,6 @@ void battery_read_info(int *adc, int *voltage, int *level) | |||
331 | *level = voltage_to_battery_level(centivolts); | 363 | *level = voltage_to_battery_level(centivolts); |
332 | } | 364 | } |
333 | 365 | ||
334 | unsigned int battery_voltage(void) | ||
335 | { | ||
336 | return battery_centivolts; | ||
337 | } | ||
338 | |||
339 | void reset_poweroff_timer(void) | 366 | void reset_poweroff_timer(void) |
340 | { | 367 | { |
341 | last_event_tick = current_tick; | 368 | last_event_tick = current_tick; |
@@ -372,12 +399,30 @@ int battery_level(void) | |||
372 | return battery_percent; | 399 | return battery_percent; |
373 | } | 400 | } |
374 | 401 | ||
402 | /* Returns filtered battery voltage [centivolts] */ | ||
403 | unsigned int battery_voltage(void) | ||
404 | { | ||
405 | return battery_centivolts; | ||
406 | } | ||
407 | |||
408 | /* Returns battery voltage from ADC [centivolts] */ | ||
409 | int battery_adc_voltage(void) | ||
410 | { | ||
411 | return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR + 5000) / 10000; | ||
412 | } | ||
413 | |||
375 | /* Tells if the battery level is safe for disk writes */ | 414 | /* Tells if the battery level is safe for disk writes */ |
376 | bool battery_level_safe(void) | 415 | bool battery_level_safe(void) |
377 | { | 416 | { |
378 | return battery_centivolts > battery_level_dangerous[battery_type]; | 417 | return battery_centivolts > battery_level_dangerous[battery_type]; |
379 | } | 418 | } |
380 | 419 | ||
420 | /* Tells if the battery is in critical powersaving state */ | ||
421 | bool battery_level_critical(void) | ||
422 | { | ||
423 | return ((battery_capacity * battery_percent / BATTERY_CAPACITY_MIN) < 10); | ||
424 | } | ||
425 | |||
381 | void set_poweroff_timeout(int timeout) | 426 | void set_poweroff_timeout(int timeout) |
382 | { | 427 | { |
383 | poweroff_timeout = timeout; | 428 | poweroff_timeout = timeout; |
@@ -403,8 +448,7 @@ int get_sleep_timer(void) | |||
403 | return 0; | 448 | return 0; |
404 | } | 449 | } |
405 | 450 | ||
406 | /* look into the percent_to_volt_* table and get a realistic battery level | 451 | /* look into the percent_to_volt_* table and get a realistic battery level */ |
407 | percentage */ | ||
408 | static int voltage_to_percent(int voltage, const short* table) | 452 | static int voltage_to_percent(int voltage, const short* table) |
409 | { | 453 | { |
410 | if (voltage <= table[0]) | 454 | if (voltage <= table[0]) |
@@ -430,7 +474,33 @@ static int voltage_to_battery_level(int battery_centivolts) | |||
430 | { | 474 | { |
431 | int level; | 475 | int level; |
432 | 476 | ||
433 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 477 | #if defined(CONFIG_CHARGER) && CONFIG_BATTERY == BATT_LIPOL1300 |
478 | if (charger_input_state == NO_CHARGER) { | ||
479 | /* discharging. calculate new battery level and average with last */ | ||
480 | level = voltage_to_percent(battery_centivolts, | ||
481 | percent_to_volt_discharge[battery_type]); | ||
482 | if (level != (battery_percent - 1)) | ||
483 | level = (level + battery_percent + 1) / 2; | ||
484 | } | ||
485 | else if (charger_input_state == CHARGER_UNPLUGGED) { | ||
486 | /* just unplugged. adjust filtered values */ | ||
487 | battery_centivolts -= percent_to_volt_charge[battery_percent/10] - | ||
488 | percent_to_volt_discharge[0][battery_percent/10]; | ||
489 | avgbat = battery_centivolts * 10000 * BATT_AVE_SAMPLES; | ||
490 | level = battery_percent; | ||
491 | } | ||
492 | else if (charger_input_state == CHARGER_PLUGGED) { | ||
493 | /* just plugged in. adjust battery values */ | ||
494 | battery_centivolts += percent_to_volt_charge[battery_percent/10] - | ||
495 | percent_to_volt_discharge[0][battery_percent/10]; | ||
496 | avgbat = battery_centivolts * 10000 * BATT_AVE_SAMPLES; | ||
497 | level = MIN(12 * battery_percent / 10, 99); | ||
498 | } | ||
499 | else { /* charging. calculate new battery level */ | ||
500 | level = voltage_to_percent(battery_centivolts, | ||
501 | percent_to_volt_charge); | ||
502 | } | ||
503 | #elif CONFIG_CHARGING >= CHARGING_MONITOR | ||
434 | if (charge_state == DISCHARGING) { | 504 | if (charge_state == DISCHARGING) { |
435 | level = voltage_to_percent(battery_centivolts, | 505 | level = voltage_to_percent(battery_centivolts, |
436 | percent_to_volt_discharge[battery_type]); | 506 | percent_to_volt_discharge[battery_type]); |
@@ -440,7 +510,7 @@ static int voltage_to_battery_level(int battery_centivolts) | |||
440 | level = MIN(voltage_to_percent(battery_centivolts, | 510 | level = MIN(voltage_to_percent(battery_centivolts, |
441 | percent_to_volt_charge), 99); | 511 | percent_to_volt_charge), 99); |
442 | } | 512 | } |
443 | else { /* in topoff/trickle charge, the battery is by definition 100% full */ | 513 | else { /* in topoff/trickle charge, battery is by definition 100% full */ |
444 | level = 100; | 514 | level = 100; |
445 | } | 515 | } |
446 | #else | 516 | #else |
@@ -456,35 +526,71 @@ static void battery_status_update(void) | |||
456 | { | 526 | { |
457 | int level = voltage_to_battery_level(battery_centivolts); | 527 | int level = voltage_to_battery_level(battery_centivolts); |
458 | 528 | ||
459 | #ifndef HAVE_MMC /* this adjustment is only needed for HD based */ | ||
460 | if (battery_percent == -1) { /* first run of this procedure */ | ||
461 | /* The battery voltage is usually a little lower directly after | ||
462 | turning on, because the disk was used heavily. Raise it by 5. % */ | ||
463 | level = (level > 95) ? 100 : level + 5; | ||
464 | } | ||
465 | #endif | ||
466 | battery_percent = level; | ||
467 | 529 | ||
468 | /* calculate estimated remaining running time */ | 530 | /* calculate estimated remaining running time */ |
469 | /* discharging: remaining running time */ | 531 | /* discharging: remaining running time */ |
470 | /* charging: remaining charging time */ | 532 | /* charging: remaining charging time */ |
471 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 533 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
472 | if (charge_state == CHARGING) { | 534 | if (charge_state == CHARGING) { |
473 | powermgmt_est_runningtime_min = (100 - level) * battery_capacity / 100 | 535 | powermgmt_est_runningtime_min = (100 - level) * battery_capacity * 60 |
474 | * 60 / (CURRENT_MAX_CHG - runcurrent()); | 536 | / 100 / (CURRENT_MAX_CHG - runcurrent()); |
475 | } | 537 | } |
476 | else | 538 | else |
539 | #elif defined(CONFIG_CHARGING) && CONFIG_BATTERY == BATT_LIPOL1300 | ||
540 | if (charger_inserted()) { | ||
541 | #ifdef IRIVER_H300_SERIES | ||
542 | /* H300_SERIES use CURRENT_MAX_CHG for basic charge time (80%) | ||
543 | * plus 110 min top off charge time */ | ||
544 | powermgmt_est_runningtime_min = ((100-level) * battery_capacity * 80 | ||
545 | /100 / CURRENT_MAX_CHG) + 110; | ||
546 | #else | ||
547 | /* H100_SERIES scaled for 160 min basic charge time (80%) on | ||
548 | * 1600 mAh battery plus 110 min top off charge time */ | ||
549 | powermgmt_est_runningtime_min = ((100 - level) * battery_capacity | ||
550 | / 993) + 110; | ||
551 | #endif | ||
552 | level = (level * 80) / 100; | ||
553 | if (level > 72) { /* > 91% */ | ||
554 | int i = POWER_HISTORY_LEN; | ||
555 | int d = 1; | ||
556 | #ifdef HAVE_CHARGE_STATE | ||
557 | if (charge_state == DISCHARGING) | ||
558 | d = -2; | ||
477 | #endif | 559 | #endif |
560 | while ((i > 2) && (d > 0)) /* search zero or neg. delta */ | ||
561 | d = power_history[0] - power_history[--i]; | ||
562 | if ((((d == 0) && (i > 6)) || (d == -1)) && (i < 118)) { | ||
563 | /* top off charging */ | ||
564 | level = MIN(80 + (i*19 / 113), 99); /* show 81% .. 99% */ | ||
565 | powermgmt_est_runningtime_min = MAX(116 - i, 0); | ||
566 | } | ||
567 | else if ((d < 0) || (i > 117)) { | ||
568 | /* charging finished */ | ||
569 | level = 100; | ||
570 | powermgmt_est_runningtime_min = battery_capacity * 60 | ||
571 | / runcurrent(); | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | else | ||
576 | #endif /* BATT_LIPOL1300 */ | ||
478 | { | 577 | { |
479 | powermgmt_est_runningtime_min = level * battery_capacity / 100 | 578 | if ((battery_centivolts + 2) > percent_to_volt_discharge[0][0]) |
480 | * 60 / runcurrent(); | 579 | powermgmt_est_runningtime_min = (level + battery_percent) * 60 * |
580 | battery_capacity / 200 / runcurrent(); | ||
581 | else | ||
582 | powermgmt_est_runningtime_min = (battery_centivolts - | ||
583 | battery_level_shutoff[0]) / 2; | ||
481 | } | 584 | } |
585 | |||
586 | battery_percent = level; | ||
482 | } | 587 | } |
483 | 588 | ||
484 | /* | 589 | /* |
485 | * We shut off in the following cases: | 590 | * We shut off in the following cases: |
486 | * 1) The unit is idle, not playing music | 591 | * 1) The unit is idle, not playing music |
487 | * 2) The unit is playing music, but is paused | 592 | * 2) The unit is playing music, but is paused |
593 | * 3) The battery level has reached shutdown limit | ||
488 | * | 594 | * |
489 | * We do not shut off in the following cases: | 595 | * We do not shut off in the following cases: |
490 | * 1) The USB is connected | 596 | * 1) The USB is connected |
@@ -507,6 +613,41 @@ static void handle_auto_poweroff(void) | |||
507 | } | 613 | } |
508 | #endif | 614 | #endif |
509 | 615 | ||
616 | /* For low battery condition do some power-saving stuff */ | ||
617 | if (!low_battery && battery_level_critical()) { | ||
618 | #if CONFIG_BACKLIGHT == BL_IRIVER_H100 | ||
619 | backlight_set_fade_in(0); | ||
620 | backlight_set_fade_out(0); | ||
621 | #endif | ||
622 | #if defined(CONFIG_BACKLIGHT) && !defined(BOOTLOADER) | ||
623 | if (backlight_get_current_timeout() > 2) | ||
624 | #endif | ||
625 | backlight_set_timeout(2); | ||
626 | #ifdef HAVE_REMOTE_LCD | ||
627 | remote_backlight_set_timeout(2); | ||
628 | #endif | ||
629 | ata_spindown(3); | ||
630 | #ifdef HAVE_ATA_POWER_OFF | ||
631 | ata_poweroff(true); | ||
632 | #endif | ||
633 | low_battery = true; | ||
634 | } else if (low_battery && (battery_percent > 11)) { | ||
635 | backlight_set_timeout(10); | ||
636 | ata_spindown(10); | ||
637 | low_battery = false; | ||
638 | } | ||
639 | |||
640 | /* switch off unit if battery level is too low for reliable operation */ | ||
641 | #if (CONFIG_BATTERY!=BATT_4AA_NIMH) && (CONFIG_BATTERY!=BATT_3AAA)&& \ | ||
642 | (CONFIG_BATTERY!=BATT_1AA) | ||
643 | if(battery_centivolts < battery_level_shutoff[battery_type]) { | ||
644 | if(!shutdown_timeout) { | ||
645 | backlight_on(); | ||
646 | sys_poweroff(); | ||
647 | } | ||
648 | } | ||
649 | #endif | ||
650 | |||
510 | if(timeout && | 651 | if(timeout && |
511 | #if defined(CONFIG_TUNER) && !defined(BOOTLOADER) | 652 | #if defined(CONFIG_TUNER) && !defined(BOOTLOADER) |
512 | (!(get_radio_status() & FMRADIO_PLAYING)) && | 653 | (!(get_radio_status() & FMRADIO_PLAYING)) && |
@@ -581,6 +722,30 @@ static int runcurrent(void) | |||
581 | current += CURRENT_BACKLIGHT; | 722 | current += CURRENT_BACKLIGHT; |
582 | #endif | 723 | #endif |
583 | 724 | ||
725 | #if defined(HAVE_RECORDING) && defined(CURRENT_RECORD) | ||
726 | #if CONFIG_CODEC == SWCODEC | ||
727 | unsigned int audio_stat = pcm_rec_status(); | ||
728 | #else | ||
729 | int audio_stat = audio_status(); | ||
730 | #endif | ||
731 | if (audio_stat & AUDIO_STATUS_RECORD) | ||
732 | current += CURRENT_RECORD; | ||
733 | #endif | ||
734 | |||
735 | #ifdef HAVE_SPDIF_POWER | ||
736 | #ifdef SPDIF_POWER_INVERTED | ||
737 | if (GPIO1_OUT & 0x01000000) | ||
738 | #else | ||
739 | if (!(GPIO1_OUT & 0x01000000)) | ||
740 | #endif | ||
741 | current += CURRENT_SPDIF_OUT; | ||
742 | #endif | ||
743 | |||
744 | #ifdef HAVE_REMOTE_LCD | ||
745 | if ((GPIO_READ & 0x40000000) == 0) | ||
746 | current += CURRENT_REMOTE; | ||
747 | #endif | ||
748 | |||
584 | return(current); | 749 | return(current); |
585 | } | 750 | } |
586 | 751 | ||
@@ -689,17 +854,31 @@ static void power_thread_sleep(int ticks) | |||
689 | * likely always be spinning in USB mode). | 854 | * likely always be spinning in USB mode). |
690 | */ | 855 | */ |
691 | if (!ata_disk_is_active() || usb_inserted()) { | 856 | if (!ata_disk_is_active() || usb_inserted()) { |
692 | avgbat = avgbat - (avgbat / BATT_AVE_SAMPLES) + | 857 | avgbat += adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR |
693 | adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR; | 858 | - (avgbat / BATT_AVE_SAMPLES); |
694 | /* | 859 | /* |
695 | * battery_centivolts is the centivolt-scaled filtered battery value. | 860 | * battery_centivolts is the centivolt-scaled filtered battery value. |
696 | */ | 861 | */ |
697 | battery_centivolts = avgbat / BATT_AVE_SAMPLES / 10000; | 862 | battery_centivolts = (avgbat / BATT_AVE_SAMPLES + 5000) / 10000; |
698 | |||
699 | /* update battery status every time an update is available */ | ||
700 | battery_status_update(); | ||
701 | |||
702 | } | 863 | } |
864 | else if (battery_percent < 8) { | ||
865 | /* If battery is low, observe voltage during disk activity. | ||
866 | * Shut down if voltage drops below shutoff level and we are not | ||
867 | * using NiMH or Alkaline batteries. | ||
868 | */ | ||
869 | battery_centivolts = (battery_adc_voltage() + | ||
870 | battery_centivolts + 1) / 2; | ||
871 | #if (CONFIG_BATTERY!=BATT_4AA_NIMH) && (CONFIG_BATTERY!=BATT_3AAA)&& \ | ||
872 | (CONFIG_BATTERY!=BATT_1AA) | ||
873 | if (!shutdown_timeout && | ||
874 | (battery_centivolts < battery_level_shutoff[battery_type])) | ||
875 | sys_poweroff(); | ||
876 | else | ||
877 | #endif | ||
878 | avgbat += battery_centivolts * 10000 | ||
879 | - (avgbat / BATT_AVE_SAMPLES); | ||
880 | } | ||
881 | |||
703 | #if CONFIG_CHARGING == CHARGING_CONTROL | 882 | #if CONFIG_CHARGING == CHARGING_CONTROL |
704 | if (ata_disk_is_active()) { | 883 | if (ata_disk_is_active()) { |
705 | /* flag hdd use for charging calculation */ | 884 | /* flag hdd use for charging calculation */ |
@@ -711,8 +890,7 @@ static void power_thread_sleep(int ticks) | |||
711 | * If we have a lot of pending writes or if the disk is spining, | 890 | * If we have a lot of pending writes or if the disk is spining, |
712 | * fsync the debug log file. | 891 | * fsync the debug log file. |
713 | */ | 892 | */ |
714 | if((wrcount > 10) || | 893 | if((wrcount > 10) || ((wrcount > 0) && ata_disk_is_active())) { |
715 | ((wrcount > 0) && ata_disk_is_active())) { | ||
716 | fsync(fd); | 894 | fsync(fd); |
717 | wrcount = 0; | 895 | wrcount = 0; |
718 | } | 896 | } |
@@ -745,10 +923,35 @@ static void power_thread(void) | |||
745 | #endif | 923 | #endif |
746 | 924 | ||
747 | /* initialize the voltages for the exponential filter */ | 925 | /* initialize the voltages for the exponential filter */ |
748 | avgbat = adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR * | 926 | avgbat = adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR + 15000; |
749 | BATT_AVE_SAMPLES; | 927 | |
928 | #ifndef HAVE_MMC /* this adjustment is only needed for HD based */ | ||
929 | /* The battery voltage is usually a little lower directly after | ||
930 | turning on, because the disk was used heavily. Raise it by 5% */ | ||
931 | #ifdef HAVE_CHARGING | ||
932 | if(!charger_inserted()) /* only if charger not connected */ | ||
933 | #endif | ||
934 | avgbat += (percent_to_volt_discharge[battery_type][6] - | ||
935 | percent_to_volt_discharge[battery_type][5]) * 5000; | ||
936 | #endif /* not HAVE_MMC */ | ||
937 | |||
938 | avgbat = avgbat * BATT_AVE_SAMPLES; | ||
750 | battery_centivolts = avgbat / BATT_AVE_SAMPLES / 10000; | 939 | battery_centivolts = avgbat / BATT_AVE_SAMPLES / 10000; |
751 | 940 | ||
941 | #ifdef CONFIG_CHARING | ||
942 | if(charger_inserted()) { | ||
943 | battery_percent = voltage_to_percent(battery_centivolts, | ||
944 | percent_to_volt_charge); | ||
945 | #if CONFIG_BATTERY == BATT_LIPOL1300 | ||
946 | charger_input_state = CHARGER; | ||
947 | #endif | ||
948 | } else | ||
949 | #endif | ||
950 | { battery_percent = voltage_to_percent(battery_centivolts, | ||
951 | percent_to_volt_discharge[battery_type]); | ||
952 | battery_percent += (battery_percent < 100); | ||
953 | } | ||
954 | |||
752 | #if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL) | 955 | #if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL) |
753 | fd = -1; | 956 | fd = -1; |
754 | wrcount = 0; | 957 | wrcount = 0; |
@@ -954,7 +1157,7 @@ static void power_thread(void) | |||
954 | pid_p = pid_p * PID_PCONST; | 1157 | pid_p = pid_p * PID_PCONST; |
955 | else | 1158 | else |
956 | pid_p = 0; | 1159 | pid_p = 0; |
957 | if(battery_centivolts < target_voltage) { | 1160 | if((unsigned) battery_centivolts < target_voltage) { |
958 | if(pid_i < 60) { | 1161 | if(pid_i < 60) { |
959 | pid_i++; /* limit so it doesn't "wind up" */ | 1162 | pid_i++; /* limit so it doesn't "wind up" */ |
960 | } | 1163 | } |
@@ -1067,7 +1270,18 @@ void sys_poweroff(void) | |||
1067 | /* If the main thread fails to shut down the system, we will force a | 1270 | /* If the main thread fails to shut down the system, we will force a |
1068 | power off after an 20 second timeout */ | 1271 | power off after an 20 second timeout */ |
1069 | shutdown_timeout = HZ*20; | 1272 | shutdown_timeout = HZ*20; |
1070 | 1273 | #if defined(HAVE_RECORDING) | |
1274 | #if CONFIG_CODEC == SWCODEC | ||
1275 | unsigned int audio_stat = pcm_rec_status(); | ||
1276 | #else | ||
1277 | int audio_stat = audio_status(); | ||
1278 | #endif | ||
1279 | if (audio_stat & AUDIO_STATUS_RECORD) { | ||
1280 | audio_stop_recording(); | ||
1281 | shutdown_timeout += 8*HZ; | ||
1282 | } | ||
1283 | #endif | ||
1284 | |||
1071 | queue_post(&button_queue, SYS_POWEROFF, NULL); | 1285 | queue_post(&button_queue, SYS_POWEROFF, NULL); |
1072 | } | 1286 | } |
1073 | 1287 | ||
@@ -1095,30 +1309,42 @@ void shutdown_hw(void) | |||
1095 | } | 1309 | } |
1096 | #endif | 1310 | #endif |
1097 | audio_stop(); | 1311 | audio_stop(); |
1312 | if (!battery_level_critical()) { /* do not save on critical battery */ | ||
1098 | #ifdef HAVE_LCD_BITMAP | 1313 | #ifdef HAVE_LCD_BITMAP |
1099 | glyph_cache_save(); | 1314 | glyph_cache_save(); |
1100 | #endif | 1315 | #endif |
1101 | ata_spindown(1); | 1316 | if(ata_disk_is_active()) |
1317 | ata_spindown(1); | ||
1318 | } | ||
1102 | while(ata_disk_is_active()) | 1319 | while(ata_disk_is_active()) |
1103 | sleep(HZ/10); | 1320 | sleep(HZ/10); |
1104 | 1321 | ||
1322 | #ifndef IAUDIO_X5 | ||
1323 | #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR) | ||
1324 | backlight_set_fade_out(0); | ||
1325 | #endif | ||
1326 | backlight_off(); | ||
1327 | #endif /* IAUDIO_X5 */ | ||
1328 | #ifdef HAVE_REMOTE_LCD | ||
1329 | remote_backlight_off(); | ||
1330 | #endif | ||
1331 | |||
1105 | mp3_shutdown(); | 1332 | mp3_shutdown(); |
1106 | #ifdef HAVE_UDA1380 | 1333 | #ifdef HAVE_UDA1380 |
1107 | uda1380_close(); | 1334 | uda1380_close(); |
1108 | #elif defined(HAVE_TLV320) | 1335 | #elif defined(HAVE_TLV320) |
1109 | tlv320_close(); | 1336 | tlv320_close(); |
1110 | #elif defined(HAVE_WM8758) || defined(HAVE_WM8975) | 1337 | #elif defined(HAVE_WM8758) || defined(HAVE_WM8975) | defined(HAVE_WM8731) |
1111 | wmcodec_close(); | 1338 | wmcodec_close(); |
1112 | #endif | 1339 | #endif |
1340 | /* If HD is still active we try to wait for spindown, otherwise the | ||
1341 | shutdown_timeout in power_thread_sleep will force a power off */ | ||
1342 | while(ata_disk_is_active()) | ||
1343 | sleep(HZ/10); | ||
1113 | #ifndef IAUDIO_X5 | 1344 | #ifndef IAUDIO_X5 |
1114 | #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR) | ||
1115 | backlight_set_fade_out(0); | ||
1116 | #endif | ||
1117 | backlight_off(); | ||
1118 | lcd_set_contrast(0); | 1345 | lcd_set_contrast(0); |
1119 | #endif /* IAUDIO_X5 */ | 1346 | #endif /* IAUDIO_X5 */ |
1120 | #ifdef HAVE_REMOTE_LCD | 1347 | #ifdef HAVE_REMOTE_LCD |
1121 | remote_backlight_off(); | ||
1122 | lcd_remote_set_contrast(0); | 1348 | lcd_remote_set_contrast(0); |
1123 | #endif | 1349 | #endif |
1124 | power_off(); | 1350 | power_off(); |