Prepare new maemo release
[maemo-rb.git] / apps / plugins / battery_bench.c
blob973315d06b1e56be576f51bdabdc05426b2ca089
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 HOME_DIR"/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 \
129 || CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
131 #define BATTERY_ON BUTTON_SELECT
132 #define BATTERY_OFF BUTTON_BACK
133 #define BATTERY_ON_TXT "SELECT - start"
134 #define BATTERY_OFF_TXT "BACK"
136 #elif CONFIG_KEYPAD == MROBE500_PAD
138 #define BATTERY_OFF BUTTON_POWER
139 #define BATTERY_OFF_TXT "POWER"
141 #elif CONFIG_KEYPAD == MROBE100_PAD
143 #define BATTERY_ON BUTTON_SELECT
144 #define BATTERY_OFF BUTTON_POWER
145 #define BATTERY_ON_TXT "SELECT - start"
146 #define BATTERY_OFF_TXT "POWER"
148 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
150 #define BATTERY_ON BUTTON_PLAY
151 #define BATTERY_OFF BUTTON_REC
152 #define BATTERY_RC_ON BUTTON_RC_PLAY
153 #define BATTERY_RC_OFF BUTTON_RC_REC
154 #define BATTERY_ON_TXT "PLAY - start"
155 #define BATTERY_OFF_TXT "REC"
157 #elif CONFIG_KEYPAD == COWON_D2_PAD
159 #define BATTERY_OFF BUTTON_POWER
160 #define BATTERY_OFF_TXT "POWER"
162 #elif CONFIG_KEYPAD == IAUDIO67_PAD
164 #define BATTERY_OFF BUTTON_POWER
165 #define BATTERY_OFF_TXT "POWER"
166 #define BATTERY_ON BUTTON_PLAY
167 #define BATTERY_ON_TXT "PLAY - start"
169 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
170 #define BATTERY_ON BUTTON_PLAY
171 #define BATTERY_ON_TXT "PLAY - start"
172 #define BATTERY_OFF BUTTON_BACK
173 #define BATTERY_OFF_TXT "BACK"
175 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
177 #define BATTERY_ON BUTTON_MENU
178 #define BATTERY_OFF BUTTON_POWER
179 #define BATTERY_ON_TXT "MENU - start"
180 #define BATTERY_OFF_TXT "POWER"
182 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
184 #define BATTERY_ON BUTTON_MENU
185 #define BATTERY_OFF BUTTON_POWER
186 #define BATTERY_ON_TXT "MENU - start"
187 #define BATTERY_OFF_TXT "POWER"
189 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
191 #define BATTERY_ON BUTTON_MENU
192 #define BATTERY_OFF BUTTON_POWER
193 #define BATTERY_ON_TXT "MENU - start"
194 #define BATTERY_OFF_TXT "POWER"
196 #elif CONFIG_KEYPAD == ONDAVX747_PAD
198 #define BATTERY_OFF BUTTON_POWER
199 #define BATTERY_OFF_TXT "POWER"
200 #elif CONFIG_KEYPAD == ONDAVX777_PAD
202 #define BATTERY_OFF BUTTON_POWER
203 #define BATTERY_OFF_TXT "POWER"
205 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
207 #define BATTERY_ON BUTTON_LEFT
208 #define BATTERY_OFF BUTTON_RIGHT
209 #define BATTERY_ON_TXT "LEFT"
210 #define BATTERY_OFF_TXT "RIGHT"
212 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
214 #define BATTERY_ON BUTTON_PLAY
215 #define BATTERY_OFF BUTTON_REC
216 #define BATTERY_ON_TXT "PLAY - start"
217 #define BATTERY_OFF_TXT "REC"
219 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
220 #define BATTERY_ON BUTTON_PLAY
221 #define BATTERY_OFF BUTTON_REC
222 #define BATTERY_ON_TXT "PLAY - start"
223 #define BATTERY_OFF_TXT "REC"
225 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
226 #define BATTERY_ON BUTTON_PLAY
227 #define BATTERY_OFF BUTTON_REC
228 #define BATTERY_ON_TXT "PLAY - start"
229 #define BATTERY_OFF_TXT "REC"
231 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
232 #define BATTERY_ON BUTTON_PLAYPAUSE
233 #define BATTERY_OFF BUTTON_POWER
234 #define BATTERY_ON_TXT "PLAYPAUSE - start"
235 #define BATTERY_OFF_TXT "POWER"
237 #elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
238 #define BATTERY_ON BUTTON_SELECT
239 #define BATTERY_OFF BUTTON_POWER
240 #define BATTERY_ON_TXT "SELECT - start"
241 #define BATTERY_OFF_TXT "POWER"
243 #elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD
244 #define BATTERY_ON BUTTON_PLAY
245 #define BATTERY_OFF BUTTON_POWER
246 #define BATTERY_ON_TXT "PLAY - start"
247 #define BATTERY_OFF_TXT "POWER"
249 #elif (CONFIG_KEYPAD == HM60X_PAD) || (CONFIG_KEYPAD == HM801_PAD)
250 #define BATTERY_ON BUTTON_SELECT
251 #define BATTERY_OFF BUTTON_POWER
252 #define BATTERY_ON_TXT "SELECT - start"
254 #define BATTERY_OFF_TXT "POWER"
256 #else
257 #error No keymap defined!
258 #endif
260 #ifdef HAVE_TOUCHSCREEN
261 #ifndef BATTERY_ON
262 #define BATTERY_ON BUTTON_CENTER
263 #endif
264 #ifndef BATTERY_OFF
265 #define BATTERY_OFF BUTTON_TOPLEFT
266 #endif
267 #ifndef BATTERY_ON_TXT
268 #define BATTERY_ON_TXT "CENTRE - start"
269 #endif
270 #ifndef BATTERY_OFF_TXT
271 #define BATTERY_OFF_TXT "TOPLEFT"
272 #endif
273 #endif
275 /****************************** Plugin Entry Point ****************************/
276 static long start_tick;
278 /* Struct for battery information */
279 static struct batt_info
281 /* the size of the struct elements is optimised to make the struct size
282 * a power of 2 */
283 unsigned secs;
284 int eta;
285 unsigned int voltage;
286 short level;
287 unsigned short flags;
288 } bat[BUF_SIZE/sizeof(struct batt_info)];
290 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
292 static unsigned int thread_id;
293 static struct event_queue thread_q SHAREDBSS_ATTR;
294 static bool in_usb_mode;
295 static unsigned int buf_idx;
297 static bool exit_tsr(bool reenter)
299 long button;
300 (void)reenter;
301 rb->lcd_clear_display();
302 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
303 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
304 #ifdef HAVE_LCD_BITMAP
305 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
306 #endif
307 rb->lcd_update();
309 while (1)
311 button = rb->button_get(true);
312 if (IS_SYSEVENT(button))
313 continue;
314 if (button == BATTERY_OFF)
316 rb->queue_post(&thread_q, EV_EXIT, 0);
317 rb->thread_wait(thread_id);
318 /* remove the thread's queue from the broadcast list */
319 rb->queue_delete(&thread_q);
320 return true;
322 else return false;
326 #define BIT_CHARGER 0x1
327 #define BIT_CHARGING 0x2
328 #define BIT_USB_POWER 0x4
330 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
332 /* use long for aligning */
333 static unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
335 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
336 static unsigned int charge_state(void)
338 unsigned int ret = 0;
339 #if CONFIG_CHARGING
340 if (rb->charger_inserted())
341 ret = BIT_CHARGER;
342 #if CONFIG_CHARGING >= CHARGING_MONITOR
343 if (rb->charging_state())
344 ret |= BIT_CHARGING;
345 #endif
346 #endif
347 #ifdef HAVE_USB_POWER
348 if (rb->usb_powered())
349 ret |= BIT_USB_POWER;
350 #endif
351 return ret;
353 #endif
356 static void flush_buffer(void* data)
358 (void)data;
359 int fd;
360 unsigned int i;
362 /* don't access the disk when in usb mode, or when no data is available */
363 if (in_usb_mode || (buf_idx == 0))
364 return;
366 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
367 if (fd < 0)
368 return;
370 for (i = 0; i < buf_idx; i++)
372 rb->fdprintf(fd,
373 "%02d:%02d:%02d, %05d, %03d%%, "
374 "%02d:%02d, %04d, "
375 #if CONFIG_CHARGING
376 " %c"
377 #if CONFIG_CHARGING >= CHARGING_MONITOR
378 ", %c"
379 #endif
380 #endif
381 #ifdef HAVE_USB_POWER
382 ", %c"
383 #endif
384 "\n",
386 HMS(bat[i].secs), bat[i].secs, bat[i].level,
387 bat[i].eta / 60, bat[i].eta % 60,
388 bat[i].voltage
389 #if CONFIG_CHARGING
390 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
391 #if CONFIG_CHARGING >= CHARGING_MONITOR
392 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
393 #endif
394 #endif
395 #ifdef HAVE_USB_POWER
396 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
397 #endif
400 rb->close(fd);
402 buf_idx = 0;
406 static void thread(void)
408 bool exit = false;
409 char *exit_reason = "unknown";
410 long sleep_time = 60 * HZ;
411 struct queue_event ev;
412 int fd;
414 in_usb_mode = false;
415 buf_idx = 0;
417 while (!exit)
419 /* add data to buffer */
420 if (buf_idx < BUF_ELEMENTS)
422 bat[buf_idx].secs = (*rb->current_tick - start_tick) / HZ;
423 bat[buf_idx].level = rb->battery_level();
424 bat[buf_idx].eta = rb->battery_time();
425 bat[buf_idx].voltage = rb->battery_voltage();
426 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
427 bat[buf_idx].flags = charge_state();
428 #endif
429 buf_idx++;
430 #if USING_STORAGE_CALLBACK
431 rb->register_storage_idle_func(flush_buffer);
432 #endif
435 /* What to do when the measurement buffer is full:
436 1) save our measurements to disk but waste some power doing so?
437 2) throw away measurements to save some power?
438 The choice made here is to save the measurements. It is quite unusual
439 for this to occur because it requires > 16 hours of no disk activity.
441 if (buf_idx == BUF_ELEMENTS) {
442 flush_buffer(NULL);
445 /* sleep some time until next measurement */
446 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
447 switch (ev.id)
449 case SYS_USB_CONNECTED:
450 in_usb_mode = true;
451 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
452 break;
453 case SYS_USB_DISCONNECTED:
454 in_usb_mode = false;
455 break;
456 case SYS_POWEROFF:
457 exit_reason = "power off";
458 exit = true;
459 break;
460 case EV_EXIT:
461 #ifdef HAVE_LCD_BITMAP
462 rb->splash(HZ, "Exiting battery_bench...");
463 #else
464 rb->splash(HZ, "bench exit");
465 #endif
466 exit_reason = "plugin exit";
467 exit = true;
468 break;
472 #if USING_STORAGE_CALLBACK
473 /* unregister flush callback and flush to disk */
474 rb->unregister_storage_idle_func(flush_buffer, true);
475 #else
476 flush_buffer(NULL);
477 #endif
479 /* log end of bench and exit reason */
480 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
481 if (fd >= 0)
483 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
484 rb->close(fd);
489 #ifdef HAVE_LCD_BITMAP
490 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
492 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
494 int strwdt, strhgt;
495 rb->lcd_getstringsize(str, &strwdt, &strhgt);
496 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
498 #endif
500 enum plugin_status plugin_start(const void* parameter)
502 (void)parameter;
503 int button, fd;
504 bool on = false;
505 start_tick = *rb->current_tick;
506 #ifdef HAVE_LCD_BITMAP
507 int i;
508 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
509 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
510 #endif
511 rb->lcd_clear_display();
513 #ifdef HAVE_LCD_BITMAP
514 rb->lcd_clear_display();
515 rb->lcd_setfont(FONT_SYSFIXED);
517 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
518 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
519 #else
520 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
521 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
522 #endif
523 rb->lcd_update();
525 #ifdef HAVE_REMOTE_LCD
526 rb->lcd_remote_clear_display();
527 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
528 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
529 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
530 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
531 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
532 rb->lcd_remote_update();
533 #endif
537 button = rb->button_get(true);
538 switch (button)
540 case BATTERY_ON:
541 #ifdef BATTERY_RC_ON
542 case BATTERY_RC_ON:
543 #endif
544 on = true;
545 break;
546 case BATTERY_OFF:
547 #ifdef BATTERY_RC_OFF
548 case BATTERY_RC_OFF:
549 #endif
550 return PLUGIN_OK;
552 default:
553 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
554 return PLUGIN_USB_CONNECTED;
556 }while(!on);
558 fd = rb->open(BATTERY_LOG, O_RDONLY);
559 if (fd < 0)
561 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT, 0666);
562 if (fd >= 0)
564 rb->fdprintf(fd,
565 "# This plugin will log your battery performance in a\n"
566 "# file (%s) every minute.\n"
567 "# To properly test your battery:\n"
568 "# 1) Select and playback an album. "
569 "(Be sure to be more than the player's buffer)\n"
570 "# 2) Set to repeat.\n"
571 "# 3) Let the player run completely out of battery.\n"
572 "# 4) Recharge and copy (or whatever you want) the txt file to "
573 "your computer.\n"
574 "# Now you can make graphs with the data of the battery log.\n"
575 "# Do not enter another plugin during the test or else the \n"
576 "# logging activity will end.\n\n"
577 "# P.S: You can decide how you will make your tests.\n"
578 "# Just don't open another plugin to be sure that your log "
579 "will continue.\n\n",BATTERY_LOG);
580 rb->fdprintf(fd,
581 "# Battery bench run for %s version %s\n\n"
582 ,MODEL_NAME,rb->rbversion);
584 rb->fdprintf(fd, "# Battery type: %d mAh Buffer Entries: %d\n",
585 rb->global_settings->battery_capacity, (int)BUF_ELEMENTS);
587 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
588 HMS((unsigned)start_tick/HZ));
590 rb->fdprintf(fd,
591 "# Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
592 #if CONFIG_CHARGING
593 ", C:"
594 #endif
595 #if CONFIG_CHARGING >= CHARGING_MONITOR
596 ", S:"
597 #endif
598 #ifdef HAVE_USB_POWER
599 ", U:"
600 #endif
601 "\n");
602 rb->close(fd);
604 else
606 rb->splash(HZ / 2, "Cannot create file!");
607 return PLUGIN_ERROR;
610 else
612 rb->close(fd);
613 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
614 rb->fdprintf(fd, "\n# --File already present. Resuming Benchmark--\n");
615 rb->fdprintf(fd,
616 "# Battery bench run for %s version %s\n\n"
617 ,MODEL_NAME,rb->rbversion);
618 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
619 HMS((unsigned)start_tick/HZ));
620 rb->close(fd);
623 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
624 if ((thread_id = rb->create_thread(thread, thread_stack,
625 sizeof(thread_stack), 0, "Battery Benchmark"
626 IF_PRIO(, PRIORITY_BACKGROUND)
627 IF_COP(, CPU))) == 0)
629 rb->splash(HZ, "Cannot create thread!");
630 return PLUGIN_ERROR;
633 rb->plugin_tsr(exit_tsr);
635 return PLUGIN_OK;