summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-12-24 16:58:41 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-12-24 16:58:41 +0000
commit3157e1395674a930c74e2ef4cc4ce78dffea8569 (patch)
tree5b2a9befc3b051caf0806995ebd32a5ab3bcf5ff
parent0f9729739f2fd90759c1caeca86e487c36f98834 (diff)
downloadrockbox-3157e1395674a930c74e2ef4cc4ce78dffea8569.tar.gz
rockbox-3157e1395674a930c74e2ef4cc4ce78dffea8569.zip
Simplify powermgmt thread loops so it calls functions turn (no more power_thread_sleep). Do other target-friendly simplifications, generic battery switch handling and split sim-specific code. Whoever can, please verify charging on the Archos Recorder (due to change in the charger duty cycle code).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19579 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/debug_menu.c34
-rw-r--r--apps/menus/main_menu.c21
-rw-r--r--apps/screens.c8
-rw-r--r--firmware/export/config-c200.h5
-rw-r--r--firmware/export/config-e200.h5
-rw-r--r--firmware/export/config-h100.h9
-rw-r--r--firmware/export/config-h120.h8
-rw-r--r--firmware/export/config-h300.h7
-rw-r--r--firmware/export/config-iaudiom3.h3
-rw-r--r--firmware/export/config-iaudiom5.h3
-rw-r--r--firmware/export/config-iaudiox5.h3
-rw-r--r--firmware/export/config-ipod4g.h7
-rw-r--r--firmware/export/config-ipodnano.h6
-rw-r--r--firmware/export/config-ipodvideo.h7
-rw-r--r--firmware/export/config-ondiofm.h5
-rw-r--r--firmware/export/config-ondiosp.h5
-rw-r--r--firmware/export/config-recorder.h2
-rw-r--r--firmware/export/config.h8
-rw-r--r--firmware/export/power.h11
-rw-r--r--firmware/export/powermgmt.h195
-rw-r--r--firmware/powermgmt.c1200
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/powermgmt-imx31.c97
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/powermgmt-target.h21
-rw-r--r--firmware/target/arm/iriver/h10/power-h10.c4
-rw-r--r--firmware/target/arm/olympus/mrobe-100/power-mr100.c4
-rwxr-xr-xfirmware/target/arm/philips/hdd1630/power-hdd1630.c4
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/powermgmt-meg-fx.c17
-rw-r--r--firmware/target/arm/tatung/tpj1022/power-tpj1022.c4
-rw-r--r--firmware/target/sh/archos/recorder/power-recorder.c12
-rw-r--r--firmware/target/sh/archos/recorder/powermgmt-recorder.c437
-rw-r--r--firmware/target/sh/archos/recorder/powermgmt-target.h101
-rw-r--r--flash/bootbox/main.c3
-rw-r--r--uisimulator/common/SOURCES2
-rw-r--r--uisimulator/common/powermgmt-sim.c159
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
25extern bool charger_enabled;
26void charger_enable(bool on);
27#endif
28
29#if CONFIG_CHARGING 24#if CONFIG_CHARGING
30enum power_input_flags { 25enum power_input_flags {
31 /* No external power source? Default. */ 26 /* No external power source? Default. */
@@ -82,9 +77,9 @@ bool power_input_present(void);
82void power_off(void); 77void power_off(void);
83void ide_power_enable(bool on); 78void ide_power_enable(bool on);
84 79
85# if CONFIG_CHARGING == CHARGING_MONITOR 80#if CONFIG_CHARGING >= CHARGING_MONITOR
86bool charging_state(void); 81bool 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);
102bool tuner_power(bool status); 97bool 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 28enum 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
33typedef 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 */
52extern charge_state_type charge_state; 49extern 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 */
59typedef enum { 56enum 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 */
67extern charger_input_state_type charger_input_state; 65extern enum charger_input_state_type charger_input_state;
66
67/* Power input status saved on the power thread each loop */
68extern 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
90extern char power_message[POWER_MESSAGE_LEN];
91
92extern int long_delta; /* long term delta battery voltage */
93extern int short_delta; /* short term delta battery voltage */
94
95extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was the charging started or stopped? */
96extern int powermgmt_last_cycle_level; /* which level had the batteries at this time? */
97
98extern int pid_p; /* PID proportional term */
99extern int pid_i; /* PID integral term */
100extern 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
171extern unsigned short power_history[POWER_HISTORY_LEN]; 125extern 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 */
180void powermgmt_init(void); 134void powermgmt_init(void);
181 135
182/* Do target portion of init (for CHARGING_TARGET) - called on power thread */
183void powermgmt_init_target(void);
184
185/* Handle frequent tasks and call charging_algorithm_small_step */
186void 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 */
193unsigned int battery_adc_voltage(void); /* voltage from ADC in millivolts */ 141unsigned int battery_adc_voltage(void); /* voltage from ADC in millivolts */
194unsigned int battery_voltage(void); /* filtered batt. voltage in millivolts */ 142unsigned int battery_voltage(void); /* filtered batt. voltage in millivolts */
195 143
144#ifdef HAVE_BATTERY_SWITCH
145unsigned 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).
198void set_filtered_battery_voltage(int millivolts); 149 * Also readjust when battery switch is opened or closed.
150 */
151void reset_battery_filter(int millivolts);
152#endif /* HAVE_BATTERY_SWITCH */
199 153
200/* read unfiltered battery info */ 154/* read unfiltered battery info */
201void battery_read_info(int *voltage, int *level); 155void 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 */
204bool battery_level_safe(void); 158bool battery_level_safe(void);
205 159
206#ifdef TARGET_POWERMGMT_FILTER_CHARGE_STATE
207int powermgmt_filter_charge_state(void);
208#endif
209
210void set_poweroff_timeout(int timeout); 160void set_poweroff_timeout(int timeout);
211void set_battery_capacity(int capacity); /* set local battery capacity value */ 161void set_battery_capacity(int capacity); /* set local battery capacity value */
212void set_battery_type(int type); /* set local battery type */ 162int get_battery_capacity(void); /* get local battery capacity value */
163void set_battery_type(int type); /* set local battery type */
213 164
214void set_sleep_timer(int seconds); 165void set_sleep_timer(int seconds);
215int get_sleep_timer(void); 166int 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 57int 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 */ 59int battery_percent = -1;
64#undef DEBUG_FILE 60void 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
69static char debug_message[DEBUG_MESSAGE_LEN];
70#define DEBUG_STACK ((0x1000)/sizeof(long))
71static int fd = -1; /* write debug information to this file */
72static int wrcount = 0;
73#else
74#define DEBUG_STACK 0
75#endif
76
77static int shutdown_timeout = 0;
78#if CONFIG_CHARGING >= CHARGING_MONITOR
79charge_state_type charge_state = DISCHARGING; /* charging mode */
80#endif
81
82static void send_battery_level_event(void);
83static int last_sent_battery_level = 100;
84 61
85#if CONFIG_CHARGING 62#if CONFIG_CHARGING
86charger_input_state_type charger_input_state IDATA_ATTR; 63/* State of the charger input as seen by the power thread */
87#endif 64enum charger_input_state_type charger_input_state;
88 65/* Power inputs as seen by the power thread */
89#ifdef SIMULATOR /***********************************************************/ 66unsigned 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 */ 69enum charge_state_type charge_state = DISCHARGING;
93#define BATT_MAXRUNTIME (10 * 60) /* maximum runtime with full battery in minutes */
94
95static unsigned int battery_millivolts = (unsigned int)BATT_MAXMVOLT;
96static int battery_percent = 100; /* battery capacity level in percent */
97static int powermgmt_est_runningtime_min = BATT_MAXRUNTIME; /* estimated remaining time in minutes */
98
99static 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
143void 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
154unsigned int battery_voltage(void)
155{
156 battery_status_update();
157 return battery_millivolts;
158}
159
160int battery_level(void)
161{
162 battery_status_update();
163 return battery_percent;
164}
165
166int battery_time(void)
167{
168 battery_status_update();
169 return powermgmt_est_runningtime_min;
170}
171
172bool battery_level_safe(void)
173{
174 return battery_level() >= 10;
175}
176
177void set_poweroff_timeout(int timeout)
178{
179 (void)timeout;
180}
181
182void set_battery_capacity(int capacity)
183{
184 (void)capacity;
185}
186
187#if BATTERY_TYPES_COUNT > 1
188void set_battery_type(int type)
189{
190 (void)type;
191}
192#endif
193
194void reset_poweroff_timer(void)
195{
196}
197
198#ifdef HAVE_ACCESSORY_SUPPLY
199void 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 74static 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 */
212static unsigned int avgbat; /* average battery voltage (filtering) */ 80static unsigned int avgbat;
213static unsigned int battery_millivolts;/* filtered battery voltage, millivolts */ 81/* filtered battery voltage, millivolts */
82static unsigned int battery_millivolts;
83/* default value, mAh */
84static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
85
214 86
215/* battery level (0-100%) of this minute, updated once per minute */
216static int battery_percent = -1;
217static int battery_capacity = BATTERY_CAPACITY_DEFAULT; /* default value, mAh */
218#if BATTERY_TYPES_COUNT > 1 87#if BATTERY_TYPES_COUNT > 1
219static int battery_type = 0; 88static 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 */
225unsigned short power_history[POWER_HISTORY_LEN]; 94unsigned short power_history[POWER_HISTORY_LEN];
226 95
227static char power_stack[DEFAULT_STACK_SIZE/2 + DEBUG_STACK]; 96static char power_stack[DEFAULT_STACK_SIZE/2 + POWERMGMT_DEBUG_STACK];
228static const char power_thread_name[] = "power"; 97static const char power_thread_name[] = "power";
229 98
230static int poweroff_timeout = 0; 99static int poweroff_timeout = 0;
@@ -239,19 +108,6 @@ static int voltage_to_battery_level(int battery_millivolts);
239static void battery_status_update(void); 108static void battery_status_update(void);
240static int runcurrent(void); 109static int runcurrent(void);
241 110
242#ifndef TARGET_POWERMGMT_FILTER_CHARGE_STATE
243static 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
255void battery_read_info(int *voltage, int *level) 111void 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)
272void set_battery_type(int type) 128void 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
281void set_battery_capacity(int capacity) 140void 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 */ 152int get_battery_capacity(void)
153{
154 return battery_capacity;
289} 155}
290 156
291int battery_time(void) 157int 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 */
314bool battery_level_safe(void) 179bool 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
320void set_poweroff_timeout(int timeout) 192void set_poweroff_timeout(int timeout)
321{ 193{
@@ -324,7 +196,7 @@ void set_poweroff_timeout(int timeout)
324 196
325void set_sleep_timer(int seconds) 197void 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
337int get_sleep_timer(void) 209int 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 */
346static int voltage_to_percent(int voltage, const short* table) 218static 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 */
367static int voltage_to_battery_level(int battery_millivolts) 241static 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)
434static void handle_auto_poweroff(void) 306static 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
551static void power_thread_rtc_process(void) 415static 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 */
560bool query_force_shutdown(void) 423bool 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 */
582int long_delta; /* long term delta battery voltage */ 441void reset_battery_filter(int millivolts)
583int short_delta; /* short term delta battery voltage */
584bool disk_activity_last_cycle = false; /* flag set to aid charger time
585 * calculation */
586char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in
587 debug menu */
588 /* percentage at which charging
589 starts */
590int powermgmt_last_cycle_startstop_min = 0; /* how many minutes ago was the
591 charging started or
592 stopped? */
593int powermgmt_last_cycle_level = 0; /* which level had the
594 batteries at this time? */
595int trickle_sec = 0; /* how many seconds should the
596 charger be enabled per
597 minute for trickle
598 charging? */
599int pid_p = 0; /* PID proportional term */
600int pid_i = 0; /* PID integral term */
601
602static 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
621static inline void charging_algorithm_big_step(void) 449/** Generic charging algorithms for common charging types **/
450#if CONFIG_CHARGING == CHARGING_SIMPLE
451static 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 */
912static inline void charging_algorithm_close(void) 456static 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
922extern void charging_algorithm_big_step(void);
923extern void charging_algorithm_small_step(void);
924extern void charging_algorithm_close(void);
925
926void 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 */
936static inline void charging_algorithm_small_step(void) 464static 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
957static 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 */
966static inline void charging_algorithm_close(void) 482static 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. */
976bool charger_inserted(void) 492bool 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. */
983bool power_input_present(void) 499bool 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 */
998void power_thread_sleep(int ticks) 507static 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 */
563static 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
1109static void power_thread(void) 618static 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
1163void powermgmt_init(void) 716void 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
1174void 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
1196void 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 */
1210void shutdown_hw(void) 726void 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
770void 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
791void 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. */
1256static void send_battery_level_event(void) 807void 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. */
170static uint32_t int_sense0 = 0; /* Interrupt Sense 0 bits */ 170static uint32_t int_sense0 = 0; /* Interrupt Sense 0 bits */
171static unsigned int power_status = POWER_INPUT_NONE; /* Detect input changes */ 171static unsigned int last_inputs = POWER_INPUT_NONE; /* Detect input changes */
172static int charger_total_timer = 0; /* Total allowed charging time */ 172static int charger_total_timer = 0; /* Total allowed charging time */
173static int icharger_ave = 0; /* Filtered charging current */ 173static int icharger_ave = 0; /* Filtered charging current */
174static bool charger_close = false; /* Shutdown notification */ 174static bool charger_close = false; /* Shutdown notification */
@@ -181,7 +181,7 @@ static int autorecharge_counter = 0 ; /* Battery < threshold debounce */
181static int chgcurr_timer = 0; /* Countdown to CHGCURR error */ 181static 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 */
187static enum 187static 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. */
218static bool main_charger_connected(void) 218static 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. */
238static unsigned int input_millivolts(void) 237unsigned 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. */
248static int stat_battery_reading(int type) 246static 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. */
595int 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. */
609bool charging_state(void) 593bool 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
628bool 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
637bool 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
646static void charger_plugged(void) 612static 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
673static void charger_none(void) 639static 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
717static void charger_control(void) 679static 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 */
861void charging_algorithm_small_step(void) 820void 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
912void 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. */
920void charging_algorithm_close(void) 875void 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
96void powermgmt_init_target(void);
97void charging_algorithm_step(void);
98void charging_algorithm_close(void);
99
95/* Provide filtered charge current */ 100/* Provide filtered charge current */
96int battery_charge_current(void); 101int 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
37bool charger_enabled;
38#endif
39
40#if CONFIG_TUNER 36#if CONFIG_TUNER
41 37
42bool tuner_power(bool status) 38bool 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
33bool charger_enabled;
34#endif
35
36void power_init(void) 32void 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
33bool charger_enabled;
34#endif
35
36void power_init(void) 32void 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
27const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = 28const 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
62unsigned 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
37bool charger_enabled;
38#endif
39
40void power_init(void) 36void 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
30bool charger_enabled; 31static bool charger_on;
31 32
32void power_init(void) 33void 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
61bool charger_enabled(void)
62{
63 return charger_on;
58} 64}
59 65
60void ide_power_enable(bool on) 66void 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
27const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = 31const 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
73static char debug_message[DEBUG_MESSAGE_LEN];
74static int fd = -1; /* write debug information to this file */
75static 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 */
82int long_delta; /* long term delta battery voltage */
83int short_delta; /* short term delta battery voltage */
84bool disk_activity_last_cycle = false; /* flag set to aid charger time
85 * calculation */
86char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in
87 debug menu */
88 /* percentage at which charging
89 starts */
90int powermgmt_last_cycle_startstop_min = 0; /* how many minutes ago was the
91 charging started or
92 stopped? */
93int powermgmt_last_cycle_level = 0; /* which level had the
94 batteries at this time? */
95int trickle_sec = 0; /* how many seconds should the
96 charger be enabled per
97 minute for trickle
98 charging? */
99int pid_p = 0; /* PID proportional term */
100int pid_i = 0; /* PID integral term */
101
102static unsigned int target_voltage = TRICKLE_VOLTAGE; /* desired topoff/trickle
103 * voltage level */
104static int charge_max_time_idle = 0; /* max. charging duration, calculated at
105 * beginning of charging */
106static int charge_max_time_now = 0; /* max. charging duration including
107 * hdd activity */
108static int minutes_disk_activity = 0; /* count minutes of hdd use during
109 * charging */
110static int last_disk_activity = CHARGE_END_LONGD + 1; /* last hdd use x mins ago */
111
112#ifdef CHARGING_DEBUG_FILE
113static void debug_file_close(void)
114{
115 if (fd >= 0) {
116 close(fd);
117 fd = -1;
118 }
119}
120
121static 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
149static 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 */
171static 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 */
187static 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 */
241static 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
255static 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
385static 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
430void 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
487void 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. */
494bool 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
66extern char power_message[POWER_MESSAGE_LEN];
67
68extern int long_delta; /* long term delta battery voltage */
69extern int short_delta; /* short term delta battery voltage */
70
71extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was
72 the charging started or
73 stopped? */
74extern int powermgmt_last_cycle_level; /* which level had the batteries
75 at this time? */
76
77extern int pid_p; /* PID proportional term */
78extern int pid_i; /* PID integral term */
79extern int trickle_sec; /* how many seconds should the
80 charger be enabled per
81 minute for trickle
82 charging? */
83void charger_enable(bool on);
84bool charger_enabled(void);
85
86/* Battery filter lengths in samples */
87#define BATT_AVE_SAMPLES 32
88
89/* No init to do */
90static inline void powermgmt_init_target(void) {}
91void charging_algorithm_step(void);
92
93#ifdef CHARGING_DEBUG_FILE
94/* Need to flush and close debug file */
95void charging_algorithm_close(void);
96#else
97/* No poweroff operation to do */
98static 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
8sim_icons.c 8sim_icons.c
9stubs.c 9stubs.c
10powermgmt-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
33extern void send_battery_level_event(void);
34extern int last_sent_battery_level;
35extern int battery_percent;
36
37static unsigned int battery_millivolts = BATT_MAXMVOLT;
38/* estimated remaining time in minutes */
39static int powermgmt_est_runningtime_min = BATT_MAXRUNTIME;
40
41static 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
87void 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
98unsigned int battery_voltage(void)
99{
100 battery_status_update();
101 return battery_millivolts;
102}
103
104int battery_level(void)
105{
106 battery_status_update();
107 return battery_percent;
108}
109
110int battery_time(void)
111{
112 battery_status_update();
113 return powermgmt_est_runningtime_min;
114}
115
116bool battery_level_safe(void)
117{
118 return battery_level() >= 10;
119}
120
121void set_poweroff_timeout(int timeout)
122{
123 (void)timeout;
124}
125
126void set_battery_capacity(int capacity)
127{
128 (void)capacity;
129}
130
131#if BATTERY_TYPES_COUNT > 1
132void set_battery_type(int type)
133{
134 (void)type;
135}
136#endif
137
138#ifdef HAVE_ACCESSORY_SUPPLY
139void accessory_supply_set(bool enable)
140{
141 (void)enable;
142}
143#endif
144
145void reset_poweroff_timer(void)
146{
147}
148
149void shutdown_hw(void)
150{
151}
152
153void sys_poweroff(void)
154{
155}
156
157void cancel_shutdown(void)
158{
159}