Fix voicing of incorrect run time (top time instead of run time). Simplify runtime...
[kugel-rb.git] / apps / plugins / battery_bench.c
blob0cc028ebd096795c649600ae61e4fb47e9df758c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
11 * Copyright (C) 2006 Alexander Spyridakis, Hristo Kovachev
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #ifndef SIMULATOR /* not for the simulator */
24 #include "plugin.h"
25 PLUGIN_HEADER
27 #define BATTERY_LOG "/battery_bench.txt"
28 #define BUF_SIZE 16000
29 #define DISK_SPINDOWN_TIMEOUT 3600
31 #define EV_EXIT 1337
33 /* seems to work with 1300, but who knows... */
34 #define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200
36 #if CONFIG_KEYPAD == RECORDER_PAD
38 #define BATTERY_ON BUTTON_PLAY
39 #define BATTERY_OFF BUTTON_OFF
40 #define BATTERY_ON_TXT "PLAY - start"
41 #define BATTERY_OFF_TXT "OFF - quit"
43 #if BUTTON_REMOTE != 0
44 #define BATTERY_RC_ON BUTTON_RC_PLAY
45 #define BATTERY_RC_OFF BUTTON_RC_STOP
46 #endif
48 #elif CONFIG_KEYPAD == ONDIO_PAD
50 #define BATTERY_ON BUTTON_RIGHT
51 #define BATTERY_OFF BUTTON_OFF
52 #define BATTERY_ON_TXT "RIGHT - start"
53 #define BATTERY_OFF_TXT "OFF - quit"
55 #elif CONFIG_KEYPAD == PLAYER_PAD
57 #define BATTERY_ON BUTTON_PLAY
58 #define BATTERY_OFF BUTTON_STOP
60 #define BATTERY_RC_ON BUTTON_RC_PLAY
61 #define BATTERY_RC_OFF BUTTON_RC_STOP
63 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
64 (CONFIG_KEYPAD == IRIVER_H300_PAD)
66 #define BATTERY_ON BUTTON_ON
67 #define BATTERY_RC_ON BUTTON_RC_ON
69 #define BATTERY_OFF BUTTON_OFF
70 #define BATTERY_RC_OFF BUTTON_RC_STOP
72 #define BATTERY_ON_TXT "PLAY - start"
73 #define BATTERY_OFF_TXT "STOP - quit"
75 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
76 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
77 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
79 #define BATTERY_ON BUTTON_PLAY
80 #define BATTERY_OFF BUTTON_MENU
81 #define BATTERY_ON_TXT "PLAY - start"
82 #define BATTERY_OFF_TXT "MENU - quit"
84 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
86 #define BATTERY_ON BUTTON_SELECT
87 #define BATTERY_OFF BUTTON_POWER
88 #define BATTERY_ON_TXT "SELECT - start"
89 #define BATTERY_OFF_TXT "POWER - quit"
91 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
93 #define BATTERY_ON BUTTON_SELECT
94 #define BATTERY_OFF BUTTON_PLAY
95 #define BATTERY_ON_TXT "SELECT - start"
96 #define BATTERY_OFF_TXT "PLAY - quit"
98 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
99 (CONFIG_KEYPAD == SANSA_C200_PAD)
100 #define BATTERY_ON BUTTON_SELECT
101 #define BATTERY_OFF BUTTON_POWER
102 #define BATTERY_ON_TXT "SELECT - start"
103 #define BATTERY_OFF_TXT "POWER - quit"
105 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
107 #define BATTERY_ON BUTTON_PLAY
108 #define BATTERY_OFF BUTTON_POWER
109 #define BATTERY_ON_TXT "PLAY - start"
110 #define BATTERY_OFF_TXT "POWER - quit"
112 #elif CONFIG_KEYPAD == GIGABEAT_PAD
114 #define BATTERY_ON BUTTON_SELECT
115 #define BATTERY_OFF BUTTON_POWER
116 #define BATTERY_ON_TXT "SELECT - start"
117 #define BATTERY_OFF_TXT "POWER - quit"
119 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
121 #define BATTERY_ON BUTTON_SELECT
122 #define BATTERY_OFF BUTTON_BACK
123 #define BATTERY_ON_TXT "SELECT - start"
124 #define BATTERY_OFF_TXT "BACK - quit"
126 #elif CONFIG_KEYPAD == MROBE500_PAD
128 #define BATTERY_ON BUTTON_RC_PLAY
129 #define BATTERY_OFF BUTTON_POWER
130 #define BATTERY_ON_TXT "PLAY - start"
131 #define BATTERY_OFF_TXT "POWER - quit"
133 #elif CONFIG_KEYPAD == MROBE100_PAD
135 #define BATTERY_ON BUTTON_SELECT
136 #define BATTERY_OFF BUTTON_POWER
137 #define BATTERY_ON_TXT "SELECT - start"
138 #define BATTERY_OFF_TXT "POWER - quit"
140 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
142 #define BATTERY_ON BUTTON_PLAY
143 #define BATTERY_OFF BUTTON_REC
144 #define BATTERY_RC_ON BUTTON_RC_PLAY
145 #define BATTERY_RC_OFF BUTTON_RC_REC
146 #define BATTERY_ON_TXT "PLAY - start"
147 #define BATTERY_OFF_TXT "REC - quit"
149 #elif CONFIG_KEYPAD == COWOND2_PAD
151 #define BATTERY_OFF BUTTON_POWER
152 #define BATTERY_OFF_TXT "POWER - quit"
154 #else
155 #error No keymap defined!
156 #endif
158 #ifdef HAVE_TOUCHPAD
159 #ifndef BATTERY_ON
160 #define BATTERY_ON BUTTON_CENTER
161 #endif
162 #ifndef BATTERY_OFF
163 #define BATTERY_OFF BUTTON_TOPLEFT
164 #endif
165 #ifndef BATTERY_ON_TXT
166 #define BATTERY_ON_TXT "CENTRE - start"
167 #endif
168 #ifndef BATTERY_OFF_TXT
169 #define BATTERY_OFF_TXT "TOPLEFT - quit"
170 #endif
171 #endif
173 /****************************** Plugin Entry Point ****************************/
174 static const struct plugin_api* rb;
175 MEM_FUNCTION_WRAPPERS(rb);
176 int main(void);
177 bool exit_tsr(bool);
178 void thread(void);
181 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
183 (void)parameter;
184 rb = api;
186 return main();
189 /* Struct for battery information */
190 struct batt_info
192 /* the size of the struct elements is optimised to make the struct size
193 * a power of 2 */
194 long ticks;
195 int eta;
196 unsigned int voltage;
197 short level;
198 unsigned short flags;
199 } bat[BUF_SIZE/sizeof(struct batt_info)];
201 struct thread_entry *thread_id;
202 struct event_queue thread_q;
204 bool exit_tsr(bool reenter)
206 bool exit = true;
207 (void)reenter;
208 rb->lcd_clear_display();
209 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
210 rb->lcd_puts_scroll(0, 1, "Press OFF to cancel the test");
211 #ifdef HAVE_LCD_BITMAP
212 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
213 #endif
214 rb->lcd_update();
216 if (rb->button_get(true) != BATTERY_OFF)
217 exit = false;
218 if (exit)
220 rb->queue_post(&thread_q, EV_EXIT, 0);
221 rb->thread_wait(thread_id);
222 /* remove the thread's queue from the broadcast list */
223 rb->queue_delete(&thread_q);
224 return true;
226 else return false;
229 #define BIT_CHARGER 0x1
230 #define BIT_CHARGING 0x2
231 #define BIT_USB_POWER 0x4
233 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
235 /* use long for aligning */
236 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
238 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
239 unsigned int charge_state(void)
241 unsigned int ret = 0;
242 #if CONFIG_CHARGING
243 if(rb->charger_inserted())
244 ret = BIT_CHARGER;
245 #if CONFIG_CHARGING == CHARGING_MONITOR
246 if(rb->charging_state())
247 ret |= BIT_CHARGING;
248 #endif
249 #endif
250 #ifdef HAVE_USB_POWER
251 if(rb->usb_powered())
252 ret |= BIT_USB_POWER;
253 #endif
254 return ret;
256 #endif
258 void thread(void)
260 bool got_info = false, timeflag = false, in_usb_mode = false;
261 int fd, buffelements, tick = 1, i = 0, skipped = 0, exit = 0;
262 int fst = 0, lst = 0; /* first and last skipped tick */
263 unsigned int last_voltage = 0;
264 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
265 unsigned int last_state = 0;
266 #endif
267 long sleep_time = 5 * HZ;
269 struct queue_event ev;
271 buffelements = sizeof(bat)/sizeof(struct batt_info);
273 #ifndef HAVE_FLASH_STORAGE
274 if(rb->global_settings->disk_spindown > 1)
275 sleep_time = (rb->global_settings->disk_spindown - 1) * HZ;
276 #endif
280 if(!in_usb_mode && got_info &&
281 (exit || timeflag || rb->ata_disk_is_active()) )
283 int last, secs, j, temp = skipped;
285 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
286 if(fd < 0)
287 exit = 1;
288 else
292 if(skipped)
294 last = buffelements;
295 fst /= HZ;
296 lst /= HZ;
297 rb->fdprintf(fd,"-Skipped %d measurements from "
298 "%02d:%02d:%02d to %02d:%02d:%02d-\n",skipped,
299 HMS(fst),HMS(lst));
300 skipped = 0;
302 else
304 last = i;
305 i = 0;
308 for(j = i; j < last; j++)
310 secs = bat[j].ticks/HZ;
311 rb->fdprintf(fd,
312 "%02d:%02d:%02d, %05d, %03d%%, "
313 "%02d:%02d, %04d, %04d"
314 #if CONFIG_CHARGING
315 ", %c"
316 #if CONFIG_CHARGING == CHARGING_MONITOR
317 ", %c"
318 #endif
319 #endif
320 #ifdef HAVE_USB_POWER
321 ", %c"
322 #endif
323 "\n",
325 HMS(secs), secs, bat[j].level,
326 bat[j].eta / 60, bat[j].eta % 60,
327 bat[j].voltage,
328 temp + 1 + (j-i)
329 #if CONFIG_CHARGING
330 ,(bat[j].flags & BIT_CHARGER)?'A':'-'
331 #if CONFIG_CHARGING == CHARGING_MONITOR
332 ,(bat[j].flags & BIT_CHARGING)?'C':'-'
333 #endif
334 #endif
335 #ifdef HAVE_USB_POWER
336 ,(bat[j].flags & BIT_USB_POWER)?'U':'-'
337 #endif
340 if(!j % 100 && !j) /* yield() at every 100 writes */
341 rb->yield();
343 temp += j - i;
345 }while(i != 0);
347 rb->close(fd);
348 tick = *rb->current_tick;
349 got_info = false;
350 timeflag = false;
353 else
355 unsigned int current_voltage;
357 #if CONFIG_CODEC == SWCODEC
358 !rb->pcm_is_playing()
359 #else
360 !rb->mp3_is_playing()
361 #endif
362 && (*rb->current_tick - tick) > DISK_SPINDOWN_TIMEOUT * HZ)
363 timeflag = true;
365 if(last_voltage != (current_voltage=rb->battery_voltage())
366 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
367 || last_state != charge_state()
368 #endif
371 if(i == buffelements)
373 if(!skipped++)
374 fst = bat[0].ticks;
375 i = 0;
377 else if(skipped)
379 skipped++;
380 lst = bat[i].ticks;
382 bat[i].ticks = *rb->current_tick;
383 bat[i].level = rb->battery_level();
384 bat[i].eta = rb->battery_time();
385 last_voltage = bat[i].voltage = current_voltage;
386 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
387 bat[i].flags = last_state = charge_state();
388 #endif
389 i++;
390 got_info = true;
395 if(exit)
397 if(exit == 2)
398 rb->splash(HZ,
399 #ifdef HAVE_LCD_BITMAP
400 "Exiting battery_bench...");
401 #else
402 "bench exit");
403 #endif
404 return;
407 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
408 switch (ev.id)
410 case SYS_USB_CONNECTED:
411 in_usb_mode = true;
412 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
413 break;
414 case SYS_USB_DISCONNECTED:
415 in_usb_mode = false;
416 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
417 break;
418 case SYS_POWEROFF:
419 exit = 1;
420 break;
421 case EV_EXIT:
422 exit = 2;
423 break;
425 } while (1);
429 #ifdef HAVE_LCD_BITMAP
430 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
432 void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
434 int strwdt, strhgt;
435 rb->lcd_getstringsize(str, &strwdt, &strhgt);
436 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
438 #endif
440 int main(void)
442 int button, fd;
443 bool on = false;
444 #ifdef HAVE_LCD_BITMAP
445 int i;
446 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
447 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT };
448 #endif
449 rb->lcd_clear_display();
451 #ifdef HAVE_LCD_BITMAP
452 rb->lcd_clear_display();
453 rb->lcd_setfont(FONT_SYSFIXED);
455 for(i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
456 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
457 #else
458 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
459 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
460 #endif
461 rb->lcd_update();
463 #ifdef HAVE_REMOTE_LCD
464 rb->lcd_remote_clear_display();
465 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
466 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
467 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
468 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
469 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
470 rb->lcd_remote_update();
471 #endif
475 button = rb->button_get(true);
476 switch(button)
478 case BATTERY_ON:
479 #ifdef BATTERY_RC_ON
480 case BATTERY_RC_ON:
481 #endif
482 on = true;
483 break;
484 case BATTERY_OFF:
485 #ifdef BATTERY_RC_OFF
486 case BATTERY_RC_OFF:
487 #endif
488 return PLUGIN_OK;
490 default: if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
491 return PLUGIN_USB_CONNECTED;
493 }while(!on);
495 fd = rb->open(BATTERY_LOG, O_RDONLY);
496 if(fd < 0)
498 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
499 if(fd >= 0)
501 rb->fdprintf(fd,
502 "This plugin will log your battery performance in a\n"
503 "file (%s) every time the disk is accessed (or every hour).\n"
504 "To properly test your battery:\n"
505 "1) Select and playback an album. "
506 "(Be sure to be more than the player's buffer)\n"
507 "2) Set to repeat.\n"
508 "3) Let the player run completely out of battery.\n"
509 "4) Recharge and copy (or whatever you want) the txt file to "
510 "your computer.\n"
511 "Now you can make graphs with the data of the battery log.\n"
512 "Do not enter another plugin during the test or else the "
513 "logging activity will end.\n\n"
514 "P.S: You can decide how you will make your tests.\n"
515 "Just don't open another plugin to be sure that your log "
516 "will continue.\n"
517 "M/DA (Measurements per Disk Activity) shows how many times\n"
518 "data was logged in the buffer between Disk Activity.\n\n"
519 "Battery type: %d mAh Buffer Entries: %d\n"
520 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:,"
521 " M/DA:"
522 #if CONFIG_CHARGING
523 ", C:"
524 #endif
525 #if CONFIG_CHARGING == CHARGING_MONITOR
526 ", S:"
527 #endif
528 #ifdef HAVE_USB_POWER
529 ", U:"
530 #endif
531 "\n"
532 ,BATTERY_LOG,rb->global_settings->battery_capacity,
533 BUF_SIZE / (unsigned)sizeof(struct batt_info));
534 rb->close(fd);
536 else
538 rb->splash(HZ / 2, "Cannot create file!");
539 return PLUGIN_ERROR;
542 else
544 rb->close(fd);
545 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
546 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
547 rb->close(fd);
550 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
551 if((thread_id = rb->create_thread(thread, thread_stack,
552 sizeof(thread_stack), 0, "Battery Benchmark"
553 IF_PRIO(, PRIORITY_BACKGROUND)
554 IF_COP(, CPU))) == NULL)
556 rb->splash(HZ, "Cannot create thread!");
557 return PLUGIN_ERROR;
560 rb->plugin_tsr(exit_tsr);
562 return PLUGIN_OK;
565 #endif