summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/powermgmt.c132
1 files changed, 70 insertions, 62 deletions
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index 0fdf8c8fe0..59d1a2fe7b 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -63,35 +63,39 @@ void set_battery_capacity(int capacity)
63} 63}
64#else /* not SIMULATOR */ 64#else /* not SIMULATOR */
65 65
66int battery_capacity = 1500; /* only a default value */
67int battery_level_cached = -1; /* battery level of this minute, updated once per minute */
68
66static int poweroff_idle_timeout_value[15] = 69static int poweroff_idle_timeout_value[15] =
67{ 70{
68 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 30, 45, 60 71 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 30, 45, 60
69}; 72};
70 73
71static int percent_to_volt_nocharge[11] = /* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */ 74static int percent_to_volt_decharge[11] = /* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */
72{ 75{
73 450, 481, 491, 497, 503, 507, 512, 514, 517, 528, 560 76 /* original values were taken directly after charging, */
77 /* but it should show 100% after turning off the device for some hours, too */
78 450, 481, 491, 497, 503, 507, 512, 514, 517, 525, 540 /* orig. values: ...,528,560 */
74}; 79};
75 80
76int battery_capacity = 1500; /* only a default value */
77
78void set_battery_capacity(int capacity) 81void set_battery_capacity(int capacity)
79{ 82{
80 battery_capacity = capacity; 83 battery_capacity = capacity;
81 if ((battery_capacity > BATTERY_CAPACITY_MAX) || (battery_capacity < 1500)) 84 if (battery_capacity > BATTERY_CAPACITY_MAX)
85 battery_capacity = BATTERY_CAPACITY_MAX;
86 if (battery_capacity < 1500)
82 battery_capacity = 1500; 87 battery_capacity = 1500;
83} 88}
84 89
85#ifdef HAVE_CHARGE_CTRL 90#ifdef HAVE_CHARGE_CTRL
86 91
87char power_message[POWER_MESSAGE_LEN] = ""; 92char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in debug menu */
88char charge_restart_level = CHARGE_RESTART_HI; 93char charge_restart_level = CHARGE_RESTART_HI; /* level at which charging starts */
89 94int powermgmt_last_cycle_startstop_min = 25; /* how many minutes ago was the charging started or stopped? */
90int powermgmt_last_cycle_startstop_min = 20; /* how many minutes ago was the charging started or stopped? */ 95int powermgmt_last_cycle_level = 0; /* which level had the batteries at this time? */
91int powermgmt_last_cycle_level = 0; /* which level had the batteries at this time? */
92bool trickle_charge_enabled = true; 96bool trickle_charge_enabled = true;
93int trickle_sec = 0; /* how many seconds should the charger be enabled per minute for trickle charging? */ 97int trickle_sec = 0; /* how many seconds should the charger be enabled per minute for trickle charging? */
94int charge_state = 0; /* at the beginning, the charger does nothing */ 98int charge_state = 0; /* at the beginning, the charger does nothing */
95 99
96static int percent_to_volt_charge[11] = /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ 100static int percent_to_volt_charge[11] = /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */
97{ 101{
@@ -104,11 +108,6 @@ void enable_trickle_charge(bool on)
104} 108}
105#endif /* HAVE_CHARGE_CTRL */ 109#endif /* HAVE_CHARGE_CTRL */
106 110
107int battery_lazyness[20] = /* how does the battery react when plugging in/out the charger */
108{
109 0, 17, 31, 42, 52, 60, 67, 72, 77, 81, 84, 87, 89, 91, 92, 94, 95, 95, 96, 97
110};
111
112static char power_stack[DEFAULT_STACK_SIZE]; 111static char power_stack[DEFAULT_STACK_SIZE];
113static char power_thread_name[] = "power"; 112static char power_thread_name[] = "power";
114 113
@@ -121,7 +120,6 @@ static unsigned long sleeptimer_endtick;
121 120
122unsigned short power_history[POWER_HISTORY_LEN]; 121unsigned short power_history[POWER_HISTORY_LEN];
123 122
124
125int battery_time(void) 123int battery_time(void)
126{ 124{
127 return powermgmt_est_runningtime_min; 125 return powermgmt_est_runningtime_min;
@@ -146,8 +144,8 @@ int voltage_to_percent(int voltage, int* table)
146 } 144 }
147} 145}
148 146
149/* Returns battery level in percent */ 147/* update battery level, called only once per minute */
150int battery_level(void) 148void battery_level_update(void)
151{ 149{
152 int level = 0; 150 int level = 0;
153 int c = 0; 151 int c = 0;
@@ -171,33 +169,42 @@ int battery_level(void)
171 if(level < BATTERY_LEVEL_EMPTY) 169 if(level < BATTERY_LEVEL_EMPTY)
172 level = BATTERY_LEVEL_EMPTY; 170 level = BATTERY_LEVEL_EMPTY;
173 171
174 /* level now stores the voltage in centivolts */
175 /* let's calculate a percentage now with using the voltage arrays */
176
177#ifdef HAVE_CHARGE_CTRL 172#ifdef HAVE_CHARGE_CTRL
178 if (powermgmt_last_cycle_startstop_min < 20) { 173 if (charge_state == 0) { /* decharge */
179 /* the batteries are lazy, so take a value between the result of the two table lookups */ 174 level = voltage_to_percent(level, percent_to_volt_decharge);
180 if (charge_state == 1) 175 } else if (charge_state == 1) { /* charge */
181 level = (voltage_to_percent(level, percent_to_volt_charge) 176 level = voltage_to_percent(level, percent_to_volt_charge);
182 * battery_lazyness[powermgmt_last_cycle_startstop_min] 177 } else {/* in trickle charge, the battery is per definition 100% full */
183 + voltage_to_percent(level, percent_to_volt_nocharge) 178 battery_level_cached = level = 100;
184 * (100 - battery_lazyness[powermgmt_last_cycle_startstop_min])) / 100;
185 else
186 level = (voltage_to_percent(level, percent_to_volt_nocharge)
187 * battery_lazyness[powermgmt_last_cycle_startstop_min]
188 + voltage_to_percent(level, percent_to_volt_charge)
189 * (100 - battery_lazyness[powermgmt_last_cycle_startstop_min])) / 100;
190 } else {
191 if (charge_state == 1)
192 level = voltage_to_percent(level, percent_to_volt_charge);
193 else
194 level = voltage_to_percent(level, percent_to_volt_nocharge);
195 } 179 }
196#else 180#else
197 level = voltage_to_percent(level, percent_to_volt_nocharge); /* always use the nocharge table */ 181 level = voltage_to_percent(level, percent_to_volt_decharge); /* always use the decharge table */
198#endif 182#endif
199 183
200 return level; 184 if (battery_level_cached == -1) { /* first run of this procedure */
185 /* the battery voltage is usually a little lower directly after turning on, because the disk was used heavily */
186 /* raise it by 5 % */
187 battery_level_cached = (level > 95) ? 100 : level + 5;
188 } else {
189 /* the level is allowed to be +1/-1 of the last value when usb not connected */
190 /* and to be +1/-3 of the last value when usb is connected */
191 if (level > battery_level_cached + 1)
192 level = battery_level_cached + 1;
193 if (usb_inserted()) {
194 if (level < battery_level_cached - 3)
195 level = battery_level_cached - 3;
196 } else {
197 if (level < battery_level_cached - 1)
198 level = battery_level_cached - 1;
199 }
200 battery_level_cached = level;
201 }
202}
203
204/* Returns battery level in percent */
205int battery_level(void)
206{
207 return battery_level_cached;
201} 208}
202 209
203/* Tells if the battery level is safe for disk writes */ 210/* Tells if the battery level is safe for disk writes */
@@ -301,7 +308,6 @@ static void handle_auto_poweroff(void)
301 * docs/CHARGING_ALGORITHM. 308 * docs/CHARGING_ALGORITHM.
302 */ 309 */
303 310
304
305static void power_thread(void) 311static void power_thread(void)
306{ 312{
307 int i; 313 int i;
@@ -310,7 +316,7 @@ static void power_thread(void)
310#ifdef HAVE_CHARGE_CTRL 316#ifdef HAVE_CHARGE_CTRL
311 int delta; 317 int delta;
312 int charged_time = 0; 318 int charged_time = 0;
313 int charge_max_time_now = 0; 319 int charge_max_time_now = 0; /* max. charging duration, calculated at beginning of charging */
314 int charge_pause = 0; /* no charging pause at the beginning */ 320 int charge_pause = 0; /* no charging pause at the beginning */
315 int trickle_time = 0; /* how many minutes trickle charging already? */ 321 int trickle_time = 0; /* how many minutes trickle charging already? */
316#endif 322#endif
@@ -340,7 +346,7 @@ static void power_thread(void)
340 sleep(HZ*POWER_AVG_SLEEP); 346 sleep(HZ*POWER_AVG_SLEEP);
341 } 347 }
342 avg = avg / ((ok_samples) ? ok_samples : spin_samples); 348 avg = avg / ((ok_samples) ? ok_samples : spin_samples);
343 349
344 /* rotate the power history */ 350 /* rotate the power history */
345 for (i = 0; i < POWER_HISTORY_LEN-1; i++) 351 for (i = 0; i < POWER_HISTORY_LEN-1; i++)
346 power_history[i] = power_history[i+1]; 352 power_history[i] = power_history[i+1];
@@ -348,20 +354,19 @@ static void power_thread(void)
348 /* insert new value in the end, in centivolts 8-) */ 354 /* insert new value in the end, in centivolts 8-) */
349 power_history[POWER_HISTORY_LEN-1] = (avg * BATTERY_SCALE_FACTOR) / 10000; 355 power_history[POWER_HISTORY_LEN-1] = (avg * BATTERY_SCALE_FACTOR) / 10000;
350 356
357 /* update battery level every minute, ignoring first 15 minutes after start charge/decharge */
358#ifdef HAVE_CHARGE_CTRL
359 if ((powermgmt_last_cycle_startstop_min > 25) || (charge_state > 1))
360#endif
361 battery_level_update();
362
351 /* calculate estimated remaining running time */ 363 /* calculate estimated remaining running time */
352 /* not charging: remaining running time */ 364 /* decharging: remaining running time */
353 /* charging: remaining charging time */ 365 /* charging: remaining charging time */
354 366
355#ifdef HAVE_CHARGE_CTRL 367#ifdef HAVE_CHARGE_CTRL
356 if (charge_state == 1) 368 if (charge_state == 1)
357 /* if taking the nocharge battery level, charging lasts 30% longer than the value says */ 369 powermgmt_est_runningtime_min = (100 - battery_level()) * battery_capacity / 100 * 60 / CURRENT_CHARGING;
358 /* so consider it because there's the battery lazyness inside the the battery_level */
359 if (powermgmt_last_cycle_startstop_min < 20) {
360 i = (100 - battery_lazyness[powermgmt_last_cycle_startstop_min]) * 30 / 100 ; /* 0..30 */
361 powermgmt_est_runningtime_min = (100 - battery_level()) * battery_capacity / 100 * (100 + i) / 100 * 60 / CURRENT_CHARGING;
362 } else {
363 powermgmt_est_runningtime_min = (100 - battery_level()) * battery_capacity / 100 * 60 / CURRENT_CHARGING;
364 }
365 else { 370 else {
366 current = CURRENT_NORMAL; 371 current = CURRENT_NORMAL;
367 if ((backlight_get_timeout() == 1) || (charger_inserted() && backlight_get_on_when_charging())) 372 if ((backlight_get_timeout() == 1) || (charger_inserted() && backlight_get_on_when_charging()))
@@ -479,6 +484,7 @@ static void power_thread(void)
479 if (trickle_time++ > TRICKLE_MAX_TIME + TOPOFF_MAX_TIME) { 484 if (trickle_time++ > TRICKLE_MAX_TIME + TOPOFF_MAX_TIME) {
480 trickle_sec = 0; /* show in debug menu that trickle is off */ 485 trickle_sec = 0; /* show in debug menu that trickle is off */
481 charge_state = 0; /* 0: decharging/charger off, 1: charge, 2: top-off, 3: trickle */ 486 charge_state = 0; /* 0: decharging/charger off, 1: charge, 2: top-off, 3: trickle */
487 powermgmt_last_cycle_startstop_min = 0;
482 } 488 }
483 489
484 if ((charge_state == 2) && (trickle_time > TOPOFF_MAX_TIME)) /* change state? */ 490 if ((charge_state == 2) && (trickle_time > TOPOFF_MAX_TIME)) /* change state? */
@@ -492,13 +498,15 @@ static void power_thread(void)
492 charger_enable(false); 498 charger_enable(false);
493 499
494 /* if battery is not full, enable charging */ 500 /* if battery is not full, enable charging */
495 if (battery_level() < charge_restart_level) { 501 /* make sure charging starts if 1%-lazyness in battery_level_update() is too slow */
502 if ( (battery_level() < charge_restart_level)
503 || (power_history[POWER_HISTORY_LEN-1] < BATTERY_LEVEL_DANGEROUS)) {
496 if (charge_pause) { 504 if (charge_pause) {
497 DEBUGF("power: batt level < restart level, but charge pause, not enabling\n"); 505 DEBUGF("power: batt level < restart level, but charge pause, not enabling\n");
498 snprintf(power_message, POWER_MESSAGE_LEN, "chg pause %d min", charge_pause); 506 snprintf(power_message, POWER_MESSAGE_LEN, "chg pause %d min", charge_pause);
499 } else { 507 } else {
500 /* calculate max charge time depending on current battery level */ 508 /* calculate max charge time depending on current battery level */
501 /* take 35% more because battery level is not linear */ 509 /* take 35% more because some more energy is used for heating up the battery */
502 i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500; 510 i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500;
503 charge_max_time_now = i * (100 + 35 - battery_level()) / 100; 511 charge_max_time_now = i * (100 + 35 - battery_level()) / 100;
504 if (charge_max_time_now > i) { 512 if (charge_max_time_now > i) {
@@ -529,10 +537,7 @@ static void power_thread(void)
529 /* charger not inserted but was enabled */ 537 /* charger not inserted but was enabled */
530 DEBUGF("power: charger disconnected, disabling\n"); 538 DEBUGF("power: charger disconnected, disabling\n");
531 powermgmt_last_cycle_level = battery_level(); 539 powermgmt_last_cycle_level = battery_level();
532 /* if the user only charged some minutes, we don't really have */ 540 powermgmt_last_cycle_startstop_min = 0;
533 /* a battery level that's usual for charging */
534 /* the next line prevents the battery level being too low when the charger is connected for only some minutes */
535 powermgmt_last_cycle_startstop_min = (powermgmt_last_cycle_startstop_min > 10) ? 0 : 20;
536 /* show in debug menu that trickle is off */ 541 /* show in debug menu that trickle is off */
537 trickle_sec = 0; 542 trickle_sec = 0;
538 charger_enable(false); 543 charger_enable(false);
@@ -565,9 +570,11 @@ void power_init(void)
565 /* initialize the history with a single sample to prevent level 570 /* initialize the history with a single sample to prevent level
566 flickering during the first minute of execution */ 571 flickering during the first minute of execution */
567 power_history[POWER_HISTORY_LEN-1] = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000; 572 power_history[POWER_HISTORY_LEN-1] = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000;
573 /* calculate the first battery level */
574 battery_level_update();
568 /* calculate the remaining time to that the info screen displays something useful */ 575 /* calculate the remaining time to that the info screen displays something useful */
569 powermgmt_est_runningtime_min = battery_level() * battery_capacity / 100 * 60 / CURRENT_NORMAL; 576 powermgmt_est_runningtime_min = battery_level() * battery_capacity / 100 * 60 / CURRENT_NORMAL;
570 577
571#ifdef HAVE_CHARGE_CTRL 578#ifdef HAVE_CHARGE_CTRL
572 snprintf(power_message, POWER_MESSAGE_LEN, "Powermgmt started"); 579 snprintf(power_message, POWER_MESSAGE_LEN, "Powermgmt started");
573 580
@@ -575,6 +582,7 @@ void power_init(void)
575 if (power_history[POWER_HISTORY_LEN-1] < BATTERY_LEVEL_DANGEROUS) 582 if (power_history[POWER_HISTORY_LEN-1] < BATTERY_LEVEL_DANGEROUS)
576 charger_enable(true); 583 charger_enable(true);
577#endif 584#endif
585
578 create_thread(power_thread, power_stack, sizeof(power_stack), power_thread_name); 586 create_thread(power_thread, power_stack, sizeof(power_stack), power_thread_name);
579} 587}
580 588