summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/debug_menu.c53
-rw-r--r--apps/settings.c3
-rw-r--r--apps/settings_menu.c3
-rwxr-xr-xdocs/CHARGING_ALGORITHM82
-rw-r--r--firmware/export/adc.h2
-rw-r--r--firmware/export/powermgmt.h39
-rw-r--r--firmware/powermgmt.c819
7 files changed, 507 insertions, 494 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 815eb5af67..7b81869e69 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -968,7 +968,7 @@ bool dbg_mas_codec(void)
968 * The power_history array is updated in power_thread of powermgmt.c. 968 * The power_history array is updated in power_thread of powermgmt.c.
969 */ 969 */
970 970
971#define BAT_FIRST_VAL MAX(POWER_HISTORY_LEN - LCD_WIDTH - 1, 0) 971#define BAT_LAST_VAL MIN(LCD_WIDTH, POWER_HISTORY_LEN)
972#define BAT_YSPACE (LCD_HEIGHT - 20) 972#define BAT_YSPACE (LCD_HEIGHT - 20)
973 973
974bool view_battery(void) 974bool view_battery(void)
@@ -986,30 +986,32 @@ bool view_battery(void)
986 switch (view) { 986 switch (view) {
987 case 0: /* voltage history graph */ 987 case 0: /* voltage history graph */
988 /* Find maximum and minimum voltage for scaling */ 988 /* Find maximum and minimum voltage for scaling */
989 maxv = minv = 0; 989 maxv = 0;
990 for (i = BAT_FIRST_VAL; i < POWER_HISTORY_LEN; i++) { 990 minv = 65535;
991 for (i = 0; i < BAT_LAST_VAL; i++) {
991 if (power_history[i] > maxv) 992 if (power_history[i] > maxv)
992 maxv = power_history[i]; 993 maxv = power_history[i];
993 if ((minv == 0) || ((power_history[i]) && 994 if (power_history[i] && (power_history[i] < minv))
994 (power_history[i] < minv)) )
995 { 995 {
996 minv = power_history[i]; 996 minv = power_history[i];
997 } 997 }
998 } 998 }
999 999
1000 if (minv < 1) 1000 if ((minv < 1) || (minv >= 65535))
1001 minv = 1; 1001 minv = 1;
1002 if (maxv < 2) 1002 if (maxv < 2)
1003 maxv = 2; 1003 maxv = 2;
1004 1004
1005 lcd_clear_display(); 1005 lcd_clear_display();
1006 lcd_puts(0, 0, "Battery voltage:"); 1006 snprintf(buf, 30, "Battery %d.%02d", power_history[0] / 100,
1007 power_history[0] % 100);
1008 lcd_puts(0, 0, buf);
1007 snprintf(buf, 30, "scale %d.%02d-%d.%02d V", 1009 snprintf(buf, 30, "scale %d.%02d-%d.%02d V",
1008 minv / 100, minv % 100, maxv / 100, maxv % 100); 1010 minv / 100, minv % 100, maxv / 100, maxv % 100);
1009 lcd_puts(0, 1, buf); 1011 lcd_puts(0, 1, buf);
1010 1012
1011 x = 0; 1013 x = 0;
1012 for (i = BAT_FIRST_VAL+1; i < POWER_HISTORY_LEN; i++) { 1014 for (i = BAT_LAST_VAL - 1; i >= 0; i--) {
1013 y = (power_history[i] - minv) * BAT_YSPACE / (maxv - minv); 1015 y = (power_history[i] - minv) * BAT_YSPACE / (maxv - minv);
1014 lcd_clearline(x, LCD_HEIGHT-1, x, 20); 1016 lcd_clearline(x, LCD_HEIGHT-1, x, 20);
1015 lcd_drawline(x, LCD_HEIGHT-1, x, 1017 lcd_drawline(x, LCD_HEIGHT-1, x,
@@ -1035,31 +1037,15 @@ bool view_battery(void)
1035 snprintf(buf, 30, "Charger: %s", 1037 snprintf(buf, 30, "Charger: %s",
1036 charger_inserted() ? "present" : "absent"); 1038 charger_inserted() ? "present" : "absent");
1037 lcd_puts(0, 3, buf); 1039 lcd_puts(0, 3, buf);
1040#endif
1038#ifdef HAVE_CHARGE_CTRL 1041#ifdef HAVE_CHARGE_CTRL
1039 snprintf(buf, 30, "Charging: %s", 1042 snprintf(buf, 30, "Charging: %s",
1040 charger_enabled ? "yes" : "no"); 1043 charger_enabled ? "yes" : "no");
1041 lcd_puts(0, 4, buf); 1044 lcd_puts(0, 4, buf);
1042#endif 1045 snprintf(buf, 30, "short delta: %d", short_delta);
1043#endif
1044 y = ( power_history[POWER_HISTORY_LEN-1] * 100
1045 + power_history[POWER_HISTORY_LEN-2] * 100
1046 - power_history[POWER_HISTORY_LEN-1-CHARGE_END_NEGD+1] * 100
1047 - power_history[POWER_HISTORY_LEN-1-CHARGE_END_NEGD] * 100 )
1048 / CHARGE_END_NEGD / 2;
1049
1050 snprintf(buf, 30, "short delta: %d", y);
1051 lcd_puts(0, 5, buf); 1046 lcd_puts(0, 5, buf);
1052 1047 snprintf(buf, 30, "long delta: %d", long_delta);
1053 y = ( power_history[POWER_HISTORY_LEN-1] * 100
1054 + power_history[POWER_HISTORY_LEN-2] * 100
1055 - power_history[POWER_HISTORY_LEN-1-CHARGE_END_ZEROD+1] * 100
1056 - power_history[POWER_HISTORY_LEN-1-CHARGE_END_ZEROD] * 100 )
1057 / CHARGE_END_ZEROD / 2;
1058
1059 snprintf(buf, 30, "long delta: %d", y);
1060 lcd_puts(0, 6, buf); 1048 lcd_puts(0, 6, buf);
1061
1062#ifdef HAVE_CHARGE_CTRL
1063 lcd_puts(0, 7, power_message); 1049 lcd_puts(0, 7, power_message);
1064#endif 1050#endif
1065 break; 1051 break;
@@ -1069,8 +1055,7 @@ bool view_battery(void)
1069 lcd_puts(0, 0, "Voltage deltas:"); 1055 lcd_puts(0, 0, "Voltage deltas:");
1070 1056
1071 for (i = 0; i <= 6; i++) { 1057 for (i = 0; i <= 6; i++) {
1072 y = power_history[POWER_HISTORY_LEN-1-i] - 1058 y = power_history[i] - power_history[i+i];
1073 power_history[POWER_HISTORY_LEN-1-i-1];
1074 snprintf(buf, 30, "-%d min: %s%d.%02d V", i, 1059 snprintf(buf, 30, "-%d min: %s%d.%02d V", i,
1075 (y < 0) ? "-" : "", ((y < 0) ? y * -1 : y) / 100, 1060 (y < 0) ? "-" : "", ((y < 0) ? y * -1 : y) / 100,
1076 ((y < 0) ? y * -1 : y ) % 100); 1061 ((y < 0) ? y * -1 : y ) % 100);
@@ -1088,19 +1073,19 @@ bool view_battery(void)
1088 snprintf(buf, 30, "Cycle time: %d m", powermgmt_last_cycle_startstop_min); 1073 snprintf(buf, 30, "Cycle time: %d m", powermgmt_last_cycle_startstop_min);
1089 lcd_puts(0, 1, buf); 1074 lcd_puts(0, 1, buf);
1090 1075
1091 snprintf(buf, 30, "Lev.at cycle start: %d%%", powermgmt_last_cycle_level); 1076 snprintf(buf, 30, "Lvl@cyc st: %d%%", powermgmt_last_cycle_level);
1092 lcd_puts(0, 2, buf); 1077 lcd_puts(0, 2, buf);
1093#endif 1078#endif
1094 1079
1095 snprintf(buf, 30, "Last PwrHist val: %d.%02d V", 1080 snprintf(buf, 30, "Last PwrHist: %d.%02d V",
1096 power_history[POWER_HISTORY_LEN-1] / 100, 1081 power_history[0] / 100,
1097 power_history[POWER_HISTORY_LEN-1] % 100); 1082 power_history[0] % 100);
1098 lcd_puts(0, 3, buf); 1083 lcd_puts(0, 3, buf);
1099 1084
1100 snprintf(buf, 30, "battery level: %d%%", battery_level()); 1085 snprintf(buf, 30, "battery level: %d%%", battery_level());
1101 lcd_puts(0, 5, buf); 1086 lcd_puts(0, 5, buf);
1102 1087
1103 snprintf(buf, 30, "Est. remaining: %d m", battery_time()); 1088 snprintf(buf, 30, "Est. remain: %d m", battery_time());
1104 lcd_puts(0, 6, buf); 1089 lcd_puts(0, 6, buf);
1105 1090
1106#ifdef HAVE_CHARGE_CTRL 1091#ifdef HAVE_CHARGE_CTRL
diff --git a/apps/settings.c b/apps/settings.c
index 86c1178745..866f87879e 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -763,8 +763,7 @@ void settings_apply(void)
763 763
764 set_poweroff_timeout(global_settings.poweroff); 764 set_poweroff_timeout(global_settings.poweroff);
765#ifdef HAVE_CHARGE_CTRL 765#ifdef HAVE_CHARGE_CTRL
766 charge_restart_level = global_settings.discharge ? 766 enable_deep_discharge(global_settings.discharge);
767 CHARGE_RESTART_LO : CHARGE_RESTART_HI;
768 enable_trickle_charge(global_settings.trickle_charge); 767 enable_trickle_charge(global_settings.trickle_charge);
769#endif 768#endif
770 769
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index b19f2eda3c..4d164180dc 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -727,8 +727,7 @@ static bool deep_discharge(void)
727{ 727{
728 bool result; 728 bool result;
729 result = set_bool( str(LANG_DISCHARGE), &global_settings.discharge ); 729 result = set_bool( str(LANG_DISCHARGE), &global_settings.discharge );
730 charge_restart_level = global_settings.discharge ? 730 enable_deep_discharge(global_settings.discharge);
731 CHARGE_RESTART_LO : CHARGE_RESTART_HI;
732 return result; 731 return result;
733} 732}
734static bool trickle_charge(void) 733static bool trickle_charge(void)
diff --git a/docs/CHARGING_ALGORITHM b/docs/CHARGING_ALGORITHM
index a1a6e2b56e..4a89cac149 100755
--- a/docs/CHARGING_ALGORITHM
+++ b/docs/CHARGING_ALGORITHM
@@ -8,12 +8,13 @@ miss some information here, write to mail@uwe-freese.de.
8 8
9[INTRODUCTION] 9[INTRODUCTION]
10 10
11This doc describes how the charging works for the recorder. The algorithm can 11This doc describes how the charging works for the recorder. The algorithm
12be found in firmware/powermgmt.[c|h]. Debug output is done in 12can be found in firmware/powermgmt.[c|h]. Debug output is done in
13 apps/debug_menu.c. 13apps/debug_menu.c.
14Charging for the player and the FM/V2 recorder is done by the hardware and 14
15therefore isn't implemented in rockbox. Only the functions that calculate the 15Charging for the player and the FM/V2 recorder is done by the hardware and
16battery level are also used for these models. 16therefore isn't implemented in rockbox. Only the functions that
17calculate the battery level are also used for these models.
17 18
18All following information is related to the recorder. 19All following information is related to the recorder.
19 20
@@ -38,15 +39,13 @@ voltage. Both voltage curves (charging and decharging) are used here.
38[CHARGE OVERVIEW] 39[CHARGE OVERVIEW]
39 40
40- If voltage drops under a certain value (with "deep discharge" option on the 41- If voltage drops under a certain value (with "deep discharge" option on the
41 value is lower), charging is started. 42 value is a lot lower), charging is started.
42- If end of charge is detected, go to top off charge. 43- If end of charge is detected, go to top off charge.
43- Make the batteries completely full. 90 minutes of top off charge (voltage 44- Make the batteries completely full. 90 minutes of top off charge (voltage
44 regulation at a high value). 45 regulation at a higher value).
45- After that, do trickle charge (max. 12 hours with voltage regulation at a 46- After that, trickle charge (voltage regulation at a nominal battery value).
46 lower value). 47 The trickle charge will continue as long as the charger is plugged in (this
47- When trickle charge is done and you did not disconnect or shut off your AJB 48 is a change from the original charge algorithm).
48 by now, the AJB decharges normally since it reaches a low voltage and
49 everything starts from the beginning.
50 49
51 50
52[NORMAL CHARGE] 51[NORMAL CHARGE]
@@ -89,7 +88,7 @@ Two facts on batteries are the reason why this works:
89 goes down when the temperature goes up. 88 goes down when the temperature goes up.
90 89
91NiMH batteries have a smaller delta peak than NiCd, but is is enough for 90NiMH batteries have a smaller delta peak than NiCd, but is is enough for
92Rockbox to detect that the batteries are full. 91Rockbox to detect that the batteries are full (in theory :-).
93 92
94Related documents on the web: 93Related documents on the web:
95 94
@@ -114,20 +113,33 @@ It goes on again and then the archos firmware charger code would charge again.
114So we have trickle charge in rockbox. 113So we have trickle charge in rockbox.
115 114
116In simple words, rockbox charges about 15 seconds per minute in trickle mode. 115In simple words, rockbox charges about 15 seconds per minute in trickle mode.
117An AJB consumes 100 mA when it's on and the charging current is about 300mA. 116An AJB consumes 100 mA when it's on and the charging current is about 350mA.
118So charging 15 s and decharge 45 s will keep the batteries full. 117So charging 15 s and decharge 45 s will keep the batteries full.
119 118
120But the number of seconds the charger is on in trickle charge mode is also 119But the number of seconds the charger is on in trickle charge mode is
121adjusted dynamically (between 1 and 24 sec). Rockbox tries to hold the battery 120also adjusted dynamically. Rockbox tries to hold the battery level at
122level at 5,65 V (top off charge, that means "make the batteries completely 1215,65 V (top off charge, that means "make the batteries completely full")
123full") for 90 minutes, then a level of 5,45 V. If the voltage drops below the 122for 90 minutes, then a level of 5,45 V. If the voltage drops below the
124wanted value, rockbox will charge one second more the next minute. If is is 123desired value, rockbox will charge one second more the next minute. If
125greater than this value, is will charge one second less. 124is is greater than this value, is will charge one second less.
126 125
127Trickle charging runs 12 hours after finishing the normal charging. That 126The number of seconds the charger is on in top off and trickle charge
128should be enough for charging the AJB over night and then unplug the charger 127modes is also dependant on the charger's output voltage: if the charger
129sometime in this 12 hour trickle charge time. It is not recommended to trickle 128supplies less than about 10v, the current into the batteries is less and
130charge over days, that's because it is stopped after 12 hours. 129thus the percentage on is increased to maintain the proper current into
130the batteries.
131
132The original recharging algorithm stopped trickle charging after 12 hours,
133at which time the battery would be discharged until the the batteries
134fell below the "start charging" level. At that time the charge cycle
135would be repeated.
136
137The time limit was removed by Jerry Van Baren (along with other changes)
138in the February, 2005 timeframe. The rationale for this is that the
139trickle charge level is very low. In addition, it is disconcerting to
140have a AJR plugged in and "recharged" only to find out that the battery
141is only 86% full. This was giving the Rockbox recharging algorithm a
142bad name and frustrating our users.
131 143
132Many chargers do top off and trickle charge by feeding a constant (low) 144Many chargers do top off and trickle charge by feeding a constant (low)
133current to the batteries. Rockbox, as described, makes a voltage regulation. 145current to the batteries. Rockbox, as described, makes a voltage regulation.
@@ -177,25 +189,23 @@ because it uses the raw voltages):
177 always set the battery level to 100% 189 always set the battery level to 100%
178- the battery level is only allowed to change 1% per minute (exception: when 190- the battery level is only allowed to change 1% per minute (exception: when
179 usb is connected, it is allowed to go 3% down/min) 191 usb is connected, it is allowed to go 3% down/min)
180- if charging just started (or stopped), ignore the battery voltage for the
181 first 25 minutes
182- after turning on the device, add another 5% to the battery level, because 192- after turning on the device, add another 5% to the battery level, because
183 the drive is used heavily when booting and the voltage usually gets a 193 the drive is used heavily when booting and the voltage usually gets a
184 little higher after that 194 little higher after that (rebounds)
185 195
186 196
187[WHICH CHARGING MODE TO USE] 197[WHICH CHARGING MODE TO USE]
188 198
189If you use your AJB connected to the power supply the whole time, select "deep 199Jerry Van Baren's revised recommendation: Select "deep discharge OFF"
190discharge on" and "trickle charge off". 200and "trickle charge ON". This will keep your batteries charged up and
201IMHO will not damage them.
191 202
192If you want to charge your AJB over night and take it with you the next day, 203Original recommendation:
193select "deep discharge off" (that it starts charging immediately) and "trickle
194charge on" (that the batteries remain full).
195 204
196A special case: If you fill up the batteries that are still nearly full every 205A special case: If you use your AJR connected to the power supply all
206the time or if you fill up the batteries that are still nearly full every
197night, it is recommended that you make a complete charge cycle from time to 207night, it is recommended that you make a complete charge cycle from time to
198time. Select "deep discharge on" and "trickle charge on" and wait till the 208time. Select "deep discharge ON" and "trickle charge OFF" and wait till the
199whole cycle is over (you can speed up the discharging a little bit by turning 209whole cycle is over (you can speed up the discharging a little bit by turning
200on the LED backlight). Even if the battery sellers say NiMH cells don't show a 210on the LED backlight). Even if the battery sellers say NiMH cells don't show a
201memory effect, I recommend making this procedure from time to time (every 10th 211memory effect, I recommend making this procedure from time to time (every 10th
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