summaryrefslogtreecommitdiffstats
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.tar.bz2
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);
static int poweroff_timeout = 0;
static long last_event_tick = 0;
-#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0)
+#if (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) == PERCENTAGE_MEASURE
+int _battery_voltage(void) { return -1; }
+
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
+const unsigned short percent_to_volt_charge[11];
+
+#elif (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE) == VOLTAGE_MEASURE
+int _battery_level(void) { return -1; }
/*
* Average battery voltage and charger voltage, filtered via a digital
* exponential filter (aka. exponential moving average, scaled):
@@ -95,10 +102,22 @@ static long last_event_tick = 0;
static unsigned int avgbat;
/* filtered battery voltage, millivolts */
static unsigned int battery_millivolts;
+#elif (CONFIG_BATTERY_MEASURE == 0)
+int _battery_voltage(void) { return -1; }
+int _battery_level(void) { return -1; }
+
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11];
+const unsigned short percent_to_volt_charge[11];
+#endif
+
+#if !(CONFIG_BATTERY_MEASURE & TIME_MEASURE)
+static int powermgmt_est_runningtime_min;
+int _battery_time(void) { return powermgmt_est_runningtime_min; }
+#endif
+
/* default value, mAh */
static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
-
#if BATTERY_TYPES_COUNT > 1
static int battery_type = 0;
#else
@@ -115,7 +134,6 @@ static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK];
#endif
static const char power_thread_name[] = "power";
-static int powermgmt_est_runningtime_min = -1;
static int voltage_to_battery_level(int battery_millivolts);
static void battery_status_update(void);
@@ -126,13 +144,18 @@ static int runcurrent(void);
void battery_read_info(int *voltage, int *level)
{
- int millivolts = battery_adc_voltage();
+ int millivolts = _battery_voltage();
+ int percent;
if (voltage)
*voltage = millivolts;
- if (level)
- *level = voltage_to_battery_level(millivolts);
+ if (level) {
+ percent = voltage_to_battery_level(millivolts);
+ if (percent < 0)
+ percent = _battery_level();
+ *level = percent;
+ }
}
#if BATTERY_TYPES_COUNT > 1
@@ -148,6 +171,7 @@ void set_battery_type(int type)
}
#endif
+#ifdef BATTERY_CAPACITY_MIN
void set_battery_capacity(int capacity)
{
if (capacity > BATTERY_CAPACITY_MAX)
@@ -159,6 +183,7 @@ void set_battery_capacity(int capacity)
battery_status_update(); /* recalculate the battery status */
}
+#endif
int get_battery_capacity(void)
{
@@ -167,7 +192,16 @@ int get_battery_capacity(void)
int battery_time(void)
{
- return powermgmt_est_runningtime_min;
+#if ((CONFIG_BATTERY_MEASURE & TIME_MEASURE) == 0)
+
+#ifndef CURRENT_NORMAL /* no estimation without current */
+ return -1;
+#endif
+ if (battery_capacity <= 0) /* nor without capacity */
+ return -1;
+
+#endif
+ return _battery_time();
}
/* Returns battery level in percent */
@@ -180,17 +214,13 @@ int battery_level(void)
return battery_percent;
}
-/* Returns filtered battery voltage [millivolts] */
-unsigned int battery_voltage(void)
-{
- return battery_millivolts;
-}
-
/* Tells if the battery level is safe for disk writes */
bool battery_level_safe(void)
{
#if defined(NO_LOW_BATTERY_SHUTDOWN)
return true;
+#elif (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE)
+ return (battery_percent > 0);
#elif defined(HAVE_BATTERY_SWITCH)
/* Cannot rely upon the battery reading to be valid and the
* device could be powered externally. */
@@ -228,6 +258,9 @@ static int voltage_to_battery_level(int battery_millivolts)
{
int level;
+ if (battery_millivolts < 0)
+ return -1;
+
#if CONFIG_CHARGING >= CHARGING_MONITOR
if (charging_state()) {
/* battery level is defined to be < 100% until charging is finished */
@@ -249,7 +282,8 @@ static int voltage_to_battery_level(int battery_millivolts)
static void battery_status_update(void)
{
- int level = voltage_to_battery_level(battery_millivolts);
+ int millivolt, level;
+ battery_read_info(&millivolt, &level);
#ifdef CURRENT_NORMAL /*don't try to estimate run or charge
time without normal current defined*/
@@ -264,7 +298,8 @@ static void battery_status_update(void)
#endif
/* discharging: remaining running time */
- if (battery_millivolts > percent_to_volt_discharge[0][0]) {
+ if (level > 0 && (millivolt > percent_to_volt_discharge[battery_type][0]
+ || millivolt < 0)) {
/* linear extrapolation */
powermgmt_est_runningtime_min = (level + battery_percent)*60
* battery_capacity / 200 / runcurrent();
@@ -272,8 +307,6 @@ static void battery_status_update(void)
if (0 > powermgmt_est_runningtime_min) {
powermgmt_est_runningtime_min = 0;
}
-#else
- powermgmt_est_runningtime_min=-1;
#endif
battery_percent = level;
@@ -348,6 +381,8 @@ bool query_force_shutdown(void)
{
#if defined(NO_LOW_BATTERY_SHUTDOWN)
return false;
+#elif CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE
+ return battery_percent == 0;
#elif defined(HAVE_BATTERY_SWITCH)
/* Cannot rely upon the battery reading to be valid and the
* device could be powered externally. */
@@ -490,6 +525,101 @@ static inline bool detect_charger(unsigned int pwr)
}
#endif /* CONFIG_CHARGING */
+
+#if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
+/* Returns filtered battery voltage [millivolts] */
+int battery_voltage(void)
+{
+ return battery_millivolts;
+}
+
+static void average_init(void)
+{
+ /* initialize the voltages for the exponential filter */
+ avgbat = _battery_voltage() + 15;
+
+#ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */
+ /* The battery voltage is usually a little lower directly after
+ turning on, because the disk was used heavily. Raise it by 5% */
+#if CONFIG_CHARGING
+ if (!charger_inserted()) /* only if charger not connected */
+#endif
+ {
+ avgbat += (percent_to_volt_discharge[battery_type][6] -
+ percent_to_volt_discharge[battery_type][5]) / 2;
+ }
+#endif /* HAVE_DISK_STORAGE */
+
+ avgbat = avgbat * BATT_AVE_SAMPLES;
+ battery_millivolts = power_history[0] = avgbat / BATT_AVE_SAMPLES;
+}
+
+static void average_step(void)
+{
+ avgbat += _battery_voltage() - avgbat / BATT_AVE_SAMPLES;
+ /*
+ * battery_millivolts is the millivolt-scaled filtered battery value.
+ */
+ battery_millivolts = avgbat / BATT_AVE_SAMPLES;
+}
+
+static void average_step_low(void)
+{
+ battery_millivolts = (_battery_voltage() + battery_millivolts + 1) / 2;
+ avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES;
+}
+
+static void init_battery_percent(void)
+{
+#if CONFIG_CHARGING
+ if (charger_inserted()) {
+ battery_percent = voltage_to_percent(battery_millivolts,
+ percent_to_volt_charge);
+ }
+ else
+#endif
+ {
+ battery_percent = voltage_to_percent(battery_millivolts,
+ percent_to_volt_discharge[battery_type]);
+ battery_percent += battery_percent < 100;
+ }
+
+}
+
+static int power_hist_item(void)
+{
+ return battery_millivolts;
+}
+#define power_history_unit() battery_millivolts
+
+#else
+int battery_voltage(void)
+{
+ return -1;
+}
+
+static void average_init(void) {}
+static void average_step(void) {}
+static void average_step_low(void) {}
+static void init_battery_percent(void)
+{
+ battery_percent = _battery_level();
+}
+
+static int power_hist_item(void)
+{
+ return battery_percent;
+}
+#endif
+
+static void collect_power_history(void)
+{
+ /* rotate the power history */
+ memmove(&power_history[1], &power_history[0],
+ sizeof(power_history) - sizeof(power_history[0]));
+ power_history[0] = power_hist_item();
+}
+
/*
* Monitor the presence of a charger and perform critical frequent steps
* such as running the battery voltage filter.
@@ -519,33 +649,23 @@ static inline void power_thread_step(void)
|| charger_input_state == CHARGER
#endif
) {
- avgbat += battery_adc_voltage() - avgbat / BATT_AVE_SAMPLES;
- /*
- * battery_millivolts is the millivolt-scaled filtered battery value.
- */
- battery_millivolts = avgbat / BATT_AVE_SAMPLES;
-
+ average_step();
/* update battery status every time an update is available */
battery_status_update();
}
else if (battery_percent < 8) {
+ average_step_low();
+ /* update battery status every time an update is available */
+ battery_status_update();
+
/*
* If battery is low, observe voltage during disk activity.
* Shut down if voltage drops below shutoff level and we are not
* using NiMH or Alkaline batteries.
*/
- battery_millivolts = (battery_adc_voltage() +
- battery_millivolts + 1) / 2;
-
- /* update battery status every time an update is available */
- battery_status_update();
-
if (!shutdown_timeout && query_force_shutdown()) {
sys_poweroff();
}
- else {
- avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES;
- }
}
} /* power_thread_step */
@@ -555,7 +675,7 @@ static void power_thread(void)
/* Delay reading the first battery level */
#ifdef MROBE_100
- while (battery_adc_voltage() > 4200) /* gives false readings initially */
+ while (_battery_voltage() > 4200) /* gives false readings initially */
#endif
{
sleep(HZ/100);
@@ -566,38 +686,13 @@ static void power_thread(void)
power_thread_inputs = power_input_status();
#endif
- /* initialize the voltages for the exponential filter */
- avgbat = battery_adc_voltage() + 15;
-
-#ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */
- /* The battery voltage is usually a little lower directly after
- turning on, because the disk was used heavily. Raise it by 5% */
-#if CONFIG_CHARGING
- if (!charger_inserted()) /* only if charger not connected */
-#endif
- {
- avgbat += (percent_to_volt_discharge[battery_type][6] -
- percent_to_volt_discharge[battery_type][5]) / 2;
- }
-#endif /* HAVE_DISK_STORAGE */
-
- avgbat = avgbat * BATT_AVE_SAMPLES;
- battery_millivolts = avgbat / BATT_AVE_SAMPLES;
- power_history[0] = battery_millivolts;
-
-#if CONFIG_CHARGING
- if (charger_inserted()) {
- battery_percent = voltage_to_percent(battery_millivolts,
- percent_to_volt_charge);
- }
- else
-#endif
- {
- battery_percent = voltage_to_percent(battery_millivolts,
- percent_to_volt_discharge[battery_type]);
- battery_percent += battery_percent < 100;
- }
-
+ /* initialize voltage averaging (if available) */
+ average_init();
+ /* get initial battery level value (in %) */
+ init_battery_percent();
+ /* get some initial data for the power curve */
+ collect_power_history();
+ /* call target specific init now */
powermgmt_init_target();
next_power_hist = current_tick + HZ*60;
@@ -609,7 +704,7 @@ static void power_thread(void)
#ifdef HAVE_BATTERY_SWITCH
if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) {
sleep(HZ/10);
- reset_battery_filter(battery_adc_voltage());
+ reset_battery_filter(_battery_voltage());
}
#endif
power_thread_inputs = pwr;
@@ -627,21 +722,15 @@ static void power_thread(void)
/* Perform target tasks */
charging_algorithm_step();
- if (TIME_BEFORE(current_tick, next_power_hist))
- continue;
-
- /* increment to ensure there is a record for every minute
- * rather than go forward from the current tick */
- next_power_hist += HZ*60;
-
- /* rotate the power history */
- memmove(&power_history[1], &power_history[0],
- sizeof(power_history) - sizeof(power_history[0]));
-
- /* insert new value at the start, in millivolts 8-) */
- power_history[0] = battery_millivolts;
-
+ /* check if some idle or sleep timer wears off */
handle_auto_poweroff();
+
+ if (TIME_AFTER(current_tick, next_power_hist)) {
+ /* increment to ensure there is a record for every minute
+ * rather than go forward from the current tick */
+ next_power_hist += HZ*60;
+ collect_power_history();
+ }
}
} /* power_thread */
@@ -701,7 +790,6 @@ void shutdown_hw(void)
sleep(HZ/4);
power_off();
}
-#endif /* PLATFORM_NATIVE */
void set_poweroff_timeout(int timeout)
{
@@ -855,12 +943,10 @@ void handle_auto_poweroff(void)
last_event_tick = current_tick;
}
-#if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0)
if (!shutdown_timeout && query_force_shutdown()) {
backlight_on();
sys_poweroff();
}
-#endif
if (timeout &&
#if CONFIG_TUNER