A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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 <stdio.h>
23#include <ctype.h>
24#include "config.h"
25#include "system.h"
26#include "kernel.h"
27#include "thread.h"
28#include "debug.h"
29#include "adc.h"
30#include "string.h"
31#include "storage.h"
32#include "power.h"
33#include "audio.h"
34#include "usb.h"
35#include "powermgmt.h"
36#include "backlight.h"
37#include "lcd.h"
38#include "rtc.h"
39#if CONFIG_TUNER
40#include "fmradio.h"
41#endif
42#include "sound.h"
43#include "font.h"
44#include "logf.h"
45#ifdef HAVE_REMOTE_LCD
46#include "lcd-remote.h"
47#endif
48#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
49#include <time.h>
50#endif
51
52#if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) \
53 && !defined (SIMULATOR)
54#include "pcf50606.h"
55#endif
56
57#if (BATTERY_CAPACITY_DEFAULT > 0)
58extern unsigned short power_history[POWER_HISTORY_LEN];
59extern unsigned short battery_level_disksafe;
60extern unsigned short battery_level_shutoff;
61extern unsigned short percent_to_volt_discharge[11];
62#endif
63#if CONFIG_CHARGING
64extern unsigned short percent_to_volt_charge[11];
65#endif
66
67#ifndef BOOTLOADER
68#include "misc.h"
69#include "splash.h"
70
71struct battery_tables_t device_battery_tables =
72{
73#if (BATTERY_CAPACITY_DEFAULT > 0)
74 .history = power_history,
75 .disksafe = &battery_level_disksafe,
76 .shutoff = &battery_level_shutoff,
77 .discharge = percent_to_volt_discharge,
78#if CONFIG_CHARGING
79 .charge = percent_to_volt_charge,
80#endif
81 .elems = ARRAYLEN(percent_to_volt_discharge),
82#endif
83 .isdefault = true,
84};
85#endif
86
87static int last_sent_battery_level = 100;
88static void set_sleep_timer(int seconds);
89
90static bool sleeptimer_active = false;
91static long sleeptimer_endtick;
92/* Whether an active sleep timer should be restarted when a key is pressed */
93static bool sleeptimer_key_restarts = false;
94/* The number of seconds the sleep timer was last set to */
95static unsigned int sleeptimer_duration = 0;
96
97#if CONFIG_CHARGING
98/* State of the charger input as seen by the power thread */
99enum charger_input_state_type charger_input_state;
100/* Power inputs as seen by the power thread */
101unsigned int power_thread_inputs;
102#if CONFIG_CHARGING >= CHARGING_MONITOR
103/* Charging state (mode) as seen by the power thread */
104enum charge_state_type charge_state = DISCHARGING;
105#endif
106#endif /* CONFIG_CHARGING */
107
108static int shutdown_timeout = 0;
109
110void handle_auto_poweroff(void);
111static int poweroff_timeout = 0;
112static long last_event_tick = 0;
113
114#if BATTERY_CAPACITY_INC > 0
115static int battery_capacity = BATTERY_CAPACITY_DEFAULT;
116#else
117# define battery_capacity BATTERY_CAPACITY_DEFAULT
118#endif
119
120/* Power history: power_history[0] is the newest sample */
121unsigned short power_history[POWER_HISTORY_LEN] = {0};
122
123#if (CONFIG_CPU == JZ4732) || (CONFIG_CPU == JZ4760B) || \
124 (CONFIG_CPU == X1000) || (CONFIG_PLATFORM & PLATFORM_HOSTED)
125static long power_stack[DEFAULT_STACK_SIZE/sizeof(long)];
126#else
127static long power_stack[DEFAULT_STACK_SIZE/2/sizeof(long)];
128#endif
129static const char power_thread_name[] = "power";
130
131/* Time estimation requires 64 bit math so don't use it in the bootloader.
132 * Also we need to be able to measure current, and not have a better time
133 * estimate source available. */
134#if (!defined(BOOTLOADER) && !(CONFIG_BATTERY_MEASURE & TIME_MEASURE) && \
135 (defined(CURRENT_NORMAL) || (CONFIG_BATTERY_MEASURE & CURRENT_MEASURE)))
136#define HAVE_TIME_ESTIMATION
137#endif
138
139#if !(CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE)
140int _battery_level(void) { return -1; }
141#endif
142static int percent_now; /* Cached to avoid polling too often */
143
144#if !(CONFIG_BATTERY_MEASURE & TIME_MEASURE)
145int _battery_time(void) { return -1; }
146#else
147static int time_now; /* Cached to avoid polling too often */
148#endif
149
150#ifdef HAVE_TIME_ESTIMATION
151static int time_now; /* reported time in minutes */
152static int64_t time_cnt; /* reported time in seconds */
153static int64_t time_err; /* error... it's complicated */
154#endif
155
156#if !(CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE)
157int _battery_voltage(void) { return -1; }
158#else
159/* Data for the digital exponential filter */
160static int voltage_avg, voltage_now;
161#endif
162
163#if !(CONFIG_BATTERY_MEASURE & CURRENT_MEASURE)
164int _battery_current(void) { return -1; }
165#else
166static int current_avg, current_now;
167#endif
168
169/* The battery level can be obtained in two ways. If the target reports
170 * voltage, the battery level can be estminated using percent_to_volt_*
171 * curves. If the target can report the percentage directly, then that
172 * will be used instead of voltage-based estimation. */
173int battery_level(void)
174{
175#ifdef HAVE_BATTERY_SWITCH
176 if ((power_input_status() & POWER_INPUT_BATTERY) == 0)
177 return -1;
178#endif
179
180 return percent_now;
181}
182
183/* The time remaining to full charge/discharge can be provided by the
184 * target if it has an accurate way of doing this. Otherwise, if the
185 * target defines a valid battery capacity and can report the charging
186 * and discharging current, the time remaining will be estimated based
187 * on the battery level and the actual current usage. */
188int battery_time(void)
189{
190#if (CONFIG_BATTERY_MEASURE & TIME_MEASURE) || defined(HAVE_TIME_ESTIMATION)
191 return time_now;
192#else
193 return -1;
194#endif
195}
196
197/* Battery voltage should always be reported if available, but it is
198 * optional if the the target reports battery percentage directly. */
199int battery_voltage(void)
200{
201#if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
202 return voltage_now;
203#else
204 return -1;
205#endif
206}
207
208/* Battery current can be estimated if the target defines CURRENT_NORMAL
209 * as the number of milliamps usually consumed by the device in a normal
210 * state. The target can also define other CURRENT_* values to estimate
211 * the power consumed by the backlight, remote display, SPDIF, etc. */
212int battery_current(void)
213{
214#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE
215 return current_now;
216#elif defined(CURRENT_NORMAL)
217 int current = CURRENT_NORMAL;
218
219#ifndef BOOTLOADER
220#if defined(HAVE_BACKLIGHT) && defined(CURRENT_BACKLIGHT)
221 if (backlight_get_current_timeout() == 0) /* LED always on */
222 current += CURRENT_BACKLIGHT;
223#endif
224
225#if defined(HAVE_RECORDING) && defined(CURRENT_RECORD)
226 if (audio_status() & AUDIO_STATUS_RECORD)
227 current += CURRENT_RECORD;
228#endif
229
230#if defined(HAVE_SPDIF_POWER) && defined(CURRENT_SPDIF_OUT)
231 if (spdif_powered())
232 current += CURRENT_SPDIF_OUT;
233#endif
234
235#if defined(HAVE_REMOTE_LCD) && defined(CURRENT_REMOTE)
236 if (remote_detect())
237 current += CURRENT_REMOTE;
238#endif
239
240#if defined(HAVE_ATA_POWER_OFF) && defined(CURRENT_ATA)
241 if (ide_powered())
242 current += CURRENT_ATA;
243#endif
244
245#if CONFIG_CHARGING >= CHARGING_MONITOR
246 /* While charging we must report the charging current. */
247 if (charging_state()) {
248 current = CURRENT_MAX_CHG - current;
249 current = MIN(current, 1);
250 }
251#endif
252
253#endif /* BOOTLOADER */
254
255 return current;
256#else
257 return -1;
258#endif
259}
260
261/* Initialize the battery voltage/current filters. This is called
262 * once by the power thread before entering the main polling loop. */
263static void average_init(void)
264{
265#if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
266 voltage_now = _battery_voltage() + 15;
267
268 /* The battery voltage is usually a little lower directly after
269 turning on, because the disk was used heavily. Raise it by 5% */
270#ifdef HAVE_DISK_STORAGE
271#if CONFIG_CHARGING
272 if(!charger_inserted())
273#endif
274 {
275 voltage_now += (percent_to_volt_discharge[6] -
276 percent_to_volt_discharge[5]) / 2;
277 }
278#endif /* HAVE_DISK_STORAGE */
279
280 voltage_avg = voltage_now * BATT_AVE_SAMPLES;
281#endif /* CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE */
282
283#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE
284 current_now = _battery_current();
285 current_avg = current_now * BATT_CURRENT_AVE_SAMPLES;
286#endif
287}
288
289/* Sample the battery voltage/current and update the filters.
290 * Updated once every POWER_THREAD_STEP_TICKS. */
291static void average_step(bool low_battery)
292{
293#if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
294 int millivolts = _battery_voltage();
295 if(low_battery) {
296 voltage_now = (millivolts + voltage_now + 1) / 2;
297 voltage_avg += voltage_now - voltage_avg / BATT_AVE_SAMPLES;
298 } else {
299 voltage_avg += millivolts - voltage_avg / BATT_AVE_SAMPLES;
300 voltage_now = voltage_avg / BATT_AVE_SAMPLES;
301 }
302#else
303 (void)low_battery;
304#endif
305
306#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE
307 current_avg += _battery_current() - current_avg / BATT_CURRENT_AVE_SAMPLES;
308 current_now = current_avg / BATT_CURRENT_AVE_SAMPLES;
309#endif
310}
311
312/* Send system battery level update events on reaching certain significant
313 * levels. This is called by battery_status_update() and does not have to
314 * be called separately. */
315static void send_battery_level_event(int percent)
316{
317 static const int levels[] = { 5, 15, 30, 50, 0 };
318 const int *level = levels;
319
320 while (*level)
321 {
322 if (percent <= *level && last_sent_battery_level > *level) {
323 last_sent_battery_level = *level;
324 queue_broadcast(SYS_BATTERY_UPDATE, last_sent_battery_level);
325 break;
326 }
327
328 level++;
329 }
330}
331
332#if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
333/* Look into the percent_to_volt_* table and estimate the battery level. */
334static int voltage_to_percent(int voltage, const short* table)
335{
336 if (voltage <= table[0]) {
337 return 0;
338 }
339 else if (voltage >= table[10]) {
340 return 100;
341 }
342 else {
343 /* search nearest value */
344 int i = 0;
345
346 while (i < 10 && table[i+1] < voltage)
347 i++;
348
349 /* interpolate linear between the smaller and greater value */
350 /* Tens digit, 10% per entry, ones digit: interpolated */
351 return i*10 + (voltage - table[i])*10 / (table[i+1] - table[i]);
352 }
353}
354
355/* Convert voltage to a battery level percentage using the appropriate
356 * percent_to_volt_* lookup table. */
357static int voltage_to_battery_level(int millivolts)
358{
359 int level;
360
361 if (millivolts < 0)
362 return -1;
363
364#if CONFIG_CHARGING >= CHARGING_MONITOR
365 if (charging_state()) {
366 /* battery level is defined to be < 100% until charging is finished */
367 level = voltage_to_percent(millivolts, percent_to_volt_charge);
368 if (level > 99)
369 level = 99;
370 }
371 else
372#endif /* CONFIG_CHARGING >= CHARGING_MONITOR */
373 {
374 /* DISCHARGING or error state */
375 level = voltage_to_percent(millivolts, percent_to_volt_discharge);
376 }
377
378 return level;
379}
380#endif /* CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE */
381
382/* Update battery percentage and time remaining information.
383 *
384 * This will be called by the power thread after polling new battery data.
385 * It must also be called if the battery type or capacity changes.
386 */
387static void battery_status_update(void)
388{
389#if ((CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) && (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE))
390 int level = _battery_level();
391 if (level == -1) {
392 level = voltage_to_battery_level(voltage_now);
393 }
394#elif CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE
395 int level = _battery_level();
396#elif CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
397 int level = voltage_to_battery_level(voltage_now);
398#else
399 /* This should be a compile time error? */
400 int level = -1;
401#endif
402
403#if CONFIG_BATTERY_MEASURE & TIME_MEASURE
404 time_now = _battery_time();
405#elif defined(HAVE_TIME_ESTIMATION)
406 /* TODO: This is essentially a bad version of coloumb counting,
407 * so in theory using coloumb counters when they are available
408 * should provide a more accurate result. Also note that this
409 * is hard-coded with a HZ/2 update rate to simplify arithmetic. */
410
411 int current = battery_current();
412 int resolution = battery_capacity * 36;
413
414 int time_est = 0;
415 if(level >= 0 && current > 0) {
416#if CONFIG_CHARGING >= CHARGING_MONITOR
417 if (charging_state())
418 time_est = (100 - level) * battery_capacity * 36 / current;
419 else
420#endif
421 time_est = level * battery_capacity * 36 / current;
422
423 /* The first term nudges the counter toward the estimate. */
424 time_err += current * (time_est - time_cnt);
425 }
426
427 /* The second term decrements the counter due to elapsed time. */
428 time_err -= resolution;
429
430 /* Arbitrary cutoff to ensure we don't get too far out
431 * of sync. Seems to work well on synthetic tests. */
432 if(time_err > resolution * 12 ||
433 time_err < -resolution * 13) {
434 time_cnt = time_est;
435 time_err = 0;
436 }
437
438 if(resolution > 0) {
439 /* Convert the error into a time and adjust the counter. */
440 int64_t adjustment = time_err / (2 * resolution);
441 time_cnt += adjustment;
442 time_err -= adjustment * (2 * resolution);
443 }
444
445 /* Update the reported time based on the counter. */
446 time_now = (time_cnt + 30) / 60;
447 if(time_now < 0)
448 time_now = 0;
449#endif
450
451 percent_now = level;
452 send_battery_level_event(level);
453}
454
455void battery_read_info(int *voltage, int *level)
456{
457 int millivolts = _battery_voltage();
458
459 if (voltage)
460 *voltage = millivolts;
461
462 if (level) {
463#if ((CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) && (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE))
464 *level = _battery_level();
465 if (*level == -1) {
466 *level = voltage_to_battery_level(millivolts);
467 }
468#elif (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE)
469 *level = _battery_level();
470#elif (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE)
471 *level = voltage_to_battery_level(millivolts);
472#else
473 *level = -1;
474#endif
475 }
476}
477
478#if BATTERY_CAPACITY_INC > 0
479void set_battery_capacity(int capacity)
480{
481 if (capacity > BATTERY_CAPACITY_MAX)
482 capacity = BATTERY_CAPACITY_MAX;
483 if (capacity < BATTERY_CAPACITY_MIN)
484 capacity = BATTERY_CAPACITY_MIN;
485
486 if (capacity != battery_capacity) {
487 battery_capacity = capacity;
488 battery_status_update(); /* recalculate the battery status */
489 }
490}
491#endif
492
493int get_battery_capacity(void)
494{
495 return battery_capacity;
496}
497
498/* Tells if the battery level is safe for disk writes */
499bool battery_level_safe(void)
500{
501#if defined(NO_LOW_BATTERY_SHUTDOWN)
502 return true;
503#elif ((CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) && (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE))
504 return voltage_now > battery_level_disksafe;
505#elif CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE
506 return percent_now > 0;
507#elif defined(HAVE_BATTERY_SWITCH)
508 /* Cannot rely upon the battery reading to be valid and the
509 * device could be powered externally. */
510 return input_millivolts() > battery_level_disksafe;
511#else
512 return voltage_now > battery_level_disksafe;
513#endif
514}
515
516/* Check to see whether or not we've received an alarm in the last second */
517#ifdef HAVE_RTC_ALARM
518static void power_thread_rtc_process(void)
519{
520 if (rtc_check_alarm_flag())
521 rtc_enable_alarm(false);
522}
523#endif
524
525/* switch off unit if battery level is too low for reliable operation */
526bool query_force_shutdown(void)
527{
528#if CONFIG_CHARGING
529 /* It doesn't make sense to force shutdown when externally powered. */
530 if (power_input_present())
531 return false;
532#endif
533
534#if defined(NO_LOW_BATTERY_SHUTDOWN)
535 return false;
536#elif ((CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) && (CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE))
537 /* If we have both, prefer voltage */
538 return voltage_now < battery_level_shutoff;
539#elif CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE
540 return percent_now == 0;
541#elif defined(HAVE_BATTERY_SWITCH)
542 /* Cannot rely upon the battery reading to be valid and the
543 * device could be powered externally. */
544 return input_millivolts() < battery_level_shutoff;
545#else
546 return voltage_now < battery_level_shutoff;
547#endif
548}
549
550#if defined(HAVE_BATTERY_SWITCH) || defined(HAVE_RESET_BATTERY_FILTER)
551/*
552 * Reset the battery voltage filter to a new value and update the
553 * status.
554 */
555void reset_battery_filter(int millivolts)
556{
557 voltage_avg = millivolts * BATT_AVE_SAMPLES;
558 voltage_now = millivolts;
559#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE
560 /* current would probably be inaccurate too */
561 current_now = _battery_current();
562 current_avg = current_now * BATT_CURRENT_AVE_SAMPLES;
563#endif
564 battery_status_update();
565}
566#endif /* HAVE_BATTERY_SWITCH */
567
568/** Generic charging algorithms for common charging types **/
569#if CONFIG_CHARGING == 0 || CONFIG_CHARGING == CHARGING_SIMPLE
570static inline void powermgmt_init_target(void)
571{
572 /* Nothing to do */
573}
574
575static inline void charging_algorithm_step(void)
576{
577 /* Nothing to do */
578}
579
580static inline void charging_algorithm_close(void)
581{
582 /* Nothing to do */
583}
584#elif CONFIG_CHARGING == CHARGING_MONITOR
585/*
586 * Monitor CHARGING/DISCHARGING state.
587 */
588static inline void powermgmt_init_target(void)
589{
590 /* Nothing to do */
591}
592
593static inline void charging_algorithm_step(void)
594{
595 switch (charger_input_state)
596 {
597 case CHARGER_PLUGGED:
598 case CHARGER:
599 if (charging_state()) {
600 charge_state = CHARGING;
601 break;
602 }
603 /* Fallthrough */
604 case CHARGER_UNPLUGGED:
605 case NO_CHARGER:
606 charge_state = DISCHARGING;
607 break;
608 }
609}
610
611static inline void charging_algorithm_close(void)
612{
613 /* Nothing to do */
614}
615#endif /* CONFIG_CHARGING == * */
616
617#if CONFIG_CHARGING
618/* Shortcut function calls - compatibility, simplicity. */
619
620/* Returns true if any power input is capable of charging. */
621bool charger_inserted(void)
622{
623#ifndef BOOTLOADER
624 unsigned int data = power_thread_inputs;
625#else
626 unsigned int data = power_input_status();
627#endif
628 return data & POWER_INPUT_CHARGER;
629}
630
631/* Returns true if any power input is connected - charging-capable
632 * or not. */
633bool power_input_present(void)
634{
635#ifndef BOOTLOADER
636 unsigned int data = power_thread_inputs;
637#else
638 unsigned int data = power_input_status();
639#endif
640 return data & POWER_INPUT;
641}
642
643/*
644 * Detect charger inserted. Return true if the state is transistional.
645 */
646static inline bool detect_charger(unsigned int pwr)
647{
648 /*
649 * Detect charger plugged/unplugged transitions. On a plugged or
650 * unplugged event, we return immediately, run once through the main
651 * loop (including the subroutines), and end up back here where we
652 * transition to the appropriate steady state charger on/off state.
653 */
654 if (pwr & POWER_INPUT_CHARGER) {
655 switch (charger_input_state)
656 {
657 case NO_CHARGER:
658 case CHARGER_UNPLUGGED:
659 charger_input_state = CHARGER_PLUGGED;
660 break;
661
662 case CHARGER_PLUGGED:
663 queue_broadcast(SYS_CHARGER_CONNECTED, 0);
664 last_sent_battery_level = 0;
665 charger_input_state = CHARGER;
666 break;
667
668 case CHARGER:
669 /* Steady state */
670 return false;
671 }
672 }
673 else { /* charger not inserted */
674 switch (charger_input_state)
675 {
676 case NO_CHARGER:
677 /* Steady state */
678 return false;
679
680 case CHARGER_UNPLUGGED:
681 queue_broadcast(SYS_CHARGER_DISCONNECTED, 0);
682 last_sent_battery_level = 100;
683 charger_input_state = NO_CHARGER;
684 break;
685
686 case CHARGER_PLUGGED:
687 case CHARGER:
688 charger_input_state = CHARGER_UNPLUGGED;
689 break;
690 }
691 }
692
693 /* Transitional state */
694 return true;
695}
696#endif /* CONFIG_CHARGING */
697
698#if CONFIG_BATTERY_MEASURE & VOLTAGE_MEASURE
699static int power_hist_item(void)
700{
701 return voltage_now;
702}
703#else
704static int power_hist_item(void)
705{
706 return percent_now;
707}
708#endif
709
710static void collect_power_history(void)
711{
712 /* rotate the power history */
713 memmove(&power_history[1], &power_history[0],
714 sizeof(power_history) - sizeof(power_history[0]));
715 power_history[0] = power_hist_item();
716}
717
718/*
719 * Monitor the presence of a charger and perform critical frequent steps
720 * such as running the battery voltage filter.
721 */
722static inline void power_thread_step(void)
723{
724 /* If the power off timeout expires, the main thread has failed
725 to shut down the system, and we need to force a power off */
726 if (shutdown_timeout) {
727 shutdown_timeout -= POWER_THREAD_STEP_TICKS;
728
729 if (shutdown_timeout <= 0)
730 power_off();
731 }
732
733#ifdef HAVE_RTC_ALARM
734 power_thread_rtc_process();
735#endif
736
737 /*
738 * Do a digital exponential filter. We don't sample the battery if
739 * the disk is spinning unless we are in USB mode (the disk will most
740 * likely always be spinning in USB mode) or charging.
741 */
742 if (!storage_disk_is_active() || usb_inserted()
743#if CONFIG_CHARGING >= CHARGING_MONITOR
744 || charger_input_state == CHARGER
745#endif
746 ) {
747 average_step(false);
748 battery_status_update();
749 }
750 else if (percent_now < 8) {
751 average_step(true);
752 battery_status_update();
753
754 /*
755 * If battery is low, observe voltage during disk activity.
756 * Shut down if voltage drops below shutoff level and we are not
757 * using NiMH or Alkaline batteries.
758 */
759 if (!shutdown_timeout && query_force_shutdown()) {
760 sys_poweroff();
761 }
762 }
763} /* power_thread_step */
764
765static void power_thread(void)
766{
767 long next_power_hist;
768
769 /* Delay reading the first battery level */
770#ifdef MROBE_100
771 while (_battery_voltage() > 4200) /* gives false readings initially */
772 {
773#elif defined(DX50) || defined(DX90)
774 while (_battery_voltage() < 1) /* can give false readings initially */
775 {
776#elif defined(EROS_QN) || defined(FIIO_M3K) || defined(SHANLING_Q1)
777
778 /* wait until the first battery read is ready */
779 while (_battery_voltage() <= 0)
780 {
781#else
782 {
783#endif
784 sleep(HZ/100);
785 }
786
787#if CONFIG_CHARGING
788 /* Initialize power input status before calling other routines. */
789 power_thread_inputs = power_input_status();
790#endif
791
792 /* call target specific init now */
793 powermgmt_init_target();
794 /* initialize voltage averaging (if available) */
795 average_init();
796 /* get initial battery level value (in %) */
797 battery_status_update();
798 /* get some initial data for the power curve */
799 collect_power_history();
800
801 next_power_hist = current_tick + HZ*60;
802
803 while (1)
804 {
805#if CONFIG_CHARGING
806 unsigned int pwr = power_input_status();
807#ifdef HAVE_BATTERY_SWITCH
808 if ((pwr ^ power_thread_inputs) & POWER_INPUT_BATTERY) {
809 sleep(HZ/10);
810 reset_battery_filter(_battery_voltage());
811 }
812#endif
813 power_thread_inputs = pwr;
814
815 if (!detect_charger(pwr))
816#endif /* CONFIG_CHARGING */
817 {
818 /* Steady state */
819 sleep(POWER_THREAD_STEP_TICKS);
820
821 /* Do common power tasks */
822 power_thread_step();
823 }
824
825 /* Perform target tasks */
826 charging_algorithm_step();
827
828 /* check if some idle or sleep timer wears off */
829 handle_auto_poweroff();
830
831 if (TIME_AFTER(current_tick, next_power_hist)) {
832 /* increment to ensure there is a record for every minute
833 * rather than go forward from the current tick */
834 next_power_hist += HZ*60;
835 collect_power_history();
836 }
837 }
838} /* power_thread */
839
840#if (BATTERY_CAPACITY_DEFAULT > 0) && !defined(BOOTLOADER)
841static bool battery_table_readln(int fd, char * buf, size_t bufsz,
842 const char *name, char **value, int* linect) INIT_ATTR;
843static bool battery_table_readln(int fd, char * buf, size_t bufsz,
844 const char *name, char **value, int* linect)
845{
846 /* reads a line from user battery level file skips comments
847 * if name is NULL and the line is a continuation (no setting:)
848 * or name matches the found setting then remaining line contents are returned in value
849 * name if supplied should contain the name of the setting you are searching for */
850 int rd;
851 char *setting;
852 if (name)
853 {
854 /* DEBUGF("%s Searching for '%s'\n", __func__, name); */
855 lseek(fd, 0, SEEK_SET);
856 *linect = 0;
857 }
858
859 while(1)
860 {
861 rd = read_line(fd, buf, bufsz);
862 if (rd > 0)
863 {
864 /*DEBUGF("\nREAD '%s'\n", buf);*/
865 *linect = *linect + 1;
866 if (buf[0] == '#' || buf[0] == '\0')
867 continue; /* skip empty lines and comments to EOL */
868
869 bool found = settings_parseline(buf, &setting, value);
870
871 if (!name) /* if name is not supplied just return value */
872 {
873 *value = buf;
874 if(found) /* expected more values but got a new setting instead */
875 return false; /* error */
876 }
877 else if (strcasecmp(name, setting) != 0)
878 continue; /* not the correct setting */
879 }
880 break;
881 }
882 return rd > 0;
883}
884#endif
885
886void init_battery_tables(void)
887{
888#if (BATTERY_CAPACITY_DEFAULT > 0) && !defined(BOOTLOADER)
889 /* parse and load user battery levels file */
890#define PWRELEMS (ARRAYLEN(percent_to_volt_discharge))
891
892
893 unsigned short tmparr[PWRELEMS];
894 char buf[MAX_PATH];
895 unsigned int i, bl_op;
896
897 enum { eSHUTOFF = 0, eDISKSAFE, eDISCHARGE, eCHARGE };
898 static const char * const bl_options[4] = {
899 [eSHUTOFF] = "shutoff",
900 [eDISKSAFE] = "disksafe",
901 [eDISCHARGE] = "discharge",
902 [eCHARGE] = "charge"
903 };
904
905 int fd = open(BATTERY_LEVELS_USER, O_RDONLY);
906 int line_num = 0;
907
908 unsigned short val;
909 unsigned short disksafe = *device_battery_tables.disksafe;
910 unsigned short shutoff = *device_battery_tables.shutoff;
911 char *value;
912
913 if (fd < 0)
914 return;
915
916 DEBUGF("%s %s\n", __func__, BATTERY_LEVELS_USER);
917 /* force order of reads to do error checking of values */
918 for(bl_op = 0; bl_op < ARRAYLEN(bl_options); bl_op++)
919 {
920 if(!battery_table_readln(fd, buf, sizeof(buf),
921 bl_options[bl_op], &value, &line_num))
922 {
923 continue;
924 }
925
926 switch(bl_op)
927 {
928 default:
929 goto error_loading;
930 case eSHUTOFF:
931 /*fall-through*/
932 case eDISKSAFE:
933 /* parse single short */
934 DEBUGF("%s ", bl_options[bl_op]);
935
936 while (*value != '\0' && !isdigit(*value))
937 value++;
938 if (*value)
939 {
940 val = atoi(value);
941 DEBUGF("value = %u\n", val);
942 if (bl_op == eDISKSAFE)
943 {
944 if (val < shutoff)
945 {
946 goto error_loading;
947 }
948 disksafe = val;
949 break;
950 }
951 /* shutoff */
952 shutoff = val;
953 break;
954 }
955 goto error_loading;
956 case eDISCHARGE:
957 /*fall-through*/
958 case eCHARGE:
959 /* parse array of short */
960 DEBUGF("%s = { ", bl_options[bl_op]);
961 val = shutoff; /* don't allow a value lower than shutoff */
962 i = 0;
963 while(i < PWRELEMS)
964 {
965 while (*value != '\0' && !isdigit(*value))
966 {value++;}
967 if (*value)
968 {
969 tmparr[i] = atoi(value);
970 while (isdigit(*value)) /* skip digits just read */
971 {value++;}
972 if (tmparr[i] < val)
973 {
974 goto error_loading; /* value is not >= previous */
975 }
976 val = tmparr[i];
977 DEBUGF("%u, ", val);
978 i++;
979 }
980 else if (!battery_table_readln(fd, buf, sizeof(buf),
981 NULL, &value, &line_num))
982 {
983 goto error_loading; /* failed to get another line */
984 }
985
986 } /* while */
987 DEBUGF("}\n");
988
989 /* if we made it here, the values should be OK to use */
990 if (bl_op == eCHARGE)
991 {
992#if CONFIG_CHARGING
993 memcpy(device_battery_tables.charge, &tmparr, PWRELEMS);
994#endif
995 break;
996 }
997 memcpy(device_battery_tables.discharge, &tmparr, PWRELEMS);
998 break;
999 } /* switch */
1000 } /* for */
1001 close(fd);
1002
1003 *device_battery_tables.disksafe = disksafe;
1004 *device_battery_tables.shutoff = shutoff;
1005 device_battery_tables.isdefault = false;
1006 battery_status_update();
1007
1008 return;
1009
1010error_loading:
1011 if (fd >= 0)
1012 close(fd);
1013 splashf(HZ * 2, "Error line:(%d) loading %s", line_num, BATTERY_LEVELS_USER);
1014 DEBUGF("Error line:(%d) loading %s\n", line_num, BATTERY_LEVELS_USER);
1015#undef PWRELEMS
1016#endif /* ndef BOOTLOADER*/
1017}
1018
1019void powermgmt_init(void)
1020{
1021 create_thread(power_thread, power_stack, sizeof(power_stack), 0,
1022 power_thread_name IF_PRIO(, PRIORITY_SYSTEM)
1023 IF_COP(, CPU));
1024}
1025
1026/* Various hardware housekeeping tasks relating to shutting down the player */
1027void shutdown_hw(enum shutdown_type sd_type)
1028{
1029 charging_algorithm_close();
1030 audio_stop();
1031
1032 if (battery_level_safe()) { /* do not save on critical battery */
1033 font_unload_all();
1034
1035/* Commit pending writes if needed. Even though we don't do write caching,
1036 things like flash translation layers may need this to commit scattered
1037 pages to their final locations. So far only used for iPod Nano 2G. */
1038#ifdef HAVE_STORAGE_FLUSH
1039 storage_flush();
1040#endif
1041
1042 if (storage_disk_is_active())
1043 storage_spindown(1);
1044 }
1045
1046 audiohw_close();
1047
1048 /* If HD is still active we try to wait for spindown, otherwise the
1049 shutdown_timeout in power_thread_step will force a power off */
1050 while (storage_disk_is_active())
1051 sleep(HZ/10);
1052
1053#ifndef HAVE_LCD_COLOR
1054 lcd_set_contrast(0);
1055#endif
1056#ifdef HAVE_REMOTE_LCD
1057 lcd_remote_set_contrast(0);
1058#endif
1059#ifdef HAVE_LCD_SHUTDOWN
1060 lcd_shutdown();
1061#endif
1062
1063 /* Small delay to make sure all HW gets time to flush. Especially
1064 eeprom chips are quite slow and might be still writing the last
1065 byte. */
1066 sleep(HZ/4);
1067
1068 switch (sd_type) {
1069 case SHUTDOWN_POWER_OFF:
1070 default:
1071 power_off();
1072 break;
1073
1074 case SHUTDOWN_REBOOT:
1075 system_reboot();
1076 break;
1077 }
1078}
1079
1080void set_poweroff_timeout(int timeout)
1081{
1082 poweroff_timeout = timeout;
1083}
1084
1085void reset_poweroff_timer(void)
1086{
1087 last_event_tick = current_tick;
1088 if (sleeptimer_active && sleeptimer_key_restarts)
1089 set_sleep_timer(sleeptimer_duration);
1090}
1091
1092#ifndef BOOTLOADER
1093static void sys_shutdown_common(void)
1094{
1095 /* If the main thread fails to shut down the system, we will force a
1096 power off after an 20 second timeout - 28 seconds if recording */
1097 if (shutdown_timeout == 0) {
1098#if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
1099 pcf50606_reset_timeout(); /* Reset timer on first attempt only */
1100#endif
1101#ifdef HAVE_RECORDING
1102 if (audio_status() & AUDIO_STATUS_RECORD)
1103 shutdown_timeout += HZ*8;
1104#endif
1105#ifdef IPOD_NANO2G
1106 /* The FTL alone may take half a minute to shut down cleanly. */
1107 shutdown_timeout += HZ*60;
1108#else
1109 shutdown_timeout += HZ*20;
1110#endif
1111 }
1112}
1113#endif /* BOOTLOADER */
1114
1115void sys_poweroff(void)
1116{
1117#ifndef BOOTLOADER
1118 logf("sys_poweroff()");
1119 sys_shutdown_common();
1120 queue_broadcast(SYS_POWEROFF, 0);
1121#endif
1122}
1123
1124/* not to be confused with system_reboot... :( */
1125void sys_reboot(void)
1126{
1127#ifndef BOOTLOADER
1128 logf("sys_reboot()");
1129 sys_shutdown_common();
1130 queue_broadcast(SYS_REBOOT, 0);
1131#endif
1132}
1133
1134void cancel_shutdown(void)
1135{
1136 logf("cancel_shutdown()");
1137
1138#if (defined(IAUDIO_X5) || defined(IAUDIO_M5) || defined(COWON_D2)) && !defined(SIMULATOR)
1139 /* TODO: Move some things to target/ tree */
1140 if (shutdown_timeout)
1141 pcf50606_reset_timeout();
1142#endif
1143
1144 shutdown_timeout = 0;
1145}
1146
1147void set_sleeptimer_duration(int minutes)
1148{
1149 set_sleep_timer(minutes * 60);
1150}
1151
1152static void set_sleep_timer(int seconds)
1153{
1154 if (seconds) {
1155 sleeptimer_active = true;
1156 sleeptimer_endtick = current_tick + seconds * HZ;
1157 }
1158 else {
1159 sleeptimer_active = false;
1160 sleeptimer_endtick = 0;
1161 }
1162 sleeptimer_duration = seconds;
1163}
1164
1165bool get_sleep_timer_active(void)
1166{
1167 return sleeptimer_active;
1168}
1169
1170int get_sleep_timer(void)
1171{
1172 if (sleeptimer_active && (sleeptimer_endtick >= current_tick))
1173 return (sleeptimer_endtick - current_tick) / HZ;
1174 else
1175 return 0;
1176}
1177
1178void set_keypress_restarts_sleep_timer(bool enable)
1179{
1180 sleeptimer_key_restarts = enable;
1181}
1182
1183#ifndef BOOTLOADER
1184static void handle_sleep_timer(void)
1185{
1186 if (TIME_AFTER(current_tick, sleeptimer_endtick)) {
1187 if (usb_inserted()
1188#if CONFIG_CHARGING
1189 || charger_input_state != NO_CHARGER
1190#endif
1191 ) {
1192 DEBUGF("Sleep timer timeout. Stopping...\n");
1193 audio_pause();
1194 set_sleep_timer(0);
1195 backlight_off(); /* Nighty, nighty... */
1196 }
1197 else {
1198 DEBUGF("Sleep timer timeout. Shutting off...\n");
1199 // sys_poweroff();
1200 }
1201 }
1202}
1203#endif /* BOOTLOADER */
1204
1205/*
1206 * We shut off in the following cases:
1207 * 1) The unit is idle, not playing music
1208 * 2) The unit is playing music, but is paused
1209 * 3) The battery level has reached shutdown limit
1210 *
1211 * We do not shut off in the following cases:
1212 * 1) The USB is connected
1213 * 2) The charger is connected
1214 * 3) We are recording, or recording with pause
1215 * 4) The radio is playing
1216 */
1217void handle_auto_poweroff(void)
1218{
1219#ifndef BOOTLOADER
1220 long timeout = poweroff_timeout*60*HZ;
1221 int audio_stat = audio_status();
1222 long tick = current_tick;
1223
1224 /*
1225 * Inhibit shutdown as long as the charger is plugged in. If it is
1226 * unplugged, wait for a timeout period and then shut down.
1227 */
1228 if (audio_stat == AUDIO_STATUS_PLAY
1229#if CONFIG_CHARGING
1230 || charger_input_state == CHARGER
1231#endif
1232 ) {
1233 last_event_tick = current_tick;
1234 }
1235
1236 if (!shutdown_timeout && query_force_shutdown()) {
1237 backlight_on();
1238 sys_poweroff();
1239 }
1240
1241 if (timeout &&
1242#if CONFIG_TUNER
1243 !(get_radio_status() & FMRADIO_PLAYING) &&
1244#endif
1245 !usb_inserted() &&
1246 (audio_stat == 0 ||
1247 audio_stat == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE)))
1248 {
1249 if (TIME_AFTER(tick, last_event_tick + timeout)
1250#if !(CONFIG_PLATFORM & PLATFORM_HOSTED)
1251 && TIME_AFTER(tick, storage_last_disk_activity() + timeout)
1252#endif
1253 ) {
1254 // sys_poweroff();
1255 }
1256 }
1257
1258 if (sleeptimer_active)
1259 handle_sleep_timer();
1260#endif
1261}