Fixed red build...
[kugel-rb.git] / firmware / powermgmt.c
blob26759b647d8b71bbeb28c32323576c844a675865
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "config.h"
20 #include "sh7034.h"
21 #include "kernel.h"
22 #include "thread.h"
23 #include "system.h"
24 #include "debug.h"
25 #include "panic.h"
26 #include "adc.h"
27 #include "string.h"
28 #include "sprintf.h"
29 #include "ata.h"
30 #include "power.h"
31 #include "button.h"
32 #include "ata.h"
33 #include "mpeg.h"
34 #include "usb.h"
35 #include "powermgmt.h"
36 #include "backlight.h"
37 #ifdef CONFIG_TUNER
38 #include "fmradio.h"
39 #endif
41 long last_event_tick;
43 void reset_poweroff_timer(void)
45 last_event_tick = current_tick;
48 #ifdef SIMULATOR
50 int battery_level(void)
52 return 75;
55 int battery_time(void)
57 return 500;
60 bool battery_level_safe(void)
62 return battery_level() >= 10;
65 void set_poweroff_timeout(int timeout)
67 (void)timeout;
70 void set_battery_capacity(int capacity)
72 (void)capacity;
75 void set_car_adapter_mode(bool setting)
77 (void)setting;
80 #else /* not SIMULATOR */
82 int battery_capacity = BATTERY_CAPACITY_MIN; /* only a default value */
83 int battery_level_cached = -1; /* battery level of this minute, updated once
84 per minute */
85 static bool car_adapter_mode_enabled = false;
87 static const int poweroff_idle_timeout_value[15] =
89 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 30, 45, 60
92 static const int percent_to_volt_decharge[11] =
93 /* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */
95 #if CONFIG_BATTERY == BATT_LIION2200
96 /* measured values */
97 260, 285, 295, 303, 311, 320, 330, 345, 360, 380, 400
98 #elif CONFIG_BATTERY == BATT_3AAA_ALKALINE
99 /* taken from a textbook alkaline discharge graph, not measured */
100 270, 303, 324, 336, 348, 357, 366, 378, 390, 408, 450
101 #else /* NiMH */
102 /* original values were taken directly after charging, but it should show
103 100% after turning off the device for some hours, too */
104 450, 481, 491, 497, 503, 507, 512, 514, 517, 525, 540 /* orig. values:
105 ...,528,560 */
106 #endif
109 void set_battery_capacity(int capacity)
111 battery_capacity = capacity;
112 if (battery_capacity > BATTERY_CAPACITY_MAX)
113 battery_capacity = BATTERY_CAPACITY_MAX;
114 if (battery_capacity < BATTERY_CAPACITY_MIN)
115 battery_capacity = BATTERY_CAPACITY_MIN;
118 #if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200
119 int charge_state = 0; /* at the beginning, the
120 charger does nothing */
121 #endif
123 #ifdef HAVE_CHARGE_CTRL
125 char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in
126 debug menu */
127 char charge_restart_level = CHARGE_RESTART_HI; /* level at which charging
128 starts */
129 int powermgmt_last_cycle_startstop_min = 25; /* how many minutes ago was the
130 charging started or
131 stopped? */
132 int powermgmt_last_cycle_level = 0; /* which level had the
133 batteries at this time? */
134 bool trickle_charge_enabled = true;
135 int trickle_sec = 0; /* how many seconds should the
136 charger be enabled per
137 minute for trickle
138 charging? */
139 static const int percent_to_volt_charge[11] =
140 /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */
142 /* values guessed, see
143 http://www.seattlerobotics.org/encoder/200210/LiIon2.pdf until someone
144 measures voltages over a charging cycle */
145 476, 544, 551, 556, 561, 564, 566, 576, 582, 584, 585 /* NiMH */
148 void enable_trickle_charge(bool on)
150 trickle_charge_enabled = on;
152 #endif /* HAVE_CHARGE_CTRL */
154 static char power_stack[DEFAULT_STACK_SIZE];
155 static const char power_thread_name[] = "power";
157 static int poweroff_timeout = 0;
158 static long last_charge_time = 0;
159 int powermgmt_est_runningtime_min = -1;
161 static bool sleeptimer_active = false;
162 static unsigned long sleeptimer_endtick;
164 unsigned short power_history[POWER_HISTORY_LEN];
166 int battery_time(void)
168 return powermgmt_est_runningtime_min;
171 /* look into the percent_to_volt_* table and get a realistic battery level
172 percentage */
173 int voltage_to_percent(int voltage, const int* table)
175 if (voltage <= table[0])
176 return 0;
177 else
178 if (voltage >= table[10])
179 return 100;
180 else {
181 /* search nearest value */
182 int i = 0;
183 while ((i < 10) && (table[i+1] < voltage))
184 i++;
185 /* interpolate linear between the smaller and greater value */
186 return i * 10 /* 10th */
187 + (voltage - table[i]) *
188 10 / (table[i+1] - table[i]); /* 1th */
192 /* update battery level, called only once per minute */
193 void battery_level_update(void)
195 int level = 0;
196 int c = 0;
197 int i;
199 /* calculate maximum over last 3 minutes (skip empty samples) */
200 for (i = 0; i < 3; i++)
201 if (power_history[POWER_HISTORY_LEN-1-i] > c)
202 c = power_history[POWER_HISTORY_LEN-1-i];
204 if (c)
205 level = c;
206 else /* history was empty, get a fresh sample */
207 level = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000;
209 if(level > BATTERY_LEVEL_FULL)
210 level = BATTERY_LEVEL_FULL;
212 if(level < BATTERY_LEVEL_EMPTY)
213 level = BATTERY_LEVEL_EMPTY;
215 #ifdef HAVE_CHARGE_CTRL
216 if (charge_state == 0) { /* decharge */
217 level = voltage_to_percent(level, percent_to_volt_decharge);
219 else if (charge_state == 1) { /* charge */
220 level = voltage_to_percent(level, percent_to_volt_charge);
222 else {/* in trickle charge, the battery is per definition 100% full */
223 battery_level_cached = level = 100;
225 #else
226 level = voltage_to_percent(level, percent_to_volt_decharge);
227 /* always use the decharge table */
228 #endif
230 #ifndef HAVE_MMC /* this adjustment is only needed for HD based */
231 if (battery_level_cached == -1) { /* first run of this procedure */
232 /* the battery voltage is usually a little lower directly after
233 turning on, because the disk was used heavily raise it by 5 % */
234 battery_level_cached = (level > 95) ? 100 : level + 5;
236 else
237 #endif
239 /* the level is allowed to be -1 of the last value when usb not
240 connected and to be -3 of the last value when usb is connected */
241 if (usb_inserted()) {
242 if (level < battery_level_cached - 3)
243 level = battery_level_cached - 3;
245 else {
246 if (level < battery_level_cached - 1)
247 level = battery_level_cached - 1;
249 battery_level_cached = level;
253 /* Returns battery level in percent */
254 int battery_level(void)
256 #ifdef HAVE_CHARGE_CTRL
257 if ((charge_state==1) && (battery_level_cached==100))
258 return 99;
259 #endif
260 return battery_level_cached;
263 /* Tells if the battery level is safe for disk writes */
264 bool battery_level_safe(void)
266 /* I'm pretty sure we don't want an average over a long time here */
267 if (power_history[POWER_HISTORY_LEN-1])
268 return power_history[POWER_HISTORY_LEN-1] > BATTERY_LEVEL_DANGEROUS;
269 else
270 return adc_read(ADC_UNREG_POWER) > (BATTERY_LEVEL_DANGEROUS * 10000) /
271 BATTERY_SCALE_FACTOR;
274 void set_poweroff_timeout(int timeout)
276 poweroff_timeout = timeout;
279 void set_sleep_timer(int seconds)
281 if(seconds) {
282 sleeptimer_active = true;
283 sleeptimer_endtick = current_tick + seconds * HZ;
285 else {
286 sleeptimer_active = false;
287 sleeptimer_endtick = 0;
291 int get_sleep_timer(void)
293 if(sleeptimer_active)
294 return (sleeptimer_endtick - current_tick) / HZ;
295 else
296 return 0;
299 /* We shut off in the following cases:
300 1) The unit is idle, not playing music
301 2) The unit is playing music, but is paused
303 We do not shut off in the following cases:
304 1) The USB is connected
305 2) The charger is connected
306 3) We are recording, or recording with pause
308 static void handle_auto_poweroff(void)
310 long timeout = poweroff_idle_timeout_value[poweroff_timeout]*60*HZ;
311 int mpeg_stat = mpeg_status();
312 bool charger_is_inserted = charger_inserted();
313 static bool charger_was_inserted = false;
315 /* The was_inserted thing prevents the unit to shut down immediately
316 when the charger is extracted */
317 if(charger_is_inserted || charger_was_inserted)
319 last_charge_time = current_tick;
321 charger_was_inserted = charger_is_inserted;
323 if(timeout &&
324 #ifdef CONFIG_TUNER
325 (radio_get_status() != FMRADIO_PLAYING) &&
326 #endif
327 !usb_inserted() &&
328 (mpeg_stat == 0 ||
329 ((mpeg_stat == (MPEG_STATUS_PLAY | MPEG_STATUS_PAUSE)) &&
330 !sleeptimer_active)))
332 if(TIME_AFTER(current_tick, last_event_tick + timeout) &&
333 TIME_AFTER(current_tick, last_disk_activity + timeout) &&
334 TIME_AFTER(current_tick, last_charge_time + timeout))
336 power_off();
339 else
341 /* Handle sleeptimer */
342 if(sleeptimer_active && !usb_inserted())
344 if(TIME_AFTER(current_tick, sleeptimer_endtick))
346 mpeg_stop();
347 if(charger_is_inserted)
349 DEBUGF("Sleep timer timeout. Stopping...\n");
350 set_sleep_timer(0);
351 backlight_off(); /* Nighty, nighty... */
353 else
355 DEBUGF("Sleep timer timeout. Shutting off...\n");
356 /* Make sure that the disk isn't spinning when
357 we cut the power */
358 while(ata_disk_is_active())
359 sleep(HZ);
360 power_off();
367 void set_car_adapter_mode(bool setting)
369 car_adapter_mode_enabled = setting;
372 static bool charger_power_is_on;
374 #ifdef HAVE_CHARGING
375 static void car_adapter_mode_processing(void)
377 static bool waiting_to_resume_play = false;
378 static long play_resume_time;
380 if (car_adapter_mode_enabled) {
382 if (waiting_to_resume_play) {
383 if (TIME_AFTER(current_tick, play_resume_time)) {
384 if (mpeg_status() & MPEG_STATUS_PAUSE) {
385 mpeg_resume();
387 waiting_to_resume_play = false;
390 else {
391 if (charger_power_is_on) {
393 /* if external power was turned off */
394 if (!charger_inserted()) {
396 charger_power_is_on = false;
398 /* if playing */
399 if ((mpeg_status() & MPEG_STATUS_PLAY) &&
400 !(mpeg_status() & MPEG_STATUS_PAUSE)) {
401 mpeg_pause();
405 else {
406 /* if external power was turned on */
407 if (charger_inserted()) {
409 charger_power_is_on = true;
411 /* if paused */
412 if (mpeg_status() & MPEG_STATUS_PAUSE) {
413 /* delay resume a bit while the engine is cranking */
414 play_resume_time = current_tick + HZ*5;
415 waiting_to_resume_play = true;
422 #endif
425 * This function is called to do the relativly long sleep waits from within the
426 * main power_thread loop while at the same time servicing any other periodic
427 * functions in the power thread which need to be called at a faster periodic
428 * rate than the slow periodic rate of the main power_thread loop
430 static void power_thread_sleep(int ticks)
432 #ifdef HAVE_CHARGING
433 while (ticks > 0) {
434 int small_ticks = MIN(HZ/2, ticks);
435 sleep(small_ticks);
436 ticks -= small_ticks;
438 car_adapter_mode_processing();
440 #else
441 sleep(ticks); /* no fast-processing functions, sleep the whole time */
442 #endif
447 * This power thread maintains a history of battery voltage
448 * and implements a charging algorithm.
449 * For a complete description of the charging algorithm read
450 * docs/CHARGING_ALGORITHM.
453 static void power_thread(void)
455 int i;
456 int avg, ok_samples, spin_samples;
457 int current = 0;
458 #if CONFIG_BATTERY == BATT_LIION2200
459 int charging_current;
460 #endif
461 #ifdef HAVE_CHARGE_CTRL
462 int delta;
463 int charged_time = 0;
464 int charge_max_time_now = 0; /* max. charging duration, calculated at
465 beginning of charging */
466 int charge_pause = 0; /* no charging pause at the beginning */
467 int trickle_time = 0; /* how many minutes trickle charging already? */
468 #endif
470 while (1)
472 /* never read power while disk is spinning, unless in USB mode */
473 if (ata_disk_is_active() && !usb_inserted()) {
474 sleep(HZ * 2);
475 continue;
478 /* Make POWER_AVG measurements and calculate an average of that to
479 * reduce the effect of backlights/disk spinning/other variation.
481 ok_samples = spin_samples = avg = 0;
482 for (i = 0; i < POWER_AVG_N; i++) {
483 if (ata_disk_is_active()) {
484 if (!ok_samples) {
485 /* if we don't have any good non-disk-spinning samples,
486 * we take a sample anyway in case the disk is going
487 * to spin all the time.
489 avg += adc_read(ADC_UNREG_POWER);
490 spin_samples++;
492 } else {
493 if (spin_samples) /* throw away disk-spinning samples */
494 spin_samples = avg = 0;
495 avg += adc_read(ADC_UNREG_POWER);
496 ok_samples++;
498 power_thread_sleep(HZ*POWER_AVG_SLEEP);
500 avg = avg / ((ok_samples) ? ok_samples : spin_samples);
502 /* rotate the power history */
503 for (i = 0; i < POWER_HISTORY_LEN-1; i++)
504 power_history[i] = power_history[i+1];
506 /* insert new value in the end, in centivolts 8-) */
507 power_history[POWER_HISTORY_LEN-1] =
508 (avg * BATTERY_SCALE_FACTOR) / 10000;
510 /* update battery level every minute, ignoring first 15 minutes after
511 start charge/decharge */
512 #ifdef HAVE_CHARGE_CTRL
513 if ((powermgmt_last_cycle_startstop_min > 25) || (charge_state > 1))
514 #endif
515 battery_level_update();
517 /* calculate estimated remaining running time */
518 /* decharging: remaining running time */
519 /* charging: remaining charging time */
521 #ifdef HAVE_CHARGE_CTRL
522 if (charge_state == 1)
523 powermgmt_est_runningtime_min = (100 - battery_level()) *
524 battery_capacity / 100 * 60 / CURRENT_CHARGING;
525 else {
526 current = usb_inserted() ? CURRENT_USB : CURRENT_NORMAL;
527 if ((backlight_get_timeout() == 1) ||
528 (charger_inserted() && backlight_get_on_when_charging()))
529 /* LED always on or LED on when charger connected */
530 current += CURRENT_BACKLIGHT;
531 powermgmt_est_runningtime_min = battery_level() *
532 battery_capacity / 100 * 60 / current;
533 #if MEM == 8 /* assuming 192 kbps, the running time is 22% longer with 8MB */
534 powermgmt_est_runningtime_min =
535 powermgmt_est_runningtime_min * 122 / 100;
536 #endif /* MEM == 8 */
538 #else
539 current = usb_inserted() ? CURRENT_USB : CURRENT_NORMAL;
540 if (backlight_get_timeout() == 1) /* LED always on */
541 current += CURRENT_BACKLIGHT;
542 powermgmt_est_runningtime_min = battery_level() *
543 battery_capacity / 100 * 60 / current;
544 #if MEM == 8 /* assuming 192 kbps, the running time is 22% longer with 8MB */
545 powermgmt_est_runningtime_min =
546 powermgmt_est_runningtime_min * 122 / 100;
547 #endif /* MEM == 8 */
548 #endif /* HAVE_CHARGE_CONTROL */
550 #if CONFIG_BATTERY == BATT_LIION2200
551 /* We use the information from the ADC_EXT_POWER ADC channel, which
552 tells us the charging current from the LTC1734. When DC is
553 connected (either via the external adapter, or via USB), we try
554 to determine if it is actively charging or only maintaining the
555 charge. My tests show that ADC readings is below about 0x80 means
556 that the LTC1734 is only maintaining the charge. */
557 if(charger_inserted()) {
558 charging_current = adc_read(ADC_EXT_POWER);
559 if(charging_current < 0x80) {
560 charge_state = 2; /* Trickle */
561 } else {
562 charge_state = 1; /* Charging */
564 } else {
565 charge_state = 0; /* Not charging */
567 #else
568 #ifdef HAVE_CHARGE_CTRL
570 if (charge_pause > 0)
571 charge_pause--;
573 if (charger_inserted()) {
574 if (charge_state == 1) {
575 /* charger inserted and enabled */
576 charged_time++;
577 snprintf(power_message, POWER_MESSAGE_LEN,
578 "Chg %dm max %dm", charged_time, charge_max_time_now);
580 if (charged_time > charge_max_time_now) {
581 DEBUGF("power: charged_time > charge_max_time_now, "
582 "enough!\n");
583 /* have charged too long and deltaV detection did not
584 work! */
585 powermgmt_last_cycle_level = battery_level();
586 powermgmt_last_cycle_startstop_min = 0;
587 charger_enable(false);
588 snprintf(power_message, POWER_MESSAGE_LEN,
589 "Chg tmout %d min", charge_max_time_now);
590 /* disable charging for several hours from this point,
591 just to be sure */
592 charge_pause = CHARGE_PAUSE_LEN;
593 /* no trickle charge here, because the charging cycle
594 didn't end the right way */
595 charge_state = 0; /* 0: decharging/charger off, 1: charge,
596 2: top-off, 3: trickle */
597 } else {
598 if (charged_time > CHARGE_MIN_TIME) {
599 /* have charged continuously over the minimum charging
600 time, so we monitor for deltaV going
601 negative. Multiply thingsby 100 to get more
602 accuracy without floating point arithmetic.
603 power_history[] contains centivolts so after
604 multiplying by 100 the deltas are in tenths of
605 millivolts (delta of 5 is 0.0005 V).
607 delta =
608 ( power_history[POWER_HISTORY_LEN-1] * 100
609 + power_history[POWER_HISTORY_LEN-2] * 100
610 - power_history[POWER_HISTORY_LEN-1-
611 CHARGE_END_NEGD+1] * 100
612 - power_history[POWER_HISTORY_LEN-1-
613 CHARGE_END_NEGD] * 100 )
614 / CHARGE_END_NEGD / 2;
616 if (delta < -100) { /* delta < -10 mV */
617 DEBUGF("power: short-term negative"
618 " delta, enough!\n");
619 powermgmt_last_cycle_level = battery_level();
620 powermgmt_last_cycle_startstop_min = 0;
621 charger_enable(false);
622 snprintf(power_message, POWER_MESSAGE_LEN,
623 "end negd %d %dmin", delta, charged_time);
624 /* disable charging for several hours from this
625 point, just to be sure */
626 charge_pause = CHARGE_PAUSE_LEN;
627 /* enable trickle charging */
628 if (trickle_charge_enabled) {
629 trickle_sec = CURRENT_NORMAL * 60 /
630 CURRENT_CHARGING;
631 /* first guess, maybe consider if LED
632 backlight is on, disk is active,... */
633 trickle_time = 0;
634 charge_state = 2; /* 0: decharging/charger
635 off, 1: charge,
636 2: top-off, 3: trickle */
637 } else {
638 charge_state = 0; /* 0: decharging/charger
639 off, 1: charge,
640 2: top-off, 3: trickle */
642 } else {
643 /* if we didn't disable the charger in the
644 previous test, check for low positive delta */
645 delta =
646 ( power_history[POWER_HISTORY_LEN-1] * 100
647 + power_history[POWER_HISTORY_LEN-2] * 100
648 - power_history[POWER_HISTORY_LEN-1-
649 CHARGE_END_ZEROD+1] * 100
650 - power_history[POWER_HISTORY_LEN-1-
651 CHARGE_END_ZEROD] * 100 )
652 / CHARGE_END_ZEROD / 2;
654 if (delta < 1) { /* delta < 0.1 mV */
655 DEBUGF("power: long-term small "
656 "positive delta, enough!\n");
657 powermgmt_last_cycle_level = battery_level();
658 powermgmt_last_cycle_startstop_min = 0;
659 charger_enable(false);
660 snprintf(power_message, POWER_MESSAGE_LEN,
661 "end lowd %d %dmin",
662 delta, charged_time);
663 /* disable charging for several hours from
664 this point, just to be sure */
665 charge_pause = CHARGE_PAUSE_LEN;
666 /* enable trickle charging */
667 if (trickle_charge_enabled) {
668 trickle_sec =
669 CURRENT_NORMAL * 60 / CURRENT_CHARGING;
670 /* first guess, maybe consider if LED
671 backlight is on, disk is active,... */
672 trickle_time = 0;
673 charge_state = 2;
674 /* 0: decharging/charger off, 1: charge,
675 2: top-off, 3: trickle */
676 } else {
677 charge_state = 0;
678 /* 0: decharging/charger off, 1: charge,
679 2: top-off, 3: trickle */
686 else if (charge_state > 1) { /* top off or trickle? */
687 /* adjust trickle charge time */
688 if ( ((charge_state == 2) &&
689 (power_history[POWER_HISTORY_LEN-1] > TOPOFF_VOLTAGE))
690 || ((charge_state == 3) &&
691 (power_history[POWER_HISTORY_LEN-1] >
692 TRICKLE_VOLTAGE)) ) { /* charging too much */
693 trickle_sec--;
695 else { /* charging too less */
696 trickle_sec++;
699 if (trickle_sec > 24)
700 trickle_sec = 24;
702 if (trickle_sec < 1)
703 trickle_sec = 1;
705 /* charge the calculated amount of seconds */
706 charger_enable(true);
707 power_thread_sleep(HZ * trickle_sec);
708 charger_enable(false);
710 /* trickle charging long enough? */
712 if (trickle_time++ > TRICKLE_MAX_TIME + TOPOFF_MAX_TIME) {
713 trickle_sec = 0; /* show in debug menu that trickle is
714 off */
715 charge_state = 0; /* 0: decharging/charger off, 1: charge,
716 2: top-off, 3: trickle */
717 powermgmt_last_cycle_startstop_min = 0;
720 if ((charge_state == 2) &&
721 (trickle_time > TOPOFF_MAX_TIME)) /* change state? */
722 charge_state = 3; /* 0: decharging/charger off, 1: charge,
723 2: top-off, 3: trickle */
725 } else { /* charge_state == 0 */
727 /* the charger is enabled here only in one case: if it was
728 turned on at boot time (power_init) */
729 /* turn it off now */
730 if (charger_enabled)
731 charger_enable(false);
734 /* Start new charge cycle? This must be possible also in
735 trickle/top-off, because when usb connected, */
736 /* the trickle charge amount may not be enough */
738 if ((charge_state == 0) || (charge_state > 1))
739 /* if battery is not full, enable charging */
740 /* make sure charging starts if 1%-lazyness in
741 battery_level_update() is too slow */
742 if ( (battery_level() < charge_restart_level)
743 || (power_history[POWER_HISTORY_LEN-1] <
744 BATTERY_LEVEL_DANGEROUS)) {
745 if (charge_pause) {
746 DEBUGF("power: batt level < restart level,"
747 " but charge pause, not enabling\n");
748 snprintf(power_message, POWER_MESSAGE_LEN,
749 "chg pause %d min", charge_pause);
750 } else {
751 /* calculate max charge time depending on current
752 battery level */
753 /* take 35% more because some more energy is used for
754 heating up the battery */
755 i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500;
756 charge_max_time_now =
757 i * (100 + 35 - battery_level()) / 100;
758 if (charge_max_time_now > i) {
759 charge_max_time_now = i;
761 snprintf(power_message, POWER_MESSAGE_LEN,
762 "ChgAt %d%% max %dm", battery_level(),
763 charge_max_time_now);
765 /* enable the charger after the max time calc is done,
766 because battery_level depends on if the charger is
767 on */
768 DEBUGF("power: charger inserted and battery"
769 " not full, enabling\n");
770 powermgmt_last_cycle_level = battery_level();
771 powermgmt_last_cycle_startstop_min = 0;
772 charged_time = 0;
774 charger_enable(true);
775 charge_state = 1; /* 0: decharging/charger off, 1:
776 charge, 2: top-off, 3: trickle */
777 /* clear the power history so that we don't use values
778 before discharge for the long-term delta
780 for (i = 0; i < POWER_HISTORY_LEN-1; i++)
781 power_history[i] =
782 power_history[POWER_HISTORY_LEN-1];
786 } else {
787 /* charger not inserted */
788 if (charge_state > 0) {
789 /* charger not inserted but was enabled */
790 DEBUGF("power: charger disconnected, disabling\n");
791 powermgmt_last_cycle_level = battery_level();
792 powermgmt_last_cycle_startstop_min = 0;
793 /* show in debug menu that trickle is off */
794 trickle_sec = 0;
795 charger_enable(false);
796 charge_state = 0; /* 0: decharging/charger off, 1: charge, 2:
797 top-off, 3: trickle */
798 snprintf(power_message, POWER_MESSAGE_LEN, "Charger disc");
800 /* charger not inserted and disabled, so we're discharging */
802 powermgmt_last_cycle_startstop_min++;
804 #endif /* HAVE_CHARGE_CTRL*/
805 #endif /* # if CONFIG_BATTERY == BATT_LIION2200 */
807 /* sleep for roughly a minute */
808 #ifdef HAVE_CHARGE_CTRL
809 i = 60 - trickle_sec - POWER_AVG_N * POWER_AVG_SLEEP;
810 #else
811 i = 60 - POWER_AVG_N * POWER_AVG_SLEEP;
812 #endif
813 if (i > 0)
814 power_thread_sleep(HZ*(i));
816 handle_auto_poweroff();
820 void powermgmt_init(void)
822 power_init();
824 /* init history to 0 */
825 memset(power_history, 0x00, sizeof(power_history));
827 #if 0
828 /* initialize the history with a single sample to prevent level
829 flickering during the first minute of execution */
830 power_history[POWER_HISTORY_LEN-1] =
831 (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000;
832 /* calculate the first battery level */
833 battery_level_update();
834 /* calculate the remaining time to that the info screen displays something
835 useful */
836 powermgmt_est_runningtime_min =
837 battery_level() * battery_capacity / 100 * 60 / CURRENT_NORMAL;
838 #if MEM == 8 /* assuming 192 kbps, the running time is 22% longer with 8MB */
839 powermgmt_est_runningtime_min = powermgmt_est_runningtime_min * 122 / 100;
840 #endif
842 #ifdef HAVE_CHARGE_CTRL
843 snprintf(power_message, POWER_MESSAGE_LEN, "Powermgmt started");
845 /* if the battery is nearly empty, start charging immediately */
846 if (power_history[POWER_HISTORY_LEN-1] < BATTERY_LEVEL_DANGEROUS)
847 charger_enable(true);
848 #endif
849 #endif
851 charger_power_is_on = charger_inserted();
853 create_thread(power_thread, power_stack, sizeof(power_stack),
854 power_thread_name);
857 #endif /* SIMULATOR */