summaryrefslogtreecommitdiff
path: root/firmware/powermgmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/powermgmt.c')
-rw-r--r--firmware/powermgmt.c1200
1 files changed, 376 insertions, 824 deletions
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}