summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorJörg Hohensohn <hohensoh@rockbox.org>2005-03-03 07:25:43 +0000
committerJörg Hohensohn <hohensoh@rockbox.org>2005-03-03 07:25:43 +0000
commit2584896920724cd5e72caaf9b64c3ef81b45ee9f (patch)
tree672817ced4c15a673fb557e87b0091cf90e43339 /firmware
parent384de102469fee4e0792df8fe38586d3206774ed (diff)
downloadrockbox-2584896920724cd5e72caaf9b64c3ef81b45ee9f.tar.gz
rockbox-2584896920724cd5e72caaf9b64c3ef81b45ee9f.zip
More aggressive Recorder V1 charging (patch #1116884 from Jerry Van Baren)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6105 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/adc.h2
-rw-r--r--firmware/export/powermgmt.h39
-rw-r--r--firmware/powermgmt.c819
3 files changed, 440 insertions, 420 deletions
diff --git a/firmware/export/adc.h b/firmware/export/adc.h
index a18cb1995a..40bc3e108a 100644
--- a/firmware/export/adc.h
+++ b/firmware/export/adc.h
@@ -63,7 +63,7 @@
63#define ADC_BUTTON_ROW2 5 /* Used for scanning the keys, different 63#define ADC_BUTTON_ROW2 5 /* Used for scanning the keys, different
64 voltages for different keys */ 64 voltages for different keys */
65#define ADC_UNREG_POWER 6 /* Battery voltage with a better scaling */ 65#define ADC_UNREG_POWER 6 /* Battery voltage with a better scaling */
66#define ADC_EXT_POWER 7 /* The external power voltage, V=X*0.0148 */ 66#define ADC_EXT_POWER 7 /* The external power voltage, 0v or 2.7v */
67 67
68#endif 68#endif
69 69
diff --git a/firmware/export/powermgmt.h b/firmware/export/powermgmt.h
index 922630097a..59f9465d49 100644
--- a/firmware/export/powermgmt.h
+++ b/firmware/export/powermgmt.h
@@ -48,13 +48,12 @@
48#define BATTERY_RANGE (BATTERY_LEVEL_FULL - BATTERY_LEVEL_EMPTY) 48#define BATTERY_RANGE (BATTERY_LEVEL_FULL - BATTERY_LEVEL_EMPTY)
49 49
50#define POWER_HISTORY_LEN 2*60 /* 2 hours of samples, one per minute */ 50#define POWER_HISTORY_LEN 2*60 /* 2 hours of samples, one per minute */
51#define POWER_AVG_N 4 /* how many samples to take for each measurement */
52#define POWER_AVG_SLEEP 9 /* how long do we sleep between each measurement */
53 51
54#define CHARGE_END_NEGD 6 /* stop when N minutes have passed with 52#define CHARGE_END_NEGD 6 /* stop when N minutes have passed with
55 * avg delta being < -0.05 V */ 53 * avg delta being < -0.05 V */
56#define CHARGE_END_ZEROD 50 /* stop when N minutes have passed with 54#define CHARGE_END_ZEROD 50 /* stop when N minutes have passed with
57 * avg delta being < 0.005 V */ 55 * avg delta being < 0.005 V */
56
58#ifndef SIMULATOR 57#ifndef SIMULATOR
59 58
60#ifdef HAVE_CHARGE_CTRL 59#ifdef HAVE_CHARGE_CTRL
@@ -65,27 +64,40 @@
65#define CHARGE_RESTART_HI 85 /* %: when to restart charging in 'charge' mode */ 64#define CHARGE_RESTART_HI 85 /* %: when to restart charging in 'charge' mode */
66 /* attention: if set too high, normal charging is started in trickle mode */ 65 /* attention: if set too high, normal charging is started in trickle mode */
67#define CHARGE_RESTART_LO 10 /* %: when to restart charging in 'discharge' mode */ 66#define CHARGE_RESTART_LO 10 /* %: when to restart charging in 'discharge' mode */
68#define CHARGE_PAUSE_LEN 60 /* how many minutes to pause between charging cycles */
69#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? */
70#define TOPOFF_VOLTAGE 565 /* which voltage is best? (centivolts) */ 68#define TOPOFF_VOLTAGE 565 /* which voltage is best? (centivolts) */
71#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? */
72#define TRICKLE_VOLTAGE 545 /* which voltage is best? (centivolts) */ 70#define TRICKLE_VOLTAGE 545 /* which voltage is best? (centivolts) */
73 71
72#define START_TOPOFF_SEC 25 /* initial trickle_sec for topoff */
73#define START_TRICKLE_SEC 15 /* initial trickle_sec for trickle */
74
74extern char power_message[POWER_MESSAGE_LEN]; 75extern char power_message[POWER_MESSAGE_LEN];
75extern char charge_restart_level; 76
77extern int long_delta; /* long term delta battery voltage */
78extern int short_delta; /* short term delta battery voltage */
76 79
77extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was the charging started or stopped? */ 80extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was the charging started or stopped? */
78extern int powermgmt_last_cycle_level; /* which level had the batteries at this time? */ 81extern int powermgmt_last_cycle_level; /* which level had the batteries at this time? */
79 82
80extern int battery_lazyness[20]; /* how does the battery react when plugging in/out the charger */ 83void enable_deep_discharge(bool on); /* deep discharge the battery */
84
81void enable_trickle_charge(bool on); 85void enable_trickle_charge(bool on);
82extern int trickle_sec; /* trickle charge: How many seconds per minute are we charging actually? */ 86extern int trickle_sec; /* trickle charge: How many seconds per minute are we charging actually? */
83 87
84#endif /* HAVE_CHARGE_CTRL */ 88#endif /* HAVE_CHARGE_CTRL */
85 89
86#if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200 90#if defined(HAVE_CHARGE_CTRL) || (CONFIG_BATTERY == BATT_LIION2200)
87extern int charge_state; /* tells what the charger is doing (for info display): 0: decharging/charger off, 1: charge, 2: top-off, 3: trickle */ 91typedef enum {
88#endif 92 DISCHARGING,
93 CHARGING,
94 TOPOFF,
95 TRICKLE
96} charge_state_type;
97
98/* tells what the charger is doing */
99extern charge_state_type charge_state;
100#endif /* defined(HAVE_CHARGE_CTRL) || (CONFIG_BATTERY == BATT_LIION2200) */
89 101
90#ifdef HAVE_MMC /* Values for Ondio */ 102#ifdef HAVE_MMC /* Values for Ondio */
91#define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */ 103#define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */
@@ -95,9 +107,14 @@ extern int charge_state; /* tells what the charger is doing (for info di
95#define CURRENT_NORMAL 145 /* usual current in mA when using the AJB including some disk/backlight/... activity */ 107#define CURRENT_NORMAL 145 /* usual current in mA when using the AJB including some disk/backlight/... activity */
96#define CURRENT_USB 500 /* usual current in mA in USB mode */ 108#define CURRENT_USB 500 /* usual current in mA in USB mode */
97#define CURRENT_BACKLIGHT 30 /* additional current when backlight is always on */ 109#define CURRENT_BACKLIGHT 30 /* additional current when backlight is always on */
98#define CURRENT_CHARGING 300 /* charging current */
99#endif
100 110
111#define CURRENT_MIN_CHG 70 /* minimum charge current */
112#define MIN_CHG_V 8500 /* at 8.5v charger voltage get CURRENT_MIN_CHG */
113#define CURRENT_MAX_CHG 350 /* maximum charging current */
114#define MAX_CHG_V 10250 /* anything over 10.25v gives CURRENT_MAX_CHG */
115#endif /* HAVE_MMC */
116
117extern unsigned int bat; /* filtered battery voltage, centivolts */
101extern unsigned short power_history[POWER_HISTORY_LEN]; 118extern unsigned short power_history[POWER_HISTORY_LEN];
102 119
103/* Start up power management thread */ 120/* Start up power management thread */
@@ -114,7 +131,7 @@ bool battery_level_safe(void);
114 131
115void set_poweroff_timeout(int timeout); 132void set_poweroff_timeout(int timeout);
116void set_battery_capacity(int capacity); /* set local battery capacity value */ 133void set_battery_capacity(int capacity); /* set local battery capacity value */
117void set_battery_type(int type); /* set local battery type */ 134void set_battery_type(int type); /* set local battery type */
118 135
119void set_sleep_timer(int seconds); 136void set_sleep_timer(int seconds);
120int get_sleep_timer(void); 137int get_sleep_timer(void);
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index 2a15b9dfb4..0db2f03a7b 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -8,6 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese 10 * Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese
11 * Revisions copyright (C) 2005 by Gerald Van Baren
11 * 12 *
12 * All files in this archive are subject to the GNU General Public License. 13 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement. 14 * See the file COPYING in the source tree root for full license agreement.
@@ -41,6 +42,22 @@
41#include "fmradio.h" 42#include "fmradio.h"
42#endif 43#endif
43 44
45/*
46 * Define DEBUG_FILE to create a csv (spreadsheet) with battery information
47 * in it (one sample per minute). This is only for very low level debug.
48 */
49#undef DEBUG_FILE
50#if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL)
51#include "file.h"
52#define DEBUG_FILE_NAME "/powermgmt.csv"
53#define DEBUG_MESSAGE_LEN 133
54static char debug_message[DEBUG_MESSAGE_LEN];
55#define DEBUG_STACK ((0x1000)/sizeof(long))
56static int fd; /* write debug information to this file */
57#else
58#define DEBUG_STACK 0
59#endif
60
44long last_event_tick; 61long last_event_tick;
45 62
46void reset_poweroff_timer(void) 63void reset_poweroff_timer(void)
@@ -48,7 +65,7 @@ void reset_poweroff_timer(void)
48 last_event_tick = current_tick; 65 last_event_tick = current_tick;
49} 66}
50 67
51#ifdef SIMULATOR 68#ifdef SIMULATOR /***********************************************************/
52 69
53int battery_level(void) 70int battery_level(void)
54{ 71{
@@ -80,19 +97,14 @@ void set_car_adapter_mode(bool setting)
80 (void)setting; 97 (void)setting;
81} 98}
82 99
83#else /* not SIMULATOR */ 100#else /* not SIMULATOR ******************************************************/
84
85int battery_capacity = BATTERY_CAPACITY_MIN; /* only a default value */
86int battery_level_cached = -1; /* battery level of this minute, updated once
87 per minute */
88static bool car_adapter_mode_enabled = false;
89 101
90static const int poweroff_idle_timeout_value[15] = 102static const int poweroff_idle_timeout_value[15] =
91{ 103{
92 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 30, 45, 60 104 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 30, 45, 60
93}; 105};
94 106
95static const short percent_to_volt_decharge[BATTERY_TYPES_COUNT][11] = 107static const short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
96/* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */ 108/* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */
97{ 109{
98#if CONFIG_BATTERY == BATT_LIION2200 110#if CONFIG_BATTERY == BATT_LIION2200
@@ -110,50 +122,44 @@ static const short percent_to_volt_decharge[BATTERY_TYPES_COUNT][11] =
110#endif 122#endif
111}; 123};
112 124
113void set_battery_capacity(int capacity)
114{
115 battery_capacity = capacity;
116 if (battery_capacity > BATTERY_CAPACITY_MAX)
117 battery_capacity = BATTERY_CAPACITY_MAX;
118 if (battery_capacity < BATTERY_CAPACITY_MIN)
119 battery_capacity = BATTERY_CAPACITY_MIN;
120}
121
122#if BATTERY_TYPES_COUNT > 1
123static int battery_type = 0; 125static int battery_type = 0;
124 126
125void set_battery_type(int type) 127#if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200
126{ 128charge_state_type charge_state; /* charging mode */
127 if (type != battery_type) { 129int charge_timer; /* charge timer (minutes, dec to zero) */
128 battery_type = type;
129 battery_level_cached = -1; /* reset on type change */
130 }
131}
132#endif 130#endif
133 131
134#if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200 132#ifdef HAVE_CHARGING
135int charge_state = 0; /* at the beginning, the 133/* Flag that the charger has been plugged in */
136 charger does nothing */ 134static bool charger_was_inserted = false; /* for power off logic */
135static bool charger_power_is_on; /* for car adapter mode */
137#endif 136#endif
138 137
138/* Power history: power_history[0] is the newest sample */
139unsigned short power_history[POWER_HISTORY_LEN];
140
139#ifdef HAVE_CHARGE_CTRL 141#ifdef HAVE_CHARGE_CTRL
140 142
143int long_delta; /* long term delta battery voltage */
144int short_delta; /* short term delta battery voltage */
145
141char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in 146char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in
142 debug menu */ 147 debug menu */
143char charge_restart_level = CHARGE_RESTART_HI; /* level at which charging 148static char charge_restart_level = CHARGE_RESTART_HI;
149 /* percentage at which charging
144 starts */ 150 starts */
145int powermgmt_last_cycle_startstop_min = 25; /* how many minutes ago was the 151int powermgmt_last_cycle_startstop_min = 0; /* how many minutes ago was the
146 charging started or 152 charging started or
147 stopped? */ 153 stopped? */
148int powermgmt_last_cycle_level = 0; /* which level had the 154int powermgmt_last_cycle_level = 0; /* which level had the
149 batteries at this time? */ 155 batteries at this time? */
150bool trickle_charge_enabled = true; 156bool trickle_charge_enabled = true;
151int trickle_sec = 0; /* how many seconds should the 157int trickle_sec = 0; /* how many seconds should the
152 charger be enabled per 158 charger be enabled per
153 minute for trickle 159 minute for trickle
154 charging? */ 160 charging? */
155static const short percent_to_volt_charge[11] =
156/* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ 161/* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */
162static const short percent_to_volt_charge[11] =
157{ 163{
158 /* values guessed, see 164 /* values guessed, see
159 http://www.seattlerobotics.org/encoder/200210/LiIon2.pdf until someone 165 http://www.seattlerobotics.org/encoder/200210/LiIon2.pdf until someone
@@ -161,23 +167,64 @@ static const short percent_to_volt_charge[11] =
161 476, 544, 551, 556, 561, 564, 566, 576, 582, 584, 585 /* NiMH */ 167 476, 544, 551, 556, 561, 564, 566, 576, 582, 584, 585 /* NiMH */
162}; 168};
163 169
164void enable_trickle_charge(bool on) 170#endif /* HAVE_CHARGE_CTRL || CONFIG_BATTERY == BATT_LIION2200 */
165{ 171
166 trickle_charge_enabled = on; 172/*
167} 173 * Average battery voltage and charger voltage, filtered via a digital
168#endif /* HAVE_CHARGE_CTRL */ 174 * exponential filter.
175 */
176unsigned int battery_centivolts;/* filtered battery voltage, centvolts */
177static unsigned int avgbat; /* average battery voltage */
178#define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */
179
180int battery_capacity = BATTERY_CAPACITY_MIN; /* only a default value */
169 181
170static long power_stack[DEFAULT_STACK_SIZE/sizeof(long)]; 182/* battery level (0-100%) of this minute, updated once per minute */
183static int battery_percent = -1;
184
185static bool car_adapter_mode_enabled = false;
186
187static char power_stack[DEFAULT_STACK_SIZE + DEBUG_STACK];
171static const char power_thread_name[] = "power"; 188static const char power_thread_name[] = "power";
172 189
173static int poweroff_timeout = 0; 190static int poweroff_timeout = 0;
174static long last_charge_time = 0; 191static long last_charge_time = 0;
175int powermgmt_est_runningtime_min = -1; 192int powermgmt_est_runningtime_min = -1;
176 193
177static bool sleeptimer_active = false; 194static bool sleeptimer_active = false;
178static unsigned long sleeptimer_endtick; 195static unsigned long sleeptimer_endtick;
179 196
180unsigned short power_history[POWER_HISTORY_LEN]; 197#ifdef HAVE_CHARGE_CTRL
198
199void enable_deep_discharge(bool on)
200{
201 charge_restart_level = on ? CHARGE_RESTART_LO : CHARGE_RESTART_HI;
202}
203
204void enable_trickle_charge(bool on)
205{
206 trickle_charge_enabled = on;
207}
208#endif /* HAVE_CHARGE_CTRL */
209
210#if BATTERY_TYPES_COUNT > 1
211void set_battery_type(int type)
212{
213 if (type != battery_type) {
214 battery_type = type;
215 battery_percent = -1; /* reset on type change */
216 }
217}
218#endif
219
220void set_battery_capacity(int capacity)
221{
222 battery_capacity = capacity;
223 if (battery_capacity > BATTERY_CAPACITY_MAX)
224 battery_capacity = BATTERY_CAPACITY_MAX;
225 if (battery_capacity < BATTERY_CAPACITY_MIN)
226 battery_capacity = BATTERY_CAPACITY_MIN;
227}
181 228
182int battery_time(void) 229int battery_time(void)
183{ 230{
@@ -208,23 +255,9 @@ int voltage_to_percent(int voltage, const short* table)
208/* update battery level, called only once per minute */ 255/* update battery level, called only once per minute */
209void battery_level_update(void) 256void battery_level_update(void)
210{ 257{
211 int level = 0; 258 int level;
212 unsigned short c = 0;
213 int i;
214#if BATTERY_TYPES_COUNT == 1 /* single type */
215 const int battery_type = 0;
216#endif
217
218 /* calculate maximum over last 3 minutes (skip empty samples) */
219 for (i = 0; i < 3; i++)
220 if (power_history[POWER_HISTORY_LEN-1-i] > c)
221 c = power_history[POWER_HISTORY_LEN-1-i];
222
223 if (c)
224 level = c;
225 else /* history was empty, get a fresh sample */
226 level = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000;
227 259
260 level = battery_centivolts;
228 if(level > BATTERY_LEVEL_FULL) 261 if(level > BATTERY_LEVEL_FULL)
229 level = BATTERY_LEVEL_FULL; 262 level = BATTERY_LEVEL_FULL;
230 263
@@ -232,27 +265,27 @@ void battery_level_update(void)
232 level = BATTERY_LEVEL_EMPTY; 265 level = BATTERY_LEVEL_EMPTY;
233 266
234#ifdef HAVE_CHARGE_CTRL 267#ifdef HAVE_CHARGE_CTRL
235 if (charge_state == 0) { /* decharge */ 268 if (charge_state == DISCHARGING) {
236 level = voltage_to_percent(level, 269 level = voltage_to_percent(level,
237 percent_to_volt_decharge[battery_type]); 270 percent_to_volt_discharge[battery_type]);
238 } 271 }
239 else if (charge_state == 1) { /* charge */ 272 else if (charge_state == CHARGING) {
240 level = voltage_to_percent(level, percent_to_volt_charge); 273 level = voltage_to_percent(level, percent_to_volt_charge);
241 } 274 }
242 else {/* in trickle charge, the battery is per definition 100% full */ 275 else {/* in trickle charge, the battery is by definition 100% full */
243 battery_level_cached = level = 100; 276 battery_percent = level = 100;
244 } 277 }
245#else 278#else
279 /* always use the discharge table */
246 level = voltage_to_percent(level, 280 level = voltage_to_percent(level,
247 percent_to_volt_decharge[battery_type]); 281 percent_to_volt_discharge[battery_type]);
248 /* always use the decharge table */
249#endif 282#endif
250 283
251#ifndef HAVE_MMC /* this adjustment is only needed for HD based */ 284#ifndef HAVE_MMC /* this adjustment is only needed for HD based */
252 if (battery_level_cached == -1) { /* first run of this procedure */ 285 if (battery_percent == -1) { /* first run of this procedure */
253 /* the battery voltage is usually a little lower directly after 286 /* The battery voltage is usually a little lower directly after
254 turning on, because the disk was used heavily raise it by 5 % */ 287 turning on, because the disk was used heavily. Raise it by 5. % */
255 battery_level_cached = (level > 95) ? 100 : level + 5; 288 battery_percent = (level > 95) ? 100 : level + 5;
256 } 289 }
257 else 290 else
258#endif 291#endif
@@ -260,14 +293,14 @@ void battery_level_update(void)
260 /* the level is allowed to be -1 of the last value when usb not 293 /* the level is allowed to be -1 of the last value when usb not
261 connected and to be -3 of the last value when usb is connected */ 294 connected and to be -3 of the last value when usb is connected */
262 if (usb_inserted()) { 295 if (usb_inserted()) {
263 if (level < battery_level_cached - 3) 296 if (level < battery_percent - 3)
264 level = battery_level_cached - 3; 297 level = battery_percent - 3;
265 } 298 }
266 else { 299 else {
267 if (level < battery_level_cached - 1) 300 if (level < battery_percent - 1)
268 level = battery_level_cached - 1; 301 level = battery_percent - 1;
269 } 302 }
270 battery_level_cached = level; 303 battery_percent = level;
271 } 304 }
272} 305}
273 306
@@ -275,21 +308,16 @@ void battery_level_update(void)
275int battery_level(void) 308int battery_level(void)
276{ 309{
277#ifdef HAVE_CHARGE_CTRL 310#ifdef HAVE_CHARGE_CTRL
278 if ((charge_state==1) && (battery_level_cached==100)) 311 if ((charge_state == CHARGING) && (battery_percent == 100))
279 return 99; 312 return 99;
280#endif 313#endif
281 return battery_level_cached; 314 return battery_percent;
282} 315}
283 316
284/* Tells if the battery level is safe for disk writes */ 317/* Tells if the battery level is safe for disk writes */
285bool battery_level_safe(void) 318bool battery_level_safe(void)
286{ 319{
287 /* I'm pretty sure we don't want an average over a long time here */ 320 return battery_centivolts > BATTERY_LEVEL_DANGEROUS;
288 if (power_history[POWER_HISTORY_LEN-1])
289 return power_history[POWER_HISTORY_LEN-1] > BATTERY_LEVEL_DANGEROUS;
290 else
291 return adc_read(ADC_UNREG_POWER) > (BATTERY_LEVEL_DANGEROUS * 10000L) /
292 BATTERY_SCALE_FACTOR;
293} 321}
294 322
295void set_poweroff_timeout(int timeout) 323void set_poweroff_timeout(int timeout)
@@ -329,10 +357,12 @@ int get_sleep_timer(void)
329static void handle_auto_poweroff(void) 357static void handle_auto_poweroff(void)
330{ 358{
331 long timeout = poweroff_idle_timeout_value[poweroff_timeout]*60*HZ; 359 long timeout = poweroff_idle_timeout_value[poweroff_timeout]*60*HZ;
332 int mpeg_stat = mpeg_status(); 360 int mpeg_stat = mpeg_status();
361#ifdef HAVE_CHARGING
333 bool charger_is_inserted = charger_inserted(); 362 bool charger_is_inserted = charger_inserted();
334 static bool charger_was_inserted = false; 363#endif
335 364
365#ifdef HAVE_CHARGING
336 /* The was_inserted thing prevents the unit to shut down immediately 366 /* The was_inserted thing prevents the unit to shut down immediately
337 when the charger is extracted */ 367 when the charger is extracted */
338 if(charger_is_inserted || charger_was_inserted) 368 if(charger_is_inserted || charger_was_inserted)
@@ -340,13 +370,14 @@ static void handle_auto_poweroff(void)
340 last_charge_time = current_tick; 370 last_charge_time = current_tick;
341 } 371 }
342 charger_was_inserted = charger_is_inserted; 372 charger_was_inserted = charger_is_inserted;
373#endif
343 374
344 if(timeout && 375 if(timeout &&
345#ifdef CONFIG_TUNER 376#ifdef CONFIG_TUNER
346 (radio_get_status() != FMRADIO_PLAYING) && 377 (radio_get_status() != FMRADIO_PLAYING) &&
347#endif 378#endif
348 !usb_inserted() && 379 !usb_inserted() &&
349 (mpeg_stat == 0 || 380 ((mpeg_stat == 0) ||
350 ((mpeg_stat == (MPEG_STATUS_PLAY | MPEG_STATUS_PAUSE)) && 381 ((mpeg_stat == (MPEG_STATUS_PLAY | MPEG_STATUS_PAUSE)) &&
351 !sleeptimer_active))) 382 !sleeptimer_active)))
352 { 383 {
@@ -365,6 +396,7 @@ static void handle_auto_poweroff(void)
365 if(TIME_AFTER(current_tick, sleeptimer_endtick)) 396 if(TIME_AFTER(current_tick, sleeptimer_endtick))
366 { 397 {
367 mpeg_stop(); 398 mpeg_stop();
399#ifdef HAVE_CHARGING
368 if(charger_is_inserted) 400 if(charger_is_inserted)
369 { 401 {
370 DEBUGF("Sleep timer timeout. Stopping...\n"); 402 DEBUGF("Sleep timer timeout. Stopping...\n");
@@ -372,6 +404,7 @@ static void handle_auto_poweroff(void)
372 backlight_off(); /* Nighty, nighty... */ 404 backlight_off(); /* Nighty, nighty... */
373 } 405 }
374 else 406 else
407#endif
375 { 408 {
376 DEBUGF("Sleep timer timeout. Shutting off...\n"); 409 DEBUGF("Sleep timer timeout. Shutting off...\n");
377 /* Make sure that the disk isn't spinning when 410 /* Make sure that the disk isn't spinning when
@@ -390,8 +423,6 @@ void set_car_adapter_mode(bool setting)
390 car_adapter_mode_enabled = setting; 423 car_adapter_mode_enabled = setting;
391} 424}
392 425
393static bool charger_power_is_on;
394
395#ifdef HAVE_CHARGING 426#ifdef HAVE_CHARGING
396static void car_adapter_mode_processing(void) 427static void car_adapter_mode_processing(void)
397{ 428{
@@ -442,13 +473,38 @@ static void car_adapter_mode_processing(void)
442} 473}
443#endif 474#endif
444 475
476/*
477 * Estimate how much current we are drawing just to run.
478 */
479static int runcurrent(void)
480{
481 int current;
482
483 current = CURRENT_NORMAL;
484 if(usb_inserted()) {
485 current = CURRENT_USB;
486 }
487#ifdef HAVE_CHARGE_CTRL
488 if ((backlight_get_timeout() == 1) || /* LED always on */
489 (charger_inserted() && backlight_get_on_when_charging())) {
490 current += CURRENT_BACKLIGHT;
491 }
492#else
493 if (backlight_get_timeout() == 1) { /* LED always on */
494 current += CURRENT_BACKLIGHT;
495 }
496#endif
497
498 return(current);
499}
500
501
445/* Check to see whether or not we've received an alarm in the last second */ 502/* Check to see whether or not we've received an alarm in the last second */
446#ifdef HAVE_ALARM_MOD 503#ifdef HAVE_ALARM_MOD
447static void power_thread_rtc_process(void) 504static void power_thread_rtc_process(void)
448{ 505{
449
450 if (rtc_check_alarm_flag()) { 506 if (rtc_check_alarm_flag()) {
451 rtc_enable_alarm(false); 507 rtc_enable_alarm(false);
452 } 508 }
453} 509}
454#endif 510#endif
@@ -457,24 +513,56 @@ static void power_thread_rtc_process(void)
457 * This function is called to do the relativly long sleep waits from within the 513 * This function is called to do the relativly long sleep waits from within the
458 * main power_thread loop while at the same time servicing any other periodic 514 * main power_thread loop while at the same time servicing any other periodic
459 * functions in the power thread which need to be called at a faster periodic 515 * functions in the power thread which need to be called at a faster periodic
460 * rate than the slow periodic rate of the main power_thread loop 516 * rate than the slow periodic rate of the main power_thread loop.
517 *
518 * While we are waiting for the time to expire, we average the battery
519 * voltages.
461 */ 520 */
462static void power_thread_sleep(int ticks) 521static void power_thread_sleep(int ticks)
463{ 522{
523 int small_ticks;
464#ifdef HAVE_CHARGING 524#ifdef HAVE_CHARGING
525 unsigned int tmp;
526 bool charger_plugged;
527#endif
528
529#ifdef HAVE_CHARGING
530 charger_plugged = charger_inserted();
531#endif
465 while (ticks > 0) { 532 while (ticks > 0) {
466 int small_ticks = MIN(HZ/2, ticks); 533 small_ticks = MIN(HZ/2, ticks);
467 sleep(small_ticks); 534 sleep(small_ticks);
468 ticks -= small_ticks; 535 ticks -= small_ticks;
469 536
537#ifdef HAVE_CHARGING
470 car_adapter_mode_processing(); 538 car_adapter_mode_processing();
539#endif
471#ifdef HAVE_ALARM_MOD 540#ifdef HAVE_ALARM_MOD
472 power_thread_rtc_process(); 541 power_thread_rtc_process();
473#endif 542#endif
474 } 543
475#else 544 /*
476 sleep(ticks); /* no fast-processing functions, sleep the whole time */ 545 * Do a digital exponential filter. We don't sample the battery if
546 * the disk is spinning unless we are in USB mode (the disk will most
547 * likely always be spinning in USB mode).
548 * If the charging voltage is greater than 0x3F0 charging isn't active
549 * and that voltage isn't valid.
550 */
551 if (!ata_disk_is_active() || usb_inserted()) {
552 avgbat = avgbat - (avgbat / BATT_AVE_SAMPLES) +
553 adc_read(ADC_UNREG_POWER);
554 /*
555 * battery_centivolts is the centivolt-scaled filtered battery value.
556 */
557 battery_centivolts = ((avgbat / BATT_AVE_SAMPLES) * BATTERY_SCALE_FACTOR) / 10000;
558 }
559
560#ifdef HAVE_CHARGING
561 /* If the charger was plugged in, exit now so we can start charging */
562 if(!charger_plugged && charger_inserted())
563 return;
477#endif 564#endif
565 }
478} 566}
479 567
480 568
@@ -488,102 +576,60 @@ static void power_thread_sleep(int ticks)
488static void power_thread(void) 576static void power_thread(void)
489{ 577{
490 int i; 578 int i;
491 int avg, ok_samples, spin_samples; 579 short *phps, *phpd; /* power history rotation pointers */
492 int current = 0;
493#if CONFIG_BATTERY == BATT_LIION2200 580#if CONFIG_BATTERY == BATT_LIION2200
494 int charging_current; 581 int charging_current;
495#endif 582#endif
496#ifdef HAVE_CHARGE_CTRL 583#ifdef HAVE_CHARGE_CTRL
497 int delta;
498 int charged_time = 0;
499 int charge_max_time_now = 0; /* max. charging duration, calculated at 584 int charge_max_time_now = 0; /* max. charging duration, calculated at
500 beginning of charging */ 585 beginning of charging */
501 int charge_pause = 0; /* no charging pause at the beginning */
502 int trickle_time = 0; /* how many minutes trickle charging already? */
503#endif 586#endif
587
588 /* initialize the voltages for the exponential filter */
504 589
590 avgbat = adc_read(ADC_UNREG_POWER) * BATT_AVE_SAMPLES;
591 battery_centivolts = ((avgbat / BATT_AVE_SAMPLES) * BATTERY_SCALE_FACTOR) / 10000;
592
593#if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL)
594 fd = -1;
595#endif
596
505 while (1) 597 while (1)
506 { 598 {
507 /* never read power while disk is spinning, unless in USB mode */
508 if (ata_disk_is_active() && !usb_inserted()) {
509#ifdef HAVE_ALARM_MOD
510 power_thread_rtc_process();
511#endif
512 sleep(HZ);
513 continue;
514 }
515
516 /* Make POWER_AVG measurements and calculate an average of that to
517 * reduce the effect of backlights/disk spinning/other variation.
518 */
519 ok_samples = spin_samples = avg = 0;
520 for (i = 0; i < POWER_AVG_N; i++) {
521 if (ata_disk_is_active()) {
522 if (!ok_samples) {
523 /* if we don't have any good non-disk-spinning samples,
524 * we take a sample anyway in case the disk is going
525 * to spin all the time.
526 */
527 avg += adc_read(ADC_UNREG_POWER);
528 spin_samples++;
529 }
530 } else {
531 if (spin_samples) /* throw away disk-spinning samples */
532 spin_samples = avg = 0;
533 avg += adc_read(ADC_UNREG_POWER);
534 ok_samples++;
535 }
536 power_thread_sleep(HZ*POWER_AVG_SLEEP);
537 }
538 avg = avg / ((ok_samples) ? ok_samples : spin_samples);
539
540 /* rotate the power history */ 599 /* rotate the power history */
600 phpd = &power_history[POWER_HISTORY_LEN - 1];
601 phps = phpd - 1;
541 for (i = 0; i < POWER_HISTORY_LEN-1; i++) 602 for (i = 0; i < POWER_HISTORY_LEN-1; i++)
542 power_history[i] = power_history[i+1]; 603 *phpd-- = *phps--;
543
544 /* insert new value in the end, in centivolts 8-) */
545 power_history[POWER_HISTORY_LEN-1] =
546 (avg * BATTERY_SCALE_FACTOR) / 10000;
547 604
548 /* update battery level every minute, ignoring first 15 minutes after 605 /* insert new value at the start, in centivolts 8-) */
549 start charge/decharge */ 606 power_history[0] = battery_centivolts;
550#ifdef HAVE_CHARGE_CTRL 607
551 if ((powermgmt_last_cycle_startstop_min > 25) || (charge_state > 1)) 608 /* update battery level every minute */
552#endif 609 battery_level_update();
553 battery_level_update();
554 610
555 /* calculate estimated remaining running time */ 611 /* calculate estimated remaining running time */
556 /* decharging: remaining running time */ 612 /* discharging: remaining running time */
557 /* charging: remaining charging time */ 613 /* charging: remaining charging time */
558 614
559#ifdef HAVE_CHARGE_CTRL
560 if (charge_state == 1)
561 powermgmt_est_runningtime_min = (100 - battery_level()) *
562 battery_capacity / 100 * 60 / CURRENT_CHARGING;
563 else {
564 current = usb_inserted() ? CURRENT_USB : CURRENT_NORMAL;
565 if ((backlight_get_timeout() == 1) ||
566 (charger_inserted() && backlight_get_on_when_charging()))
567 /* LED always on or LED on when charger connected */
568 current += CURRENT_BACKLIGHT;
569 powermgmt_est_runningtime_min = battery_level() *
570 battery_capacity / 100 * 60 / current;
571#if MEM == 8 /* assuming 192 kbps, the running time is 22% longer with 8MB */
572 powermgmt_est_runningtime_min =
573 powermgmt_est_runningtime_min * 122 / 100;
574#endif /* MEM == 8 */
575 }
576#else
577 current = usb_inserted() ? CURRENT_USB : CURRENT_NORMAL;
578 if (backlight_get_timeout() == 1) /* LED always on */
579 current += CURRENT_BACKLIGHT;
580 powermgmt_est_runningtime_min = battery_level() * 615 powermgmt_est_runningtime_min = battery_level() *
581 battery_capacity / 100 * 60 / current; 616 battery_capacity / 100 * 60 / runcurrent();
582#if MEM == 8 /* assuming 192 kbps, the running time is 22% longer with 8MB */ 617#if MEM == 8 /* assuming 192 kbps, the running time is 22% longer with 8MB */
583 powermgmt_est_runningtime_min = 618 powermgmt_est_runningtime_min =
584 powermgmt_est_runningtime_min * 122 / 100; 619 powermgmt_est_runningtime_min * 122 / 100;
585#endif /* MEM == 8 */ 620#endif /* MEM == 8 */
586#endif /* HAVE_CHARGE_CONTROL */ 621
622#ifdef HAVE_CHARGE_CTRL
623 /*
624 * If we are charging, the "runtime" is estimated time till the battery
625 * is recharged.
626 */
627 // TBD: use real charging current estimate
628 if (charge_state == CHARGING) {
629 powermgmt_est_runningtime_min = (100 - battery_level()) *
630 battery_capacity / 100 * 60 / (CURRENT_MAX_CHG - runcurrent());
631 }
632#endif /* HAVE_CHARGE_CTRL */
587 633
588#if CONFIG_BATTERY == BATT_LIION2200 634#if CONFIG_BATTERY == BATT_LIION2200
589 /* We use the information from the ADC_EXT_POWER ADC channel, which 635 /* We use the information from the ADC_EXT_POWER ADC channel, which
@@ -595,262 +641,235 @@ static void power_thread(void)
595 if(charger_inserted()) { 641 if(charger_inserted()) {
596 charging_current = adc_read(ADC_EXT_POWER); 642 charging_current = adc_read(ADC_EXT_POWER);
597 if(charging_current < 0x80) { 643 if(charging_current < 0x80) {
598 charge_state = 2; /* Trickle */ 644 charge_state = TRICKLE;
599 } else { 645 } else {
600 charge_state = 1; /* Charging */ 646 charge_state = CHARGING;
601 } 647 }
602 } else { 648 } else {
603 charge_state = 0; /* Not charging */ 649 charge_state = DISCHARGING;
604 } 650 }
605#else 651#endif /* # if CONFIG_BATTERY == BATT_LIION2200 */
652
606#ifdef HAVE_CHARGE_CTRL 653#ifdef HAVE_CHARGE_CTRL
607 654
608 if (charge_pause > 0)
609 charge_pause--;
610
611 if (charger_inserted()) { 655 if (charger_inserted()) {
612 if (charge_state == 1) { 656 /*
613 /* charger inserted and enabled */ 657 * Time to start charging again?
614 charged_time++; 658 * 1) If we are currently discharging but trickle is enabled,
615 snprintf(power_message, POWER_MESSAGE_LEN, 659 * the charger must have just been plugged in.
616 "Chg %dm max %dm", charged_time, charge_max_time_now); 660 * 2) If our battery level falls below the restart level, charge!
617 661 */
618 if (charged_time > charge_max_time_now) { 662 if (((charge_state == DISCHARGING) && trickle_charge_enabled) ||
619 DEBUGF("power: charged_time > charge_max_time_now, " 663 (battery_level() < charge_restart_level)) {
620 "enough!\n"); 664
621 /* have charged too long and deltaV detection did not 665 /*
622 work! */ 666 * If the battery level is nearly charged, just trickle.
623 powermgmt_last_cycle_level = battery_level(); 667 * If the battery is in between, top-off and then trickle.
668 */
669 if(battery_percent > charge_restart_level) {
670 powermgmt_last_cycle_level = battery_percent;
624 powermgmt_last_cycle_startstop_min = 0; 671 powermgmt_last_cycle_startstop_min = 0;
625 charger_enable(false); 672 if(battery_percent >= 95) {
626 snprintf(power_message, POWER_MESSAGE_LEN, 673 trickle_sec = START_TRICKLE_SEC;
627 "Chg tmout %d min", charge_max_time_now); 674 charge_state = TRICKLE;
628 /* disable charging for several hours from this point, 675 } else {
629 just to be sure */ 676 trickle_sec = START_TOPOFF_SEC;
630 charge_pause = CHARGE_PAUSE_LEN; 677 charge_state = TOPOFF;
631 /* no trickle charge here, because the charging cycle 678 }
632 didn't end the right way */
633 charge_state = 0; /* 0: decharging/charger off, 1: charge,
634 2: top-off, 3: trickle */
635 } else { 679 } else {
636 if (charged_time > CHARGE_MIN_TIME) { 680 /*
637 /* have charged continuously over the minimum charging 681 * Start the charger full strength
638 time, so we monitor for deltaV going 682 */
639 negative. Multiply thingsby 100 to get more 683 i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500;
640 accuracy without floating point arithmetic. 684 charge_max_time_now =
641 power_history[] contains centivolts so after 685 i * (100 + 35 - battery_percent) / 100;
642 multiplying by 100 the deltas are in tenths of 686 if (charge_max_time_now > i) {
643 millivolts (delta of 5 is 0.0005 V). 687 charge_max_time_now = i;
644 */ 688 }
645 delta = 689 snprintf(power_message, POWER_MESSAGE_LEN,
646 ( power_history[POWER_HISTORY_LEN-1] * 100 690 "ChgAt %d%% max %dm", battery_level(),
647 + power_history[POWER_HISTORY_LEN-2] * 100 691 charge_max_time_now);
648 - power_history[POWER_HISTORY_LEN-1- 692
649 CHARGE_END_NEGD+1] * 100 693 /* enable the charger after the max time calc is done,
650 - power_history[POWER_HISTORY_LEN-1- 694 because battery_level depends on if the charger is
651 CHARGE_END_NEGD] * 100 ) 695 on */
652 / CHARGE_END_NEGD / 2; 696 DEBUGF("power: charger inserted and battery"
653 697 " not full, enabling\n");
654 if (delta < -100) { /* delta < -10 mV */ 698 powermgmt_last_cycle_level = battery_percent;
699 powermgmt_last_cycle_startstop_min = 0;
700 trickle_sec = 60;
701 charge_state = CHARGING;
702 }
703 }
704 if (charge_state == CHARGING) {
705 /* charger inserted and enabled 100% of the time */
706 trickle_sec = 60; /* 100% on */
707
708 snprintf(power_message, POWER_MESSAGE_LEN,
709 "Chg %dm, max %dm", powermgmt_last_cycle_startstop_min,
710 charge_max_time_now);
711 /*
712 * Sum the deltas over the last X minutes so we can do our
713 * end-of-charge logic based on the battery level change.
714 */
715 long_delta = short_delta = 999999;
716 if (powermgmt_last_cycle_startstop_min > CHARGE_MIN_TIME) {
717 short_delta = power_history[0] -
718 power_history[CHARGE_END_NEGD - 1];
719 }
720 if (powermgmt_last_cycle_startstop_min > CHARGE_END_ZEROD) {
721 /*
722 * Scan the history: if we have a big delta in the middle of
723 * our history, the long term delta isn't a valid end-of-charge
724 * indicator.
725 */
726 long_delta = power_history[0] -
727 power_history[CHARGE_END_ZEROD - 1];
728 for(i = 0; i < CHARGE_END_ZEROD; i++) {
729 if(((power_history[i] - power_history[i+1]) > 5) ||
730 ((power_history[i] - power_history[i+1]) < -5)) {
731 long_delta = 888888;
732 break;
733 }
734 }
735 }
736
737 /*
738 * End of charge criteria (any qualify):
739 * 1) Charged a long time
740 * 2) DeltaV went negative for a short time
741 * 3) DeltaV was close to zero for a long time
742 * Note: short_delta and long_delta are centivolts
743 */
744 if ((powermgmt_last_cycle_startstop_min > charge_max_time_now) ||
745 (short_delta < -5) || (long_delta < 5))
746 {
747 if (powermgmt_last_cycle_startstop_min > charge_max_time_now) {
748 DEBUGF("power: powermgmt_last_cycle_startstop_min > charge_max_time_now, "
749 "enough!\n");
750 /* have charged too long and deltaV detection did not
751 work! */
752 snprintf(power_message, POWER_MESSAGE_LEN,
753 "Chg tmout %d min", charge_max_time_now);
754 } else {
755 if(short_delta < -5) {
655 DEBUGF("power: short-term negative" 756 DEBUGF("power: short-term negative"
656 " delta, enough!\n"); 757 " delta, enough!\n");
657 powermgmt_last_cycle_level = battery_level();
658 powermgmt_last_cycle_startstop_min = 0;
659 charger_enable(false);
660 snprintf(power_message, POWER_MESSAGE_LEN, 758 snprintf(power_message, POWER_MESSAGE_LEN,
661 "end negd %d %dmin", delta, charged_time); 759 "end negd %d %dmin", short_delta,
662 /* disable charging for several hours from this 760 powermgmt_last_cycle_startstop_min);
663 point, just to be sure */
664 charge_pause = CHARGE_PAUSE_LEN;
665 /* enable trickle charging */
666 if (trickle_charge_enabled) {
667 trickle_sec = CURRENT_NORMAL * 60 /
668 CURRENT_CHARGING;
669 /* first guess, maybe consider if LED
670 backlight is on, disk is active,... */
671 trickle_time = 0;
672 charge_state = 2; /* 0: decharging/charger
673 off, 1: charge,
674 2: top-off, 3: trickle */
675 } else {
676 charge_state = 0; /* 0: decharging/charger
677 off, 1: charge,
678 2: top-off, 3: trickle */
679 }
680 } else { 761 } else {
681 /* if we didn't disable the charger in the 762 DEBUGF("power: long-term small "
682 previous test, check for low positive delta */ 763 "positive delta, enough!\n");
683 delta = 764 snprintf(power_message, POWER_MESSAGE_LEN,
684 ( power_history[POWER_HISTORY_LEN-1] * 100 765 "end lowd %d %dmin", long_delta,
685 + power_history[POWER_HISTORY_LEN-2] * 100 766 powermgmt_last_cycle_startstop_min);
686 - power_history[POWER_HISTORY_LEN-1-
687 CHARGE_END_ZEROD+1] * 100
688 - power_history[POWER_HISTORY_LEN-1-
689 CHARGE_END_ZEROD] * 100 )
690 / CHARGE_END_ZEROD / 2;
691
692 if (delta < 1) { /* delta < 0.1 mV */
693 DEBUGF("power: long-term small "
694 "positive delta, enough!\n");
695 powermgmt_last_cycle_level = battery_level();
696 powermgmt_last_cycle_startstop_min = 0;
697 charger_enable(false);
698 snprintf(power_message, POWER_MESSAGE_LEN,
699 "end lowd %d %dmin",
700 delta, charged_time);
701 /* disable charging for several hours from
702 this point, just to be sure */
703 charge_pause = CHARGE_PAUSE_LEN;
704 /* enable trickle charging */
705 if (trickle_charge_enabled) {
706 trickle_sec =
707 CURRENT_NORMAL * 60 / CURRENT_CHARGING;
708 /* first guess, maybe consider if LED
709 backlight is on, disk is active,... */
710 trickle_time = 0;
711 charge_state = 2;
712 /* 0: decharging/charger off, 1: charge,
713 2: top-off, 3: trickle */
714 } else {
715 charge_state = 0;
716 /* 0: decharging/charger off, 1: charge,
717 2: top-off, 3: trickle */
718 }
719 }
720 } 767 }
721 } 768 }
769 /* Switch to trickle charging. We skip the top-off
770 since we've effectively done the top-off operation
771 already since we charged for the maximum full
772 charge time. For trickle charging, we use 0.05C */
773 powermgmt_last_cycle_level = battery_percent;
774 powermgmt_last_cycle_startstop_min = 0;
775 if (trickle_charge_enabled) {
776 trickle_sec = START_TRICKLE_SEC;
777 charge_state = TRICKLE;
778 } else {
779 /* If we don't trickle charge, we discharge */
780 trickle_sec = 0; /* off */
781 charge_state = DISCHARGING;
782 }
722 } 783 }
723 } 784 }
724 else if (charge_state > 1) { /* top off or trickle? */ 785 else if (charge_state > CHARGING) /* top off or trickle */
725 /* adjust trickle charge time */ 786 {
726 if ( ((charge_state == 2) && 787 /* Time to switch from topoff to trickle? Note that we don't
727 (power_history[POWER_HISTORY_LEN-1] > TOPOFF_VOLTAGE)) 788 * adjust trickle_sec: it will get adjusted down by the
728 || ((charge_state == 3) && 789 * charge level adjustment in the loop and will drift down
729 (power_history[POWER_HISTORY_LEN-1] > 790 * from the topoff level to the trickle level.
730 TRICKLE_VOLTAGE)) ) { /* charging too much */ 791 */
731 trickle_sec--; 792 if ((charge_state == TOPOFF) &&
732 } 793 (powermgmt_last_cycle_startstop_min > TOPOFF_MAX_TIME))
733 else { /* charging too less */ 794 {
734 trickle_sec++; 795 powermgmt_last_cycle_level = battery_percent;
735 }
736
737 if (trickle_sec > 24)
738 trickle_sec = 24;
739
740 if (trickle_sec < 1)
741 trickle_sec = 1;
742
743 /* charge the calculated amount of seconds */
744 charger_enable(true);
745 power_thread_sleep(HZ * trickle_sec);
746 charger_enable(false);
747
748 /* trickle charging long enough? */
749
750 if (trickle_time++ > TRICKLE_MAX_TIME + TOPOFF_MAX_TIME) {
751 trickle_sec = 0; /* show in debug menu that trickle is
752 off */
753 charge_state = 0; /* 0: decharging/charger off, 1: charge,
754 2: top-off, 3: trickle */
755 powermgmt_last_cycle_startstop_min = 0; 796 powermgmt_last_cycle_startstop_min = 0;
797 charge_state = TRICKLE;
756 } 798 }
757 799
758 if ((charge_state == 2) && 800 /* Adjust trickle charge time. I considered setting the level
759 (trickle_time > TOPOFF_MAX_TIME)) /* change state? */ 801 * higher if the USB is plugged in, but it doesn't appear to
760 charge_state = 3; /* 0: decharging/charger off, 1: charge, 802 * be necessary and will generate more heat [gvb].
761 2: top-off, 3: trickle */ 803 */
762 804 if(((charge_state == TOPOFF) && (battery_centivolts > TOPOFF_VOLTAGE)) ||
763 } else { /* charge_state == 0 */ 805 ((charge_state == TRICKLE) && (battery_centivolts > TRICKLE_VOLTAGE)))
806 { /* charging too much */
807 if(trickle_sec > 0)
808 trickle_sec--;
809 }
810 else { /* charging too little */
811 if(trickle_sec < 60)
812 trickle_sec++;
813 }
764 814
815 } else if (charge_state == DISCHARGING) {
816 trickle_sec = 0;
765 /* the charger is enabled here only in one case: if it was 817 /* the charger is enabled here only in one case: if it was
766 turned on at boot time (power_init) */ 818 turned on at boot time (power_init) */
767 /* turn it off now */ 819 /* turn it off now */
768 if (charger_enabled) 820 if (charger_enabled)
769 charger_enable(false); 821 charger_enable(false);
770 } 822 }
771
772 /* Start new charge cycle? This must be possible also in
773 trickle/top-off, because when usb connected, */
774 /* the trickle charge amount may not be enough */
775
776 if ((charge_state == 0) || (charge_state > 1))
777 /* if battery is not full, enable charging */
778 /* make sure charging starts if 1%-lazyness in
779 battery_level_update() is too slow */
780 if ( (battery_level() < charge_restart_level)
781 || (power_history[POWER_HISTORY_LEN-1] <
782 BATTERY_LEVEL_DANGEROUS)) {
783 if (charge_pause) {
784 DEBUGF("power: batt level < restart level,"
785 " but charge pause, not enabling\n");
786 snprintf(power_message, POWER_MESSAGE_LEN,
787 "chg pause %d min", charge_pause);
788 } else {
789 /* calculate max charge time depending on current
790 battery level */
791 /* take 35% more because some more energy is used for
792 heating up the battery */
793 i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500;
794 charge_max_time_now =
795 i * (100 + 35 - battery_level()) / 100;
796 if (charge_max_time_now > i) {
797 charge_max_time_now = i;
798 }
799 snprintf(power_message, POWER_MESSAGE_LEN,
800 "ChgAt %d%% max %dm", battery_level(),
801 charge_max_time_now);
802
803 /* enable the charger after the max time calc is done,
804 because battery_level depends on if the charger is
805 on */
806 DEBUGF("power: charger inserted and battery"
807 " not full, enabling\n");
808 powermgmt_last_cycle_level = battery_level();
809 powermgmt_last_cycle_startstop_min = 0;
810 charged_time = 0;
811
812 charger_enable(true);
813 charge_state = 1; /* 0: decharging/charger off, 1:
814 charge, 2: top-off, 3: trickle */
815 /* clear the power history so that we don't use values
816 before discharge for the long-term delta
817 */
818 for (i = 0; i < POWER_HISTORY_LEN-1; i++)
819 power_history[i] =
820 power_history[POWER_HISTORY_LEN-1];
821 }
822 }
823
824 } else { 823 } else {
825 /* charger not inserted */ 824 if (charge_state != DISCHARGING) {
826 if (charge_state > 0) {
827 /* charger not inserted but was enabled */ 825 /* charger not inserted but was enabled */
828 DEBUGF("power: charger disconnected, disabling\n"); 826 DEBUGF("power: charger disconnected, disabling\n");
829 powermgmt_last_cycle_level = battery_level(); 827
828 charger_enable(false);
829 powermgmt_last_cycle_level = battery_percent;
830 powermgmt_last_cycle_startstop_min = 0; 830 powermgmt_last_cycle_startstop_min = 0;
831 /* show in debug menu that trickle is off */
832 trickle_sec = 0; 831 trickle_sec = 0;
833 charger_enable(false); 832 charge_state = DISCHARGING;
834 charge_state = 0; /* 0: decharging/charger off, 1: charge, 2: 833 snprintf(power_message, POWER_MESSAGE_LEN, "Charger: discharge");
835 top-off, 3: trickle */
836 snprintf(power_message, POWER_MESSAGE_LEN, "Charger disc");
837 } 834 }
838 /* charger not inserted and disabled, so we're discharging */
839 } 835 }
840 powermgmt_last_cycle_startstop_min++; 836 powermgmt_last_cycle_startstop_min++;
841 837
842#endif /* HAVE_CHARGE_CTRL*/ 838#endif /* HAVE_CHARGE_CTRL*/
843#endif /* # if CONFIG_BATTERY == BATT_LIION2200 */ 839
844 840 /* sleep for a minute */
845 /* sleep for roughly a minute */ 841
846#ifdef HAVE_CHARGE_CTRL 842#ifdef HAVE_CHARGE_CTRL
847 i = 60 - trickle_sec - POWER_AVG_N * POWER_AVG_SLEEP; 843 if(trickle_sec > 0) {
844 charger_enable(true);
845 power_thread_sleep(HZ * trickle_sec);
846 }
847 if(trickle_sec < 60)
848 charger_enable(false);
849 power_thread_sleep(HZ * (60 - trickle_sec));
848#else 850#else
849 i = 60 - POWER_AVG_N * POWER_AVG_SLEEP; 851 power_thread_sleep(HZ * 60);
850#endif 852#endif
851 if (i > 0)
852 power_thread_sleep(HZ*(i));
853 853
854#if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL)
855 if((fd < 0) && !usb_inserted()) {
856 fd = open(DEBUG_FILE_NAME, O_WRONLY | O_APPEND | O_CREAT);
857 snprintf(debug_message, DEBUG_MESSAGE_LEN,
858 "cycle_min, bat_centivolts, bat_percent, chgr, chg_state, trickle_sec\n");
859 write(fd, debug_message, strlen(debug_message));
860 fsync(fd);
861 } else if((fd >= 0) && !usb_inserted()) {
862 snprintf(debug_message, DEBUG_MESSAGE_LEN, "%d, %d, %d, %d, %d, %d\n",
863 powermgmt_last_cycle_startstop_min, battery_centivolts,
864 battery_percent, charger_inserted(), charge_state, trickle_sec);
865 write(fd, debug_message, strlen(debug_message));
866 fsync(fd);
867 } else if((fd >= 0) && usb_inserted()) {
868 /* NOTE: It is probably already TOO LATE to close the file */
869 close(fd);
870 fd = -1;
871 }
872#endif
854 handle_auto_poweroff(); 873 handle_auto_poweroff();
855 } 874 }
856} 875}
@@ -862,31 +881,9 @@ void powermgmt_init(void)
862 /* init history to 0 */ 881 /* init history to 0 */
863 memset(power_history, 0x00, sizeof(power_history)); 882 memset(power_history, 0x00, sizeof(power_history));
864 883
865#if 0 884#ifdef HAVE_CHARGING
866 /* initialize the history with a single sample to prevent level
867 flickering during the first minute of execution */
868 power_history[POWER_HISTORY_LEN-1] =
869 (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000;
870 /* calculate the first battery level */
871 battery_level_update();
872 /* calculate the remaining time to that the info screen displays something
873 useful */
874 powermgmt_est_runningtime_min =
875 battery_level() * battery_capacity / 100 * 60 / CURRENT_NORMAL;
876#if MEM == 8 /* assuming 192 kbps, the running time is 22% longer with 8MB */
877 powermgmt_est_runningtime_min = powermgmt_est_runningtime_min * 122 / 100;
878#endif
879
880#ifdef HAVE_CHARGE_CTRL
881 snprintf(power_message, POWER_MESSAGE_LEN, "Powermgmt started");
882
883 /* if the battery is nearly empty, start charging immediately */
884 if (power_history[POWER_HISTORY_LEN-1] < BATTERY_LEVEL_DANGEROUS)
885 charger_enable(true);
886#endif
887#endif
888
889 charger_power_is_on = charger_inserted(); 885 charger_power_is_on = charger_inserted();
886#endif
890 887
891 create_thread(power_thread, power_stack, sizeof(power_stack), 888 create_thread(power_thread, power_stack, sizeof(power_stack),
892 power_thread_name); 889 power_thread_name);
@@ -898,11 +895,17 @@ void powermgmt_init(void)
898void shutdown_hw(void) 895void shutdown_hw(void)
899{ 896{
900#ifndef SIMULATOR 897#ifndef SIMULATOR
898#if defined(DEBUG_FILE) && defined(HAVE_CHARGE_CTRL)
899 if(fd > 0) {
900 close(fd);
901 fd = 0;
902 }
903#endif
901 mpeg_stop(); 904 mpeg_stop();
902 ata_flush(); 905 ata_flush();
903 ata_spindown(1); 906 ata_spindown(1);
904 while(ata_disk_is_active()) 907 while(ata_disk_is_active())
905 sleep(HZ/10); 908 sleep(HZ/10);
906 909
907 mp3_shutdown(); 910 mp3_shutdown();
908#if CONFIG_KEYPAD == ONDIO_PAD 911#if CONFIG_KEYPAD == ONDIO_PAD