1
0
Fork 0
forked from len0rd/rockbox

Get a good start on cleaning up powermgmt.c

1) Consolidate charging types' code as much as possible at the moment.

2) Remove the iRiver code for the moment. It so happens that it isn't being
   compiled anyway so it's just noise. Grab it out of the revision history
   when needed again.

3) A small fix to CHARGING_CONTROL where changing of #defines somewhere in
   earlier revisions actually ended up having it use the wrong battery filter
   constant.  A few state variables that were locals but stay in scope for
   the life of the power thread get static storage to help separate algorithms.



git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17580 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2008-05-19 03:59:52 +00:00
parent d2f47da4e2
commit cb1b388a57

View file

@ -69,8 +69,8 @@
#define DEBUG_MESSAGE_LEN 133 #define DEBUG_MESSAGE_LEN 133
static char debug_message[DEBUG_MESSAGE_LEN]; static char debug_message[DEBUG_MESSAGE_LEN];
#define DEBUG_STACK ((0x1000)/sizeof(long)) #define DEBUG_STACK ((0x1000)/sizeof(long))
static int fd; /* write debug information to this file */ static int fd = -1; /* write debug information to this file */
static int wrcount; static int wrcount = 0;
#else #else
#define DEBUG_STACK 0 #define DEBUG_STACK 0
#endif #endif
@ -134,7 +134,8 @@ static void battery_status_update(void)
else else
battery_millivolts -= (BATT_MAXMVOLT - BATT_MINMVOLT) / 100; battery_millivolts -= (BATT_MAXMVOLT - BATT_MINMVOLT) / 100;
battery_percent = 100 * (battery_millivolts - BATT_MINMVOLT) / (BATT_MAXMVOLT - BATT_MINMVOLT); battery_percent = 100 * (battery_millivolts - BATT_MINMVOLT) /
(BATT_MAXMVOLT - BATT_MINMVOLT);
powermgmt_est_runningtime_min = battery_percent * BATT_MAXRUNTIME / 100; powermgmt_est_runningtime_min = battery_percent * BATT_MAXRUNTIME / 100;
} }
send_battery_level_event(); send_battery_level_event();
@ -204,41 +205,16 @@ void accessory_supply_set(bool enable)
#else /* not SIMULATOR ******************************************************/ #else /* not SIMULATOR ******************************************************/
#if CONFIG_CHARGING == CHARGING_CONTROL static void power_thread_sleep(int ticks);
int long_delta; /* long term delta battery voltage */
int short_delta; /* short term delta battery voltage */
bool disk_activity_last_cycle = false; /* flag set to aid charger time
* calculation */
char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in
debug menu */
/* percentage at which charging
starts */
int powermgmt_last_cycle_startstop_min = 0; /* how many minutes ago was the
charging started or
stopped? */
int powermgmt_last_cycle_level = 0; /* which level had the
batteries at this time? */
int trickle_sec = 0; /* how many seconds should the
charger be enabled per
minute for trickle
charging? */
int pid_p = 0; /* PID proportional term */
int pid_i = 0; /* PID integral term */
#endif /* CONFIG_CHARGING == CHARGING_CONTROL */
/* /*
* Average battery voltage and charger voltage, filtered via a digital * Average battery voltage and charger voltage, filtered via a digital
* exponential filter. * exponential filter (aka. exponential moving average, scaled):
* avgbat = y[n] = (N-1)/N*y[n-1] + x[n]. battery_millivolts = y[n] / N.
*/ */
static unsigned int avgbat; /* average battery voltage (filtering) */ static unsigned int avgbat; /* average battery voltage (filtering) */
static unsigned int battery_millivolts;/* filtered battery voltage, millivolts */ static unsigned int battery_millivolts;/* filtered battery voltage, millivolts */
#ifdef HAVE_CHARGE_CTRL
#define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */
#else
#define BATT_AVE_SAMPLES 128 /* slw filter constant for all others */
#endif
/* battery level (0-100%) of this minute, updated once per minute */ /* battery level (0-100%) of this minute, updated once per minute */
static int battery_percent = -1; static int battery_percent = -1;
static int battery_capacity = BATTERY_CAPACITY_DEFAULT; /* default value, mAh */ static int battery_capacity = BATTERY_CAPACITY_DEFAULT; /* default value, mAh */
@ -376,36 +352,7 @@ static int voltage_to_battery_level(int battery_millivolts)
{ {
int level; int level;
#if defined(CONFIG_CHARGER) \ #if CONFIG_CHARGING >= CHARGING_MONITOR
&& (defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES))
/* Checking for iriver is a temporary kludge.
* This code needs rework/unification */
if (charger_input_state == NO_CHARGER) {
/* discharging. calculate new battery level and average with last */
level = voltage_to_percent(battery_millivolts,
percent_to_volt_discharge[battery_type]);
if (level != (battery_percent - 1))
level = (level + battery_percent + 1) / 2;
}
else if (charger_input_state == CHARGER_UNPLUGGED) {
/* just unplugged. adjust filtered values */
battery_millivolts -= percent_to_volt_charge[battery_percent/10] -
percent_to_volt_discharge[0][battery_percent/10];
avgbat = battery_millivolts * 1000 * BATT_AVE_SAMPLES;
level = battery_percent;
}
else if (charger_input_state == CHARGER_PLUGGED) {
/* just plugged in. adjust battery values */
battery_millivolts += percent_to_volt_charge[battery_percent/10] -
percent_to_volt_discharge[0][battery_percent/10];
avgbat = battery_millivolts * 1000 * BATT_AVE_SAMPLES;
level = MIN(12 * battery_percent / 10, 99);
}
else { /* charging. calculate new battery level */
level = voltage_to_percent(battery_millivolts,
percent_to_volt_charge);
}
#elif CONFIG_CHARGING >= CHARGING_MONITOR
if (charge_state == DISCHARGING) { if (charge_state == DISCHARGING) {
level = voltage_to_percent(battery_millivolts, level = voltage_to_percent(battery_millivolts,
percent_to_volt_discharge[battery_type]); percent_to_volt_discharge[battery_type]);
@ -422,7 +369,7 @@ static int voltage_to_battery_level(int battery_millivolts)
/* always use the discharge table */ /* always use the discharge table */
level = voltage_to_percent(battery_millivolts, level = voltage_to_percent(battery_millivolts,
percent_to_volt_discharge[battery_type]); percent_to_volt_discharge[battery_type]);
#endif #endif /* CONFIG_CHARGING ... */
return level; return level;
} }
@ -440,47 +387,7 @@ static void battery_status_update(void)
/ 100 / (CURRENT_MAX_CHG - runcurrent()); / 100 / (CURRENT_MAX_CHG - runcurrent());
} }
else else
#elif CONFIG_CHARGING \
&& (defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES))
/* Checking for iriver is a temporary kludge.
* This code needs rework/unification */
if (charger_inserted()) {
#ifdef IRIVER_H300_SERIES
/* H300_SERIES use CURRENT_MAX_CHG for basic charge time (80%)
* plus 110 min top off charge time */
powermgmt_est_runningtime_min = ((100-level) * battery_capacity * 80
/100 / CURRENT_MAX_CHG) + 110;
#else
/* H100_SERIES scaled for 160 min basic charge time (80%) on
* 1600 mAh battery plus 110 min top off charge time */
powermgmt_est_runningtime_min = ((100 - level) * battery_capacity
/ 993) + 110;
#endif #endif
level = (level * 80) / 100;
if (level > 72) { /* > 91% */
int i = POWER_HISTORY_LEN;
int d = 1;
#ifdef HAVE_CHARGE_STATE
if (charge_state == DISCHARGING)
d = -2;
#endif
while ((i > 2) && (d > 0)) /* search zero or neg. delta */
d = power_history[0] - power_history[--i];
if ((((d == 0) && (i > 6)) || (d == -1)) && (i < 118)) {
/* top off charging */
level = MIN(80 + (i*19 / 113), 99); /* show 81% .. 99% */
powermgmt_est_runningtime_min = MAX(116 - i, 0);
}
else if ((d < 0) || (i > 117)) {
/* charging finished */
level = 100;
powermgmt_est_runningtime_min = battery_capacity * 60
/ runcurrent();
}
}
}
else
#endif /* BATT_LIPOL1300 */
{ {
if ((battery_millivolts + 20) > percent_to_volt_discharge[0][0]) if ((battery_millivolts + 20) > percent_to_volt_discharge[0][0])
powermgmt_est_runningtime_min = (level + battery_percent) * 60 * powermgmt_est_runningtime_min = (level + battery_percent) * 60 *
@ -639,140 +546,44 @@ static void power_thread_rtc_process(void)
#endif #endif
/* /*
* This function is called to do the relativly long sleep waits from within the * This power thread maintains a history of battery voltage
* main power_thread loop while at the same time servicing any other periodic * and implements a charging algorithm.
* functions in the power thread which need to be called at a faster periodic
* rate than the slow periodic rate of the main power_thread loop.
*
* While we are waiting for the time to expire, we average the battery
* voltages.
*/ */
static void power_thread_sleep(int ticks)
{
int small_ticks;
while (ticks > 0) {
#if CONFIG_CHARGING
/*
* Detect charger plugged/unplugged transitions. On a plugged or
* unplugged event, we return immediately, run once through the main
* loop (including the subroutines), and end up back here where we
* transition to the appropriate steady state charger on/off state.
*/
if(charger_inserted()
#ifdef HAVE_USB_POWER /* USB powered or USB inserted both provide power */
|| usb_powered()
#if CONFIG_CHARGING
|| (usb_inserted() && usb_charging_enabled())
#endif
#endif
) {
switch(charger_input_state) {
case NO_CHARGER:
case CHARGER_UNPLUGGED:
charger_input_state = CHARGER_PLUGGED;
return;
case CHARGER_PLUGGED:
queue_broadcast(SYS_CHARGER_CONNECTED, 0);
last_sent_battery_level = 0;
charger_input_state = CHARGER;
break;
case CHARGER:
break;
}
} else { /* charger not inserted */
switch(charger_input_state) {
case NO_CHARGER:
break;
case CHARGER_UNPLUGGED:
queue_broadcast(SYS_CHARGER_DISCONNECTED, 0);
last_sent_battery_level = 100;
charger_input_state = NO_CHARGER;
break;
case CHARGER_PLUGGED:
case CHARGER:
charger_input_state = CHARGER_UNPLUGGED;
return;
}
}
#endif
#if CONFIG_CHARGING == CHARGING_MONITOR
switch (charger_input_state) {
case CHARGER_UNPLUGGED:
case NO_CHARGER:
charge_state = DISCHARGING;
break;
case CHARGER_PLUGGED:
case CHARGER:
if (charging_state()) {
charge_state = CHARGING;
} else {
charge_state = DISCHARGING;
}
break;
}
#endif /* CONFIG_CHARGING == CHARGING_MONITOR */
small_ticks = MIN(HZ/2, ticks);
sleep(small_ticks);
ticks -= small_ticks;
/* If the power off timeout expires, the main thread has failed
to shut down the system, and we need to force a power off */
if(shutdown_timeout) {
shutdown_timeout -= small_ticks;
if(shutdown_timeout <= 0)
power_off();
}
#ifdef HAVE_RTC_ALARM
power_thread_rtc_process();
#endif
/*
* Do a digital exponential filter. We don't sample the battery if
* the disk is spinning unless we are in USB mode (the disk will most
* likely always be spinning in USB mode).
*/
if (!ata_disk_is_active() || usb_inserted()) {
avgbat += battery_adc_voltage() - (avgbat / BATT_AVE_SAMPLES);
/*
* battery_millivolts is the millivolt-scaled filtered battery value.
*/
battery_millivolts = avgbat / BATT_AVE_SAMPLES;
/* update battery status every time an update is available */
battery_status_update();
}
else if (battery_percent < 8) {
/* 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();
#ifndef NO_LOW_BATTERY_SHUTDOWN
if (!shutdown_timeout &&
(battery_millivolts < battery_level_shutoff[battery_type]))
sys_poweroff();
else
#endif
avgbat += battery_millivolts - (avgbat / BATT_AVE_SAMPLES);
}
#if CONFIG_CHARGING == CHARGING_CONTROL #if CONFIG_CHARGING == CHARGING_CONTROL
#define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */
/*
* For a complete description of the charging algorithm read
* docs/CHARGING_ALGORITHM.
*/
int long_delta; /* long term delta battery voltage */
int short_delta; /* short term delta battery voltage */
bool disk_activity_last_cycle = false; /* flag set to aid charger time
* calculation */
char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in
debug menu */
/* percentage at which charging
starts */
int powermgmt_last_cycle_startstop_min = 0; /* how many minutes ago was the
charging started or
stopped? */
int powermgmt_last_cycle_level = 0; /* which level had the
batteries at this time? */
int trickle_sec = 0; /* how many seconds should the
charger be enabled per
minute for trickle
charging? */
int pid_p = 0; /* PID proportional term */
int pid_i = 0; /* PID integral term */
static inline void charging_algorithm_small_step(void)
{
if (ata_disk_is_active()) { if (ata_disk_is_active()) {
/* flag hdd use for charging calculation */ /* flag hdd use for charging calculation */
disk_activity_last_cycle = true; disk_activity_last_cycle = true;
} }
#endif
#if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL) #if defined(DEBUG_FILE)
/* /*
* If we have a lot of pending writes or if the disk is spining, * If we have a lot of pending writes or if the disk is spining,
* fsync the debug log file. * fsync the debug log file.
@ -781,85 +592,22 @@ static void power_thread_sleep(int ticks)
fsync(fd); fsync(fd);
wrcount = 0; wrcount = 0;
} }
#endif #endif /* defined(DEBUG_FILE) */
}
} }
static inline void charging_algorithm_big_step(void)
/*
* This power thread maintains a history of battery voltage
* and implements a charging algorithm.
* For a complete description of the charging algorithm read
* docs/CHARGING_ALGORITHM.
*/
static void power_thread(void)
{ {
#if CONFIG_CHARGING == CHARGING_CONTROL static unsigned int target_voltage = TRICKLE_VOLTAGE; /* desired topoff/trickle
int i;
unsigned int target_voltage = TRICKLE_VOLTAGE; /* desired topoff/trickle
* voltage level */ * voltage level */
int charge_max_time_idle = 0; /* max. charging duration, calculated at static int charge_max_time_idle = 0; /* max. charging duration, calculated at
* beginning of charging */ * beginning of charging */
int charge_max_time_now = 0; /* max. charging duration including static int charge_max_time_now = 0; /* max. charging duration including
* hdd activity */ * hdd activity */
int minutes_disk_activity = 0; /* count minutes of hdd use during static int minutes_disk_activity = 0; /* count minutes of hdd use during
* charging */ * charging */
int last_disk_activity = CHARGE_END_LONGD + 1; /* last hdd use x mins ago */ static int last_disk_activity = CHARGE_END_LONGD + 1; /* last hdd use x mins ago */
#endif int i;
/* Delay reading the first battery level */
#ifdef MROBE_100
while(battery_adc_voltage()>4200) /* gives false readings initially */
#endif
sleep(HZ/100);
/* initialize the voltages for the exponential filter */
avgbat = battery_adc_voltage() + 15;
#ifndef HAVE_MMC /* 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% */
#ifdef HAVE_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 /* not HAVE_MMC */
avgbat = avgbat * BATT_AVE_SAMPLES;
battery_millivolts = avgbat / BATT_AVE_SAMPLES;
#if CONFIG_CHARGING
if(charger_inserted()) {
battery_percent = voltage_to_percent(battery_millivolts,
percent_to_volt_charge);
#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
/* Checking for iriver is a temporary kludge. */
charger_input_state = CHARGER;
#endif
} else
#endif
{ battery_percent = voltage_to_percent(battery_millivolts,
percent_to_volt_discharge[battery_type]);
battery_percent += (battery_percent < 100);
}
#if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL)
fd = -1;
wrcount = 0;
#endif
while (1)
{
/* rotate the power history */
memmove(power_history + 1, power_history,
sizeof(power_history) - sizeof(power_history[0]));
/* insert new value at the start, in millivolts 8-) */
power_history[0] = battery_millivolts;
#if CONFIG_CHARGING == CHARGING_CONTROL
if (charger_input_state == CHARGER_PLUGGED) { if (charger_input_state == CHARGER_PLUGGED) {
pid_p = 0; pid_p = 0;
pid_i = 0; pid_i = 0;
@ -908,6 +656,7 @@ static void power_thread(void)
charge_state = CHARGING; charge_state = CHARGING;
} }
} }
if (charge_state == CHARGING) { if (charge_state == CHARGING) {
/* alter charge time max length with extra disk use */ /* alter charge time max length with extra disk use */
if (disk_activity_last_cycle) { if (disk_activity_last_cycle) {
@ -1092,11 +841,7 @@ static void power_thread(void)
snprintf(power_message, POWER_MESSAGE_LEN, "Charger: discharge"); snprintf(power_message, POWER_MESSAGE_LEN, "Charger: discharge");
} }
#endif /* CONFIG_CHARGING == CHARGING_CONTROL */
/* sleep for a minute */ /* sleep for a minute */
#if CONFIG_CHARGING == CHARGING_CONTROL
if(trickle_sec > 0) { if(trickle_sec > 0) {
charger_enable(true); charger_enable(true);
power_thread_sleep(HZ * trickle_sec); power_thread_sleep(HZ * trickle_sec);
@ -1104,11 +849,8 @@ static void power_thread(void)
if(trickle_sec < 60) if(trickle_sec < 60)
charger_enable(false); charger_enable(false);
power_thread_sleep(HZ * (60 - trickle_sec)); power_thread_sleep(HZ * (60 - trickle_sec));
#else
power_thread_sleep(HZ * 60);
#endif
#if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL) #if defined(DEBUG_FILE)
if(usb_inserted()) { if(usb_inserted()) {
if(fd >= 0) { if(fd >= 0) {
/* It is probably too late to close the file but we can try...*/ /* It is probably too late to close the file but we can try...*/
@ -1120,7 +862,8 @@ static void power_thread(void)
fd = open(DEBUG_FILE_NAME, O_WRONLY | O_APPEND | O_CREAT); fd = open(DEBUG_FILE_NAME, O_WRONLY | O_APPEND | O_CREAT);
if(fd >= 0) { if(fd >= 0) {
snprintf(debug_message, DEBUG_MESSAGE_LEN, snprintf(debug_message, DEBUG_MESSAGE_LEN,
"cycle_min, bat_millivolts, bat_percent, chgr_state, charge_state, pid_p, pid_i, trickle_sec\n"); "cycle_min, bat_millivolts, bat_percent, chgr_state"
" ,charge_state, pid_p, pid_i, trickle_sec\n");
write(fd, debug_message, strlen(debug_message)); write(fd, debug_message, strlen(debug_message));
wrcount = 99; /* force a flush */ wrcount = 99; /* force a flush */
} }
@ -1135,12 +878,222 @@ static void power_thread(void)
wrcount++; wrcount++;
} }
} }
#endif #endif /* defined(DEBUG_FILE) */
handle_auto_poweroff();
#if CONFIG_CHARGING == CHARGING_CONTROL
powermgmt_last_cycle_startstop_min++; powermgmt_last_cycle_startstop_min++;
}
/*
* Prepare charging for poweroff
*/
static inline void charging_algorithm_close(void)
{
#if defined(DEBUG_FILE)
if(fd >= 0) {
close(fd);
fd = -1;
}
#endif #endif
}
#else
#define BATT_AVE_SAMPLES 128 /* slw filter constant for all others */
static inline void charging_algorithm_small_step(void)
{
#if CONFIG_CHARGING == CHARGING_MONITOR
switch (charger_input_state)
{
case CHARGER_UNPLUGGED:
case NO_CHARGER:
charge_state = DISCHARGING;
break;
case CHARGER_PLUGGED:
case CHARGER:
if (charging_state()) {
charge_state = CHARGING;
} else {
charge_state = DISCHARGING;
}
break;
}
#endif /* CONFIG_CHARGING == CHARGING_MONITOR */
}
static inline void charging_algorithm_big_step(void)
{
/* sleep for a minute */
power_thread_sleep(HZ * 60);
}
/*
* Prepare charging for poweroff
*/
static inline void charging_algorithm_close(void)
{
/* Nothing to do */
}
#endif /* CONFIG_CHARGING == CHARGING_CONTROL */
/*
* This function is called to do the relativly long sleep waits from within the
* main power_thread loop while at the same time servicing any other periodic
* functions in the power thread which need to be called at a faster periodic
* rate than the slow periodic rate of the main power_thread loop.
*
* While we are waiting for the time to expire, we average the battery
* voltages.
*/
static void power_thread_sleep(int ticks)
{
int small_ticks;
while (ticks > 0) {
#if CONFIG_CHARGING
/*
* Detect charger plugged/unplugged transitions. On a plugged or
* unplugged event, we return immediately, run once through the main
* loop (including the subroutines), and end up back here where we
* transition to the appropriate steady state charger on/off state.
*/
if(charger_inserted()
#ifdef HAVE_USB_POWER /* USB powered or USB inserted both provide power */
|| usb_powered()
|| (usb_inserted() && usb_charging_enabled())
#endif
) {
switch(charger_input_state) {
case NO_CHARGER:
case CHARGER_UNPLUGGED:
charger_input_state = CHARGER_PLUGGED;
return;
case CHARGER_PLUGGED:
queue_broadcast(SYS_CHARGER_CONNECTED, 0);
last_sent_battery_level = 0;
charger_input_state = CHARGER;
break;
case CHARGER:
break;
}
} else { /* charger not inserted */
switch(charger_input_state) {
case NO_CHARGER:
break;
case CHARGER_UNPLUGGED:
queue_broadcast(SYS_CHARGER_DISCONNECTED, 0);
last_sent_battery_level = 100;
charger_input_state = NO_CHARGER;
break;
case CHARGER_PLUGGED:
case CHARGER:
charger_input_state = CHARGER_UNPLUGGED;
return;
}
}
#endif /* CONFIG_CHARGING */
small_ticks = MIN(HZ/2, ticks);
sleep(small_ticks);
ticks -= small_ticks;
/* If the power off timeout expires, the main thread has failed
to shut down the system, and we need to force a power off */
if(shutdown_timeout) {
shutdown_timeout -= small_ticks;
if(shutdown_timeout <= 0)
power_off();
}
#ifdef HAVE_RTC_ALARM
power_thread_rtc_process();
#endif
/*
* Do a digital exponential filter. We don't sample the battery if
* the disk is spinning unless we are in USB mode (the disk will most
* likely always be spinning in USB mode).
*/
if (!ata_disk_is_active() || usb_inserted()) {
avgbat += battery_adc_voltage() - (avgbat / BATT_AVE_SAMPLES);
/*
* battery_millivolts is the millivolt-scaled filtered battery value.
*/
battery_millivolts = avgbat / BATT_AVE_SAMPLES;
/* update battery status every time an update is available */
battery_status_update();
}
else if (battery_percent < 8) {
/* 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();
#ifndef NO_LOW_BATTERY_SHUTDOWN
if (!shutdown_timeout &&
(battery_millivolts < battery_level_shutoff[battery_type]))
sys_poweroff();
else
#endif
avgbat += battery_millivolts - (avgbat / BATT_AVE_SAMPLES);
}
charging_algorithm_small_step();
}
}
static void power_thread(void)
{
/* Delay reading the first battery level */
#ifdef MROBE_100
while(battery_adc_voltage()>4200) /* gives false readings initially */
#endif
sleep(HZ/100);
/* initialize the voltages for the exponential filter */
avgbat = battery_adc_voltage() + 15;
#ifndef HAVE_MMC /* 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% */
#ifdef HAVE_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 /* not HAVE_MMC */
avgbat = avgbat * BATT_AVE_SAMPLES;
battery_millivolts = avgbat / BATT_AVE_SAMPLES;
#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);
}
while (1)
{
/* rotate the power history */
memmove(power_history + 1, power_history,
sizeof(power_history) - sizeof(power_history[0]));
/* insert new value at the start, in millivolts 8-) */
power_history[0] = battery_millivolts;
charging_algorithm_big_step();
handle_auto_poweroff();
} }
} }
@ -1192,12 +1145,7 @@ void cancel_shutdown(void)
void shutdown_hw(void) void shutdown_hw(void)
{ {
#ifndef SIMULATOR #ifndef SIMULATOR
#if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL) charging_algorithm_close();
if(fd >= 0) {
close(fd);
fd = -1;
}
#endif
audio_stop(); audio_stop();
if (battery_level_safe()) { /* do not save on critical battery */ if (battery_level_safe()) { /* do not save on critical battery */
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP