summaryrefslogtreecommitdiff
path: root/firmware/powermgmt.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2012-01-03 23:44:38 +0000
committerThomas Martitz <kugel@rockbox.org>2012-01-03 23:44:38 +0000
commitc1bd9b0361ba92c29ceef68d74093e70a1a3e481 (patch)
tree1a42acdf2099b7f5ac06eee11e1d488b388c6d9f /firmware/powermgmt.c
parent949e6398c89e3c277a4c542f67a5ee788c6f642d (diff)
downloadrockbox-c1bd9b0361ba92c29ceef68d74093e70a1a3e481.tar.gz
rockbox-c1bd9b0361ba92c29ceef68d74093e70a1a3e481.zip
Rework powermgmt to enable code re-use on appliation and sims.
* Introduce CONFIG_BATTERY_MEASURE define, to allow targets (application) to break powermgmt.c's assumption about the ability to read battery voltage. There's now additionally percentage (android) and remaining time measure (maemo). No measure at all also works (sdl app). If voltage can't be measured, then battery_level() is king and it'll be used for power_history and runtime estimation. * Implement target's API in the simulator, i.e. _battery_voltage(), so it doesn't need to implement it's own powermgmt.c and other stubs. Now the sim behaves much more like a native target, although it still changes the simulated battery voltage quickly, * Other changes include include renaming battery_adc_voltage() to _battery_voltage(), for consistency with the new target functions and making some of the apps code aware that voltage and runtime estimation is not always available. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31548 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/powermgmt.c')
-rw-r--r--firmware/powermgmt.c252
1 files changed, 169 insertions, 83 deletions
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index 008e4a45cb..b4f8aab815 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -86,7 +86,14 @@ void handle_auto_poweroff(void);
86static int poweroff_timeout = 0; 86static int poweroff_timeout = 0;
87static long last_event_tick = 0; 87static long last_event_tick = 0;
88 88
89#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) 89#if (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) == PERCENTAGE_MEASURE
90int _battery_voltage(void) { return -1; }
91
92const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
93const unsigned short percent_to_volt_charge[11];
94
95#elif (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE) == VOLTAGE_MEASURE
96int _battery_level(void) { return -1; }
90/* 97/*
91 * Average battery voltage and charger voltage, filtered via a digital 98 * Average battery voltage and charger voltage, filtered via a digital
92 * exponential filter (aka. exponential moving average, scaled): 99 * exponential filter (aka. exponential moving average, scaled):
@@ -95,10 +102,22 @@ static long last_event_tick = 0;
95static unsigned int avgbat; 102static unsigned int avgbat;
96/* filtered battery voltage, millivolts */ 103/* filtered battery voltage, millivolts */
97static unsigned int battery_millivolts; 104static unsigned int battery_millivolts;
105#elif (CONFIG_BATTERY_MEASURE == 0)
106int _battery_voltage(void) { return -1; }
107int _battery_level(void) { return -1; }
108
109const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
110const unsigned short percent_to_volt_charge[11];
111#endif
112
113#if !(CONFIG_BATTERY_MEASURE & TIME_MEASURE)
114static int powermgmt_est_runningtime_min;
115int _battery_time(void) { return powermgmt_est_runningtime_min; }
116#endif
117
98/* default value, mAh */ 118/* default value, mAh */
99static int battery_capacity = BATTERY_CAPACITY_DEFAULT; 119static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
100 120
101
102#if BATTERY_TYPES_COUNT > 1 121#if BATTERY_TYPES_COUNT > 1
103static int battery_type = 0; 122static int battery_type = 0;
104#else 123#else
@@ -115,7 +134,6 @@ static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK];
115#endif 134#endif
116static const char power_thread_name[] = "power"; 135static const char power_thread_name[] = "power";
117 136
118static int powermgmt_est_runningtime_min = -1;
119 137
120static int voltage_to_battery_level(int battery_millivolts); 138static int voltage_to_battery_level(int battery_millivolts);
121static void battery_status_update(void); 139static void battery_status_update(void);
@@ -126,13 +144,18 @@ static int runcurrent(void);
126 144
127void battery_read_info(int *voltage, int *level) 145void battery_read_info(int *voltage, int *level)
128{ 146{
129 int millivolts = battery_adc_voltage(); 147 int millivolts = _battery_voltage();
148 int percent;
130 149
131 if (voltage) 150 if (voltage)
132 *voltage = millivolts; 151 *voltage = millivolts;
133 152
134 if (level) 153 if (level) {
135 *level = voltage_to_battery_level(millivolts); 154 percent = voltage_to_battery_level(millivolts);
155 if (percent < 0)
156 percent = _battery_level();
157 *level = percent;
158 }
136} 159}
137 160
138#if BATTERY_TYPES_COUNT > 1 161#if BATTERY_TYPES_COUNT > 1
@@ -148,6 +171,7 @@ void set_battery_type(int type)
148} 171}
149#endif 172#endif
150 173
174#ifdef BATTERY_CAPACITY_MIN
151void set_battery_capacity(int capacity) 175void set_battery_capacity(int capacity)
152{ 176{
153 if (capacity > BATTERY_CAPACITY_MAX) 177 if (capacity > BATTERY_CAPACITY_MAX)
@@ -159,6 +183,7 @@ void set_battery_capacity(int capacity)
159 183
160 battery_status_update(); /* recalculate the battery status */ 184 battery_status_update(); /* recalculate the battery status */
161} 185}
186#endif
162 187
163int get_battery_capacity(void) 188int get_battery_capacity(void)
164{ 189{
@@ -167,7 +192,16 @@ int get_battery_capacity(void)
167 192
168int battery_time(void) 193int battery_time(void)
169{ 194{
170 return powermgmt_est_runningtime_min; 195#if ((CONFIG_BATTERY_MEASURE & TIME_MEASURE) == 0)
196
197#ifndef CURRENT_NORMAL /* no estimation without current */
198 return -1;
199#endif
200 if (battery_capacity <= 0) /* nor without capacity */
201 return -1;
202
203#endif
204 return _battery_time();
171} 205}
172 206
173/* Returns battery level in percent */ 207/* Returns battery level in percent */
@@ -180,17 +214,13 @@ int battery_level(void)
180 return battery_percent; 214 return battery_percent;
181} 215}
182 216
183/* Returns filtered battery voltage [millivolts] */
184unsigned int battery_voltage(void)
185{
186 return battery_millivolts;
187}
188
189/* Tells if the battery level is safe for disk writes */ 217/* Tells if the battery level is safe for disk writes */
190bool battery_level_safe(void) 218bool battery_level_safe(void)
191{ 219{
192#if defined(NO_LOW_BATTERY_SHUTDOWN) 220#if defined(NO_LOW_BATTERY_SHUTDOWN)
193 return true; 221 return true;
222#elif (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE)
223 return (battery_percent > 0);
194#elif defined(HAVE_BATTERY_SWITCH) 224#elif defined(HAVE_BATTERY_SWITCH)
195 /* Cannot rely upon the battery reading to be valid and the 225 /* Cannot rely upon the battery reading to be valid and the
196 * device could be powered externally. */ 226 * device could be powered externally. */
@@ -228,6 +258,9 @@ static int voltage_to_battery_level(int battery_millivolts)
228{ 258{
229 int level; 259 int level;
230 260
261 if (battery_millivolts < 0)
262 return -1;
263
231#if CONFIG_CHARGING >= CHARGING_MONITOR 264#if CONFIG_CHARGING >= CHARGING_MONITOR
232 if (charging_state()) { 265 if (charging_state()) {
233 /* battery level is defined to be < 100% until charging is finished */ 266 /* battery level is defined to be < 100% until charging is finished */
@@ -249,7 +282,8 @@ static int voltage_to_battery_level(int battery_millivolts)
249 282
250static void battery_status_update(void) 283static void battery_status_update(void)
251{ 284{
252 int level = voltage_to_battery_level(battery_millivolts); 285 int millivolt, level;
286 battery_read_info(&millivolt, &level);
253 287
254#ifdef CURRENT_NORMAL /*don't try to estimate run or charge 288#ifdef CURRENT_NORMAL /*don't try to estimate run or charge
255 time without normal current defined*/ 289 time without normal current defined*/
@@ -264,7 +298,8 @@ static void battery_status_update(void)
264#endif 298#endif
265 299
266 /* discharging: remaining running time */ 300 /* discharging: remaining running time */
267 if (battery_millivolts > percent_to_volt_discharge[0][0]) { 301 if (level > 0 && (millivolt > percent_to_volt_discharge[battery_type][0]
302 || millivolt < 0)) {
268 /* linear extrapolation */ 303 /* linear extrapolation */
269 powermgmt_est_runningtime_min = (level + battery_percent)*60 304 powermgmt_est_runningtime_min = (level + battery_percent)*60
270 * battery_capacity / 200 / runcurrent(); 305 * battery_capacity / 200 / runcurrent();
@@ -272,8 +307,6 @@ static void battery_status_update(void)
272 if (0 > powermgmt_est_runningtime_min) { 307 if (0 > powermgmt_est_runningtime_min) {
273 powermgmt_est_runningtime_min = 0; 308 powermgmt_est_runningtime_min = 0;
274 } 309 }
275#else
276 powermgmt_est_runningtime_min=-1;
277#endif 310#endif
278 311
279 battery_percent = level; 312 battery_percent = level;
@@ -348,6 +381,8 @@ bool query_force_shutdown(void)
348{ 381{
349#if defined(NO_LOW_BATTERY_SHUTDOWN) 382#if defined(NO_LOW_BATTERY_SHUTDOWN)
350 return false; 383 return false;
384#elif CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE
385 return battery_percent == 0;
351#elif defined(HAVE_BATTERY_SWITCH) 386#elif defined(HAVE_BATTERY_SWITCH)
352 /* Cannot rely upon the battery reading to be valid and the 387 /* Cannot rely upon the battery reading to be valid and the
353 * device could be powered externally. */ 388 * device could be powered externally. */
@@ -490,6 +525,101 @@ static inline bool detect_charger(unsigned int pwr)
490} 525}
491#endif /* CONFIG_CHARGING */ 526#endif /* CONFIG_CHARGING */
492 527
528
529#if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
530/* Returns filtered battery voltage [millivolts] */
531int battery_voltage(void)
532{
533 return battery_millivolts;
534}
535
536static void average_init(void)
537{
538 /* initialize the voltages for the exponential filter */
539 avgbat = _battery_voltage() + 15;
540
541#ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */
542 /* The battery voltage is usually a little lower directly after
543 turning on, because the disk was used heavily. Raise it by 5% */
544#if CONFIG_CHARGING
545 if (!charger_inserted()) /* only if charger not connected */
546#endif
547 {
548 avgbat += (percent_to_volt_discharge[battery_type][6] -
549 percent_to_volt_discharge[battery_type][5]) / 2;
550 }
551#endif /* HAVE_DISK_STORAGE */
552
553 avgbat = avgbat * BATT_AVE_SAMPLES;
554 battery_millivolts = power_history[0] = avgbat / BATT_AVE_SAMPLES;
555}
556
557static void average_step(void)
558{
559 avgbat += _battery_voltage() - avgbat / BATT_AVE_SAMPLES;
560 /*
561 * battery_millivolts is the millivolt-scaled filtered battery value.
562 */
563 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
564}
565
566static void average_step_low(void)
567{
568 battery_millivolts = (_battery_voltage() + battery_millivolts + 1) / 2;
569 avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES;
570}
571
572static void init_battery_percent(void)
573{
574#if CONFIG_CHARGING
575 if (charger_inserted()) {
576 battery_percent = voltage_to_percent(battery_millivolts,
577 percent_to_volt_charge);
578 }
579 else
580#endif
581 {
582 battery_percent = voltage_to_percent(battery_millivolts,
583 percent_to_volt_discharge[battery_type]);
584 battery_percent += battery_percent < 100;
585 }
586
587}
588
589static int power_hist_item(void)
590{
591 return battery_millivolts;
592}
593#define power_history_unit() battery_millivolts
594
595#else
596int battery_voltage(void)
597{
598 return -1;
599}
600
601static void average_init(void) {}
602static void average_step(void) {}
603static void average_step_low(void) {}
604static void init_battery_percent(void)
605{
606 battery_percent = _battery_level();
607}
608
609static int power_hist_item(void)
610{
611 return battery_percent;
612}
613#endif
614
615static void collect_power_history(void)
616{
617 /* rotate the power history */
618 memmove(&power_history[1], &power_history[0],
619 sizeof(power_history) - sizeof(power_history[0]));
620 power_history[0] = power_hist_item();
621}
622
493/* 623/*
494 * Monitor the presence of a charger and perform critical frequent steps 624 * Monitor the presence of a charger and perform critical frequent steps
495 * such as running the battery voltage filter. 625 * such as running the battery voltage filter.
@@ -519,33 +649,23 @@ static inline void power_thread_step(void)
519 || charger_input_state == CHARGER 649 || charger_input_state == CHARGER
520#endif 650#endif
521 ) { 651 ) {
522 avgbat += battery_adc_voltage() - avgbat / BATT_AVE_SAMPLES; 652 average_step();
523 /*
524 * battery_millivolts is the millivolt-scaled filtered battery value.
525 */
526 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
527
528 /* update battery status every time an update is available */ 653 /* update battery status every time an update is available */
529 battery_status_update(); 654 battery_status_update();
530 } 655 }
531 else if (battery_percent < 8) { 656 else if (battery_percent < 8) {
657 average_step_low();
658 /* update battery status every time an update is available */
659 battery_status_update();
660
532 /* 661 /*
533 * If battery is low, observe voltage during disk activity. 662 * If battery is low, observe voltage during disk activity.
534 * Shut down if voltage drops below shutoff level and we are not 663 * Shut down if voltage drops below shutoff level and we are not
535 * using NiMH or Alkaline batteries. 664 * using NiMH or Alkaline batteries.
536 */ 665 */
537 battery_millivolts = (battery_adc_voltage() +
538 battery_millivolts + 1) / 2;
539
540 /* update battery status every time an update is available */
541 battery_status_update();
542
543 if (!shutdown_timeout && query_force_shutdown()) { 666 if (!shutdown_timeout && query_force_shutdown()) {
544 sys_poweroff(); 667 sys_poweroff();
545 } 668 }
546 else {
547 avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES;
548 }
549 } 669 }
550} /* power_thread_step */ 670} /* power_thread_step */
551 671
@@ -555,7 +675,7 @@ static void power_thread(void)
555 675
556 /* Delay reading the first battery level */ 676 /* Delay reading the first battery level */
557#ifdef MROBE_100 677#ifdef MROBE_100
558 while (battery_adc_voltage() > 4200) /* gives false readings initially */ 678 while (_battery_voltage() > 4200) /* gives false readings initially */
559#endif 679#endif
560 { 680 {
561 sleep(HZ/100); 681 sleep(HZ/100);
@@ -566,38 +686,13 @@ static void power_thread(void)
566 power_thread_inputs = power_input_status(); 686 power_thread_inputs = power_input_status();
567#endif 687#endif
568 688
569 /* initialize the voltages for the exponential filter */ 689 /* initialize voltage averaging (if available) */
570 avgbat = battery_adc_voltage() + 15; 690 average_init();
571 691 /* get initial battery level value (in %) */
572#ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */ 692 init_battery_percent();
573 /* The battery voltage is usually a little lower directly after 693 /* get some initial data for the power curve */
574 turning on, because the disk was used heavily. Raise it by 5% */ 694 collect_power_history();
575#if CONFIG_CHARGING 695 /* call target specific init now */
576 if (!charger_inserted()) /* only if charger not connected */
577#endif
578 {
579 avgbat += (percent_to_volt_discharge[battery_type][6] -
580 percent_to_volt_discharge[battery_type][5]) / 2;
581 }
582#endif /* HAVE_DISK_STORAGE */
583
584 avgbat = avgbat * BATT_AVE_SAMPLES;
585 battery_millivolts = avgbat / BATT_AVE_SAMPLES;
586 power_history[0] = battery_millivolts;
587
588#if CONFIG_CHARGING
589 if (charger_inserted()) {
590 battery_percent = voltage_to_percent(battery_millivolts,
591 percent_to_volt_charge);
592 }
593 else
594#endif
595 {
596 battery_percent = voltage_to_percent(battery_millivolts,
597 percent_to_volt_discharge[battery_type]);
598 battery_percent += battery_percent < 100;
599 }
600
601 powermgmt_init_target(); 696 powermgmt_init_target();
602 697
603 next_power_hist = current_tick + HZ*60; 698 next_power_hist = current_tick + HZ*60;
@@ -609,7 +704,7 @@ static void power_thread(void)
609#ifdef HAVE_BATTERY_SWITCH 704#ifdef HAVE_BATTERY_SWITCH
610 if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) { 705 if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) {
611 sleep(HZ/10); 706 sleep(HZ/10);
612 reset_battery_filter(battery_adc_voltage()); 707 reset_battery_filter(_battery_voltage());
613 } 708 }
614#endif 709#endif
615 power_thread_inputs = pwr; 710 power_thread_inputs = pwr;
@@ -627,21 +722,15 @@ static void power_thread(void)
627 /* Perform target tasks */ 722 /* Perform target tasks */
628 charging_algorithm_step(); 723 charging_algorithm_step();
629 724
630 if (TIME_BEFORE(current_tick, next_power_hist)) 725 /* check if some idle or sleep timer wears off */
631 continue;
632
633 /* increment to ensure there is a record for every minute
634 * rather than go forward from the current tick */
635 next_power_hist += HZ*60;
636
637 /* rotate the power history */
638 memmove(&power_history[1], &power_history[0],
639 sizeof(power_history) - sizeof(power_history[0]));
640
641 /* insert new value at the start, in millivolts 8-) */
642 power_history[0] = battery_millivolts;
643
644 handle_auto_poweroff(); 726 handle_auto_poweroff();
727
728 if (TIME_AFTER(current_tick, next_power_hist)) {
729 /* increment to ensure there is a record for every minute
730 * rather than go forward from the current tick */
731 next_power_hist += HZ*60;
732 collect_power_history();
733 }
645 } 734 }
646} /* power_thread */ 735} /* power_thread */
647 736
@@ -701,7 +790,6 @@ void shutdown_hw(void)
701 sleep(HZ/4); 790 sleep(HZ/4);
702 power_off(); 791 power_off();
703} 792}
704#endif /* PLATFORM_NATIVE */
705 793
706void set_poweroff_timeout(int timeout) 794void set_poweroff_timeout(int timeout)
707{ 795{
@@ -855,12 +943,10 @@ void handle_auto_poweroff(void)
855 last_event_tick = current_tick; 943 last_event_tick = current_tick;
856 } 944 }
857 945
858#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0)
859 if (!shutdown_timeout && query_force_shutdown()) { 946 if (!shutdown_timeout && query_force_shutdown()) {
860 backlight_on(); 947 backlight_on();
861 sys_poweroff(); 948 sys_poweroff();
862 } 949 }
863#endif
864 950
865 if (timeout && 951 if (timeout &&
866#if CONFIG_TUNER 952#if CONFIG_TUNER