There's no good reason for requiring the mr500 remote just to run battery_bench
[maemo-rb.git] / apps / plugins / battery_bench.c
bloba16302e8b0ec129c90ebaafcd12e224778cf76eb
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 ****************************************************************************/
23 #include "version.h"
24 #include "plugin.h"
27 #define BATTERY_LOG "/battery_bench.txt"
28 #define BUF_SIZE 16000
30 #define EV_EXIT 1337
32 /* seems to work with 1300, but who knows... */
33 #define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200
35 #if CONFIG_KEYPAD == RECORDER_PAD
37 #define BATTERY_ON BUTTON_PLAY
38 #define BATTERY_OFF BUTTON_OFF
39 #define BATTERY_ON_TXT "PLAY - start"
40 #define BATTERY_OFF_TXT "OFF"
42 #if BUTTON_REMOTE != 0
43 #define BATTERY_RC_ON BUTTON_RC_PLAY
44 #define BATTERY_RC_OFF BUTTON_RC_STOP
45 #endif
47 #elif CONFIG_KEYPAD == ONDIO_PAD
49 #define BATTERY_ON BUTTON_RIGHT
50 #define BATTERY_OFF BUTTON_OFF
51 #define BATTERY_ON_TXT "RIGHT - start"
52 #define BATTERY_OFF_TXT "OFF"
54 #elif CONFIG_KEYPAD == PLAYER_PAD
56 #define BATTERY_ON BUTTON_PLAY
57 #define BATTERY_OFF BUTTON_STOP
58 #define BATTERY_ON_TXT "PLAY - start"
59 #define BATTERY_OFF_TXT "STOP"
61 #define BATTERY_RC_ON BUTTON_RC_PLAY
62 #define BATTERY_RC_OFF BUTTON_RC_STOP
64 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
65 (CONFIG_KEYPAD == IRIVER_H300_PAD)
67 #define BATTERY_ON BUTTON_ON
68 #define BATTERY_RC_ON BUTTON_RC_ON
70 #define BATTERY_OFF BUTTON_OFF
71 #define BATTERY_RC_OFF BUTTON_RC_STOP
73 #define BATTERY_ON_TXT "PLAY - start"
74 #define BATTERY_OFF_TXT "STOP"
76 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
77 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
78 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
80 #define BATTERY_ON BUTTON_PLAY
81 #define BATTERY_OFF BUTTON_MENU
82 #define BATTERY_ON_TXT "PLAY - start"
83 #define BATTERY_OFF_TXT "MENU"
85 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
87 #define BATTERY_ON BUTTON_SELECT
88 #define BATTERY_OFF BUTTON_POWER
89 #define BATTERY_ON_TXT "SELECT - start"
90 #define BATTERY_OFF_TXT "POWER"
92 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
94 #define BATTERY_ON BUTTON_SELECT
95 #define BATTERY_OFF BUTTON_PLAY
96 #define BATTERY_ON_TXT "SELECT - start"
97 #define BATTERY_OFF_TXT "PLAY"
99 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
100 (CONFIG_KEYPAD == SANSA_C200_PAD) || \
101 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
102 (CONFIG_KEYPAD == SANSA_M200_PAD)
103 #define BATTERY_ON BUTTON_SELECT
104 #define BATTERY_OFF BUTTON_POWER
105 #define BATTERY_ON_TXT "SELECT - start"
106 #define BATTERY_OFF_TXT "POWER"
108 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
109 #define BATTERY_ON BUTTON_SELECT
110 #define BATTERY_OFF BUTTON_HOME
111 #define BATTERY_ON_TXT "SELECT - start"
112 #define BATTERY_OFF_TXT "HOME"
114 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
116 #define BATTERY_ON BUTTON_PLAY
117 #define BATTERY_OFF BUTTON_POWER
118 #define BATTERY_ON_TXT "PLAY - start"
119 #define BATTERY_OFF_TXT "POWER"
121 #elif CONFIG_KEYPAD == GIGABEAT_PAD
123 #define BATTERY_ON BUTTON_SELECT
124 #define BATTERY_OFF BUTTON_POWER
125 #define BATTERY_ON_TXT "SELECT - start"
126 #define BATTERY_OFF_TXT "POWER"
128 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
130 #define BATTERY_ON BUTTON_SELECT
131 #define BATTERY_OFF BUTTON_BACK
132 #define BATTERY_ON_TXT "SELECT - start"
133 #define BATTERY_OFF_TXT "BACK"
135 #elif CONFIG_KEYPAD == MROBE500_PAD
137 #define BATTERY_OFF BUTTON_POWER
138 #define BATTERY_OFF_TXT "POWER"
140 #elif CONFIG_KEYPAD == MROBE100_PAD
142 #define BATTERY_ON BUTTON_SELECT
143 #define BATTERY_OFF BUTTON_POWER
144 #define BATTERY_ON_TXT "SELECT - start"
145 #define BATTERY_OFF_TXT "POWER"
147 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
149 #define BATTERY_ON BUTTON_PLAY
150 #define BATTERY_OFF BUTTON_REC
151 #define BATTERY_RC_ON BUTTON_RC_PLAY
152 #define BATTERY_RC_OFF BUTTON_RC_REC
153 #define BATTERY_ON_TXT "PLAY - start"
154 #define BATTERY_OFF_TXT "REC"
156 #elif CONFIG_KEYPAD == COWON_D2_PAD
158 #define BATTERY_OFF BUTTON_POWER
159 #define BATTERY_OFF_TXT "POWER"
161 #elif CONFIG_KEYPAD == IAUDIO67_PAD
163 #define BATTERY_OFF BUTTON_POWER
164 #define BATTERY_OFF_TXT "POWER"
165 #define BATTERY_ON BUTTON_PLAY
166 #define BATTERY_ON_TXT "PLAY - start"
168 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
169 #define BATTERY_ON BUTTON_PLAY
170 #define BATTERY_ON_TXT "PLAY - start"
171 #define BATTERY_OFF BUTTON_BACK
172 #define BATTERY_OFF_TXT "BACK"
174 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
176 #define BATTERY_ON BUTTON_MENU
177 #define BATTERY_OFF BUTTON_POWER
178 #define BATTERY_ON_TXT "MENU - start"
179 #define BATTERY_OFF_TXT "POWER"
181 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
183 #define BATTERY_ON BUTTON_MENU
184 #define BATTERY_OFF BUTTON_POWER
185 #define BATTERY_ON_TXT "MENU - start"
186 #define BATTERY_OFF_TXT "POWER"
188 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
190 #define BATTERY_ON BUTTON_MENU
191 #define BATTERY_OFF BUTTON_POWER
192 #define BATTERY_ON_TXT "MENU - start"
193 #define BATTERY_OFF_TXT "POWER"
195 #elif CONFIG_KEYPAD == ONDAVX747_PAD
197 #define BATTERY_OFF BUTTON_POWER
198 #define BATTERY_OFF_TXT "POWER"
199 #elif CONFIG_KEYPAD == ONDAVX777_PAD
201 #define BATTERY_OFF BUTTON_POWER
202 #define BATTERY_OFF_TXT "POWER"
204 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
206 #define BATTERY_ON BUTTON_LEFT
207 #define BATTERY_OFF BUTTON_RIGHT
208 #define BATTERY_ON_TXT "LEFT"
209 #define BATTERY_OFF_TXT "RIGHT"
211 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
213 #define BATTERY_ON BUTTON_PLAY
214 #define BATTERY_OFF BUTTON_REC
215 #define BATTERY_ON_TXT "PLAY - start"
216 #define BATTERY_OFF_TXT "REC"
218 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
219 #define BATTERY_ON BUTTON_PLAY
220 #define BATTERY_OFF BUTTON_REC
221 #define BATTERY_ON_TXT "PLAY - start"
222 #define BATTERY_OFF_TXT "REC"
224 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
225 #define BATTERY_ON BUTTON_PLAY
226 #define BATTERY_OFF BUTTON_REC
227 #define BATTERY_ON_TXT "PLAY - start"
228 #define BATTERY_OFF_TXT "REC"
230 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
231 #define BATTERY_ON BUTTON_PLAYPAUSE
232 #define BATTERY_OFF BUTTON_POWER
233 #define BATTERY_ON_TXT "PLAYPAUSE - start"
234 #define BATTERY_OFF_TXT "POWER"
236 #elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
237 #define BATTERY_ON BUTTON_SELECT
238 #define BATTERY_OFF BUTTON_POWER
239 #define BATTERY_ON_TXT "SELECT - start"
240 #define BATTERY_OFF_TXT "POWER"
242 #else
243 #error No keymap defined!
244 #endif
246 #ifdef HAVE_TOUCHSCREEN
247 #ifndef BATTERY_ON
248 #define BATTERY_ON BUTTON_CENTER
249 #endif
250 #ifndef BATTERY_OFF
251 #define BATTERY_OFF BUTTON_TOPLEFT
252 #endif
253 #ifndef BATTERY_ON_TXT
254 #define BATTERY_ON_TXT "CENTRE - start"
255 #endif
256 #ifndef BATTERY_OFF_TXT
257 #define BATTERY_OFF_TXT "TOPLEFT"
258 #endif
259 #endif
261 /****************************** Plugin Entry Point ****************************/
262 static long start_tick;
264 /* Struct for battery information */
265 static struct batt_info
267 /* the size of the struct elements is optimised to make the struct size
268 * a power of 2 */
269 unsigned secs;
270 int eta;
271 unsigned int voltage;
272 short level;
273 unsigned short flags;
274 } bat[BUF_SIZE/sizeof(struct batt_info)];
276 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
278 static unsigned int thread_id;
279 static struct event_queue thread_q SHAREDBSS_ATTR;
280 static bool in_usb_mode;
281 static unsigned int buf_idx;
283 static bool exit_tsr(bool reenter)
285 long button;
286 (void)reenter;
287 rb->lcd_clear_display();
288 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
289 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
290 #ifdef HAVE_LCD_BITMAP
291 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
292 #endif
293 rb->lcd_update();
295 while (1)
297 button = rb->button_get(true);
298 if (IS_SYSEVENT(button))
299 continue;
300 if (button == BATTERY_OFF)
302 rb->queue_post(&thread_q, EV_EXIT, 0);
303 rb->thread_wait(thread_id);
304 /* remove the thread's queue from the broadcast list */
305 rb->queue_delete(&thread_q);
306 return true;
308 else return false;
312 #define BIT_CHARGER 0x1
313 #define BIT_CHARGING 0x2
314 #define BIT_USB_POWER 0x4
316 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
318 /* use long for aligning */
319 static unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
321 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
322 static unsigned int charge_state(void)
324 unsigned int ret = 0;
325 #if CONFIG_CHARGING
326 if (rb->charger_inserted())
327 ret = BIT_CHARGER;
328 #if CONFIG_CHARGING >= CHARGING_MONITOR
329 if (rb->charging_state())
330 ret |= BIT_CHARGING;
331 #endif
332 #endif
333 #ifdef HAVE_USB_POWER
334 if (rb->usb_powered())
335 ret |= BIT_USB_POWER;
336 #endif
337 return ret;
339 #endif
342 static void flush_buffer(void* data)
344 (void)data;
345 int fd;
346 unsigned int i;
348 /* don't access the disk when in usb mode, or when no data is available */
349 if (in_usb_mode || (buf_idx == 0))
350 return;
352 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
353 if (fd < 0)
354 return;
356 for (i = 0; i < buf_idx; i++)
358 rb->fdprintf(fd,
359 "%02d:%02d:%02d, %05d, %03d%%, "
360 "%02d:%02d, %04d, "
361 #if CONFIG_CHARGING
362 " %c"
363 #if CONFIG_CHARGING >= CHARGING_MONITOR
364 ", %c"
365 #endif
366 #endif
367 #ifdef HAVE_USB_POWER
368 ", %c"
369 #endif
370 "\n",
372 HMS(bat[i].secs), bat[i].secs, bat[i].level,
373 bat[i].eta / 60, bat[i].eta % 60,
374 bat[i].voltage
375 #if CONFIG_CHARGING
376 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
377 #if CONFIG_CHARGING >= CHARGING_MONITOR
378 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
379 #endif
380 #endif
381 #ifdef HAVE_USB_POWER
382 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
383 #endif
386 rb->close(fd);
388 buf_idx = 0;
392 static void thread(void)
394 bool exit = false;
395 char *exit_reason = "unknown";
396 long sleep_time = 60 * HZ;
397 struct queue_event ev;
398 int fd;
400 in_usb_mode = false;
401 buf_idx = 0;
403 while (!exit)
405 /* add data to buffer */
406 if (buf_idx < BUF_ELEMENTS)
408 bat[buf_idx].secs = (*rb->current_tick - start_tick) / HZ;
409 bat[buf_idx].level = rb->battery_level();
410 bat[buf_idx].eta = rb->battery_time();
411 bat[buf_idx].voltage = rb->battery_voltage();
412 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
413 bat[buf_idx].flags = charge_state();
414 #endif
415 buf_idx++;
416 rb->register_storage_idle_func(flush_buffer);
419 /* What to do when the measurement buffer is full:
420 1) save our measurements to disk but waste some power doing so?
421 2) throw away measurements to save some power?
422 The choice made here is to save the measurements. It is quite unusual
423 for this to occur because it requires > 16 hours of no disk activity.
425 if (buf_idx == BUF_ELEMENTS) {
426 flush_buffer(NULL);
429 /* sleep some time until next measurement */
430 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
431 switch (ev.id)
433 case SYS_USB_CONNECTED:
434 in_usb_mode = true;
435 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
436 break;
437 case SYS_USB_DISCONNECTED:
438 in_usb_mode = false;
439 break;
440 case SYS_POWEROFF:
441 exit_reason = "power off";
442 exit = true;
443 break;
444 case EV_EXIT:
445 #ifdef HAVE_LCD_BITMAP
446 rb->splash(HZ, "Exiting battery_bench...");
447 #else
448 rb->splash(HZ, "bench exit");
449 #endif
450 exit_reason = "plugin exit";
451 exit = true;
452 break;
456 /* unregister flush callback and flush to disk */
457 rb->unregister_storage_idle_func(flush_buffer, true);
459 /* log end of bench and exit reason */
460 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
461 if (fd >= 0)
463 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
464 rb->close(fd);
469 #ifdef HAVE_LCD_BITMAP
470 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
472 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
474 int strwdt, strhgt;
475 rb->lcd_getstringsize(str, &strwdt, &strhgt);
476 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
478 #endif
480 enum plugin_status plugin_start(const void* parameter)
482 (void)parameter;
483 int button, fd;
484 bool on = false;
485 start_tick = *rb->current_tick;
486 #ifdef HAVE_LCD_BITMAP
487 int i;
488 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
489 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
490 #endif
491 rb->lcd_clear_display();
493 #ifdef HAVE_LCD_BITMAP
494 rb->lcd_clear_display();
495 rb->lcd_setfont(FONT_SYSFIXED);
497 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
498 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
499 #else
500 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
501 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
502 #endif
503 rb->lcd_update();
505 #ifdef HAVE_REMOTE_LCD
506 rb->lcd_remote_clear_display();
507 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
508 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
509 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
510 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
511 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
512 rb->lcd_remote_update();
513 #endif
517 button = rb->button_get(true);
518 switch (button)
520 case BATTERY_ON:
521 #ifdef BATTERY_RC_ON
522 case BATTERY_RC_ON:
523 #endif
524 on = true;
525 break;
526 case BATTERY_OFF:
527 #ifdef BATTERY_RC_OFF
528 case BATTERY_RC_OFF:
529 #endif
530 return PLUGIN_OK;
532 default:
533 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
534 return PLUGIN_USB_CONNECTED;
536 }while(!on);
538 fd = rb->open(BATTERY_LOG, O_RDONLY);
539 if (fd < 0)
541 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT, 0666);
542 if (fd >= 0)
544 rb->fdprintf(fd,
545 "# This plugin will log your battery performance in a\n"
546 "# file (%s) every minute.\n"
547 "# To properly test your battery:\n"
548 "# 1) Select and playback an album. "
549 "(Be sure to be more than the player's buffer)\n"
550 "# 2) Set to repeat.\n"
551 "# 3) Let the player run completely out of battery.\n"
552 "# 4) Recharge and copy (or whatever you want) the txt file to "
553 "your computer.\n"
554 "# Now you can make graphs with the data of the battery log.\n"
555 "# Do not enter another plugin during the test or else the \n"
556 "# logging activity will end.\n\n"
557 "# P.S: You can decide how you will make your tests.\n"
558 "# Just don't open another plugin to be sure that your log "
559 "will continue.\n\n",BATTERY_LOG);
560 rb->fdprintf(fd,
561 "# Battery bench run for %s version %s\n\n"
562 ,MODEL_NAME,rb->rbversion);
564 rb->fdprintf(fd, "# Battery type: %d mAh Buffer Entries: %d\n",
565 rb->global_settings->battery_capacity, (int)BUF_ELEMENTS);
567 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
568 HMS((unsigned)start_tick/HZ));
570 rb->fdprintf(fd,
571 "# Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
572 #if CONFIG_CHARGING
573 ", C:"
574 #endif
575 #if CONFIG_CHARGING >= CHARGING_MONITOR
576 ", S:"
577 #endif
578 #ifdef HAVE_USB_POWER
579 ", U:"
580 #endif
581 "\n");
582 rb->close(fd);
584 else
586 rb->splash(HZ / 2, "Cannot create file!");
587 return PLUGIN_ERROR;
590 else
592 rb->close(fd);
593 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
594 rb->fdprintf(fd, "\n# --File already present. Resuming Benchmark--\n");
595 rb->fdprintf(fd,
596 "# Battery bench run for %s version %s\n\n"
597 ,MODEL_NAME,rb->rbversion);
598 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
599 HMS((unsigned)start_tick/HZ));
600 rb->close(fd);
603 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
604 if ((thread_id = rb->create_thread(thread, thread_stack,
605 sizeof(thread_stack), 0, "Battery Benchmark"
606 IF_PRIO(, PRIORITY_BACKGROUND)
607 IF_COP(, CPU))) == 0)
609 rb->splash(HZ, "Cannot create thread!");
610 return PLUGIN_ERROR;
613 rb->plugin_tsr(exit_tsr);
615 return PLUGIN_OK;