diff options
34 files changed, 1315 insertions, 1102 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index beee39a09b..abb6018a10 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -1603,10 +1603,10 @@ static bool view_battery(void) | |||
1603 | lcd_puts(0, 2, buf); | 1603 | lcd_puts(0, 2, buf); |
1604 | #endif | 1604 | #endif |
1605 | #if CONFIG_CHARGING | 1605 | #if CONFIG_CHARGING |
1606 | #if CONFIG_CHARGING == CHARGING_CONTROL | 1606 | #if defined ARCHOS_RECORDER |
1607 | snprintf(buf, 30, "Chgr: %s %s", | 1607 | snprintf(buf, 30, "Chgr: %s %s", |
1608 | charger_inserted() ? "present" : "absent", | 1608 | charger_inserted() ? "present" : "absent", |
1609 | charger_enabled ? "on" : "off"); | 1609 | charger_enabled() ? "on" : "off"); |
1610 | lcd_puts(0, 3, buf); | 1610 | lcd_puts(0, 3, buf); |
1611 | snprintf(buf, 30, "short delta: %d", short_delta); | 1611 | snprintf(buf, 30, "short delta: %d", short_delta); |
1612 | lcd_puts(0, 5, buf); | 1612 | lcd_puts(0, 5, buf); |
@@ -1616,13 +1616,11 @@ static bool view_battery(void) | |||
1616 | snprintf(buf, 30, "USB Inserted: %s", | 1616 | snprintf(buf, 30, "USB Inserted: %s", |
1617 | usb_inserted() ? "yes" : "no"); | 1617 | usb_inserted() ? "yes" : "no"); |
1618 | lcd_puts(0, 8, buf); | 1618 | lcd_puts(0, 8, buf); |
1619 | #if defined IRIVER_H300_SERIES | 1619 | #elif defined IRIVER_H300_SERIES |
1620 | snprintf(buf, 30, "USB Charging Enabled: %s", | 1620 | snprintf(buf, 30, "USB Charging Enabled: %s", |
1621 | usb_charging_enabled() ? "yes" : "no"); | 1621 | usb_charging_enabled() ? "yes" : "no"); |
1622 | lcd_puts(0, 9, buf); | 1622 | lcd_puts(0, 9, buf); |
1623 | #endif | 1623 | #elif defined IPOD_NANO || defined IPOD_VIDEO |
1624 | #else /* CONFIG_CHARGING != CHARGING_CONTROL */ | ||
1625 | #if defined IPOD_NANO || defined IPOD_VIDEO | ||
1626 | int usb_pwr = (GPIOL_INPUT_VAL & 0x10)?true:false; | 1624 | int usb_pwr = (GPIOL_INPUT_VAL & 0x10)?true:false; |
1627 | int ext_pwr = (GPIOL_INPUT_VAL & 0x08)?false:true; | 1625 | int ext_pwr = (GPIOL_INPUT_VAL & 0x08)?false:true; |
1628 | int dock = (GPIOA_INPUT_VAL & 0x10)?true:false; | 1626 | int dock = (GPIOA_INPUT_VAL & 0x10)?true:false; |
@@ -1644,12 +1642,8 @@ static bool view_battery(void) | |||
1644 | snprintf(buf, 30, "Headphone: %s", | 1642 | snprintf(buf, 30, "Headphone: %s", |
1645 | headphone ? "connected" : "disconnected"); | 1643 | headphone ? "connected" : "disconnected"); |
1646 | lcd_puts(0, 7, buf); | 1644 | lcd_puts(0, 7, buf); |
1647 | #else | 1645 | #elif defined TOSHIBA_GIGABEAT_S |
1648 | snprintf(buf, 30, "Charger: %s", | 1646 | int line = 3; |
1649 | charger_inserted() ? "present" : "absent"); | ||
1650 | lcd_puts(0, 3, buf); | ||
1651 | #if defined TOSHIBA_GIGABEAT_S | ||
1652 | int line = 4; | ||
1653 | unsigned int st; | 1647 | unsigned int st; |
1654 | 1648 | ||
1655 | static const unsigned char * const chrgstate_strings[] = | 1649 | static const unsigned char * const chrgstate_strings[] = |
@@ -1663,6 +1657,10 @@ static bool view_battery(void) | |||
1663 | "<unknown>", | 1657 | "<unknown>", |
1664 | }; | 1658 | }; |
1665 | 1659 | ||
1660 | snprintf(buf, 30, "Charger: %s", | ||
1661 | charger_inserted() ? "present" : "absent"); | ||
1662 | lcd_puts(0, line++, buf); | ||
1663 | |||
1666 | st = power_input_status() & | 1664 | st = power_input_status() & |
1667 | (POWER_INPUT_CHARGER | POWER_INPUT_BATTERY); | 1665 | (POWER_INPUT_CHARGER | POWER_INPUT_BATTERY); |
1668 | snprintf(buf, 30, "%s%s", | 1666 | snprintf(buf, 30, "%s%s", |
@@ -1730,9 +1728,11 @@ static bool view_battery(void) | |||
1730 | } | 1728 | } |
1731 | 1729 | ||
1732 | lcd_puts(0, line++, buf); | 1730 | lcd_puts(0, line++, buf); |
1733 | #endif /* defined TOSHIBA_GIGABEAT_S */ | 1731 | #else |
1734 | #endif /* defined IPOD_NANO || defined IPOD_VIDEO */ | 1732 | snprintf(buf, 30, "Charger: %s", |
1735 | #endif /* CONFIG_CHARGING != CHARGING_CONTROL */ | 1733 | charger_inserted() ? "present" : "absent"); |
1734 | lcd_puts(0, 3, buf); | ||
1735 | #endif /* target type */ | ||
1736 | #endif /* CONFIG_CHARGING */ | 1736 | #endif /* CONFIG_CHARGING */ |
1737 | break; | 1737 | break; |
1738 | 1738 | ||
@@ -1750,7 +1750,7 @@ static bool view_battery(void) | |||
1750 | 1750 | ||
1751 | case 3: /* remaining time estimation: */ | 1751 | case 3: /* remaining time estimation: */ |
1752 | 1752 | ||
1753 | #if CONFIG_CHARGING == CHARGING_CONTROL | 1753 | #ifdef ARCHOS_RECORDER |
1754 | snprintf(buf, 30, "charge_state: %d", charge_state); | 1754 | snprintf(buf, 30, "charge_state: %d", charge_state); |
1755 | lcd_puts(0, 0, buf); | 1755 | lcd_puts(0, 0, buf); |
1756 | 1756 | ||
@@ -1765,7 +1765,7 @@ static bool view_battery(void) | |||
1765 | 1765 | ||
1766 | snprintf(buf, 30, "Trickle sec: %d/60", trickle_sec); | 1766 | snprintf(buf, 30, "Trickle sec: %d/60", trickle_sec); |
1767 | lcd_puts(0, 4, buf); | 1767 | lcd_puts(0, 4, buf); |
1768 | #endif /* CONFIG_CHARGING == CHARGING_CONTROL */ | 1768 | #endif /* ARCHOS_RECORDER */ |
1769 | 1769 | ||
1770 | snprintf(buf, 30, "Last PwrHist: %d.%03dV", | 1770 | snprintf(buf, 30, "Last PwrHist: %d.%03dV", |
1771 | power_history[0] / 1000, | 1771 | power_history[0] / 1000, |
diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c index 4c15b1de4b..b22824d8bd 100644 --- a/apps/menus/main_menu.c +++ b/apps/menus/main_menu.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "lang.h" | 27 | #include "lang.h" |
28 | #include "action.h" | 28 | #include "action.h" |
29 | #include "settings.h" | 29 | #include "settings.h" |
30 | #include "power.h" | ||
30 | #include "powermgmt.h" | 31 | #include "powermgmt.h" |
31 | #include "menu.h" | 32 | #include "menu.h" |
32 | #include "misc.h" | 33 | #include "misc.h" |
@@ -199,15 +200,14 @@ static char* info_getname(int selected_item, void *data, | |||
199 | if (charge_state == CHARGING) | 200 | if (charge_state == CHARGING) |
200 | return (char *)str(LANG_BATTERY_CHARGE); | 201 | return (char *)str(LANG_BATTERY_CHARGE); |
201 | else | 202 | else |
202 | #if CONFIG_CHARGING == CHARGING_CONTROL | 203 | #ifdef ARCHOS_RECORDER |
203 | if (charge_state == TOPOFF) | 204 | if (charge_state == TOPOFF) |
204 | return (char *)str(LANG_BATTERY_TOPOFF_CHARGE); | 205 | return (char *)str(LANG_BATTERY_TOPOFF_CHARGE); |
205 | else | 206 | else if (charge_state == TRICKLE) |
206 | #endif | ||
207 | if (charge_state == TRICKLE) | ||
208 | return (char *)str(LANG_BATTERY_TRICKLE_CHARGE); | 207 | return (char *)str(LANG_BATTERY_TRICKLE_CHARGE); |
209 | else | 208 | else |
210 | #endif | 209 | #endif /* ARCHOS_RECORDER */ |
210 | #endif /* CONFIG_CHARGING = */ | ||
211 | if (battery_level() >= 0) | 211 | if (battery_level() >= 0) |
212 | snprintf(buffer, buffer_len, (char *)str(LANG_BATTERY_TIME), | 212 | snprintf(buffer, buffer_len, (char *)str(LANG_BATTERY_TIME), |
213 | battery_level(), battery_time() / 60, battery_time() % 60); | 213 | battery_level(), battery_time() / 60, battery_time() % 60); |
@@ -282,22 +282,21 @@ static int info_speak_item(int selected_item, void * data) | |||
282 | } | 282 | } |
283 | case INFO_BATTERY: /* battery */ | 283 | case INFO_BATTERY: /* battery */ |
284 | #if CONFIG_CHARGING == CHARGING_SIMPLE | 284 | #if CONFIG_CHARGING == CHARGING_SIMPLE |
285 | if (charger_input_state == CHARGER) | 285 | if (charger_inserted()) |
286 | talk_id(LANG_BATTERY_CHARGE, true); | 286 | talk_id(LANG_BATTERY_CHARGE, true); |
287 | else | 287 | else |
288 | #elif CONFIG_CHARGING >= CHARGING_MONITOR | 288 | #elif CONFIG_CHARGING >= CHARGING_MONITOR |
289 | if (charge_state == CHARGING) | 289 | if (charge_state == CHARGING) |
290 | talk_id(LANG_BATTERY_CHARGE, true); | 290 | talk_id(LANG_BATTERY_CHARGE, true); |
291 | else | 291 | else |
292 | #if CONFIG_CHARGING == CHARGING_CONTROL | 292 | #ifdef ARCHOS_RECORDER |
293 | if (charge_state == TOPOFF) | 293 | if (charge_state == TOPOFF) |
294 | talk_id(LANG_BATTERY_TOPOFF_CHARGE, true); | 294 | talk_id(LANG_BATTERY_TOPOFF_CHARGE, true); |
295 | else | 295 | else if (charge_state == TRICKLE) |
296 | #endif | ||
297 | if (charge_state == TRICKLE) | ||
298 | talk_id(LANG_BATTERY_TRICKLE_CHARGE, true); | 296 | talk_id(LANG_BATTERY_TRICKLE_CHARGE, true); |
299 | else | 297 | else |
300 | #endif | 298 | #endif /* ARCHOS_RECORDER */ |
299 | #endif /* CONFIG_CHARGING = */ | ||
301 | if (battery_level() >= 0) | 300 | if (battery_level() >= 0) |
302 | { | 301 | { |
303 | talk_id(LANG_BATTERY_TIME, false); | 302 | talk_id(LANG_BATTERY_TIME, false); |
diff --git a/apps/screens.c b/apps/screens.c index 992c740460..230e9ae53c 100644 --- a/apps/screens.c +++ b/apps/screens.c | |||
@@ -209,8 +209,7 @@ static void charging_display_info(bool animate) | |||
209 | lcd_puts(0, 7, buf); | 209 | lcd_puts(0, 7, buf); |
210 | } | 210 | } |
211 | 211 | ||
212 | #if CONFIG_CHARGING == CHARGING_CONTROL | 212 | #ifdef ARCHOS_RECORER |
213 | |||
214 | snprintf(buf, 32, "Charge mode:"); | 213 | snprintf(buf, 32, "Charge mode:"); |
215 | lcd_puts(0, 2, buf); | 214 | lcd_puts(0, 2, buf); |
216 | 215 | ||
@@ -224,10 +223,9 @@ static void charging_display_info(bool animate) | |||
224 | snprintf(buf, 32, "not charging"); | 223 | snprintf(buf, 32, "not charging"); |
225 | 224 | ||
226 | lcd_puts(0, 3, buf); | 225 | lcd_puts(0, 3, buf); |
227 | if (!charger_enabled) | 226 | if (!charger_enabled()) |
228 | animate = false; | 227 | animate = false; |
229 | #endif /* CONFIG_CHARGING == CHARGING_CONTROL */ | 228 | #endif /* ARCHOS_RECORER */ |
230 | |||
231 | 229 | ||
232 | /* middle part */ | 230 | /* middle part */ |
233 | memset(charging_logo+3, 0x00, 32); | 231 | memset(charging_logo+3, 0x00, 32); |
diff --git a/firmware/export/config-c200.h b/firmware/export/config-c200.h index e169606510..ac64f20e62 100644 --- a/firmware/export/config-c200.h +++ b/firmware/export/config-c200.h | |||
@@ -129,6 +129,11 @@ | |||
129 | /* define this if the unit can be powered or charged via USB */ | 129 | /* define this if the unit can be powered or charged via USB */ |
130 | #define HAVE_USB_POWER | 130 | #define HAVE_USB_POWER |
131 | 131 | ||
132 | /* define current usage levels */ | ||
133 | #define CURRENT_NORMAL 45 /* Should be nearly identical to E200 */ | ||
134 | #define CURRENT_BACKLIGHT 40 /* Screen is about 20, blue LEDs are another 20, so 40 if both */ | ||
135 | #define CURRENT_RECORD 40 /* flash player, so this is just unboosted current*/ | ||
136 | |||
132 | /** Non-simulator section **/ | 137 | /** Non-simulator section **/ |
133 | #ifndef SIMULATOR | 138 | #ifndef SIMULATOR |
134 | 139 | ||
diff --git a/firmware/export/config-e200.h b/firmware/export/config-e200.h index 3cae14cc87..b290a24952 100644 --- a/firmware/export/config-e200.h +++ b/firmware/export/config-e200.h | |||
@@ -123,6 +123,11 @@ | |||
123 | /* Hardware controlled charging? FIXME */ | 123 | /* Hardware controlled charging? FIXME */ |
124 | #define CONFIG_CHARGING CHARGING_SIMPLE | 124 | #define CONFIG_CHARGING CHARGING_SIMPLE |
125 | 125 | ||
126 | /* define current usage levels */ | ||
127 | #define CURRENT_NORMAL 45 /* Mike's measurements in Jan 2008 */ | ||
128 | #define CURRENT_BACKLIGHT 40 /* Screen is about 20, blue LEDs are another 20, so 40 if both */ | ||
129 | #define CURRENT_RECORD 40 /* flash player, so this is just unboosted current*/ | ||
130 | |||
126 | /* define this if the unit can be powered or charged via USB */ | 131 | /* define this if the unit can be powered or charged via USB */ |
127 | #define HAVE_USB_POWER | 132 | #define HAVE_USB_POWER |
128 | 133 | ||
diff --git a/firmware/export/config-h100.h b/firmware/export/config-h100.h index 9c327f11fd..7f91e35fbf 100644 --- a/firmware/export/config-h100.h +++ b/firmware/export/config-h100.h | |||
@@ -110,9 +110,16 @@ | |||
110 | #define BATTERY_TYPES_COUNT 1 /* only one type */ | 110 | #define BATTERY_TYPES_COUNT 1 /* only one type */ |
111 | 111 | ||
112 | /* Hardware controlled charging */ | 112 | /* Hardware controlled charging */ |
113 | //#define CONFIG_CHARGING CHARGING_SIMPLE | 113 | |
114 | #define CONFIG_CHARGING CHARGING_MONITOR /* FIXME: remove that once monitoring is fixed properly */ | 114 | #define CONFIG_CHARGING CHARGING_MONITOR /* FIXME: remove that once monitoring is fixed properly */ |
115 | 115 | ||
116 | /* define current usage levels */ | ||
117 | #define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery */ | ||
118 | #define CURRENT_BACKLIGHT 23 /* from IriverBattery twiki page */ | ||
119 | #define CURRENT_SPDIF_OUT 10 /* optical SPDIF output on */ | ||
120 | #define CURRENT_RECORD 105 /* additional current while recording */ | ||
121 | #define CURRENT_REMOTE 8 /* additional current when remote connected */ | ||
122 | |||
116 | #ifndef SIMULATOR | 123 | #ifndef SIMULATOR |
117 | 124 | ||
118 | /* Define this if you have a Motorola SCF5249 */ | 125 | /* Define this if you have a Motorola SCF5249 */ |
diff --git a/firmware/export/config-h120.h b/firmware/export/config-h120.h index d81fa07d93..b4a687b6d7 100644 --- a/firmware/export/config-h120.h +++ b/firmware/export/config-h120.h | |||
@@ -110,9 +110,15 @@ | |||
110 | #define BATTERY_TYPES_COUNT 1 /* only one type */ | 110 | #define BATTERY_TYPES_COUNT 1 /* only one type */ |
111 | 111 | ||
112 | /* Hardware controlled charging */ | 112 | /* Hardware controlled charging */ |
113 | //#define CONFIG_CHARGING CHARGING_SIMPLE | ||
114 | #define CONFIG_CHARGING CHARGING_MONITOR /* FIXME: remove that once monitoring is fixed properly */ | 113 | #define CONFIG_CHARGING CHARGING_MONITOR /* FIXME: remove that once monitoring is fixed properly */ |
115 | 114 | ||
115 | /* define current usage levels */ | ||
116 | #define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery */ | ||
117 | #define CURRENT_BACKLIGHT 23 /* from IriverBattery twiki page */ | ||
118 | #define CURRENT_SPDIF_OUT 10 /* optical SPDIF output on */ | ||
119 | #define CURRENT_RECORD 105 /* additional current while recording */ | ||
120 | #define CURRENT_REMOTE 8 /* additional current when remote connected */ | ||
121 | |||
116 | #ifndef SIMULATOR | 122 | #ifndef SIMULATOR |
117 | 123 | ||
118 | /* Define this if you have a Motorola SCF5249 */ | 124 | /* Define this if you have a Motorola SCF5249 */ |
diff --git a/firmware/export/config-h300.h b/firmware/export/config-h300.h index fa0046ac03..05d75fc4f0 100644 --- a/firmware/export/config-h300.h +++ b/firmware/export/config-h300.h | |||
@@ -112,6 +112,13 @@ | |||
112 | /* define this if the unit can be powered or charged via USB */ | 112 | /* define this if the unit can be powered or charged via USB */ |
113 | #define HAVE_USB_POWER | 113 | #define HAVE_USB_POWER |
114 | 114 | ||
115 | /* define current usage levels */ | ||
116 | #define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery from IriverRuntime wiki page */ | ||
117 | #define CURRENT_BACKLIGHT 23 /* FIXME: This needs to be measured, copied from H100 */ | ||
118 | #define CURRENT_RECORD 110 /* additional current while recording */ | ||
119 | #define CURRENT_MAX_CHG 650 /* maximum charging current */ | ||
120 | #define CURRENT_REMOTE 8 /* additional current when remote connected */ | ||
121 | |||
115 | /* define this if the unit can have USB charging disabled by user - | 122 | /* define this if the unit can have USB charging disabled by user - |
116 | * if USB/MAIN power is discernable and hardware doesn't compel charging */ | 123 | * if USB/MAIN power is discernable and hardware doesn't compel charging */ |
117 | #define HAVE_USB_CHARGING_ENABLE | 124 | #define HAVE_USB_CHARGING_ENABLE |
diff --git a/firmware/export/config-iaudiom3.h b/firmware/export/config-iaudiom3.h index f4ced651d0..a6e1028897 100644 --- a/firmware/export/config-iaudiom3.h +++ b/firmware/export/config-iaudiom3.h | |||
@@ -102,6 +102,9 @@ | |||
102 | /* Hardware controlled charging? FIXME */ | 102 | /* Hardware controlled charging? FIXME */ |
103 | #define CONFIG_CHARGING CHARGING_SIMPLE | 103 | #define CONFIG_CHARGING CHARGING_SIMPLE |
104 | 104 | ||
105 | /* define current usage levels */ | ||
106 | #define CURRENT_REMOTE 8 /* additional current when remote connected */ | ||
107 | |||
105 | #ifndef SIMULATOR | 108 | #ifndef SIMULATOR |
106 | 109 | ||
107 | /* Define this if your LCD can set contrast */ | 110 | /* Define this if your LCD can set contrast */ |
diff --git a/firmware/export/config-iaudiom5.h b/firmware/export/config-iaudiom5.h index 5ec6b77862..26cc9c5da6 100644 --- a/firmware/export/config-iaudiom5.h +++ b/firmware/export/config-iaudiom5.h | |||
@@ -105,6 +105,9 @@ | |||
105 | /* Hardware controlled charging? FIXME */ | 105 | /* Hardware controlled charging? FIXME */ |
106 | #define CONFIG_CHARGING CHARGING_SIMPLE | 106 | #define CONFIG_CHARGING CHARGING_SIMPLE |
107 | 107 | ||
108 | /* define current usage levels */ | ||
109 | #define CURRENT_REMOTE 8 /* additional current when remote connected */ | ||
110 | |||
108 | #ifndef SIMULATOR | 111 | #ifndef SIMULATOR |
109 | 112 | ||
110 | /* Define this if your LCD can set contrast */ | 113 | /* Define this if your LCD can set contrast */ |
diff --git a/firmware/export/config-iaudiox5.h b/firmware/export/config-iaudiox5.h index 03b84606c9..8b1f9086bb 100644 --- a/firmware/export/config-iaudiox5.h +++ b/firmware/export/config-iaudiox5.h | |||
@@ -122,6 +122,9 @@ | |||
122 | /* Hardware controlled charging? FIXME */ | 122 | /* Hardware controlled charging? FIXME */ |
123 | #define CONFIG_CHARGING CHARGING_SIMPLE | 123 | #define CONFIG_CHARGING CHARGING_SIMPLE |
124 | 124 | ||
125 | /* define current usage levels */ | ||
126 | #define CURRENT_REMOTE 8 /* additional current when remote connected */ | ||
127 | |||
125 | #ifndef SIMULATOR | 128 | #ifndef SIMULATOR |
126 | 129 | ||
127 | /* define this if the backlight thread is used for fade, not for sim, needs | 130 | /* define this if the backlight thread is used for fade, not for sim, needs |
diff --git a/firmware/export/config-ipod4g.h b/firmware/export/config-ipod4g.h index 4a2207d1d6..89b14f9907 100644 --- a/firmware/export/config-ipod4g.h +++ b/firmware/export/config-ipod4g.h | |||
@@ -120,6 +120,13 @@ | |||
120 | /* define this if the unit can be powered or charged via USB */ | 120 | /* define this if the unit can be powered or charged via USB */ |
121 | #define HAVE_USB_POWER | 121 | #define HAVE_USB_POWER |
122 | 122 | ||
123 | /* define current usage levels */ | ||
124 | #define CURRENT_NORMAL 100 /* MP3: ~10.5h out of 1100mAh battery */ | ||
125 | #define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */ | ||
126 | #if defined(HAVE_RECORDING) | ||
127 | #define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ | ||
128 | #endif | ||
129 | |||
123 | #ifndef SIMULATOR | 130 | #ifndef SIMULATOR |
124 | 131 | ||
125 | /* Define this if you have a PortalPlayer PP5020 */ | 132 | /* Define this if you have a PortalPlayer PP5020 */ |
diff --git a/firmware/export/config-ipodnano.h b/firmware/export/config-ipodnano.h index 7d6515fc0f..6017d0a2e8 100644 --- a/firmware/export/config-ipodnano.h +++ b/firmware/export/config-ipodnano.h | |||
@@ -115,6 +115,12 @@ | |||
115 | /* define this if the unit can be powered or charged via USB */ | 115 | /* define this if the unit can be powered or charged via USB */ |
116 | #define HAVE_USB_POWER | 116 | #define HAVE_USB_POWER |
117 | 117 | ||
118 | #define CURRENT_NORMAL 32 /* MP3: ~9h playback out of 300mAh battery */ | ||
119 | #define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */ | ||
120 | #if defined(HAVE_RECORDING) | ||
121 | #define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ | ||
122 | #endif | ||
123 | |||
118 | #ifndef SIMULATOR | 124 | #ifndef SIMULATOR |
119 | 125 | ||
120 | /* Define this if you have a PortalPlayer PP5022 */ | 126 | /* Define this if you have a PortalPlayer PP5022 */ |
diff --git a/firmware/export/config-ipodvideo.h b/firmware/export/config-ipodvideo.h index fa6ddd304f..d04e562086 100644 --- a/firmware/export/config-ipodvideo.h +++ b/firmware/export/config-ipodvideo.h | |||
@@ -123,6 +123,13 @@ | |||
123 | /* define this if the unit can be powered or charged via USB */ | 123 | /* define this if the unit can be powered or charged via USB */ |
124 | #define HAVE_USB_POWER | 124 | #define HAVE_USB_POWER |
125 | 125 | ||
126 | /* define current usage levels */ | ||
127 | #define CURRENT_NORMAL 35 /* MP3: ~11h out of 400mAh battery (30GB) or ~17h out of 600mAh (60GB) */ | ||
128 | #define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */ | ||
129 | #if defined(HAVE_RECORDING) | ||
130 | #define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ | ||
131 | #endif | ||
132 | |||
126 | #ifndef SIMULATOR | 133 | #ifndef SIMULATOR |
127 | 134 | ||
128 | /* Define this if you have a PortalPlayer PP5022 */ | 135 | /* Define this if you have a PortalPlayer PP5022 */ |
diff --git a/firmware/export/config-ondiofm.h b/firmware/export/config-ondiofm.h index 634433fcdb..8233728f1b 100644 --- a/firmware/export/config-ondiofm.h +++ b/firmware/export/config-ondiofm.h | |||
@@ -69,6 +69,11 @@ | |||
69 | /* define this if the unit can be powered or charged via USB */ | 69 | /* define this if the unit can be powered or charged via USB */ |
70 | #define HAVE_USB_POWER | 70 | #define HAVE_USB_POWER |
71 | 71 | ||
72 | /* define current usage levels */ | ||
73 | #define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */ | ||
74 | #define CURRENT_USB 1 /* host powered in USB mode; avoid zero-div */ | ||
75 | #define CURRENT_BACKLIGHT 0 /* no backlight */ | ||
76 | |||
72 | #ifndef SIMULATOR | 77 | #ifndef SIMULATOR |
73 | 78 | ||
74 | /* Define this if you have a SH7034 */ | 79 | /* Define this if you have a SH7034 */ |
diff --git a/firmware/export/config-ondiosp.h b/firmware/export/config-ondiosp.h index 3443b839b6..5fb7806d6a 100644 --- a/firmware/export/config-ondiosp.h +++ b/firmware/export/config-ondiosp.h | |||
@@ -58,6 +58,11 @@ | |||
58 | /* define this if the unit can be powered or charged via USB */ | 58 | /* define this if the unit can be powered or charged via USB */ |
59 | #define HAVE_USB_POWER | 59 | #define HAVE_USB_POWER |
60 | 60 | ||
61 | /* define current usage levels */ | ||
62 | #define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */ | ||
63 | #define CURRENT_USB 1 /* host powered in USB mode; avoid zero-div */ | ||
64 | #define CURRENT_BACKLIGHT 0 /* no backlight */ | ||
65 | |||
61 | #ifndef SIMULATOR | 66 | #ifndef SIMULATOR |
62 | 67 | ||
63 | /* Define this if you have a SH7034 */ | 68 | /* Define this if you have a SH7034 */ |
diff --git a/firmware/export/config-recorder.h b/firmware/export/config-recorder.h index e5fa3361cc..75aa2cf789 100644 --- a/firmware/export/config-recorder.h +++ b/firmware/export/config-recorder.h | |||
@@ -72,7 +72,7 @@ | |||
72 | #define NO_LOW_BATTERY_SHUTDOWN | 72 | #define NO_LOW_BATTERY_SHUTDOWN |
73 | 73 | ||
74 | /* Software controlled charging */ | 74 | /* Software controlled charging */ |
75 | #define CONFIG_CHARGING CHARGING_CONTROL | 75 | #define CONFIG_CHARGING CHARGING_TARGET |
76 | 76 | ||
77 | #ifndef SIMULATOR | 77 | #ifndef SIMULATOR |
78 | 78 | ||
diff --git a/firmware/export/config.h b/firmware/export/config.h index d8c14ddcef..1854f59d13 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h | |||
@@ -114,11 +114,13 @@ | |||
114 | #define X5_REMOTE 3 | 114 | #define X5_REMOTE 3 |
115 | 115 | ||
116 | /* CONFIG_CHARGING */ | 116 | /* CONFIG_CHARGING */ |
117 | |||
118 | /* Generic types */ | ||
117 | #define CHARGING_SIMPLE 1 /* Simple, hardware controlled charging */ | 119 | #define CHARGING_SIMPLE 1 /* Simple, hardware controlled charging */ |
118 | #define CHARGING_MONITOR 2 /* Hardware controlled charging with monitoring */ | 120 | #define CHARGING_MONITOR 2 /* Hardware controlled charging with monitoring */ |
119 | #define CHARGING_CONTROL 3 /* Software controlled charging */ | 121 | |
120 | #define CHARGING_TARGET 4 /* Anything the target implements that is not | 122 | /* Mostly target-specific code in the /target tree */ |
121 | a generic implementation */ | 123 | #define CHARGING_TARGET 3 |
122 | 124 | ||
123 | /* CONFIG_LCD */ | 125 | /* CONFIG_LCD */ |
124 | #define LCD_SSD1815 1 /* as used by Archos Recorders and Ondios */ | 126 | #define LCD_SSD1815 1 /* as used by Archos Recorders and Ondios */ |
diff --git a/firmware/export/power.h b/firmware/export/power.h index 747887921d..edf43f8cc8 100644 --- a/firmware/export/power.h +++ b/firmware/export/power.h | |||
@@ -21,11 +21,6 @@ | |||
21 | #ifndef _POWER_H_ | 21 | #ifndef _POWER_H_ |
22 | #define _POWER_H_ | 22 | #define _POWER_H_ |
23 | 23 | ||
24 | #if CONFIG_CHARGING == CHARGING_CONTROL | ||
25 | extern bool charger_enabled; | ||
26 | void charger_enable(bool on); | ||
27 | #endif | ||
28 | |||
29 | #if CONFIG_CHARGING | 24 | #if CONFIG_CHARGING |
30 | enum power_input_flags { | 25 | enum power_input_flags { |
31 | /* No external power source? Default. */ | 26 | /* No external power source? Default. */ |
@@ -82,9 +77,9 @@ bool power_input_present(void); | |||
82 | void power_off(void); | 77 | void power_off(void); |
83 | void ide_power_enable(bool on); | 78 | void ide_power_enable(bool on); |
84 | 79 | ||
85 | # if CONFIG_CHARGING == CHARGING_MONITOR | 80 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
86 | bool charging_state(void); | 81 | bool charging_state(void); |
87 | # endif | 82 | #endif |
88 | 83 | ||
89 | #ifndef SIMULATOR | 84 | #ifndef SIMULATOR |
90 | 85 | ||
@@ -102,4 +97,4 @@ bool spdif_powered(void); | |||
102 | bool tuner_power(bool status); | 97 | bool tuner_power(bool status); |
103 | #endif | 98 | #endif |
104 | 99 | ||
105 | #endif | 100 | #endif /* _POWER_H_ */ |
diff --git a/firmware/export/powermgmt.h b/firmware/export/powermgmt.h index c333795ad7..5be3a39c1d 100644 --- a/firmware/export/powermgmt.h +++ b/firmware/export/powermgmt.h | |||
@@ -25,147 +25,101 @@ | |||
25 | 25 | ||
26 | #define POWER_HISTORY_LEN 2*60 /* 2 hours of samples, one per minute */ | 26 | #define POWER_HISTORY_LEN 2*60 /* 2 hours of samples, one per minute */ |
27 | 27 | ||
28 | #define CHARGE_END_SHORTD 6 /* stop when N minutes have passed with | 28 | enum charge_state_type |
29 | * avg delta being < -0.05 V */ | 29 | { |
30 | #define CHARGE_END_LONGD 50 /* stop when N minutes have passed with | 30 | /* sorted by increasing charging current */ |
31 | * avg delta being < -0.02 V */ | ||
32 | |||
33 | typedef enum { /* sorted by increasing charging current */ | ||
34 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 31 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
35 | CHARGE_STATE_DISABLED = -2, /* Disable charger use */ | 32 | CHARGE_STATE_DISABLED = -2, /* Disable charger use (safety measure) */ |
36 | CHARGE_STATE_ERROR = -1, /* Some error occurred that should not allow | 33 | CHARGE_STATE_ERROR = -1, /* Some error occurred that should not allow |
37 | further attempts without user intervention */ | 34 | turning on the charger again by software |
35 | without user intervention (ie. replug) */ | ||
38 | #endif | 36 | #endif |
39 | DISCHARGING = 0, | 37 | DISCHARGING = 0, |
40 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 38 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
41 | TRICKLE, /* Can occur for CONFIG_CHARGING >= CHARGING_MONITOR */ | 39 | TRICKLE, /* For NiCd, battery maintenence phase */ |
42 | /* For LiIon, the low-current precharge mode if battery | 40 | /* For LiIon, low-current precharge phase */ |
43 | was very low */ | 41 | TOPOFF, /* For NiCd, waiting for dead zone */ |
44 | TOPOFF, /* Can occur for CONFIG_CHARGING == CHARGING_CONTROL */ | ||
45 | /* For LiIon, constant voltage phase */ | 42 | /* For LiIon, constant voltage phase */ |
46 | CHARGING, /* Can occur for all CONFIG_CHARGING options */ | 43 | CHARGING, /* For NiCd, main charge phase */ |
47 | /* For LiIon, the constant current phase */ | 44 | /* For LiIon, constant current phase */ |
48 | #endif | 45 | #endif |
49 | } charge_state_type; | 46 | }; |
50 | 47 | ||
51 | /* tells what the charger is doing */ | 48 | /* tells what the charger is doing */ |
52 | extern charge_state_type charge_state; | 49 | extern enum charge_state_type charge_state; |
53 | 50 | ||
54 | #ifdef CONFIG_CHARGING | 51 | #ifdef CONFIG_CHARGING |
55 | /* | 52 | /* |
56 | * Flag that the charger has been plugged in/removed: this is set for exactly | 53 | * Flag that the charger has been plugged in/removed: this is set for exactly |
57 | * one time through the power loop when the charger has been plugged in. | 54 | * one time through the power loop when the charger has been plugged in. |
58 | */ | 55 | */ |
59 | typedef enum { | 56 | enum charger_input_state_type |
57 | { | ||
60 | NO_CHARGER = 0, /* No charger is present */ | 58 | NO_CHARGER = 0, /* No charger is present */ |
61 | CHARGER_UNPLUGGED, /* Transitional state during CHARGER=>NO_CHARGER */ | 59 | CHARGER_UNPLUGGED, /* Transitional state during CHARGER=>NO_CHARGER */ |
62 | CHARGER_PLUGGED, /* Transitional state during NO_CHARGER=>CHARGER */ | 60 | CHARGER_PLUGGED, /* Transitional state during NO_CHARGER=>CHARGER */ |
63 | CHARGER /* Charger is present */ | 61 | CHARGER /* Charger is present */ |
64 | } charger_input_state_type; | 62 | }; |
65 | 63 | ||
66 | /* tells the state of the charge input */ | 64 | /* tells the state of the charge input */ |
67 | extern charger_input_state_type charger_input_state; | 65 | extern enum charger_input_state_type charger_input_state; |
66 | |||
67 | /* Power input status saved on the power thread each loop */ | ||
68 | extern unsigned int power_thread_inputs; | ||
69 | |||
70 | #endif /* CONFIG_CHARGING */ | ||
71 | |||
72 | #if CONFIG_CHARGING == CHARGING_TARGET | ||
73 | /* Include target-specific definitions */ | ||
74 | #include "powermgmt-target.h" | ||
68 | #endif | 75 | #endif |
69 | 76 | ||
70 | #ifndef SIMULATOR | 77 | #ifndef SIMULATOR |
71 | 78 | ||
72 | #if CONFIG_CHARGING == CHARGING_CONTROL | 79 | /* Generic current values that are really rather meaningless - config header |
73 | #define START_TOPOFF_CHG 85 /* Battery % to start at top-off */ | 80 | * should define proper numbers. */ |
74 | #define START_TRICKLE_CHG 95 /* Battery % to start at trickle */ | 81 | #ifndef CURRENT_NORMAL |
75 | 82 | #define CURRENT_NORMAL 145 /* usual current in mA */ | |
76 | #define POWER_MESSAGE_LEN 32 /* power thread status message */ | ||
77 | #define CHARGE_MAX_TIME_1500 450 /* minutes: maximum charging time for 1500 mAh batteries */ | ||
78 | /* actual max time depends also on BATTERY_CAPACITY! */ | ||
79 | #define CHARGE_MIN_TIME 10 /* minutes: minimum charging time */ | ||
80 | #define TOPOFF_MAX_TIME 90 /* After charging, go to top off charge. How long should top off charge be? */ | ||
81 | #define TOPOFF_VOLTAGE 5650 /* which voltage is best? (millivolts) */ | ||
82 | #define TRICKLE_MAX_TIME 12*60 /* After top off charge, go to trickle charge. How long should trickle charge be? */ | ||
83 | #define TRICKLE_VOLTAGE 5450 /* which voltage is best? (millivolts) */ | ||
84 | |||
85 | #define START_TOPOFF_SEC 25 /* initial trickle_sec for topoff */ | ||
86 | #define START_TRICKLE_SEC 15 /* initial trickle_sec for trickle */ | ||
87 | |||
88 | #define PID_DEADZONE 4 /* PID proportional deadzone */ | ||
89 | |||
90 | extern char power_message[POWER_MESSAGE_LEN]; | ||
91 | |||
92 | extern int long_delta; /* long term delta battery voltage */ | ||
93 | extern int short_delta; /* short term delta battery voltage */ | ||
94 | |||
95 | extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was the charging started or stopped? */ | ||
96 | extern int powermgmt_last_cycle_level; /* which level had the batteries at this time? */ | ||
97 | |||
98 | extern int pid_p; /* PID proportional term */ | ||
99 | extern int pid_i; /* PID integral term */ | ||
100 | extern int trickle_sec; /* trickle charge: How many seconds per minute are we charging actually? */ | ||
101 | |||
102 | #endif /* CONFIG_CHARGING == CHARGING_CONTROL */ | ||
103 | |||
104 | #if defined(ARCHOS_ONDIOSP) || defined(ARCHOS_ONDIOFM) /* Values for Ondio */ | ||
105 | # define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */ | ||
106 | # define CURRENT_USB 1 /* host powered in USB mode; avoid zero-div */ | ||
107 | # define CURRENT_BACKLIGHT 0 /* no backlight */ | ||
108 | #else /* Values for HD based jukeboxes */ | ||
109 | #ifdef IRIVER_H100_SERIES | ||
110 | # define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery */ | ||
111 | # define CURRENT_BACKLIGHT 23 /* from IriverBattery twiki page */ | ||
112 | # define CURRENT_SPDIF_OUT 10 /* optical SPDIF output on */ | ||
113 | # define CURRENT_RECORD 105 /* additional current while recording */ | ||
114 | #elif defined(IRIVER_H300_SERIES) | ||
115 | # define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery from IriverRuntime wiki page */ | ||
116 | # define CURRENT_BACKLIGHT 23 /* FIXME: This needs to be measured, copied from H100 */ | ||
117 | # define CURRENT_RECORD 110 /* additional current while recording */ | ||
118 | #elif defined(IPOD_NANO) /* iPOD Nano */ | ||
119 | # define CURRENT_NORMAL 32 /* MP3: ~9h playback out of 300mAh battery */ | ||
120 | # define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */ | ||
121 | #if defined(HAVE_RECORDING) | ||
122 | # define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ | ||
123 | #endif | 83 | #endif |
124 | #elif defined(IPOD_VIDEO) /* iPOD Video */ | 84 | |
125 | # define CURRENT_NORMAL 35 /* MP3: ~11h out of 400mAh battery (30GB) or ~17h out of 600mAh (60GB) */ | 85 | #ifndef CURRENT_BACKLIGHT |
126 | # define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */ | 86 | #define CURRENT_BACKLIGHT 30 /* additional current when backlight always on */ |
127 | #if defined(HAVE_RECORDING) | ||
128 | # define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ | ||
129 | #endif | 87 | #endif |
130 | #elif defined(SANSA_E200) /* Sandisk E200v1 */ | 88 | |
131 | # define CURRENT_NORMAL 45 /* Mike's measurements in Jan 2008 */ | 89 | #ifdef HAVE_RECORDING |
132 | # define CURRENT_BACKLIGHT 40 /* Screen is about 20, blue LEDs are another 20, so 40 if both */ | 90 | #ifndef CURRENT_RECORD |
133 | # define CURRENT_RECORD 40 /* flash player, so this is just unboosted current*/ | 91 | #define CURRENT_RECORD 35 /* additional recording current */ |
134 | #elif defined(SANSA_C200) /* Sandisk C200v1 */ | ||
135 | # define CURRENT_NORMAL 45 /* Should be nearly identical to E200 */ | ||
136 | # define CURRENT_BACKLIGHT 40 /* Screen is about 20, blue LEDs are another 20, so 40 if both */ | ||
137 | # define CURRENT_RECORD 40 /* flash player, so this is just unboosted current*/ | ||
138 | #elif defined(IPOD_4G) /* iPOD 4G */ | ||
139 | # define CURRENT_NORMAL 100 /* MP3: ~10.5h out of 1100mAh battery */ | ||
140 | # define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */ | ||
141 | #if defined(HAVE_RECORDING) | ||
142 | # define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ | ||
143 | #endif | 92 | #endif |
144 | #else /* Not iriver H1x0, H3x0, nor Archos Ondio, nor iPod nano/Video/4G, nor Sansas */ | 93 | #endif /* HAVE_RECORDING */ |
145 | # define CURRENT_NORMAL 145 /* usual current in mA when using the AJB including some disk/backlight/... activity */ | 94 | |
146 | # define CURRENT_BACKLIGHT 30 /* additional current when backlight always on */ | 95 | #ifndef CURRENT_USB |
147 | #if defined(HAVE_RECORDING) | 96 | #define CURRENT_USB 500 /* usual current in mA in USB mode */ |
148 | # define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ | ||
149 | #endif | 97 | #endif |
150 | #endif /* Not Archos Ondio */ | 98 | |
151 | #define CURRENT_USB 500 /* usual current in mA in USB mode */ | ||
152 | #ifdef HAVE_REMOTE_LCD | 99 | #ifdef HAVE_REMOTE_LCD |
153 | # define CURRENT_REMOTE 8 /* add. current when H100-remote connected */ | 100 | #define CURRENT_REMOTE 8 /* additional current when remote connected */ |
154 | #endif /* HAVE_REMOTE_LCD */ | 101 | #endif /* HAVE_REMOTE_LCD */ |
155 | 102 | ||
156 | # define CURRENT_MIN_CHG 70 /* minimum charge current */ | 103 | #if CONFIG_CHARGING |
157 | # define MIN_CHG_V 8500 /* at 8.5v charger voltage get CURRENT_MIN_CHG */ | 104 | #ifndef CURRENT_MAX_CHG |
158 | # ifdef IRIVER_H300_SERIES | 105 | #define CURRENT_MAX_CHG 350 /* maximum charging current */ |
159 | # define CURRENT_MAX_CHG 650 /* maximum charging current */ | 106 | #endif |
160 | # else | 107 | #endif /* CONFIG_CHARGING */ |
161 | # define CURRENT_MAX_CHG 350 /* maximum charging current */ | 108 | |
162 | # endif | 109 | #ifdef CHARGING_DEBUG_FILE |
163 | # define MAX_CHG_V 10250 /* anything over 10.25v gives CURRENT_MAX_CHG */ | 110 | #define POWERMGMT_DEBUG_STACK ((0x1000)/sizeof(long)) |
164 | #endif /* not ONDIO */ | 111 | #else |
112 | #define POWERMGMT_DEBUG_STACK 0 | ||
113 | #endif | ||
165 | 114 | ||
166 | #if CONFIG_CHARGING == CHARGING_TARGET | 115 | #ifndef BATT_AVE_SAMPLES |
167 | /* Include target-specific definitions */ | 116 | /* slw filter constant unless otherwise specified */ |
168 | #include "powermgmt-target.h" | 117 | #define BATT_AVE_SAMPLES 128 |
118 | #endif | ||
119 | |||
120 | #ifndef POWER_THREAD_STEP_TICKS | ||
121 | /* 2HZ sample rate unless otherwise specified */ | ||
122 | #define POWER_THREAD_STEP_TICKS (HZ/2) | ||
169 | #endif | 123 | #endif |
170 | 124 | ||
171 | extern unsigned short power_history[POWER_HISTORY_LEN]; | 125 | extern unsigned short power_history[POWER_HISTORY_LEN]; |
@@ -179,12 +133,6 @@ extern const unsigned short percent_to_volt_charge[11]; | |||
179 | /* Start up power management thread */ | 133 | /* Start up power management thread */ |
180 | void powermgmt_init(void); | 134 | void powermgmt_init(void); |
181 | 135 | ||
182 | /* Do target portion of init (for CHARGING_TARGET) - called on power thread */ | ||
183 | void powermgmt_init_target(void); | ||
184 | |||
185 | /* Handle frequent tasks and call charging_algorithm_small_step */ | ||
186 | void power_thread_sleep(int ticks); | ||
187 | |||
188 | #endif /* SIMULATOR */ | 136 | #endif /* SIMULATOR */ |
189 | 137 | ||
190 | /* Returns battery statust */ | 138 | /* Returns battery statust */ |
@@ -193,9 +141,15 @@ int battery_time(void); /* minutes */ | |||
193 | unsigned int battery_adc_voltage(void); /* voltage from ADC in millivolts */ | 141 | unsigned int battery_adc_voltage(void); /* voltage from ADC in millivolts */ |
194 | unsigned int battery_voltage(void); /* filtered batt. voltage in millivolts */ | 142 | unsigned int battery_voltage(void); /* filtered batt. voltage in millivolts */ |
195 | 143 | ||
144 | #ifdef HAVE_BATTERY_SWITCH | ||
145 | unsigned int input_millivolts(void); /* voltage that device is running from */ | ||
146 | |||
196 | /* Set the filtered battery voltage (to adjust it before beginning a charge | 147 | /* Set the filtered battery voltage (to adjust it before beginning a charge |
197 | cycle for instance where old, loaded readings will likely be invalid). */ | 148 | * cycle for instance where old, loaded readings will likely be invalid). |
198 | void set_filtered_battery_voltage(int millivolts); | 149 | * Also readjust when battery switch is opened or closed. |
150 | */ | ||
151 | void reset_battery_filter(int millivolts); | ||
152 | #endif /* HAVE_BATTERY_SWITCH */ | ||
199 | 153 | ||
200 | /* read unfiltered battery info */ | 154 | /* read unfiltered battery info */ |
201 | void battery_read_info(int *voltage, int *level); | 155 | void battery_read_info(int *voltage, int *level); |
@@ -203,13 +157,10 @@ void battery_read_info(int *voltage, int *level); | |||
203 | /* Tells if the battery level is safe for disk writes */ | 157 | /* Tells if the battery level is safe for disk writes */ |
204 | bool battery_level_safe(void); | 158 | bool battery_level_safe(void); |
205 | 159 | ||
206 | #ifdef TARGET_POWERMGMT_FILTER_CHARGE_STATE | ||
207 | int powermgmt_filter_charge_state(void); | ||
208 | #endif | ||
209 | |||
210 | void set_poweroff_timeout(int timeout); | 160 | void set_poweroff_timeout(int timeout); |
211 | void set_battery_capacity(int capacity); /* set local battery capacity value */ | 161 | void set_battery_capacity(int capacity); /* set local battery capacity value */ |
212 | void set_battery_type(int type); /* set local battery type */ | 162 | int get_battery_capacity(void); /* get local battery capacity value */ |
163 | void set_battery_type(int type); /* set local battery type */ | ||
213 | 164 | ||
214 | void set_sleep_timer(int seconds); | 165 | void set_sleep_timer(int seconds); |
215 | int get_sleep_timer(void); | 166 | int get_sleep_timer(void); |
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index 0fed847973..5aa85c883d 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c | |||
@@ -20,18 +20,14 @@ | |||
20 | * | 20 | * |
21 | ****************************************************************************/ | 21 | ****************************************************************************/ |
22 | #include "config.h" | 22 | #include "config.h" |
23 | #include "cpu.h" | 23 | #include "system.h" |
24 | #include "kernel.h" | 24 | #include "kernel.h" |
25 | #include "thread.h" | 25 | #include "thread.h" |
26 | #include "system.h" | ||
27 | #include "debug.h" | 26 | #include "debug.h" |
28 | #include "panic.h" | ||
29 | #include "adc.h" | 27 | #include "adc.h" |
30 | #include "string.h" | 28 | #include "string.h" |
31 | #include "sprintf.h" | ||
32 | #include "storage.h" | 29 | #include "storage.h" |
33 | #include "power.h" | 30 | #include "power.h" |
34 | #include "button.h" | ||
35 | #include "audio.h" | 31 | #include "audio.h" |
36 | #include "mp3_playback.h" | 32 | #include "mp3_playback.h" |
37 | #include "usb.h" | 33 | #include "usb.h" |
@@ -57,166 +53,39 @@ | |||
57 | #include "lcd-remote-target.h" | 53 | #include "lcd-remote-target.h" |
58 | #endif | 54 | #endif |
59 | 55 | ||
60 | /* | 56 | /** Shared by sim **/ |
61 | * Define DEBUG_FILE to create a csv (spreadsheet) with battery information | 57 | int last_sent_battery_level = 100; |
62 | * in it (one sample per minute). This is only for very low level debug. | 58 | /* battery level (0-100%) */ |
63 | */ | 59 | int battery_percent = -1; |
64 | #undef DEBUG_FILE | 60 | void send_battery_level_event(void); |
65 | #if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL) | ||
66 | #include "file.h" | ||
67 | #define DEBUG_FILE_NAME "/powermgmt.csv" | ||
68 | #define DEBUG_MESSAGE_LEN 133 | ||
69 | static char debug_message[DEBUG_MESSAGE_LEN]; | ||
70 | #define DEBUG_STACK ((0x1000)/sizeof(long)) | ||
71 | static int fd = -1; /* write debug information to this file */ | ||
72 | static int wrcount = 0; | ||
73 | #else | ||
74 | #define DEBUG_STACK 0 | ||
75 | #endif | ||
76 | |||
77 | static int shutdown_timeout = 0; | ||
78 | #if CONFIG_CHARGING >= CHARGING_MONITOR | ||
79 | charge_state_type charge_state = DISCHARGING; /* charging mode */ | ||
80 | #endif | ||
81 | |||
82 | static void send_battery_level_event(void); | ||
83 | static int last_sent_battery_level = 100; | ||
84 | 61 | ||
85 | #if CONFIG_CHARGING | 62 | #if CONFIG_CHARGING |
86 | charger_input_state_type charger_input_state IDATA_ATTR; | 63 | /* State of the charger input as seen by the power thread */ |
87 | #endif | 64 | enum charger_input_state_type charger_input_state; |
88 | 65 | /* Power inputs as seen by the power thread */ | |
89 | #ifdef SIMULATOR /***********************************************************/ | 66 | unsigned int power_thread_inputs; |
90 | 67 | #if CONFIG_CHARGING >= CHARGING_MONITOR | |
91 | #define BATT_MINMVOLT 2500 /* minimum millivolts of battery */ | 68 | /* Charging state (mode) as seen by the power thread */ |
92 | #define BATT_MAXMVOLT 4500 /* maximum millivolts of battery */ | 69 | enum charge_state_type charge_state = DISCHARGING; |
93 | #define BATT_MAXRUNTIME (10 * 60) /* maximum runtime with full battery in minutes */ | ||
94 | |||
95 | static unsigned int battery_millivolts = (unsigned int)BATT_MAXMVOLT; | ||
96 | static int battery_percent = 100; /* battery capacity level in percent */ | ||
97 | static int powermgmt_est_runningtime_min = BATT_MAXRUNTIME; /* estimated remaining time in minutes */ | ||
98 | |||
99 | static void battery_status_update(void) | ||
100 | { | ||
101 | static time_t last_change = 0; | ||
102 | static bool charging = false; | ||
103 | time_t now; | ||
104 | |||
105 | time(&now); | ||
106 | if (last_change < now) | ||
107 | { | ||
108 | last_change = now; | ||
109 | |||
110 | /* change the values: */ | ||
111 | if (charging) | ||
112 | { | ||
113 | if (battery_millivolts >= BATT_MAXMVOLT) | ||
114 | { | ||
115 | /* Pretend the charger was disconnected */ | ||
116 | charging = false; | ||
117 | queue_broadcast(SYS_CHARGER_DISCONNECTED, 0); | ||
118 | last_sent_battery_level = 100; | ||
119 | } | ||
120 | } | ||
121 | else | ||
122 | { | ||
123 | if (battery_millivolts <= BATT_MINMVOLT) | ||
124 | { | ||
125 | /* Pretend the charger was connected */ | ||
126 | charging = true; | ||
127 | queue_broadcast(SYS_CHARGER_CONNECTED, 0); | ||
128 | last_sent_battery_level = 0; | ||
129 | } | ||
130 | } | ||
131 | if (charging) | ||
132 | battery_millivolts += (BATT_MAXMVOLT - BATT_MINMVOLT) / 50; | ||
133 | else | ||
134 | battery_millivolts -= (BATT_MAXMVOLT - BATT_MINMVOLT) / 100; | ||
135 | |||
136 | battery_percent = 100 * (battery_millivolts - BATT_MINMVOLT) / | ||
137 | (BATT_MAXMVOLT - BATT_MINMVOLT); | ||
138 | powermgmt_est_runningtime_min = battery_percent * BATT_MAXRUNTIME / 100; | ||
139 | } | ||
140 | send_battery_level_event(); | ||
141 | } | ||
142 | |||
143 | void battery_read_info(int *voltage, int *level) | ||
144 | { | ||
145 | battery_status_update(); | ||
146 | |||
147 | if (voltage) | ||
148 | *voltage = battery_millivolts; | ||
149 | |||
150 | if (level) | ||
151 | *level = battery_percent; | ||
152 | } | ||
153 | |||
154 | unsigned int battery_voltage(void) | ||
155 | { | ||
156 | battery_status_update(); | ||
157 | return battery_millivolts; | ||
158 | } | ||
159 | |||
160 | int battery_level(void) | ||
161 | { | ||
162 | battery_status_update(); | ||
163 | return battery_percent; | ||
164 | } | ||
165 | |||
166 | int battery_time(void) | ||
167 | { | ||
168 | battery_status_update(); | ||
169 | return powermgmt_est_runningtime_min; | ||
170 | } | ||
171 | |||
172 | bool battery_level_safe(void) | ||
173 | { | ||
174 | return battery_level() >= 10; | ||
175 | } | ||
176 | |||
177 | void set_poweroff_timeout(int timeout) | ||
178 | { | ||
179 | (void)timeout; | ||
180 | } | ||
181 | |||
182 | void set_battery_capacity(int capacity) | ||
183 | { | ||
184 | (void)capacity; | ||
185 | } | ||
186 | |||
187 | #if BATTERY_TYPES_COUNT > 1 | ||
188 | void set_battery_type(int type) | ||
189 | { | ||
190 | (void)type; | ||
191 | } | ||
192 | #endif | ||
193 | |||
194 | void reset_poweroff_timer(void) | ||
195 | { | ||
196 | } | ||
197 | |||
198 | #ifdef HAVE_ACCESSORY_SUPPLY | ||
199 | void accessory_supply_set(bool enable) | ||
200 | { | ||
201 | (void)enable; | ||
202 | } | ||
203 | #endif | 70 | #endif |
71 | #endif /* CONFIG_CHARGING */ | ||
204 | 72 | ||
205 | #else /* not SIMULATOR ******************************************************/ | 73 | #ifndef SIMULATOR |
206 | 74 | static int shutdown_timeout = 0; | |
207 | /* | 75 | /* |
208 | * Average battery voltage and charger voltage, filtered via a digital | 76 | * Average battery voltage and charger voltage, filtered via a digital |
209 | * exponential filter (aka. exponential moving average, scaled): | 77 | * exponential filter (aka. exponential moving average, scaled): |
210 | * avgbat = y[n] = (N-1)/N*y[n-1] + x[n]. battery_millivolts = y[n] / N. | 78 | * avgbat = y[n] = (N-1)/N*y[n-1] + x[n]. battery_millivolts = y[n] / N. |
211 | */ | 79 | */ |
212 | static unsigned int avgbat; /* average battery voltage (filtering) */ | 80 | static unsigned int avgbat; |
213 | static unsigned int battery_millivolts;/* filtered battery voltage, millivolts */ | 81 | /* filtered battery voltage, millivolts */ |
82 | static unsigned int battery_millivolts; | ||
83 | /* default value, mAh */ | ||
84 | static int battery_capacity = BATTERY_CAPACITY_DEFAULT; | ||
85 | |||
214 | 86 | ||
215 | /* battery level (0-100%) of this minute, updated once per minute */ | ||
216 | static int battery_percent = -1; | ||
217 | static int battery_capacity = BATTERY_CAPACITY_DEFAULT; /* default value, mAh */ | ||
218 | #if BATTERY_TYPES_COUNT > 1 | 87 | #if BATTERY_TYPES_COUNT > 1 |
219 | static int battery_type = 0; | 88 | static int battery_type = 0; |
220 | #else | 89 | #else |
221 | #define battery_type 0 | 90 | #define battery_type 0 |
222 | #endif | 91 | #endif |
@@ -224,7 +93,7 @@ static int battery_type = 0; | |||
224 | /* Power history: power_history[0] is the newest sample */ | 93 | /* Power history: power_history[0] is the newest sample */ |
225 | unsigned short power_history[POWER_HISTORY_LEN]; | 94 | unsigned short power_history[POWER_HISTORY_LEN]; |
226 | 95 | ||
227 | static char power_stack[DEFAULT_STACK_SIZE/2 + DEBUG_STACK]; | 96 | static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK]; |
228 | static const char power_thread_name[] = "power"; | 97 | static const char power_thread_name[] = "power"; |
229 | 98 | ||
230 | static int poweroff_timeout = 0; | 99 | static int poweroff_timeout = 0; |
@@ -239,19 +108,6 @@ static int voltage_to_battery_level(int battery_millivolts); | |||
239 | static void battery_status_update(void); | 108 | static void battery_status_update(void); |
240 | static int runcurrent(void); | 109 | static int runcurrent(void); |
241 | 110 | ||
242 | #ifndef TARGET_POWERMGMT_FILTER_CHARGE_STATE | ||
243 | static inline int powermgmt_filter_charge_state(void) | ||
244 | { | ||
245 | #if CONFIG_CHARGING >= CHARGING_MONITOR | ||
246 | /* No adjustment of state */ | ||
247 | return charge_state; | ||
248 | #else | ||
249 | /* Always discharging */ | ||
250 | return DISCHARGING; | ||
251 | #endif | ||
252 | } | ||
253 | #endif /* TARGET_POWERMGMT_FILTER_CHARGE_STATE */ | ||
254 | |||
255 | void battery_read_info(int *voltage, int *level) | 111 | void battery_read_info(int *voltage, int *level) |
256 | { | 112 | { |
257 | int millivolts = battery_adc_voltage(); | 113 | int millivolts = battery_adc_voltage(); |
@@ -272,20 +128,30 @@ void reset_poweroff_timer(void) | |||
272 | void set_battery_type(int type) | 128 | void set_battery_type(int type) |
273 | { | 129 | { |
274 | if (type != battery_type) { | 130 | if (type != battery_type) { |
131 | if ((unsigned)type >= BATTERY_TYPES_COUNT) | ||
132 | type = 0; | ||
133 | |||
275 | battery_type = type; | 134 | battery_type = type; |
276 | battery_status_update(); /* recalculate the battery status */ | 135 | battery_status_update(); /* recalculate the battery status */ |
277 | } | 136 | } |
278 | } | 137 | } |
279 | #endif | 138 | #endif |
280 | 139 | ||
281 | void set_battery_capacity(int capacity) | 140 | void set_battery_capacity(int capacity) |
282 | { | 141 | { |
142 | if (capacity > BATTERY_CAPACITY_MAX) | ||
143 | capacity = BATTERY_CAPACITY_MAX; | ||
144 | if (capacity < BATTERY_CAPACITY_MIN) | ||
145 | capacity = BATTERY_CAPACITY_MIN; | ||
146 | |||
283 | battery_capacity = capacity; | 147 | battery_capacity = capacity; |
284 | if (battery_capacity > BATTERY_CAPACITY_MAX) | 148 | |
285 | battery_capacity = BATTERY_CAPACITY_MAX; | 149 | battery_status_update(); /* recalculate the battery status */ |
286 | if (battery_capacity < BATTERY_CAPACITY_MIN) | 150 | } |
287 | battery_capacity = BATTERY_CAPACITY_MIN; | 151 | |
288 | battery_status_update(); /* recalculate the battery status */ | 152 | int get_battery_capacity(void) |
153 | { | ||
154 | return battery_capacity; | ||
289 | } | 155 | } |
290 | 156 | ||
291 | int battery_time(void) | 157 | int battery_time(void) |
@@ -309,13 +175,19 @@ unsigned int battery_voltage(void) | |||
309 | return battery_millivolts; | 175 | return battery_millivolts; |
310 | } | 176 | } |
311 | 177 | ||
312 | #ifndef TARGET_BATTERY_LEVEL_SAFE | ||
313 | /* Tells if the battery level is safe for disk writes */ | 178 | /* Tells if the battery level is safe for disk writes */ |
314 | bool battery_level_safe(void) | 179 | bool battery_level_safe(void) |
315 | { | 180 | { |
181 | #if defined(NO_LOW_BATTERY_SHUTDOWN) | ||
182 | return true; | ||
183 | #elif defined(HAVE_BATTERY_SWITCH) | ||
184 | /* Cannot rely upon the battery reading to be valid and the | ||
185 | * device could be powered externally. */ | ||
186 | return input_millivolts() > battery_level_dangerous[battery_type]; | ||
187 | #else | ||
316 | return battery_millivolts > battery_level_dangerous[battery_type]; | 188 | return battery_millivolts > battery_level_dangerous[battery_type]; |
317 | } | ||
318 | #endif | 189 | #endif |
190 | } | ||
319 | 191 | ||
320 | void set_poweroff_timeout(int timeout) | 192 | void set_poweroff_timeout(int timeout) |
321 | { | 193 | { |
@@ -324,7 +196,7 @@ void set_poweroff_timeout(int timeout) | |||
324 | 196 | ||
325 | void set_sleep_timer(int seconds) | 197 | void set_sleep_timer(int seconds) |
326 | { | 198 | { |
327 | if(seconds) { | 199 | if (seconds) { |
328 | sleeptimer_active = true; | 200 | sleeptimer_active = true; |
329 | sleeptimer_endtick = current_tick + seconds * HZ; | 201 | sleeptimer_endtick = current_tick + seconds * HZ; |
330 | } | 202 | } |
@@ -336,7 +208,7 @@ void set_sleep_timer(int seconds) | |||
336 | 208 | ||
337 | int get_sleep_timer(void) | 209 | int get_sleep_timer(void) |
338 | { | 210 | { |
339 | if(sleeptimer_active) | 211 | if (sleeptimer_active) |
340 | return (sleeptimer_endtick - current_tick) / HZ; | 212 | return (sleeptimer_endtick - current_tick) / HZ; |
341 | else | 213 | else |
342 | return 0; | 214 | return 0; |
@@ -345,45 +217,46 @@ int get_sleep_timer(void) | |||
345 | /* look into the percent_to_volt_* table and get a realistic battery level */ | 217 | /* look into the percent_to_volt_* table and get a realistic battery level */ |
346 | static int voltage_to_percent(int voltage, const short* table) | 218 | static int voltage_to_percent(int voltage, const short* table) |
347 | { | 219 | { |
348 | if (voltage <= table[0]) | 220 | if (voltage <= table[0]) { |
349 | return 0; | 221 | return 0; |
350 | else | 222 | } |
351 | if (voltage >= table[10]) | 223 | else if (voltage >= table[10]) { |
352 | return 100; | 224 | return 100; |
353 | else { | 225 | } |
354 | /* search nearest value */ | 226 | else { |
355 | int i = 0; | 227 | /* search nearest value */ |
356 | while ((i < 10) && (table[i+1] < voltage)) | 228 | int i = 0; |
357 | i++; | 229 | |
358 | /* interpolate linear between the smaller and greater value */ | 230 | while (i < 10 && table[i+1] < voltage) |
359 | return (i * 10) /* Tens digit, 10% per entry */ | 231 | i++; |
360 | + (((voltage - table[i]) * 10) | 232 | |
361 | / (table[i+1] - table[i])); /* Ones digit: interpolated */ | 233 | /* interpolate linear between the smaller and greater value */ |
362 | } | 234 | /* Tens digit, 10% per entry, ones digit: interpolated */ |
235 | return i*10 + (voltage - table[i])*10 / (table[i+1] - table[i]); | ||
236 | } | ||
363 | } | 237 | } |
364 | 238 | ||
365 | /* update battery level and estimated runtime, called once per minute or | 239 | /* update battery level and estimated runtime, called once per minute or |
366 | * when battery capacity / type settings are changed */ | 240 | * when battery capacity / type settings are changed */ |
367 | static int voltage_to_battery_level(int battery_millivolts) | 241 | static int voltage_to_battery_level(int battery_millivolts) |
368 | { | 242 | { |
369 | const int state = powermgmt_filter_charge_state(); | ||
370 | int level; | 243 | int level; |
371 | 244 | ||
372 | if (state == DISCHARGING) { | ||
373 | level = voltage_to_percent(battery_millivolts, | ||
374 | percent_to_volt_discharge[battery_type]); | ||
375 | } | ||
376 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 245 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
377 | else if (state == CHARGING) { | 246 | if (charging_state()) { |
378 | /* battery level is defined to be < 100% until charging is finished */ | 247 | /* battery level is defined to be < 100% until charging is finished */ |
379 | level = MIN(voltage_to_percent(battery_millivolts, | 248 | level = voltage_to_percent(battery_millivolts, |
380 | percent_to_volt_charge), 99); | 249 | percent_to_volt_charge); |
250 | if (level > 99) | ||
251 | level = 99; | ||
381 | } | 252 | } |
382 | else { | 253 | else |
383 | /* in topoff/trickle charge, battery is by definition 100% full */ | 254 | #endif /* CONFIG_CHARGING >= CHARGING_MONITOR */ |
384 | level = 100; | 255 | { |
256 | /* DISCHARGING or error state */ | ||
257 | level = voltage_to_percent(battery_millivolts, | ||
258 | percent_to_volt_discharge[battery_type]); | ||
385 | } | 259 | } |
386 | #endif | ||
387 | 260 | ||
388 | return level; | 261 | return level; |
389 | } | 262 | } |
@@ -393,26 +266,25 @@ static void battery_status_update(void) | |||
393 | int level = voltage_to_battery_level(battery_millivolts); | 266 | int level = voltage_to_battery_level(battery_millivolts); |
394 | 267 | ||
395 | /* calculate estimated remaining running time */ | 268 | /* calculate estimated remaining running time */ |
396 | /* discharging: remaining running time */ | ||
397 | /* charging: remaining charging time */ | ||
398 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 269 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
399 | if (powermgmt_filter_charge_state() == CHARGING) { | 270 | if (charging_state()) { |
400 | powermgmt_est_runningtime_min = (100 - level) * battery_capacity * 60 | 271 | /* charging: remaining charging time */ |
401 | / 100 / (CURRENT_MAX_CHG - runcurrent()); | 272 | powermgmt_est_runningtime_min = (100 - level)*battery_capacity*60 |
273 | / 100 / (CURRENT_MAX_CHG - runcurrent()); | ||
402 | } | 274 | } |
403 | else | 275 | else |
404 | #endif | 276 | #endif |
405 | { | 277 | /* discharging: remaining running time */ |
406 | if ((battery_millivolts + 20) > percent_to_volt_discharge[0][0]) | 278 | if ((battery_millivolts + 20) > percent_to_volt_discharge[0][0]) { |
407 | powermgmt_est_runningtime_min = (level + battery_percent) * 60 * | 279 | powermgmt_est_runningtime_min = (level + battery_percent)*60 |
408 | battery_capacity / 200 / runcurrent(); | 280 | * battery_capacity / 200 / runcurrent(); |
409 | 281 | } | |
410 | else if (battery_millivolts <= battery_level_shutoff[0]) | 282 | else if (battery_millivolts <= battery_level_shutoff[0]) { |
411 | powermgmt_est_runningtime_min = 0; | 283 | powermgmt_est_runningtime_min = 0; |
412 | 284 | } | |
413 | else | 285 | else { |
414 | powermgmt_est_runningtime_min = (battery_millivolts - | 286 | powermgmt_est_runningtime_min = |
415 | battery_level_shutoff[0]) / 2; | 287 | (battery_millivolts - battery_level_shutoff[0]) / 2; |
416 | } | 288 | } |
417 | 289 | ||
418 | battery_percent = level; | 290 | battery_percent = level; |
@@ -434,62 +306,55 @@ static void battery_status_update(void) | |||
434 | static void handle_auto_poweroff(void) | 306 | static void handle_auto_poweroff(void) |
435 | { | 307 | { |
436 | long timeout = poweroff_timeout*60*HZ; | 308 | long timeout = poweroff_timeout*60*HZ; |
437 | int audio_stat = audio_status(); | 309 | int audio_stat = audio_status(); |
310 | long tick = current_tick; | ||
438 | 311 | ||
439 | #if CONFIG_CHARGING | 312 | #if CONFIG_CHARGING |
440 | /* | 313 | /* |
441 | * Inhibit shutdown as long as the charger is plugged in. If it is | 314 | * Inhibit shutdown as long as the charger is plugged in. If it is |
442 | * unplugged, wait for a timeout period and then shut down. | 315 | * unplugged, wait for a timeout period and then shut down. |
443 | */ | 316 | */ |
444 | if(charger_input_state == CHARGER || audio_stat == AUDIO_STATUS_PLAY) { | 317 | if (charger_input_state == CHARGER || audio_stat == AUDIO_STATUS_PLAY) { |
445 | last_event_tick = current_tick; | 318 | last_event_tick = current_tick; |
446 | } | 319 | } |
447 | #endif | 320 | #endif |
448 | 321 | ||
449 | if( !shutdown_timeout && query_force_shutdown()) { | 322 | if (!shutdown_timeout && query_force_shutdown()) { |
450 | backlight_on(); | 323 | backlight_on(); |
451 | sys_poweroff(); | 324 | sys_poweroff(); |
452 | } | 325 | } |
453 | 326 | ||
454 | if(timeout && | 327 | if (timeout && |
455 | #if CONFIG_TUNER && !defined(BOOTLOADER) | 328 | #if CONFIG_TUNER |
456 | (!(get_radio_status() & FMRADIO_PLAYING)) && | 329 | !(get_radio_status() & FMRADIO_PLAYING) && |
457 | #endif | 330 | #endif |
458 | !usb_inserted() && | 331 | !usb_inserted() && |
459 | ((audio_stat == 0) || | 332 | (audio_stat == 0 || |
460 | ((audio_stat == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE)) && | 333 | (audio_stat == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE) && |
461 | !sleeptimer_active))) | 334 | !sleeptimer_active))) { |
462 | { | 335 | |
463 | if(TIME_AFTER(current_tick, last_event_tick + timeout) && | 336 | if (TIME_AFTER(tick, last_event_tick + timeout) && |
464 | TIME_AFTER(current_tick, storage_last_disk_activity() + timeout)) | 337 | TIME_AFTER(tick, storage_last_disk_activity() + timeout)) { |
465 | { | ||
466 | sys_poweroff(); | 338 | sys_poweroff(); |
467 | } | 339 | } |
468 | } | 340 | } |
469 | else | 341 | else if (sleeptimer_active) { |
470 | { | ||
471 | /* Handle sleeptimer */ | 342 | /* Handle sleeptimer */ |
472 | if(sleeptimer_active) | 343 | if (TIME_AFTER(tick, sleeptimer_endtick)) { |
473 | { | 344 | audio_stop(); |
474 | if(TIME_AFTER(current_tick, sleeptimer_endtick)) | 345 | |
475 | { | 346 | if (usb_inserted() |
476 | audio_stop(); | ||
477 | if (usb_inserted() | ||
478 | #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) | 347 | #if CONFIG_CHARGING && !defined(HAVE_POWEROFF_WHILE_CHARGING) |
479 | || ((charger_input_state == CHARGER) || | 348 | || charger_input_state != NO_CHARGER |
480 | (charger_input_state == CHARGER_PLUGGED)) | ||
481 | #endif | 349 | #endif |
482 | ) | 350 | ) { |
483 | { | 351 | DEBUGF("Sleep timer timeout. Stopping...\n"); |
484 | DEBUGF("Sleep timer timeout. Stopping...\n"); | 352 | set_sleep_timer(0); |
485 | set_sleep_timer(0); | 353 | backlight_off(); /* Nighty, nighty... */ |
486 | backlight_off(); /* Nighty, nighty... */ | 354 | } |
487 | } | 355 | else { |
488 | else | 356 | DEBUGF("Sleep timer timeout. Shutting off...\n"); |
489 | { | 357 | sys_poweroff(); |
490 | DEBUGF("Sleep timer timeout. Shutting off...\n"); | ||
491 | sys_poweroff(); | ||
492 | } | ||
493 | } | 358 | } |
494 | } | 359 | } |
495 | } | 360 | } |
@@ -504,25 +369,24 @@ static int runcurrent(void) | |||
504 | 369 | ||
505 | #if MEM == 8 && !(defined(ARCHOS_ONDIOSP) || defined(ARCHOS_ONDIOFM)) | 370 | #if MEM == 8 && !(defined(ARCHOS_ONDIOSP) || defined(ARCHOS_ONDIOFM)) |
506 | /* assuming 192 kbps, the running time is 22% longer with 8MB */ | 371 | /* assuming 192 kbps, the running time is 22% longer with 8MB */ |
507 | current = (CURRENT_NORMAL*100/122); | 372 | current = CURRENT_NORMAL*100 / 122; |
508 | #else | 373 | #else |
509 | current = CURRENT_NORMAL; | 374 | current = CURRENT_NORMAL; |
510 | #endif /* MEM == 8 */ | 375 | #endif /* MEM == 8 */ |
511 | 376 | ||
512 | if(usb_inserted() | 377 | if (usb_inserted() |
513 | #if defined(HAVE_USB_POWER) | 378 | #ifdef HAVE_USB_POWER |
514 | #if (CURRENT_USB < CURRENT_NORMAL) | 379 | #if (CURRENT_USB < CURRENT_NORMAL) |
515 | || usb_powered() | 380 | || usb_powered() |
516 | #else | 381 | #else |
517 | && !usb_powered() | 382 | && !usb_powered() |
518 | #endif | 383 | #endif |
519 | #endif | 384 | #endif |
520 | ) | 385 | ) { |
521 | { | ||
522 | current = CURRENT_USB; | 386 | current = CURRENT_USB; |
523 | } | 387 | } |
524 | 388 | ||
525 | #if defined(HAVE_BACKLIGHT) && !defined(BOOTLOADER) | 389 | #if defined(HAVE_BACKLIGHT) |
526 | if (backlight_get_current_timeout() == 0) /* LED always on */ | 390 | if (backlight_get_current_timeout() == 0) /* LED always on */ |
527 | current += CURRENT_BACKLIGHT; | 391 | current += CURRENT_BACKLIGHT; |
528 | #endif | 392 | #endif |
@@ -542,7 +406,7 @@ static int runcurrent(void) | |||
542 | current += CURRENT_REMOTE; | 406 | current += CURRENT_REMOTE; |
543 | #endif | 407 | #endif |
544 | 408 | ||
545 | return(current); | 409 | return current; |
546 | } | 410 | } |
547 | 411 | ||
548 | 412 | ||
@@ -550,424 +414,76 @@ static int runcurrent(void) | |||
550 | #ifdef HAVE_RTC_ALARM | 414 | #ifdef HAVE_RTC_ALARM |
551 | static void power_thread_rtc_process(void) | 415 | static void power_thread_rtc_process(void) |
552 | { | 416 | { |
553 | if (rtc_check_alarm_flag()) { | 417 | if (rtc_check_alarm_flag()) |
554 | rtc_enable_alarm(false); | 418 | rtc_enable_alarm(false); |
555 | } | ||
556 | } | 419 | } |
557 | #endif | 420 | #endif |
558 | 421 | ||
559 | #ifndef TARGET_QUERY_FORCE_SHUTDOWN | 422 | /* switch off unit if battery level is too low for reliable operation */ |
560 | bool query_force_shutdown(void) | 423 | bool query_force_shutdown(void) |
561 | { | 424 | { |
562 | #ifndef NO_LOW_BATTERY_SHUTDOWN | 425 | #if defined(NO_LOW_BATTERY_SHUTDOWN) |
563 | /* switch off unit if battery level is too low for reliable operation */ | ||
564 | return battery_millivolts < battery_level_shutoff[battery_type]; | ||
565 | #else | ||
566 | return false; | 426 | return false; |
427 | #elif defined(HAVE_BATTERY_SWITCH) | ||
428 | /* Cannot rely upon the battery reading to be valid and the | ||
429 | * device could be powered externally. */ | ||
430 | return input_millivolts() < battery_level_shutoff[battery_type]; | ||
431 | #else | ||
432 | return battery_millivolts < battery_level_shutoff[battery_type]; | ||
567 | #endif | 433 | #endif |
568 | } | 434 | } |
569 | #endif /* TARGET_QUERY_FORCE_SHUTDOWN */ | ||
570 | |||
571 | /* | ||
572 | * This power thread maintains a history of battery voltage | ||
573 | * and implements a charging algorithm. | ||
574 | */ | ||
575 | #if CONFIG_CHARGING == CHARGING_CONTROL | ||
576 | #define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */ | ||
577 | 435 | ||
436 | #ifdef HAVE_BATTERY_SWITCH | ||
578 | /* | 437 | /* |
579 | * For a complete description of the charging algorithm read | 438 | * Reset the battery voltage filter to a new value and update the |
580 | * docs/CHARGING_ALGORITHM. | 439 | * status. |
581 | */ | 440 | */ |
582 | int long_delta; /* long term delta battery voltage */ | 441 | void reset_battery_filter(int millivolts) |
583 | int short_delta; /* short term delta battery voltage */ | ||
584 | bool disk_activity_last_cycle = false; /* flag set to aid charger time | ||
585 | * calculation */ | ||
586 | char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in | ||
587 | debug menu */ | ||
588 | /* percentage at which charging | ||
589 | starts */ | ||
590 | int powermgmt_last_cycle_startstop_min = 0; /* how many minutes ago was the | ||
591 | charging started or | ||
592 | stopped? */ | ||
593 | int powermgmt_last_cycle_level = 0; /* which level had the | ||
594 | batteries at this time? */ | ||
595 | int trickle_sec = 0; /* how many seconds should the | ||
596 | charger be enabled per | ||
597 | minute for trickle | ||
598 | charging? */ | ||
599 | int pid_p = 0; /* PID proportional term */ | ||
600 | int pid_i = 0; /* PID integral term */ | ||
601 | |||
602 | static inline void charging_algorithm_small_step(void) | ||
603 | { | 442 | { |
604 | if (storage_disk_is_active()) { | 443 | avgbat = millivolts * BATT_AVE_SAMPLES; |
605 | /* flag hdd use for charging calculation */ | 444 | battery_millivolts = millivolts; |
606 | disk_activity_last_cycle = true; | 445 | battery_status_update(); |
607 | } | ||
608 | |||
609 | #if defined(DEBUG_FILE) | ||
610 | /* | ||
611 | * If we have a lot of pending writes or if the disk is spining, | ||
612 | * fsync the debug log file. | ||
613 | */ | ||
614 | if((wrcount > 10) || ((wrcount > 0) && storage_disk_is_active())) { | ||
615 | fsync(fd); | ||
616 | wrcount = 0; | ||
617 | } | ||
618 | #endif /* defined(DEBUG_FILE) */ | ||
619 | } | 446 | } |
447 | #endif /* HAVE_BATTERY_SWITCH */ | ||
620 | 448 | ||
621 | static inline void charging_algorithm_big_step(void) | 449 | /** Generic charging algorithms for common charging types **/ |
450 | #if CONFIG_CHARGING == CHARGING_SIMPLE | ||
451 | static inline void charging_algorithm_step(void) | ||
622 | { | 452 | { |
623 | static unsigned int target_voltage = TRICKLE_VOLTAGE; /* desired topoff/trickle | 453 | /* Nothing to do */ |
624 | * voltage level */ | ||
625 | static int charge_max_time_idle = 0; /* max. charging duration, calculated at | ||
626 | * beginning of charging */ | ||
627 | static int charge_max_time_now = 0; /* max. charging duration including | ||
628 | * hdd activity */ | ||
629 | static int minutes_disk_activity = 0; /* count minutes of hdd use during | ||
630 | * charging */ | ||
631 | static int last_disk_activity = CHARGE_END_LONGD + 1; /* last hdd use x mins ago */ | ||
632 | int i; | ||
633 | |||
634 | if (charger_input_state == CHARGER_PLUGGED) { | ||
635 | pid_p = 0; | ||
636 | pid_i = 0; | ||
637 | snprintf(power_message, POWER_MESSAGE_LEN, "Charger plugged in"); | ||
638 | /* | ||
639 | * The charger was just plugged in. If the battery level is | ||
640 | * nearly charged, just trickle. If the battery is low, start | ||
641 | * a full charge cycle. If the battery level is in between, | ||
642 | * top-off and then trickle. | ||
643 | */ | ||
644 | if(battery_percent > START_TOPOFF_CHG) { | ||
645 | powermgmt_last_cycle_level = battery_percent; | ||
646 | powermgmt_last_cycle_startstop_min = 0; | ||
647 | if(battery_percent >= START_TRICKLE_CHG) { | ||
648 | charge_state = TRICKLE; | ||
649 | target_voltage = TRICKLE_VOLTAGE; | ||
650 | } else { | ||
651 | charge_state = TOPOFF; | ||
652 | target_voltage = TOPOFF_VOLTAGE; | ||
653 | } | ||
654 | } else { | ||
655 | /* | ||
656 | * Start the charger full strength | ||
657 | */ | ||
658 | i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500; | ||
659 | charge_max_time_idle = | ||
660 | i * (100 + 35 - battery_percent) / 100; | ||
661 | if (charge_max_time_idle > i) { | ||
662 | charge_max_time_idle = i; | ||
663 | } | ||
664 | charge_max_time_now = charge_max_time_idle; | ||
665 | |||
666 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
667 | "ChgAt %d%% max %dm", battery_level(), | ||
668 | charge_max_time_now); | ||
669 | |||
670 | /* enable the charger after the max time calc is done, | ||
671 | because battery_level depends on if the charger is | ||
672 | on */ | ||
673 | DEBUGF("power: charger inserted and battery" | ||
674 | " not full, charging\n"); | ||
675 | powermgmt_last_cycle_level = battery_percent; | ||
676 | powermgmt_last_cycle_startstop_min = 0; | ||
677 | trickle_sec = 60; | ||
678 | long_delta = short_delta = 999999; | ||
679 | charge_state = CHARGING; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | if (charge_state == CHARGING) { | ||
684 | /* alter charge time max length with extra disk use */ | ||
685 | if (disk_activity_last_cycle) { | ||
686 | minutes_disk_activity++; | ||
687 | charge_max_time_now = charge_max_time_idle + | ||
688 | (minutes_disk_activity * 2 / 5); | ||
689 | disk_activity_last_cycle = false; | ||
690 | last_disk_activity = 0; | ||
691 | } else { | ||
692 | last_disk_activity++; | ||
693 | } | ||
694 | /* | ||
695 | * Check the delta voltage over the last X minutes so we can do | ||
696 | * our end-of-charge logic based on the battery level change. | ||
697 | *(no longer use minimum time as logic for charge end has 50 | ||
698 | * minutes minimum charge built in) | ||
699 | */ | ||
700 | if (powermgmt_last_cycle_startstop_min > CHARGE_END_SHORTD) { | ||
701 | short_delta = power_history[0] - | ||
702 | power_history[CHARGE_END_SHORTD - 1]; | ||
703 | } | ||
704 | |||
705 | if (powermgmt_last_cycle_startstop_min > CHARGE_END_LONGD) { | ||
706 | /* | ||
707 | * Scan the history: the points where measurement is taken need to | ||
708 | * be fairly static. (check prior to short delta 'area') | ||
709 | * (also only check first and last 10 cycles - delta in middle OK) | ||
710 | */ | ||
711 | long_delta = power_history[0] - | ||
712 | power_history[CHARGE_END_LONGD - 1]; | ||
713 | |||
714 | for(i = CHARGE_END_SHORTD; i < CHARGE_END_SHORTD + 10; i++) { | ||
715 | if(((power_history[i] - power_history[i+1]) > 50) || | ||
716 | ((power_history[i] - power_history[i+1]) < -50)) { | ||
717 | long_delta = 777777; | ||
718 | break; | ||
719 | } | ||
720 | } | ||
721 | for(i = CHARGE_END_LONGD - 11; i < CHARGE_END_LONGD - 1 ; i++) { | ||
722 | if(((power_history[i] - power_history[i+1]) > 50) || | ||
723 | ((power_history[i] - power_history[i+1]) < -50)) { | ||
724 | long_delta = 888888; | ||
725 | break; | ||
726 | } | ||
727 | } | ||
728 | } | ||
729 | |||
730 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
731 | "Chg %dm, max %dm", powermgmt_last_cycle_startstop_min, | ||
732 | charge_max_time_now); | ||
733 | /* | ||
734 | * End of charge criteria (any qualify): | ||
735 | * 1) Charged a long time | ||
736 | * 2) DeltaV went negative for a short time ( & long delta static) | ||
737 | * 3) DeltaV was negative over a longer period (no disk use only) | ||
738 | * Note: short_delta and long_delta are millivolts | ||
739 | */ | ||
740 | if ((powermgmt_last_cycle_startstop_min >= charge_max_time_now) || | ||
741 | (short_delta <= -50 && long_delta < 50 ) || (long_delta < -20 && | ||
742 | last_disk_activity > CHARGE_END_LONGD)) { | ||
743 | if (powermgmt_last_cycle_startstop_min > charge_max_time_now) { | ||
744 | DEBUGF("power: powermgmt_last_cycle_startstop_min > charge_max_time_now, " | ||
745 | "enough!\n"); | ||
746 | /* | ||
747 | *have charged too long and deltaV detection did not | ||
748 | *work! | ||
749 | */ | ||
750 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
751 | "Chg tmout %d min", charge_max_time_now); | ||
752 | /* | ||
753 | * Switch to trickle charging. We skip the top-off | ||
754 | * since we've effectively done the top-off operation | ||
755 | * already since we charged for the maximum full | ||
756 | * charge time. | ||
757 | */ | ||
758 | powermgmt_last_cycle_level = battery_percent; | ||
759 | powermgmt_last_cycle_startstop_min = 0; | ||
760 | charge_state = TRICKLE; | ||
761 | |||
762 | /* | ||
763 | * set trickle charge target to a relative voltage instead | ||
764 | * of an arbitrary value - the fully charged voltage may | ||
765 | * vary according to ambient temp, battery condition etc | ||
766 | * trickle target is -0.15v from full voltage acheived | ||
767 | * topup target is -0.05v from full voltage | ||
768 | */ | ||
769 | target_voltage = power_history[0] - 150; | ||
770 | |||
771 | } else { | ||
772 | if(short_delta <= -5) { | ||
773 | DEBUGF("power: short-term negative" | ||
774 | " delta, enough!\n"); | ||
775 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
776 | "end negd %d %dmin", short_delta, | ||
777 | powermgmt_last_cycle_startstop_min); | ||
778 | target_voltage = power_history[CHARGE_END_SHORTD - 1] | ||
779 | - 50; | ||
780 | } else { | ||
781 | DEBUGF("power: long-term small " | ||
782 | "positive delta, enough!\n"); | ||
783 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
784 | "end lowd %d %dmin", long_delta, | ||
785 | powermgmt_last_cycle_startstop_min); | ||
786 | target_voltage = power_history[CHARGE_END_LONGD - 1] | ||
787 | - 50; | ||
788 | } | ||
789 | /* | ||
790 | * Switch to top-off charging. | ||
791 | */ | ||
792 | powermgmt_last_cycle_level = battery_percent; | ||
793 | powermgmt_last_cycle_startstop_min = 0; | ||
794 | charge_state = TOPOFF; | ||
795 | } | ||
796 | } | ||
797 | } | ||
798 | else if (charge_state != DISCHARGING) /* top off or trickle */ | ||
799 | { | ||
800 | /* | ||
801 | *Time to switch from topoff to trickle? | ||
802 | */ | ||
803 | if ((charge_state == TOPOFF) && | ||
804 | (powermgmt_last_cycle_startstop_min > TOPOFF_MAX_TIME)) | ||
805 | { | ||
806 | powermgmt_last_cycle_level = battery_percent; | ||
807 | powermgmt_last_cycle_startstop_min = 0; | ||
808 | charge_state = TRICKLE; | ||
809 | target_voltage = target_voltage - 100; | ||
810 | } | ||
811 | /* | ||
812 | * Adjust trickle charge time (proportional and integral terms). | ||
813 | * Note: I considered setting the level higher if the USB is | ||
814 | * plugged in, but it doesn't appear to be necessary and will | ||
815 | * generate more heat [gvb]. | ||
816 | */ | ||
817 | |||
818 | pid_p = ((signed)target_voltage - (signed)battery_millivolts) / 5; | ||
819 | if((pid_p <= PID_DEADZONE) && (pid_p >= -PID_DEADZONE)) | ||
820 | pid_p = 0; | ||
821 | |||
822 | if((unsigned) battery_millivolts < target_voltage) { | ||
823 | if(pid_i < 60) { | ||
824 | pid_i++; /* limit so it doesn't "wind up" */ | ||
825 | } | ||
826 | } else { | ||
827 | if(pid_i > 0) { | ||
828 | pid_i--; /* limit so it doesn't "wind up" */ | ||
829 | } | ||
830 | } | ||
831 | |||
832 | trickle_sec = pid_p + pid_i; | ||
833 | |||
834 | if(trickle_sec > 60) { | ||
835 | trickle_sec = 60; | ||
836 | } | ||
837 | if(trickle_sec < 0) { | ||
838 | trickle_sec = 0; | ||
839 | } | ||
840 | |||
841 | } else if (charge_state == DISCHARGING) { | ||
842 | trickle_sec = 0; | ||
843 | /* | ||
844 | * The charger is enabled here only in one case: if it was | ||
845 | * turned on at boot time (power_init). Turn it off now. | ||
846 | */ | ||
847 | if (charger_enabled) | ||
848 | charger_enable(false); | ||
849 | } | ||
850 | |||
851 | if (charger_input_state == CHARGER_UNPLUGGED) { | ||
852 | /* | ||
853 | * The charger was just unplugged. | ||
854 | */ | ||
855 | DEBUGF("power: charger disconnected, disabling\n"); | ||
856 | |||
857 | charger_enable(false); | ||
858 | powermgmt_last_cycle_level = battery_percent; | ||
859 | powermgmt_last_cycle_startstop_min = 0; | ||
860 | trickle_sec = 0; | ||
861 | pid_p = 0; | ||
862 | pid_i = 0; | ||
863 | charge_state = DISCHARGING; | ||
864 | snprintf(power_message, POWER_MESSAGE_LEN, "Charger: discharge"); | ||
865 | } | ||
866 | |||
867 | /* sleep for a minute */ | ||
868 | if(trickle_sec > 0) { | ||
869 | charger_enable(true); | ||
870 | power_thread_sleep(HZ * trickle_sec); | ||
871 | } | ||
872 | if(trickle_sec < 60) | ||
873 | charger_enable(false); | ||
874 | power_thread_sleep(HZ * (60 - trickle_sec)); | ||
875 | |||
876 | #if defined(DEBUG_FILE) | ||
877 | if(usb_inserted()) { | ||
878 | if(fd >= 0) { | ||
879 | /* It is probably too late to close the file but we can try...*/ | ||
880 | close(fd); | ||
881 | fd = -1; | ||
882 | } | ||
883 | } else { | ||
884 | if(fd < 0) { | ||
885 | fd = open(DEBUG_FILE_NAME, O_WRONLY | O_APPEND | O_CREAT); | ||
886 | if(fd >= 0) { | ||
887 | snprintf(debug_message, DEBUG_MESSAGE_LEN, | ||
888 | "cycle_min, bat_millivolts, bat_percent, chgr_state" | ||
889 | " ,charge_state, pid_p, pid_i, trickle_sec\n"); | ||
890 | write(fd, debug_message, strlen(debug_message)); | ||
891 | wrcount = 99; /* force a flush */ | ||
892 | } | ||
893 | } | ||
894 | if(fd >= 0) { | ||
895 | snprintf(debug_message, DEBUG_MESSAGE_LEN, | ||
896 | "%d, %d, %d, %d, %d, %d, %d, %d\n", | ||
897 | powermgmt_last_cycle_startstop_min, battery_millivolts, | ||
898 | battery_percent, charger_input_state, charge_state, | ||
899 | pid_p, pid_i, trickle_sec); | ||
900 | write(fd, debug_message, strlen(debug_message)); | ||
901 | wrcount++; | ||
902 | } | ||
903 | } | ||
904 | #endif /* defined(DEBUG_FILE) */ | ||
905 | |||
906 | powermgmt_last_cycle_startstop_min++; | ||
907 | } | 454 | } |
908 | 455 | ||
909 | /* | ||
910 | * Prepare charging for poweroff | ||
911 | */ | ||
912 | static inline void charging_algorithm_close(void) | 456 | static inline void charging_algorithm_close(void) |
913 | { | 457 | { |
914 | #if defined(DEBUG_FILE) | 458 | /* Nothing to do */ |
915 | if(fd >= 0) { | ||
916 | close(fd); | ||
917 | fd = -1; | ||
918 | } | ||
919 | #endif | ||
920 | } | ||
921 | #elif CONFIG_CHARGING == CHARGING_TARGET | ||
922 | extern void charging_algorithm_big_step(void); | ||
923 | extern void charging_algorithm_small_step(void); | ||
924 | extern void charging_algorithm_close(void); | ||
925 | |||
926 | void set_filtered_battery_voltage(int millivolts) | ||
927 | { | ||
928 | avgbat = millivolts * BATT_AVE_SAMPLES; | ||
929 | battery_millivolts = millivolts; | ||
930 | battery_status_update(); | ||
931 | } | 459 | } |
932 | 460 | #elif CONFIG_CHARGING == CHARGING_MONITOR | |
933 | #else | 461 | /* |
934 | #define BATT_AVE_SAMPLES 128 /* slw filter constant for all others */ | 462 | * Monitor CHARGING/DISCHARGING state. |
935 | 463 | */ | |
936 | static inline void charging_algorithm_small_step(void) | 464 | static inline void charging_algorithm_step(void) |
937 | { | 465 | { |
938 | #if CONFIG_CHARGING == CHARGING_MONITOR | ||
939 | switch (charger_input_state) | 466 | switch (charger_input_state) |
940 | { | 467 | { |
941 | case CHARGER_UNPLUGGED: | 468 | case CHARGER_PLUGGED: |
942 | case NO_CHARGER: | 469 | case CHARGER: |
943 | charge_state = DISCHARGING; | 470 | if (charging_state()) { |
944 | break; | 471 | charge_state = CHARGING; |
945 | case CHARGER_PLUGGED: | ||
946 | case CHARGER: | ||
947 | if (charging_state()) { | ||
948 | charge_state = CHARGING; | ||
949 | } else { | ||
950 | charge_state = DISCHARGING; | ||
951 | } | ||
952 | break; | 472 | break; |
473 | } | ||
474 | /* Fallthrough */ | ||
475 | case CHARGER_UNPLUGGED: | ||
476 | case NO_CHARGER: | ||
477 | charge_state = DISCHARGING; | ||
478 | break; | ||
953 | } | 479 | } |
954 | #endif /* CONFIG_CHARGING == CHARGING_MONITOR */ | ||
955 | } | 480 | } |
956 | 481 | ||
957 | static inline void charging_algorithm_big_step(void) | ||
958 | { | ||
959 | /* sleep for a minute */ | ||
960 | power_thread_sleep(HZ * 60); | ||
961 | } | ||
962 | |||
963 | /* | ||
964 | * Prepare charging for poweroff | ||
965 | */ | ||
966 | static inline void charging_algorithm_close(void) | 482 | static inline void charging_algorithm_close(void) |
967 | { | 483 | { |
968 | /* Nothing to do */ | 484 | /* Nothing to do */ |
969 | } | 485 | } |
970 | #endif /* CONFIG_CHARGING == CHARGING_CONTROL */ | 486 | #endif /* CONFIG_CHARGING == * */ |
971 | 487 | ||
972 | #if CONFIG_CHARGING | 488 | #if CONFIG_CHARGING |
973 | /* Shortcut function calls - compatibility, simplicity. */ | 489 | /* Shortcut function calls - compatibility, simplicity. */ |
@@ -975,270 +491,271 @@ static inline void charging_algorithm_close(void) | |||
975 | /* Returns true if any power input is capable of charging. */ | 491 | /* Returns true if any power input is capable of charging. */ |
976 | bool charger_inserted(void) | 492 | bool charger_inserted(void) |
977 | { | 493 | { |
978 | return power_input_status() & POWER_INPUT_CHARGER; | 494 | return power_thread_inputs & POWER_INPUT_CHARGER; |
979 | } | 495 | } |
980 | 496 | ||
981 | /* Returns true if any power input is connected - charging-capable | 497 | /* Returns true if any power input is connected - charging-capable |
982 | * or not. */ | 498 | * or not. */ |
983 | bool power_input_present(void) | 499 | bool power_input_present(void) |
984 | { | 500 | { |
985 | return power_input_status() & POWER_INPUT; | 501 | return power_thread_inputs & POWER_INPUT; |
986 | } | 502 | } |
987 | #endif /* CONFIG_CHARGING */ | ||
988 | 503 | ||
989 | /* | 504 | /* |
990 | * This function is called to do the relativly long sleep waits from within the | 505 | * Detect charger inserted. Return true if the state is transistional. |
991 | * main power_thread loop while at the same time servicing any other periodic | ||
992 | * functions in the power thread which need to be called at a faster periodic | ||
993 | * rate than the slow periodic rate of the main power_thread loop. | ||
994 | * | ||
995 | * While we are waiting for the time to expire, we average the battery | ||
996 | * voltages. | ||
997 | */ | 506 | */ |
998 | void power_thread_sleep(int ticks) | 507 | static inline bool detect_charger(unsigned int pwr) |
999 | { | 508 | { |
1000 | long tick_return = current_tick + ticks; | 509 | /* |
510 | * Detect charger plugged/unplugged transitions. On a plugged or | ||
511 | * unplugged event, we return immediately, run once through the main | ||
512 | * loop (including the subroutines), and end up back here where we | ||
513 | * transition to the appropriate steady state charger on/off state. | ||
514 | */ | ||
515 | if (pwr & POWER_INPUT_CHARGER) { | ||
516 | switch (charger_input_state) | ||
517 | { | ||
518 | case NO_CHARGER: | ||
519 | case CHARGER_UNPLUGGED: | ||
520 | charger_input_state = CHARGER_PLUGGED; | ||
521 | break; | ||
1001 | 522 | ||
1002 | do | 523 | case CHARGER_PLUGGED: |
1003 | { | 524 | queue_broadcast(SYS_CHARGER_CONNECTED, 0); |
1004 | #if CONFIG_CHARGING | 525 | last_sent_battery_level = 0; |
1005 | /* | 526 | charger_input_state = CHARGER; |
1006 | * Detect charger plugged/unplugged transitions. On a plugged or | 527 | break; |
1007 | * unplugged event, we return immediately, run once through the main | 528 | |
1008 | * loop (including the subroutines), and end up back here where we | 529 | case CHARGER: |
1009 | * transition to the appropriate steady state charger on/off state. | 530 | /* Steady state */ |
1010 | */ | 531 | return false; |
1011 | if(power_input_status() & POWER_INPUT_CHARGER) { | ||
1012 | switch(charger_input_state) { | ||
1013 | case NO_CHARGER: | ||
1014 | case CHARGER_UNPLUGGED: | ||
1015 | charger_input_state = CHARGER_PLUGGED; | ||
1016 | tick_return = current_tick; | ||
1017 | goto do_small_step; /* Algorithm should see transition */ | ||
1018 | case CHARGER_PLUGGED: | ||
1019 | queue_broadcast(SYS_CHARGER_CONNECTED, 0); | ||
1020 | last_sent_battery_level = 0; | ||
1021 | charger_input_state = CHARGER; | ||
1022 | break; | ||
1023 | case CHARGER: | ||
1024 | break; | ||
1025 | } | ||
1026 | } else { /* charger not inserted */ | ||
1027 | switch(charger_input_state) { | ||
1028 | case NO_CHARGER: | ||
1029 | break; | ||
1030 | case CHARGER_UNPLUGGED: | ||
1031 | queue_broadcast(SYS_CHARGER_DISCONNECTED, 0); | ||
1032 | last_sent_battery_level = 100; | ||
1033 | charger_input_state = NO_CHARGER; | ||
1034 | break; | ||
1035 | case CHARGER_PLUGGED: | ||
1036 | case CHARGER: | ||
1037 | charger_input_state = CHARGER_UNPLUGGED; | ||
1038 | tick_return = current_tick; | ||
1039 | goto do_small_step; /* Algorithm should see transition */ | ||
1040 | } | ||
1041 | } | 532 | } |
1042 | #endif /* CONFIG_CHARGING */ | 533 | } |
534 | else { /* charger not inserted */ | ||
535 | switch (charger_input_state) | ||
536 | { | ||
537 | case NO_CHARGER: | ||
538 | /* Steady state */ | ||
539 | return false; | ||
1043 | 540 | ||
1044 | ticks = tick_return - current_tick; | 541 | case CHARGER_UNPLUGGED: |
542 | queue_broadcast(SYS_CHARGER_DISCONNECTED, 0); | ||
543 | last_sent_battery_level = 100; | ||
544 | charger_input_state = NO_CHARGER; | ||
545 | break; | ||
1045 | 546 | ||
1046 | if (ticks > 0) { | 547 | case CHARGER_PLUGGED: |
1047 | ticks = MIN(HZ/2, ticks); | 548 | case CHARGER: |
1048 | sleep(ticks); | 549 | charger_input_state = CHARGER_UNPLUGGED; |
550 | break; | ||
1049 | } | 551 | } |
552 | } | ||
1050 | 553 | ||
1051 | /* If the power off timeout expires, the main thread has failed | 554 | /* Transitional state */ |
1052 | to shut down the system, and we need to force a power off */ | 555 | return true; |
1053 | if(shutdown_timeout) { | 556 | } |
1054 | shutdown_timeout -= MAX(ticks, 1); | 557 | #endif /* CONFIG_CHARGING */ |
1055 | if(shutdown_timeout <= 0) | 558 | |
1056 | power_off(); | 559 | /* |
1057 | } | 560 | * Monitor the presence of a charger and perform critical frequent steps |
561 | * such as running the battery voltage filter. | ||
562 | */ | ||
563 | static inline void power_thread_step(void) | ||
564 | { | ||
565 | /* If the power off timeout expires, the main thread has failed | ||
566 | to shut down the system, and we need to force a power off */ | ||
567 | if (shutdown_timeout) { | ||
568 | shutdown_timeout -= POWER_THREAD_STEP_TICKS; | ||
569 | |||
570 | if (shutdown_timeout <= 0) | ||
571 | power_off(); | ||
572 | } | ||
1058 | 573 | ||
1059 | #ifdef HAVE_RTC_ALARM | 574 | #ifdef HAVE_RTC_ALARM |
1060 | power_thread_rtc_process(); | 575 | power_thread_rtc_process(); |
1061 | #endif | 576 | #endif |
1062 | 577 | ||
1063 | /* | 578 | /* |
1064 | * Do a digital exponential filter. We don't sample the battery if | 579 | * Do a digital exponential filter. We don't sample the battery if |
1065 | * the disk is spinning unless we are in USB mode (the disk will most | 580 | * the disk is spinning unless we are in USB mode (the disk will most |
1066 | * likely always be spinning in USB mode) or charging. | 581 | * likely always be spinning in USB mode) or charging. |
1067 | */ | 582 | */ |
1068 | if (!storage_disk_is_active() || usb_inserted() | 583 | if (!storage_disk_is_active() || usb_inserted() |
1069 | #if CONFIG_CHARGING >= CHARGING_MONITOR | 584 | #if CONFIG_CHARGING >= CHARGING_MONITOR |
1070 | || charger_input_state == CHARGER | 585 | || charger_input_state == CHARGER |
1071 | #endif | 586 | #endif |
1072 | ) { | 587 | ) { |
1073 | avgbat += battery_adc_voltage() - (avgbat / BATT_AVE_SAMPLES); | 588 | avgbat += battery_adc_voltage() - avgbat / BATT_AVE_SAMPLES; |
1074 | /* | 589 | /* |
1075 | * battery_millivolts is the millivolt-scaled filtered battery value. | 590 | * battery_millivolts is the millivolt-scaled filtered battery value. |
1076 | */ | 591 | */ |
1077 | battery_millivolts = avgbat / BATT_AVE_SAMPLES; | 592 | battery_millivolts = avgbat / BATT_AVE_SAMPLES; |
1078 | 593 | ||
1079 | /* update battery status every time an update is available */ | 594 | /* update battery status every time an update is available */ |
1080 | battery_status_update(); | 595 | battery_status_update(); |
596 | } | ||
597 | else if (battery_percent < 8) { | ||
598 | /* | ||
599 | * If battery is low, observe voltage during disk activity. | ||
600 | * Shut down if voltage drops below shutoff level and we are not | ||
601 | * using NiMH or Alkaline batteries. | ||
602 | */ | ||
603 | battery_millivolts = (battery_adc_voltage() + | ||
604 | battery_millivolts + 1) / 2; | ||
605 | |||
606 | /* update battery status every time an update is available */ | ||
607 | battery_status_update(); | ||
608 | |||
609 | if (!shutdown_timeout && query_force_shutdown()) { | ||
610 | sys_poweroff(); | ||
1081 | } | 611 | } |
1082 | else if (battery_percent < 8) { | 612 | else { |
1083 | /* If battery is low, observe voltage during disk activity. | 613 | avgbat += battery_millivolts - avgbat / BATT_AVE_SAMPLES; |
1084 | * Shut down if voltage drops below shutoff level and we are not | ||
1085 | * using NiMH or Alkaline batteries. | ||
1086 | */ | ||
1087 | battery_millivolts = (battery_adc_voltage() + | ||
1088 | battery_millivolts + 1) / 2; | ||
1089 | |||
1090 | /* update battery status every time an update is available */ | ||
1091 | battery_status_update(); | ||
1092 | |||
1093 | if (!shutdown_timeout && query_force_shutdown()) { | ||
1094 | sys_poweroff(); | ||
1095 | } | ||
1096 | else { | ||
1097 | avgbat += battery_millivolts - (avgbat / BATT_AVE_SAMPLES); | ||
1098 | } | ||
1099 | } | 614 | } |
1100 | |||
1101 | #if CONFIG_CHARGING | ||
1102 | do_small_step: | ||
1103 | #endif | ||
1104 | charging_algorithm_small_step(); | ||
1105 | } | 615 | } |
1106 | while (TIME_BEFORE(current_tick, tick_return)); | 616 | } /* power_thread_step */ |
1107 | } | ||
1108 | 617 | ||
1109 | static void power_thread(void) | 618 | static void power_thread(void) |
1110 | { | 619 | { |
620 | long next_power_hist; | ||
621 | |||
1111 | /* Delay reading the first battery level */ | 622 | /* Delay reading the first battery level */ |
1112 | #ifdef MROBE_100 | 623 | #ifdef MROBE_100 |
1113 | while(battery_adc_voltage()>4200) /* gives false readings initially */ | 624 | while (battery_adc_voltage() > 4200) /* gives false readings initially */ |
625 | #endif | ||
626 | { | ||
627 | sleep(HZ/100); | ||
628 | } | ||
629 | |||
630 | #if CONFIG_CHARGING | ||
631 | /* Initialize power input status before calling other routines. */ | ||
632 | power_thread_inputs = power_input_status(); | ||
1114 | #endif | 633 | #endif |
1115 | sleep(HZ/100); | ||
1116 | 634 | ||
1117 | /* initialize the voltages for the exponential filter */ | 635 | /* initialize the voltages for the exponential filter */ |
1118 | avgbat = battery_adc_voltage() + 15; | 636 | avgbat = battery_adc_voltage() + 15; |
1119 | 637 | ||
1120 | #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */ | 638 | #ifdef HAVE_DISK_STORAGE /* this adjustment is only needed for HD based */ |
1121 | /* The battery voltage is usually a little lower directly after | 639 | /* The battery voltage is usually a little lower directly after |
1122 | turning on, because the disk was used heavily. Raise it by 5% */ | 640 | turning on, because the disk was used heavily. Raise it by 5% */ |
1123 | #if CONFIG_CHARGING | 641 | #if CONFIG_CHARGING |
1124 | if(!charger_inserted()) /* only if charger not connected */ | 642 | if (!charger_inserted()) /* only if charger not connected */ |
1125 | #endif | 643 | #endif |
644 | { | ||
1126 | avgbat += (percent_to_volt_discharge[battery_type][6] - | 645 | avgbat += (percent_to_volt_discharge[battery_type][6] - |
1127 | percent_to_volt_discharge[battery_type][5]) / 2; | 646 | percent_to_volt_discharge[battery_type][5]) / 2; |
647 | } | ||
1128 | #endif /* HAVE_DISK_STORAGE */ | 648 | #endif /* HAVE_DISK_STORAGE */ |
1129 | 649 | ||
1130 | avgbat = avgbat * BATT_AVE_SAMPLES; | 650 | avgbat = avgbat * BATT_AVE_SAMPLES; |
1131 | battery_millivolts = avgbat / BATT_AVE_SAMPLES; | 651 | battery_millivolts = avgbat / BATT_AVE_SAMPLES; |
652 | power_history[0] = battery_millivolts; | ||
1132 | 653 | ||
1133 | #if CONFIG_CHARGING | 654 | #if CONFIG_CHARGING |
1134 | if(charger_inserted()) { | 655 | if (charger_inserted()) { |
1135 | battery_percent = voltage_to_percent(battery_millivolts, | 656 | battery_percent = voltage_to_percent(battery_millivolts, |
1136 | percent_to_volt_charge); | 657 | percent_to_volt_charge); |
1137 | } else | 658 | } |
659 | else | ||
1138 | #endif | 660 | #endif |
1139 | { battery_percent = voltage_to_percent(battery_millivolts, | 661 | { |
1140 | percent_to_volt_discharge[battery_type]); | 662 | battery_percent = voltage_to_percent(battery_millivolts, |
1141 | battery_percent += (battery_percent < 100); | 663 | percent_to_volt_discharge[battery_type]); |
664 | battery_percent += battery_percent < 100; | ||
1142 | } | 665 | } |
1143 | 666 | ||
1144 | #if CONFIG_CHARGING == CHARGING_TARGET | 667 | #if CONFIG_CHARGING == CHARGING_TARGET |
1145 | powermgmt_init_target(); | 668 | powermgmt_init_target(); |
1146 | #endif | 669 | #endif |
1147 | 670 | ||
671 | next_power_hist = current_tick + HZ*60; | ||
672 | |||
1148 | while (1) | 673 | while (1) |
1149 | { | 674 | { |
675 | #if CONFIG_CHARGING >= CHARGING_MONITOR | ||
676 | unsigned int pwr = power_input_status(); | ||
677 | #ifdef HAVE_BATTERY_SWITCH | ||
678 | if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) { | ||
679 | sleep(HZ/10); | ||
680 | reset_battery_filter(battery_adc_voltage()); | ||
681 | } | ||
682 | #endif | ||
683 | power_thread_inputs = pwr; | ||
684 | |||
685 | if (!detect_charger(pwr)) | ||
686 | #endif /* CONFIG_CHARGING */ | ||
687 | { | ||
688 | /* Steady state */ | ||
689 | sleep(POWER_THREAD_STEP_TICKS); | ||
690 | |||
691 | /* Do common power tasks */ | ||
692 | power_thread_step(); | ||
693 | } | ||
694 | |||
695 | /* Perform target tasks */ | ||
696 | charging_algorithm_step(); | ||
697 | |||
698 | if (TIME_BEFORE(current_tick, next_power_hist)) | ||
699 | continue; | ||
700 | |||
701 | /* increment to ensure there is a record for every minute | ||
702 | * rather than go forward from the current tick */ | ||
703 | next_power_hist += HZ*60; | ||
704 | |||
1150 | /* rotate the power history */ | 705 | /* rotate the power history */ |
1151 | memmove(power_history + 1, power_history, | 706 | memmove(&power_history[1], &power_history[0], |
1152 | sizeof(power_history) - sizeof(power_history[0])); | 707 | sizeof(power_history) - sizeof(power_history[0])); |
1153 | 708 | ||
1154 | /* insert new value at the start, in millivolts 8-) */ | 709 | /* insert new value at the start, in millivolts 8-) */ |
1155 | power_history[0] = battery_millivolts; | 710 | power_history[0] = battery_millivolts; |
1156 | 711 | ||
1157 | charging_algorithm_big_step(); | ||
1158 | |||
1159 | handle_auto_poweroff(); | 712 | handle_auto_poweroff(); |
1160 | } | 713 | } |
1161 | } | 714 | } /* power_thread */ |
1162 | 715 | ||
1163 | void powermgmt_init(void) | 716 | void powermgmt_init(void) |
1164 | { | 717 | { |
1165 | /* init history to 0 */ | 718 | /* init history to 0 */ |
1166 | memset(power_history, 0x00, sizeof(power_history)); | 719 | memset(power_history, 0, sizeof(power_history)); |
1167 | create_thread(power_thread, power_stack, sizeof(power_stack), 0, | 720 | create_thread(power_thread, power_stack, sizeof(power_stack), 0, |
1168 | power_thread_name IF_PRIO(, PRIORITY_SYSTEM) | 721 | power_thread_name IF_PRIO(, PRIORITY_SYSTEM) |
1169 | IF_COP(, CPU)); | 722 | IF_COP(, CPU)); |
1170 | } | 723 | } |
1171 | 724 | ||
1172 | #endif /* SIMULATOR */ | 725 | /* Various hardware housekeeping tasks relating to shutting down the player */ |
1173 | |||
1174 | void sys_poweroff(void) | ||
1175 | { | ||
1176 | #ifndef BOOTLOADER | ||
1177 | logf("sys_poweroff()"); | ||
1178 | /* If the main thread fails to shut down the system, we will force a | ||
1179 | power off after an 20 second timeout - 28 seconds if recording */ | ||
1180 | if (shutdown_timeout == 0) | ||
1181 | { | ||
1182 | #if (defined(IAUDIO_X5) || defined(IAUDIO_M5)) && !defined (SIMULATOR) | ||
1183 | pcf50606_reset_timeout(); /* Reset timer on first attempt only */ | ||
1184 | #endif | ||
1185 | #if defined(HAVE_RECORDING) && !defined(BOOTLOADER) | ||
1186 | if (audio_status() & AUDIO_STATUS_RECORD) | ||
1187 | shutdown_timeout += HZ*8; | ||
1188 | #endif | ||
1189 | shutdown_timeout += HZ*20; | ||
1190 | } | ||
1191 | |||
1192 | queue_broadcast(SYS_POWEROFF, 0); | ||
1193 | #endif /* BOOTLOADER */ | ||
1194 | } | ||
1195 | |||
1196 | void cancel_shutdown(void) | ||
1197 | { | ||
1198 | logf("sys_cancel_shutdown()"); | ||
1199 | |||
1200 | #if (defined(IAUDIO_X5) || defined(IAUDIO_M5)) && !defined (SIMULATOR) | ||
1201 | /* TODO: Move some things to target/ tree */ | ||
1202 | if (shutdown_timeout) | ||
1203 | pcf50606_reset_timeout(); | ||
1204 | #endif | ||
1205 | |||
1206 | shutdown_timeout = 0; | ||
1207 | } | ||
1208 | |||
1209 | /* Various hardware housekeeping tasks relating to shutting down the jukebox */ | ||
1210 | void shutdown_hw(void) | 726 | void shutdown_hw(void) |
1211 | { | 727 | { |
1212 | #ifndef SIMULATOR | ||
1213 | charging_algorithm_close(); | 728 | charging_algorithm_close(); |
1214 | audio_stop(); | 729 | audio_stop(); |
730 | |||
1215 | if (battery_level_safe()) { /* do not save on critical battery */ | 731 | if (battery_level_safe()) { /* do not save on critical battery */ |
1216 | #ifdef HAVE_LCD_BITMAP | 732 | #ifdef HAVE_LCD_BITMAP |
1217 | glyph_cache_save(); | 733 | glyph_cache_save(); |
1218 | #endif | 734 | #endif |
1219 | if(storage_disk_is_active()) | 735 | if (storage_disk_is_active()) |
1220 | storage_spindown(1); | 736 | storage_spindown(1); |
1221 | } | 737 | } |
1222 | while(storage_disk_is_active()) | 738 | |
739 | while (storage_disk_is_active()) | ||
1223 | sleep(HZ/10); | 740 | sleep(HZ/10); |
1224 | 741 | ||
1225 | #if CONFIG_CODEC != SWCODEC | 742 | #if CONFIG_CODEC == SWCODEC |
1226 | mp3_shutdown(); | ||
1227 | #else | ||
1228 | audiohw_close(); | 743 | audiohw_close(); |
744 | #else | ||
745 | mp3_shutdown(); | ||
1229 | #endif | 746 | #endif |
1230 | 747 | ||
1231 | /* If HD is still active we try to wait for spindown, otherwise the | 748 | /* If HD is still active we try to wait for spindown, otherwise the |
1232 | shutdown_timeout in power_thread_sleep will force a power off */ | 749 | shutdown_timeout in power_thread_step will force a power off */ |
1233 | while(storage_disk_is_active()) | 750 | while (storage_disk_is_active()) |
1234 | sleep(HZ/10); | 751 | sleep(HZ/10); |
752 | |||
1235 | #ifndef HAVE_LCD_COLOR | 753 | #ifndef HAVE_LCD_COLOR |
1236 | lcd_set_contrast(0); | 754 | lcd_set_contrast(0); |
1237 | #endif | 755 | #endif |
1238 | #ifdef HAVE_REMOTE_LCD | 756 | #ifdef HAVE_REMOTE_LCD |
1239 | lcd_remote_set_contrast(0); | 757 | lcd_remote_set_contrast(0); |
1240 | #endif | 758 | #endif |
1241 | |||
1242 | #ifdef HAVE_LCD_SHUTDOWN | 759 | #ifdef HAVE_LCD_SHUTDOWN |
1243 | lcd_shutdown(); | 760 | lcd_shutdown(); |
1244 | #endif | 761 | #endif |
@@ -1248,23 +765,58 @@ void shutdown_hw(void) | |||
1248 | byte. */ | 765 | byte. */ |
1249 | sleep(HZ/4); | 766 | sleep(HZ/4); |
1250 | power_off(); | 767 | power_off(); |
1251 | #endif /* #ifndef SIMULATOR */ | ||
1252 | } | 768 | } |
1253 | 769 | ||
770 | void sys_poweroff(void) | ||
771 | { | ||
772 | #ifndef BOOTLOADER | ||
773 | logf("sys_poweroff()"); | ||
774 | /* If the main thread fails to shut down the system, we will force a | ||
775 | power off after an 20 second timeout - 28 seconds if recording */ | ||
776 | if (shutdown_timeout == 0) { | ||
777 | #if defined(IAUDIO_X5) || defined(IAUDIO_M5) | ||
778 | pcf50606_reset_timeout(); /* Reset timer on first attempt only */ | ||
779 | #endif | ||
780 | #ifdef HAVE_RECORDING | ||
781 | if (audio_status() & AUDIO_STATUS_RECORD) | ||
782 | shutdown_timeout += HZ*8; | ||
783 | #endif | ||
784 | shutdown_timeout += HZ*20; | ||
785 | } | ||
786 | |||
787 | queue_broadcast(SYS_POWEROFF, 0); | ||
788 | #endif /* BOOTLOADER */ | ||
789 | } | ||
790 | |||
791 | void cancel_shutdown(void) | ||
792 | { | ||
793 | logf("cancel_shutdown()"); | ||
794 | |||
795 | #if defined(IAUDIO_X5) || defined(IAUDIO_M5) | ||
796 | /* TODO: Move some things to target/ tree */ | ||
797 | if (shutdown_timeout) | ||
798 | pcf50606_reset_timeout(); | ||
799 | #endif | ||
800 | |||
801 | shutdown_timeout = 0; | ||
802 | } | ||
803 | #endif /* SIMULATOR */ | ||
804 | |||
1254 | /* Send system battery level update events on reaching certain significant | 805 | /* Send system battery level update events on reaching certain significant |
1255 | levels. This must be called after battery_percent has been updated. */ | 806 | levels. This must be called after battery_percent has been updated. */ |
1256 | static void send_battery_level_event(void) | 807 | void send_battery_level_event(void) |
1257 | { | 808 | { |
1258 | static const int levels[] = { 5, 15, 30, 50, 0 }; | 809 | static const int levels[] = { 5, 15, 30, 50, 0 }; |
1259 | const int *level = levels; | 810 | const int *level = levels; |
811 | |||
1260 | while (*level) | 812 | while (*level) |
1261 | { | 813 | { |
1262 | if (battery_percent <= *level && last_sent_battery_level > *level) | 814 | if (battery_percent <= *level && last_sent_battery_level > *level) { |
1263 | { | ||
1264 | last_sent_battery_level = *level; | 815 | last_sent_battery_level = *level; |
1265 | queue_broadcast(SYS_BATTERY_UPDATE, last_sent_battery_level); | 816 | queue_broadcast(SYS_BATTERY_UPDATE, last_sent_battery_level); |
1266 | break; | 817 | break; |
1267 | } | 818 | } |
819 | |||
1268 | level++; | 820 | level++; |
1269 | } | 821 | } |
1270 | } | 822 | } |
diff --git a/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c b/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c index fa9c7b045f..b4a6c61fbb 100644 --- a/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c | |||
@@ -168,7 +168,7 @@ int battery_adc_temp(void) | |||
168 | /* All code has a preference for the main charger being connected over | 168 | /* All code has a preference for the main charger being connected over |
169 | * USB. USB is considered in the algorithm only if it is the sole source. */ | 169 | * USB. USB is considered in the algorithm only if it is the sole source. */ |
170 | static uint32_t int_sense0 = 0; /* Interrupt Sense 0 bits */ | 170 | static uint32_t int_sense0 = 0; /* Interrupt Sense 0 bits */ |
171 | static unsigned int power_status = POWER_INPUT_NONE; /* Detect input changes */ | 171 | static unsigned int last_inputs = POWER_INPUT_NONE; /* Detect input changes */ |
172 | static int charger_total_timer = 0; /* Total allowed charging time */ | 172 | static int charger_total_timer = 0; /* Total allowed charging time */ |
173 | static int icharger_ave = 0; /* Filtered charging current */ | 173 | static int icharger_ave = 0; /* Filtered charging current */ |
174 | static bool charger_close = false; /* Shutdown notification */ | 174 | static bool charger_close = false; /* Shutdown notification */ |
@@ -181,7 +181,7 @@ static int autorecharge_counter = 0 ; /* Battery < threshold debounce */ | |||
181 | static int chgcurr_timer = 0; /* Countdown to CHGCURR error */ | 181 | static int chgcurr_timer = 0; /* Countdown to CHGCURR error */ |
182 | #define AUTORECHARGE_COUNTDOWN (10*2) /* 10s debounce */ | 182 | #define AUTORECHARGE_COUNTDOWN (10*2) /* 10s debounce */ |
183 | #define WATCHDOG_TIMEOUT (10*2) /* If not serviced, poweroff in 10s */ | 183 | #define WATCHDOG_TIMEOUT (10*2) /* If not serviced, poweroff in 10s */ |
184 | #define CHGCURR_TIMEOUT (2*2) /* 2s debounce */ | 184 | #define CHGCURR_TIMEOUT (4*2) /* 4s debounce */ |
185 | 185 | ||
186 | /* Temperature monitoring */ | 186 | /* Temperature monitoring */ |
187 | static enum | 187 | static enum |
@@ -217,7 +217,7 @@ static bool charger_current_filter_step(void) | |||
217 | /* Return true if the main charger is connected. */ | 217 | /* Return true if the main charger is connected. */ |
218 | static bool main_charger_connected(void) | 218 | static bool main_charger_connected(void) |
219 | { | 219 | { |
220 | return (power_status & | 220 | return (last_inputs & |
221 | POWER_INPUT_MAIN_CHARGER & | 221 | POWER_INPUT_MAIN_CHARGER & |
222 | POWER_INPUT_CHARGER) != 0; | 222 | POWER_INPUT_CHARGER) != 0; |
223 | } | 223 | } |
@@ -233,16 +233,14 @@ static unsigned int auto_recharge_voltage(void) | |||
233 | return BATT_USB_VAUTO_RECHARGE; | 233 | return BATT_USB_VAUTO_RECHARGE; |
234 | } | 234 | } |
235 | 235 | ||
236 | #ifndef NO_LOW_BATTERY_SHUTDOWN | ||
237 | /* Return greater of supply (BP) or filtered battery voltage. */ | 236 | /* Return greater of supply (BP) or filtered battery voltage. */ |
238 | static unsigned int input_millivolts(void) | 237 | unsigned int input_millivolts(void) |
239 | { | 238 | { |
240 | unsigned int app_millivolts = application_supply_adc_voltage(); | 239 | unsigned int app_millivolts = application_supply_adc_voltage(); |
241 | unsigned int bat_millivolts = battery_voltage(); | 240 | unsigned int bat_millivolts = battery_voltage(); |
242 | 241 | ||
243 | return MAX(app_millivolts, bat_millivolts); | 242 | return MAX(app_millivolts, bat_millivolts); |
244 | } | 243 | } |
245 | #endif | ||
246 | 244 | ||
247 | /* Get smoothed readings for initializing filtered data. */ | 245 | /* Get smoothed readings for initializing filtered data. */ |
248 | static int stat_battery_reading(int type) | 246 | static int stat_battery_reading(int type) |
@@ -292,7 +290,7 @@ static bool update_filtered_battery_voltage(void) | |||
292 | 290 | ||
293 | if (millivolts != INT_MIN) | 291 | if (millivolts != INT_MIN) |
294 | { | 292 | { |
295 | set_filtered_battery_voltage(millivolts); | 293 | reset_battery_filter(millivolts); |
296 | return true; | 294 | return true; |
297 | } | 295 | } |
298 | 296 | ||
@@ -357,13 +355,13 @@ static bool adjust_charger_current(void) | |||
357 | int usb_select; | 355 | int usb_select; |
358 | uint32_t i; | 356 | uint32_t i; |
359 | 357 | ||
360 | usb_select = ((power_status & POWER_INPUT) == POWER_INPUT_USB) | 358 | usb_select = ((last_inputs & POWER_INPUT) == POWER_INPUT_USB) |
361 | ? 1 : 0; | 359 | ? 1 : 0; |
362 | 360 | ||
363 | if (charge_state == DISCHARGING && usb_select == 1) | 361 | if (charge_state == DISCHARGING && usb_select == 1) |
364 | { | 362 | { |
365 | /* USB-only, DISCHARGING, = maintaining battery */ | 363 | /* USB-only, DISCHARGING, = maintaining battery */ |
366 | int select = (power_status & POWER_INPUT_CHARGER) ? 0 : 1; | 364 | int select = (last_inputs & POWER_INPUT_CHARGER) ? 0 : 1; |
367 | charger_setting = charger_bits[CHARGING+1][select]; | 365 | charger_setting = charger_bits[CHARGING+1][select]; |
368 | } | 366 | } |
369 | else | 367 | else |
@@ -458,7 +456,7 @@ static bool charging_ok(void) | |||
458 | if (ok) | 456 | if (ok) |
459 | { | 457 | { |
460 | /* Is the battery even connected? */ | 458 | /* Is the battery even connected? */ |
461 | ok = (power_status & POWER_INPUT_BATTERY) != 0; | 459 | ok = (last_inputs & POWER_INPUT_BATTERY) != 0; |
462 | } | 460 | } |
463 | 461 | ||
464 | if (ok) | 462 | if (ok) |
@@ -591,20 +589,6 @@ void powermgmt_init_target(void) | |||
591 | #endif | 589 | #endif |
592 | } | 590 | } |
593 | 591 | ||
594 | /* Returns CHARGING or DISCHARGING since that's all we really do. */ | ||
595 | int powermgmt_filter_charge_state(void) | ||
596 | { | ||
597 | switch(charge_state) | ||
598 | { | ||
599 | case TRICKLE: | ||
600 | case TOPOFF: | ||
601 | case CHARGING: | ||
602 | return CHARGING; | ||
603 | default: | ||
604 | return DISCHARGING; | ||
605 | } | ||
606 | } | ||
607 | |||
608 | /* Returns true if the unit is charging the batteries. */ | 592 | /* Returns true if the unit is charging the batteries. */ |
609 | bool charging_state(void) | 593 | bool charging_state(void) |
610 | { | 594 | { |
@@ -625,24 +609,6 @@ int battery_charge_current(void) | |||
625 | return icharger_ave / ICHARGER_AVE_SAMPLES; | 609 | return icharger_ave / ICHARGER_AVE_SAMPLES; |
626 | } | 610 | } |
627 | 611 | ||
628 | bool query_force_shutdown(void) | ||
629 | { | ||
630 | #ifndef NO_LOW_BATTERY_SHUTDOWN | ||
631 | return input_millivolts() < battery_level_shutoff[0]; | ||
632 | #else | ||
633 | return false; | ||
634 | #endif | ||
635 | } | ||
636 | |||
637 | bool battery_level_safe(void) | ||
638 | { | ||
639 | #ifndef NO_LOW_BATTERY_SHUTDOWN | ||
640 | return input_millivolts() > battery_level_dangerous[0]; | ||
641 | #else | ||
642 | return true; | ||
643 | #endif | ||
644 | } | ||
645 | |||
646 | static void charger_plugged(void) | 612 | static void charger_plugged(void) |
647 | { | 613 | { |
648 | adc_enable_channel(ADC_BATTERY_TEMP, true); | 614 | adc_enable_channel(ADC_BATTERY_TEMP, true); |
@@ -662,7 +628,7 @@ static void charger_unplugged(void) | |||
662 | } | 628 | } |
663 | 629 | ||
664 | /* Might need to reevaluate these bits in charger_none. */ | 630 | /* Might need to reevaluate these bits in charger_none. */ |
665 | power_status &= ~(POWER_INPUT | POWER_INPUT_CHARGER); | 631 | last_inputs &= ~(POWER_INPUT | POWER_INPUT_CHARGER); |
666 | temp_state = TEMP_STATE_NORMAL; | 632 | temp_state = TEMP_STATE_NORMAL; |
667 | autorecharge_counter = 0; | 633 | autorecharge_counter = 0; |
668 | chgcurr_timer = 0; | 634 | chgcurr_timer = 0; |
@@ -672,15 +638,11 @@ static void charger_unplugged(void) | |||
672 | 638 | ||
673 | static void charger_none(void) | 639 | static void charger_none(void) |
674 | { | 640 | { |
675 | unsigned int pwr = power_input_status(); | 641 | unsigned int pwr = power_thread_inputs; |
676 | 642 | ||
677 | if (power_status != pwr) | 643 | if (last_inputs != pwr) |
678 | { | 644 | { |
679 | /* If battery switch state changed, reset filter. */ | 645 | last_inputs = pwr; |
680 | if ((power_status ^ pwr) & POWER_INPUT_BATTERY) | ||
681 | update_filtered_battery_voltage(); | ||
682 | |||
683 | power_status = pwr; | ||
684 | 646 | ||
685 | if (charge_state == CHARGE_STATE_DISABLED) | 647 | if (charge_state == CHARGE_STATE_DISABLED) |
686 | return; | 648 | return; |
@@ -696,7 +658,7 @@ static void charger_none(void) | |||
696 | else | 658 | else |
697 | { | 659 | { |
698 | charger_unplugged(); | 660 | charger_unplugged(); |
699 | power_status = pwr; /* Restore status */ | 661 | last_inputs = pwr; /* Restore status */ |
700 | } | 662 | } |
701 | } | 663 | } |
702 | else if (charger_setting != 0) | 664 | else if (charger_setting != 0) |
@@ -716,17 +678,13 @@ static void charger_none(void) | |||
716 | 678 | ||
717 | static void charger_control(void) | 679 | static void charger_control(void) |
718 | { | 680 | { |
719 | unsigned int pwr = power_input_status(); | 681 | unsigned int pwr = power_thread_inputs; |
720 | 682 | ||
721 | if (power_status != pwr) | 683 | if (last_inputs != pwr) |
722 | { | 684 | { |
723 | unsigned int changed = power_status ^ pwr; | 685 | unsigned int changed = last_inputs ^ pwr; |
724 | 686 | ||
725 | power_status = pwr; | 687 | last_inputs = pwr; |
726 | |||
727 | /* If battery switch state changed, reset filter. */ | ||
728 | if (changed & POWER_INPUT_BATTERY) | ||
729 | update_filtered_battery_voltage(); | ||
730 | 688 | ||
731 | if (charger_setting != 0) | 689 | if (charger_setting != 0) |
732 | charger_setting = CHARGER_ADJUST; | 690 | charger_setting = CHARGER_ADJUST; |
@@ -771,12 +729,11 @@ static void charger_control(void) | |||
771 | { | 729 | { |
772 | /* Battery voltage may have dropped and a charge cycle should | 730 | /* Battery voltage may have dropped and a charge cycle should |
773 | * start again. Debounced. */ | 731 | * start again. Debounced. */ |
774 | if (autorecharge_counter < 0) | 732 | if (autorecharge_counter < 0 && |
733 | battery_adc_voltage() < BATT_FULL_VOLTAGE) | ||
775 | { | 734 | { |
776 | /* Try starting a cycle now regardless of battery level to | 735 | /* Try starting a cycle now if battery isn't already topped |
777 | * allow user to ensure the battery is topped off. It | 736 | * off to allow user to ensure the battery is full. */ |
778 | * will soon turn off if already full. */ | ||
779 | autorecharge_counter = 0; | ||
780 | } | 737 | } |
781 | else if (battery_voltage() > auto_recharge_voltage()) | 738 | else if (battery_voltage() > auto_recharge_voltage()) |
782 | { | 739 | { |
@@ -791,6 +748,8 @@ static void charger_control(void) | |||
791 | break; | 748 | break; |
792 | } | 749 | } |
793 | 750 | ||
751 | autorecharge_counter = 0; | ||
752 | |||
794 | charging_set_thread_priority(true); | 753 | charging_set_thread_priority(true); |
795 | 754 | ||
796 | if (stat_battery_reading(ADC_BATTERY) < BATT_VTRICKLE_CHARGE) | 755 | if (stat_battery_reading(ADC_BATTERY) < BATT_VTRICKLE_CHARGE) |
@@ -858,10 +817,12 @@ static void charger_control(void) | |||
858 | } | 817 | } |
859 | 818 | ||
860 | /* Main charging algorithm - called from powermgmt.c */ | 819 | /* Main charging algorithm - called from powermgmt.c */ |
861 | void charging_algorithm_small_step(void) | 820 | void charging_algorithm_step(void) |
862 | { | 821 | { |
822 | #ifdef IMX31_ALLOW_CHARGING | ||
863 | if (service_wdt) | 823 | if (service_wdt) |
864 | watchdog_service(); | 824 | watchdog_service(); |
825 | #endif | ||
865 | 826 | ||
866 | /* Switch by input state */ | 827 | /* Switch by input state */ |
867 | switch (charger_input_state) | 828 | switch (charger_input_state) |
@@ -909,12 +870,6 @@ void charging_algorithm_small_step(void) | |||
909 | } | 870 | } |
910 | } | 871 | } |
911 | 872 | ||
912 | void charging_algorithm_big_step(void) | ||
913 | { | ||
914 | /* Sleep for one minute */ | ||
915 | power_thread_sleep(HZ*60); | ||
916 | } | ||
917 | |||
918 | /* Disable the charger and prepare for poweroff - called off-thread so we | 873 | /* Disable the charger and prepare for poweroff - called off-thread so we |
919 | * signal the charging thread to prepare to quit. */ | 874 | * signal the charging thread to prepare to quit. */ |
920 | void charging_algorithm_close(void) | 875 | void charging_algorithm_close(void) |
diff --git a/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h b/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h index 8ad4af8d18..1b55a4ed24 100644 --- a/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h | |||
@@ -53,6 +53,7 @@ | |||
53 | #define BATT_VTRICKLE_CHARGE 2900 /* Must charge slowly */ | 53 | #define BATT_VTRICKLE_CHARGE 2900 /* Must charge slowly */ |
54 | #define BATT_VSLOW_CHARGE 3500 /* Lower-current charge mode below | 54 | #define BATT_VSLOW_CHARGE 3500 /* Lower-current charge mode below |
55 | * this level */ | 55 | * this level */ |
56 | #define BATT_FULL_VOLTAGE 4161 /* Battery already topped */ | ||
56 | #define BATT_VAUTO_RECHARGE 4100 /* When to begin another cycle */ | 57 | #define BATT_VAUTO_RECHARGE 4100 /* When to begin another cycle */ |
57 | #define BATT_USB_VAUTO_RECHARGE 4000 /* When to cycle with USB only */ | 58 | #define BATT_USB_VAUTO_RECHARGE 4000 /* When to cycle with USB only */ |
58 | #define BATT_USB_VSTOP 4140 /* When to "stop" when USB only */ | 59 | #define BATT_USB_VSTOP 4140 /* When to "stop" when USB only */ |
@@ -92,23 +93,13 @@ | |||
92 | #define BATT_AVE_SAMPLES 32 | 93 | #define BATT_AVE_SAMPLES 32 |
93 | #define ICHARGER_AVE_SAMPLES 32 | 94 | #define ICHARGER_AVE_SAMPLES 32 |
94 | 95 | ||
96 | void powermgmt_init_target(void); | ||
97 | void charging_algorithm_step(void); | ||
98 | void charging_algorithm_close(void); | ||
99 | |||
95 | /* Provide filtered charge current */ | 100 | /* Provide filtered charge current */ |
96 | int battery_charge_current(void); | 101 | int battery_charge_current(void); |
97 | 102 | ||
98 | #ifndef SIMULATOR | 103 | #define CURRENT_MAX_CHG battery_charge_current() |
99 | /* Indicate various functions that require implementation at the target level. | ||
100 | * This is because the battery could be low or the battery switch is off but | ||
101 | * with the main charger attached which implies safe power for anything. The | ||
102 | * true battery reading is always reported for voltage readings and not the | ||
103 | * value at the application supply. */ | ||
104 | #define TARGET_QUERY_FORCE_SHUTDOWN | ||
105 | |||
106 | /* For this the application supply is read out if the charger is attached or | ||
107 | * the battery read if not (completely hardware selected at BP). */ | ||
108 | #define TARGET_BATTERY_LEVEL_SAFE | ||
109 | |||
110 | /* The state should be adjusted to CHARGING or DISCHARGING */ | ||
111 | #define TARGET_POWERMGMT_FILTER_CHARGE_STATE | ||
112 | #endif /* SIMULATOR */ | ||
113 | 104 | ||
114 | #endif /* POWERMGMT_TARGET_H */ | 105 | #endif /* POWERMGMT_TARGET_H */ |
diff --git a/firmware/target/arm/iriver/h10/power-h10.c b/firmware/target/arm/iriver/h10/power-h10.c index deca3258e2..1a1f6afbfb 100644 --- a/firmware/target/arm/iriver/h10/power-h10.c +++ b/firmware/target/arm/iriver/h10/power-h10.c | |||
@@ -33,10 +33,6 @@ | |||
33 | #include "logf.h" | 33 | #include "logf.h" |
34 | #include "usb.h" | 34 | #include "usb.h" |
35 | 35 | ||
36 | #if CONFIG_CHARGING == CHARGING_CONTROL | ||
37 | bool charger_enabled; | ||
38 | #endif | ||
39 | |||
40 | #if CONFIG_TUNER | 36 | #if CONFIG_TUNER |
41 | 37 | ||
42 | bool tuner_power(bool status) | 38 | bool tuner_power(bool status) |
diff --git a/firmware/target/arm/olympus/mrobe-100/power-mr100.c b/firmware/target/arm/olympus/mrobe-100/power-mr100.c index c3eb96b03c..46b99fbd46 100644 --- a/firmware/target/arm/olympus/mrobe-100/power-mr100.c +++ b/firmware/target/arm/olympus/mrobe-100/power-mr100.c | |||
@@ -29,10 +29,6 @@ | |||
29 | #include "logf.h" | 29 | #include "logf.h" |
30 | #include "usb.h" | 30 | #include "usb.h" |
31 | 31 | ||
32 | #if CONFIG_CHARGING == CHARGING_CONTROL | ||
33 | bool charger_enabled; | ||
34 | #endif | ||
35 | |||
36 | void power_init(void) | 32 | void power_init(void) |
37 | { | 33 | { |
38 | /* Enable power-off bit */ | 34 | /* Enable power-off bit */ |
diff --git a/firmware/target/arm/philips/hdd1630/power-hdd1630.c b/firmware/target/arm/philips/hdd1630/power-hdd1630.c index 03a5794791..4e7172ef6f 100755 --- a/firmware/target/arm/philips/hdd1630/power-hdd1630.c +++ b/firmware/target/arm/philips/hdd1630/power-hdd1630.c | |||
@@ -29,10 +29,6 @@ | |||
29 | #include "logf.h" | 29 | #include "logf.h" |
30 | #include "usb.h" | 30 | #include "usb.h" |
31 | 31 | ||
32 | #if CONFIG_CHARGING == CHARGING_CONTROL | ||
33 | bool charger_enabled; | ||
34 | #endif | ||
35 | |||
36 | void power_init(void) | 32 | void power_init(void) |
37 | { | 33 | { |
38 | /* power off bit */ | 34 | /* power off bit */ |
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/powermgmt-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/powermgmt-meg-fx.c index 6522e6534b..49f7e2e049 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/powermgmt-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/powermgmt-meg-fx.c | |||
@@ -19,9 +19,10 @@ | |||
19 | * KIND, either express or implied. | 19 | * KIND, either express or implied. |
20 | * | 20 | * |
21 | ****************************************************************************/ | 21 | ****************************************************************************/ |
22 | |||
23 | #include "config.h" | 22 | #include "config.h" |
23 | #include "system.h" | ||
24 | #include "adc.h" | 24 | #include "adc.h" |
25 | #include "power.h" | ||
25 | #include "powermgmt.h" | 26 | #include "powermgmt.h" |
26 | 27 | ||
27 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | 28 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = |
@@ -58,3 +59,17 @@ unsigned int battery_adc_voltage(void) | |||
58 | return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10; | 59 | return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10; |
59 | } | 60 | } |
60 | 61 | ||
62 | unsigned int input_millivolts(void) | ||
63 | { | ||
64 | |||
65 | unsigned int batt_millivolts = battery_voltage(); | ||
66 | |||
67 | if ((power_thread_inputs & POWER_INPUT_BATTERY) == 0) { | ||
68 | /* Just return a safe value if battery isn't connected */ | ||
69 | return 4050; | ||
70 | } | ||
71 | |||
72 | return batt_millivolts; | ||
73 | } | ||
74 | |||
75 | |||
diff --git a/firmware/target/arm/tatung/tpj1022/power-tpj1022.c b/firmware/target/arm/tatung/tpj1022/power-tpj1022.c index abf5790702..fe5460d609 100644 --- a/firmware/target/arm/tatung/tpj1022/power-tpj1022.c +++ b/firmware/target/arm/tatung/tpj1022/power-tpj1022.c | |||
@@ -33,10 +33,6 @@ | |||
33 | #include "logf.h" | 33 | #include "logf.h" |
34 | #include "usb.h" | 34 | #include "usb.h" |
35 | 35 | ||
36 | #if CONFIG_CHARGING == CHARGING_CONTROL | ||
37 | bool charger_enabled; | ||
38 | #endif | ||
39 | |||
40 | void power_init(void) | 36 | void power_init(void) |
41 | { | 37 | { |
42 | } | 38 | } |
diff --git a/firmware/target/sh/archos/recorder/power-recorder.c b/firmware/target/sh/archos/recorder/power-recorder.c index d90c029890..8d7ea5fc51 100644 --- a/firmware/target/sh/archos/recorder/power-recorder.c +++ b/firmware/target/sh/archos/recorder/power-recorder.c | |||
@@ -25,9 +25,10 @@ | |||
25 | #include "kernel.h" | 25 | #include "kernel.h" |
26 | #include "system.h" | 26 | #include "system.h" |
27 | #include "power.h" | 27 | #include "power.h" |
28 | #include "powermgmt-target.h" | ||
28 | #include "usb.h" | 29 | #include "usb.h" |
29 | 30 | ||
30 | bool charger_enabled; | 31 | static bool charger_on; |
31 | 32 | ||
32 | void power_init(void) | 33 | void power_init(void) |
33 | { | 34 | { |
@@ -48,13 +49,18 @@ void charger_enable(bool on) | |||
48 | if(on) | 49 | if(on) |
49 | { | 50 | { |
50 | and_b(~0x20, &PBDRL); | 51 | and_b(~0x20, &PBDRL); |
51 | charger_enabled = 1; | ||
52 | } | 52 | } |
53 | else | 53 | else |
54 | { | 54 | { |
55 | or_b(0x20, &PBDRL); | 55 | or_b(0x20, &PBDRL); |
56 | charger_enabled = 0; | ||
57 | } | 56 | } |
57 | |||
58 | charger_on = on; | ||
59 | } | ||
60 | |||
61 | bool charger_enabled(void) | ||
62 | { | ||
63 | return charger_on; | ||
58 | } | 64 | } |
59 | 65 | ||
60 | void ide_power_enable(bool on) | 66 | void ide_power_enable(bool on) |
diff --git a/firmware/target/sh/archos/recorder/powermgmt-recorder.c b/firmware/target/sh/archos/recorder/powermgmt-recorder.c index 6de5cc8037..7b1842016c 100644 --- a/firmware/target/sh/archos/recorder/powermgmt-recorder.c +++ b/firmware/target/sh/archos/recorder/powermgmt-recorder.c | |||
@@ -19,9 +19,13 @@ | |||
19 | * KIND, either express or implied. | 19 | * KIND, either express or implied. |
20 | * | 20 | * |
21 | ****************************************************************************/ | 21 | ****************************************************************************/ |
22 | |||
23 | #include "config.h" | 22 | #include "config.h" |
23 | #include "system.h" | ||
24 | #include <sprintf.h> | ||
25 | #include "debug.h" | ||
26 | #include "storage.h" | ||
24 | #include "adc.h" | 27 | #include "adc.h" |
28 | #include "power.h" | ||
25 | #include "powermgmt.h" | 29 | #include "powermgmt.h" |
26 | 30 | ||
27 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = | 31 | const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = |
@@ -60,3 +64,434 @@ unsigned int battery_adc_voltage(void) | |||
60 | { | 64 | { |
61 | return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10; | 65 | return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10; |
62 | } | 66 | } |
67 | |||
68 | /** Charger control **/ | ||
69 | #ifdef CHARGING_DEBUG_FILE | ||
70 | #include "file.h" | ||
71 | #define DEBUG_FILE_NAME "/powermgmt.csv" | ||
72 | #define DEBUG_MESSAGE_LEN 133 | ||
73 | static char debug_message[DEBUG_MESSAGE_LEN]; | ||
74 | static int fd = -1; /* write debug information to this file */ | ||
75 | static int wrcount = 0; | ||
76 | #endif /* CHARGING_DEBUG_FILE */ | ||
77 | |||
78 | /* | ||
79 | * For a complete description of the charging algorithm read | ||
80 | * docs/CHARGING_ALGORITHM. | ||
81 | */ | ||
82 | int long_delta; /* long term delta battery voltage */ | ||
83 | int short_delta; /* short term delta battery voltage */ | ||
84 | bool disk_activity_last_cycle = false; /* flag set to aid charger time | ||
85 | * calculation */ | ||
86 | char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in | ||
87 | debug menu */ | ||
88 | /* percentage at which charging | ||
89 | starts */ | ||
90 | int powermgmt_last_cycle_startstop_min = 0; /* how many minutes ago was the | ||
91 | charging started or | ||
92 | stopped? */ | ||
93 | int powermgmt_last_cycle_level = 0; /* which level had the | ||
94 | batteries at this time? */ | ||
95 | int trickle_sec = 0; /* how many seconds should the | ||
96 | charger be enabled per | ||
97 | minute for trickle | ||
98 | charging? */ | ||
99 | int pid_p = 0; /* PID proportional term */ | ||
100 | int pid_i = 0; /* PID integral term */ | ||
101 | |||
102 | static unsigned int target_voltage = TRICKLE_VOLTAGE; /* desired topoff/trickle | ||
103 | * voltage level */ | ||
104 | static int charge_max_time_idle = 0; /* max. charging duration, calculated at | ||
105 | * beginning of charging */ | ||
106 | static int charge_max_time_now = 0; /* max. charging duration including | ||
107 | * hdd activity */ | ||
108 | static int minutes_disk_activity = 0; /* count minutes of hdd use during | ||
109 | * charging */ | ||
110 | static int last_disk_activity = CHARGE_END_LONGD + 1; /* last hdd use x mins ago */ | ||
111 | |||
112 | #ifdef CHARGING_DEBUG_FILE | ||
113 | static void debug_file_close(void) | ||
114 | { | ||
115 | if (fd >= 0) { | ||
116 | close(fd); | ||
117 | fd = -1; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | static void debug_file_log(void) | ||
122 | { | ||
123 | if (usb_inserted()) { | ||
124 | /* It is probably too late to close the file but we can try... */ | ||
125 | debug_file_close(); | ||
126 | } | ||
127 | else if (fd < 0) { | ||
128 | fd = open(DEBUG_FILE_NAME, O_WRONLY | O_APPEND | O_CREAT); | ||
129 | |||
130 | if (fd >= 0) { | ||
131 | snprintf(debug_message, DEBUG_MESSAGE_LEN, | ||
132 | "cycle_min, bat_millivolts, bat_percent, chgr_state" | ||
133 | " ,charge_state, pid_p, pid_i, trickle_sec\n"); | ||
134 | write(fd, debug_message, strlen(debug_message)); | ||
135 | wrcount = 99; /* force a flush */ | ||
136 | } | ||
137 | } | ||
138 | else { | ||
139 | snprintf(debug_message, DEBUG_MESSAGE_LEN, | ||
140 | "%d, %d, %d, %d, %d, %d, %d, %d\n", | ||
141 | powermgmt_last_cycle_startstop_min, battery_voltage(), | ||
142 | battery_level(), charger_input_state, charge_state, | ||
143 | pid_p, pid_i, trickle_sec); | ||
144 | write(fd, debug_message, strlen(debug_message)); | ||
145 | wrcount++; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void debug_file_sync(void) | ||
150 | { | ||
151 | /* | ||
152 | * If we have a lot of pending writes or if the disk is spining, | ||
153 | * fsync the debug log file. | ||
154 | */ | ||
155 | if (wrcount > 10 || (wrcount > 0 && storage_disk_is_active())) { | ||
156 | if (fd >= 0) | ||
157 | fsync(fd); | ||
158 | |||
159 | wrcount = 0; | ||
160 | } | ||
161 | } | ||
162 | #else /* !CHARGING_DEBUG_FILE */ | ||
163 | #define debug_file_close() | ||
164 | #define debug_file_log() | ||
165 | #define debug_file_sync() | ||
166 | #endif /* CHARGING_DEBUG_FILE */ | ||
167 | |||
168 | /* | ||
169 | * Do tasks that should be done every step. | ||
170 | */ | ||
171 | static void do_frequent_tasks(void) | ||
172 | { | ||
173 | if (storage_disk_is_active()) { | ||
174 | /* flag hdd use for charging calculation */ | ||
175 | disk_activity_last_cycle = true; | ||
176 | } | ||
177 | |||
178 | debug_file_sync(); | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * The charger was just plugged in. If the battery level is | ||
183 | * nearly charged, just trickle. If the battery is low, start | ||
184 | * a full charge cycle. If the battery level is in between, | ||
185 | * top-off and then trickle. | ||
186 | */ | ||
187 | static void charger_plugged(void) | ||
188 | { | ||
189 | int battery_percent = battery_level(); | ||
190 | |||
191 | pid_p = 0; | ||
192 | pid_i = 0; | ||
193 | powermgmt_last_cycle_level = battery_percent; | ||
194 | powermgmt_last_cycle_startstop_min = 0; | ||
195 | |||
196 | snprintf(power_message, POWER_MESSAGE_LEN, "Charger plugged in"); | ||
197 | |||
198 | if (battery_percent > START_TOPOFF_CHG) { | ||
199 | |||
200 | if (battery_percent >= START_TRICKLE_CHG) { | ||
201 | charge_state = TRICKLE; | ||
202 | target_voltage = TRICKLE_VOLTAGE; | ||
203 | } | ||
204 | else { | ||
205 | charge_state = TOPOFF; | ||
206 | target_voltage = TOPOFF_VOLTAGE; | ||
207 | } | ||
208 | } | ||
209 | else { | ||
210 | /* | ||
211 | * Start the charger full strength | ||
212 | */ | ||
213 | int i = CHARGE_MAX_MIN_1500 * get_battery_capacity() / 1500; | ||
214 | charge_max_time_idle = i * (100 + 35 - battery_percent) / 100; | ||
215 | |||
216 | if (charge_max_time_idle > i) | ||
217 | charge_max_time_idle = i; | ||
218 | |||
219 | charge_max_time_now = charge_max_time_idle; | ||
220 | |||
221 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
222 | "ChgAt %d%% max %dm", battery_percent, | ||
223 | charge_max_time_now); | ||
224 | |||
225 | /* | ||
226 | * Enable the charger after the max time calc is done, | ||
227 | * because battery_level depends on if the charger is | ||
228 | * on. | ||
229 | */ | ||
230 | DEBUGF("power: charger inserted and battery" | ||
231 | " not full, charging\n"); | ||
232 | trickle_sec = 60; | ||
233 | long_delta = short_delta = 999999; | ||
234 | charge_state = CHARGING; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * The charger was just unplugged. | ||
240 | */ | ||
241 | static void charger_unplugged(void) | ||
242 | { | ||
243 | DEBUGF("power: charger disconnected, disabling\n"); | ||
244 | |||
245 | charger_enable(false); | ||
246 | powermgmt_last_cycle_level = battery_level(); | ||
247 | powermgmt_last_cycle_startstop_min = 0; | ||
248 | trickle_sec = 0; | ||
249 | pid_p = 0; | ||
250 | pid_i = 0; | ||
251 | charge_state = DISCHARGING; | ||
252 | snprintf(power_message, POWER_MESSAGE_LEN, "Charger: discharge"); | ||
253 | } | ||
254 | |||
255 | static void charging_step(void) | ||
256 | { | ||
257 | int i; | ||
258 | |||
259 | /* alter charge time max length with extra disk use */ | ||
260 | if (disk_activity_last_cycle) { | ||
261 | minutes_disk_activity++; | ||
262 | charge_max_time_now = charge_max_time_idle + | ||
263 | minutes_disk_activity*2 / 5; | ||
264 | disk_activity_last_cycle = false; | ||
265 | last_disk_activity = 0; | ||
266 | } | ||
267 | else { | ||
268 | last_disk_activity++; | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * Check the delta voltage over the last X minutes so we can do | ||
273 | * our end-of-charge logic based on the battery level change | ||
274 | * (no longer use minimum time as logic for charge end has 50 | ||
275 | * minutes minimum charge built in). | ||
276 | */ | ||
277 | if (powermgmt_last_cycle_startstop_min > CHARGE_END_SHORTD) { | ||
278 | short_delta = power_history[0] - | ||
279 | power_history[CHARGE_END_SHORTD - 1]; | ||
280 | } | ||
281 | |||
282 | if (powermgmt_last_cycle_startstop_min > CHARGE_END_LONGD) { | ||
283 | /* | ||
284 | * Scan the history: the points where measurement is taken need to | ||
285 | * be fairly static. Check prior to short delta 'area'. Also only | ||
286 | * check first and last 10 cycles (delta in middle OK). | ||
287 | */ | ||
288 | long_delta = power_history[0] - | ||
289 | power_history[CHARGE_END_LONGD - 1]; | ||
290 | |||
291 | for (i = CHARGE_END_SHORTD; i < CHARGE_END_SHORTD + 10; i++) | ||
292 | { | ||
293 | if ((power_history[i] - power_history[i+1]) > 50 || | ||
294 | (power_history[i] - power_history[i+1]) < -50) { | ||
295 | long_delta = 777777; | ||
296 | break; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | for (i = CHARGE_END_LONGD - 11; i < CHARGE_END_LONGD - 1 ; i++) | ||
301 | { | ||
302 | if ((power_history[i] - power_history[i+1]) > 50 || | ||
303 | (power_history[i] - power_history[i+1]) < -50) { | ||
304 | long_delta = 888888; | ||
305 | break; | ||
306 | } | ||
307 | } | ||
308 | } | ||
309 | |||
310 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
311 | "Chg %dm, max %dm", powermgmt_last_cycle_startstop_min, | ||
312 | charge_max_time_now); | ||
313 | |||
314 | /* | ||
315 | * End of charge criteria (any qualify): | ||
316 | * 1) Charged a long time | ||
317 | * 2) DeltaV went negative for a short time ( & long delta static) | ||
318 | * 3) DeltaV was negative over a longer period (no disk use only) | ||
319 | * | ||
320 | * Note: short_delta and long_delta are millivolts | ||
321 | */ | ||
322 | if (powermgmt_last_cycle_startstop_min >= charge_max_time_now || | ||
323 | (short_delta <= -50 && long_delta < 50) || | ||
324 | (long_delta < -20 && last_disk_activity > CHARGE_END_LONGD)) { | ||
325 | |||
326 | int battery_percent = battery_level(); | ||
327 | |||
328 | if (powermgmt_last_cycle_startstop_min > charge_max_time_now) { | ||
329 | DEBUGF("power: powermgmt_last_cycle_startstop_min > charge_max_time_now, " | ||
330 | "enough!\n"); | ||
331 | /* | ||
332 | * Have charged too long and deltaV detection did not | ||
333 | * work! | ||
334 | */ | ||
335 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
336 | "Chg tmout %d min", charge_max_time_now); | ||
337 | /* | ||
338 | * Switch to trickle charging. We skip the top-off | ||
339 | * since we've effectively done the top-off operation | ||
340 | * already since we charged for the maximum full | ||
341 | * charge time. | ||
342 | */ | ||
343 | powermgmt_last_cycle_level = battery_percent; | ||
344 | powermgmt_last_cycle_startstop_min = 0; | ||
345 | charge_state = TRICKLE; | ||
346 | |||
347 | /* | ||
348 | * Set trickle charge target to a relative voltage instead | ||
349 | * of an arbitrary value - the fully charged voltage may | ||
350 | * vary according to ambient temp, battery condition etc. | ||
351 | * Trickle target is -0.15v from full voltage acheived. | ||
352 | * Topup target is -0.05v from full voltage. | ||
353 | */ | ||
354 | target_voltage = power_history[0] - 150; | ||
355 | |||
356 | } | ||
357 | else { | ||
358 | if(short_delta <= -5) { | ||
359 | DEBUGF("power: short-term negative" | ||
360 | " delta, enough!\n"); | ||
361 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
362 | "end negd %d %dmin", short_delta, | ||
363 | powermgmt_last_cycle_startstop_min); | ||
364 | target_voltage = power_history[CHARGE_END_SHORTD - 1] - 50; | ||
365 | } | ||
366 | else { | ||
367 | DEBUGF("power: long-term small " | ||
368 | "positive delta, enough!\n"); | ||
369 | snprintf(power_message, POWER_MESSAGE_LEN, | ||
370 | "end lowd %d %dmin", long_delta, | ||
371 | powermgmt_last_cycle_startstop_min); | ||
372 | target_voltage = power_history[CHARGE_END_LONGD - 1] - 50; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Switch to top-off charging. | ||
377 | */ | ||
378 | powermgmt_last_cycle_level = battery_percent; | ||
379 | powermgmt_last_cycle_startstop_min = 0; | ||
380 | charge_state = TOPOFF; | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | |||
385 | static void topoff_trickle_step(void) | ||
386 | { | ||
387 | unsigned int millivolts; | ||
388 | |||
389 | /* | ||
390 | *Time to switch from topoff to trickle? | ||
391 | */ | ||
392 | if (charge_state == TOPOFF && | ||
393 | powermgmt_last_cycle_startstop_min > TOPOFF_MAX_MIN) { | ||
394 | |||
395 | powermgmt_last_cycle_level = battery_level(); | ||
396 | powermgmt_last_cycle_startstop_min = 0; | ||
397 | charge_state = TRICKLE; | ||
398 | target_voltage = target_voltage - 100; | ||
399 | } | ||
400 | /* | ||
401 | * Adjust trickle charge time (proportional and integral terms). | ||
402 | * Note: I considered setting the level higher if the USB is | ||
403 | * plugged in, but it doesn't appear to be necessary and will | ||
404 | * generate more heat [gvb]. | ||
405 | */ | ||
406 | millivolts = battery_voltage(); | ||
407 | |||
408 | pid_p = ((signed)target_voltage - (signed)millivolts) / 5; | ||
409 | if (pid_p <= PID_DEADZONE && pid_p >= -PID_DEADZONE) | ||
410 | pid_p = 0; | ||
411 | |||
412 | if ((unsigned)millivolts < target_voltage) { | ||
413 | if (pid_i < 60) | ||
414 | pid_i++; /* limit so it doesn't "wind up" */ | ||
415 | } | ||
416 | else { | ||
417 | if (pid_i > 0) | ||
418 | pid_i--; /* limit so it doesn't "wind up" */ | ||
419 | } | ||
420 | |||
421 | trickle_sec = pid_p + pid_i; | ||
422 | |||
423 | if (trickle_sec > 60) | ||
424 | trickle_sec = 60; | ||
425 | |||
426 | if (trickle_sec < 0) | ||
427 | trickle_sec = 0; | ||
428 | } | ||
429 | |||
430 | void charging_algorithm_step(void) | ||
431 | { | ||
432 | static int pwm_counter = 0; /* PWM total cycle in steps */ | ||
433 | static int pwm_duty = 0; /* PWM duty cycle in steps */ | ||
434 | |||
435 | switch (charger_input_state) | ||
436 | { | ||
437 | case CHARGER_PLUGGED: | ||
438 | charger_plugged(); | ||
439 | break; | ||
440 | |||
441 | case CHARGER_UNPLUGGED: | ||
442 | charger_unplugged(); | ||
443 | break; | ||
444 | |||
445 | case CHARGER: | ||
446 | case NO_CHARGER: | ||
447 | do_frequent_tasks(); | ||
448 | |||
449 | if (pwm_counter > 0) { | ||
450 | if (pwm_duty > 0 && --pwm_duty <= 0) | ||
451 | charger_enable(false); /* Duty cycle expired */ | ||
452 | |||
453 | if (--pwm_counter > 0) | ||
454 | return; | ||
455 | |||
456 | /* PWM cycle is complete */ | ||
457 | powermgmt_last_cycle_startstop_min++; | ||
458 | debug_file_log(); | ||
459 | } | ||
460 | break; | ||
461 | } | ||
462 | |||
463 | switch (charge_state) | ||
464 | { | ||
465 | case CHARGING: | ||
466 | charging_step(); | ||
467 | break; | ||
468 | |||
469 | case TOPOFF: | ||
470 | case TRICKLE: | ||
471 | topoff_trickle_step(); | ||
472 | break; | ||
473 | |||
474 | case DISCHARGING: | ||
475 | default: | ||
476 | break; | ||
477 | } | ||
478 | |||
479 | /* If 100%, ensure pwm_on never expires and briefly disables the | ||
480 | * charger. */ | ||
481 | pwm_duty = (trickle_sec < 60) ? trickle_sec*2 : 0; | ||
482 | pwm_counter = 60*2; | ||
483 | charger_enable(trickle_sec > 0); | ||
484 | } | ||
485 | |||
486 | #ifdef CHARGING_DEBUG_FILE | ||
487 | void charging_algorithm_close(void) | ||
488 | { | ||
489 | debug_file_close(); | ||
490 | } | ||
491 | #endif /* CHARGING_DEBUG_FILE */ | ||
492 | |||
493 | /* Returns true if the unit is charging the batteries. */ | ||
494 | bool charging_state(void) | ||
495 | { | ||
496 | return charge_state == CHARGING; | ||
497 | } | ||
diff --git a/firmware/target/sh/archos/recorder/powermgmt-target.h b/firmware/target/sh/archos/recorder/powermgmt-target.h new file mode 100644 index 0000000000..8fa2521f09 --- /dev/null +++ b/firmware/target/sh/archos/recorder/powermgmt-target.h | |||
@@ -0,0 +1,101 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese | ||
11 | * Revisions copyright (C) 2005 by Gerald Van Baren | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #ifndef POWERMGMT_TARGET_H | ||
23 | #define POWERMGMT_TARGET_H | ||
24 | |||
25 | /* | ||
26 | * Define CHARGING_DEBUG_FILE to create a csv (spreadsheet) with battery | ||
27 | * information in it (one sample per minute/connect/disconnect). | ||
28 | * | ||
29 | * This is only for very low level debug. | ||
30 | */ | ||
31 | #undef CHARGING_DEBUG_FILE | ||
32 | |||
33 | |||
34 | /* stop when N minutes have passed with avg delta being < -0.05 V */ | ||
35 | #define CHARGE_END_SHORTD 6 | ||
36 | /* stop when N minutes have passed with avg delta being < -0.02 V */ | ||
37 | #define CHARGE_END_LONGD 50 | ||
38 | |||
39 | /* Battery % to start at top-off */ | ||
40 | #define START_TOPOFF_CHG 85 | ||
41 | /* Battery % to start at trickle */ | ||
42 | #define START_TRICKLE_CHG 95 | ||
43 | /* power thread status message */ | ||
44 | #define POWER_MESSAGE_LEN 32 | ||
45 | /* minutes: maximum charging time for 1500 mAh batteries | ||
46 | * actual max time depends also on BATTERY_CAPACITY! */ | ||
47 | #define CHARGE_MAX_MIN_1500 450 | ||
48 | /* minutes: minimum charging time */ | ||
49 | #define CHARGE_MIN_MIN 10 | ||
50 | /* After charging, go to top off charge. How long should top off charge be? */ | ||
51 | #define TOPOFF_MAX_MIN 90 | ||
52 | /* which voltage is best? (millivolts) */ | ||
53 | #define TOPOFF_VOLTAGE 5650 | ||
54 | /* After top off charge, go to trickle harge. How long should trickle | ||
55 | * charge be? */ | ||
56 | #define TRICKLE_MAX_MIN 720 /* 12 hrs */ | ||
57 | /* which voltage is best? (millivolts) */ | ||
58 | #define TRICKLE_VOLTAGE 5450 | ||
59 | /* initial trickle_sec for topoff */ | ||
60 | #define START_TOPOFF_SEC 25 | ||
61 | /* initial trickle_sec for trickle */ | ||
62 | #define START_TRICKLE_SEC 15 | ||
63 | |||
64 | #define PID_DEADZONE 4 /* PID proportional deadzone */ | ||
65 | |||
66 | extern char power_message[POWER_MESSAGE_LEN]; | ||
67 | |||
68 | extern int long_delta; /* long term delta battery voltage */ | ||
69 | extern int short_delta; /* short term delta battery voltage */ | ||
70 | |||
71 | extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was | ||
72 | the charging started or | ||
73 | stopped? */ | ||
74 | extern int powermgmt_last_cycle_level; /* which level had the batteries | ||
75 | at this time? */ | ||
76 | |||
77 | extern int pid_p; /* PID proportional term */ | ||
78 | extern int pid_i; /* PID integral term */ | ||
79 | extern int trickle_sec; /* how many seconds should the | ||
80 | charger be enabled per | ||
81 | minute for trickle | ||
82 | charging? */ | ||
83 | void charger_enable(bool on); | ||
84 | bool charger_enabled(void); | ||
85 | |||
86 | /* Battery filter lengths in samples */ | ||
87 | #define BATT_AVE_SAMPLES 32 | ||
88 | |||
89 | /* No init to do */ | ||
90 | static inline void powermgmt_init_target(void) {} | ||
91 | void charging_algorithm_step(void); | ||
92 | |||
93 | #ifdef CHARGING_DEBUG_FILE | ||
94 | /* Need to flush and close debug file */ | ||
95 | void charging_algorithm_close(void); | ||
96 | #else | ||
97 | /* No poweroff operation to do */ | ||
98 | static inline void charging_algorithm_close(void) {} | ||
99 | #endif | ||
100 | |||
101 | #endif /* POWERMGMT_TARGET_H */ | ||
diff --git a/flash/bootbox/main.c b/flash/bootbox/main.c index f53a5edda2..e4be785beb 100644 --- a/flash/bootbox/main.c +++ b/flash/bootbox/main.c | |||
@@ -75,7 +75,7 @@ static void charging_screen(void) | |||
75 | 75 | ||
76 | do | 76 | do |
77 | { | 77 | { |
78 | #if CONFIG_CHARGING == CHARGING_CONTROL | 78 | #ifdef ARCHOS_RECORDER |
79 | if (charge_state == CHARGING) | 79 | if (charge_state == CHARGING) |
80 | msg = "charging"; | 80 | msg = "charging"; |
81 | else if (charge_state == TOPOFF) | 81 | else if (charge_state == TOPOFF) |
@@ -84,7 +84,6 @@ static void charging_screen(void) | |||
84 | msg = "trickle charge"; | 84 | msg = "trickle charge"; |
85 | else | 85 | else |
86 | msg = "not charging"; | 86 | msg = "not charging"; |
87 | |||
88 | #else | 87 | #else |
89 | msg = "charging"; | 88 | msg = "charging"; |
90 | #endif | 89 | #endif |
diff --git a/uisimulator/common/SOURCES b/uisimulator/common/SOURCES index 24dac31cca..881049ec59 100644 --- a/uisimulator/common/SOURCES +++ b/uisimulator/common/SOURCES | |||
@@ -7,3 +7,5 @@ lcd-playersim.c | |||
7 | #endif | 7 | #endif |
8 | sim_icons.c | 8 | sim_icons.c |
9 | stubs.c | 9 | stubs.c |
10 | powermgmt-sim.c | ||
11 | |||
diff --git a/uisimulator/common/powermgmt-sim.c b/uisimulator/common/powermgmt-sim.c new file mode 100644 index 0000000000..c06f84670d --- /dev/null +++ b/uisimulator/common/powermgmt-sim.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese | ||
11 | * Revisions copyright (C) 2005 by Gerald Van Baren | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #include "config.h" | ||
23 | #include "system.h" | ||
24 | #include <time.h> | ||
25 | #include "kernel.h" | ||
26 | #include "powermgmt.h" | ||
27 | |||
28 | #define BATT_MINMVOLT 2500 /* minimum millivolts of battery */ | ||
29 | #define BATT_MAXMVOLT 4500 /* maximum millivolts of battery */ | ||
30 | #define BATT_MAXRUNTIME (10 * 60) /* maximum runtime with full battery in | ||
31 | minutes */ | ||
32 | |||
33 | extern void send_battery_level_event(void); | ||
34 | extern int last_sent_battery_level; | ||
35 | extern int battery_percent; | ||
36 | |||
37 | static unsigned int battery_millivolts = BATT_MAXMVOLT; | ||
38 | /* estimated remaining time in minutes */ | ||
39 | static int powermgmt_est_runningtime_min = BATT_MAXRUNTIME; | ||
40 | |||
41 | static void battery_status_update(void) | ||
42 | { | ||
43 | static time_t last_change = 0; | ||
44 | static bool charging = false; | ||
45 | time_t now; | ||
46 | |||
47 | time(&now); | ||
48 | |||
49 | if (last_change < now) { | ||
50 | last_change = now; | ||
51 | |||
52 | /* change the values: */ | ||
53 | if (charging) { | ||
54 | if (battery_millivolts >= BATT_MAXMVOLT) { | ||
55 | /* Pretend the charger was disconnected */ | ||
56 | charging = false; | ||
57 | queue_broadcast(SYS_CHARGER_DISCONNECTED, 0); | ||
58 | last_sent_battery_level = 100; | ||
59 | } | ||
60 | } | ||
61 | else { | ||
62 | if (battery_millivolts <= BATT_MINMVOLT) { | ||
63 | /* Pretend the charger was connected */ | ||
64 | charging = true; | ||
65 | queue_broadcast(SYS_CHARGER_CONNECTED, 0); | ||
66 | last_sent_battery_level = 0; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | if (charging) { | ||
71 | battery_millivolts += (BATT_MAXMVOLT - BATT_MINMVOLT) / 50; | ||
72 | } | ||
73 | else { | ||
74 | battery_millivolts -= (BATT_MAXMVOLT - BATT_MINMVOLT) / 100; | ||
75 | } | ||
76 | |||
77 | battery_percent = 100 * (battery_millivolts - BATT_MINMVOLT) / | ||
78 | (BATT_MAXMVOLT - BATT_MINMVOLT); | ||
79 | |||
80 | powermgmt_est_runningtime_min = | ||
81 | battery_percent * BATT_MAXRUNTIME / 100; | ||
82 | } | ||
83 | |||
84 | send_battery_level_event(); | ||
85 | } | ||
86 | |||
87 | void battery_read_info(int *voltage, int *level) | ||
88 | { | ||
89 | battery_status_update(); | ||
90 | |||
91 | if (voltage) | ||
92 | *voltage = battery_millivolts; | ||
93 | |||
94 | if (level) | ||
95 | *level = battery_percent; | ||
96 | } | ||
97 | |||
98 | unsigned int battery_voltage(void) | ||
99 | { | ||
100 | battery_status_update(); | ||
101 | return battery_millivolts; | ||
102 | } | ||
103 | |||
104 | int battery_level(void) | ||
105 | { | ||
106 | battery_status_update(); | ||
107 | return battery_percent; | ||
108 | } | ||
109 | |||
110 | int battery_time(void) | ||
111 | { | ||
112 | battery_status_update(); | ||
113 | return powermgmt_est_runningtime_min; | ||
114 | } | ||
115 | |||
116 | bool battery_level_safe(void) | ||
117 | { | ||
118 | return battery_level() >= 10; | ||
119 | } | ||
120 | |||
121 | void set_poweroff_timeout(int timeout) | ||
122 | { | ||
123 | (void)timeout; | ||
124 | } | ||
125 | |||
126 | void set_battery_capacity(int capacity) | ||
127 | { | ||
128 | (void)capacity; | ||
129 | } | ||
130 | |||
131 | #if BATTERY_TYPES_COUNT > 1 | ||
132 | void set_battery_type(int type) | ||
133 | { | ||
134 | (void)type; | ||
135 | } | ||
136 | #endif | ||
137 | |||
138 | #ifdef HAVE_ACCESSORY_SUPPLY | ||
139 | void accessory_supply_set(bool enable) | ||
140 | { | ||
141 | (void)enable; | ||
142 | } | ||
143 | #endif | ||
144 | |||
145 | void reset_poweroff_timer(void) | ||
146 | { | ||
147 | } | ||
148 | |||
149 | void shutdown_hw(void) | ||
150 | { | ||
151 | } | ||
152 | |||
153 | void sys_poweroff(void) | ||
154 | { | ||
155 | } | ||
156 | |||
157 | void cancel_shutdown(void) | ||
158 | { | ||
159 | } | ||