Update the french translation regarding the previous revision.
[kugel-rb.git] / apps / plugins / battery_bench.c
blobbe71701c6f819165156cd8f1e1dd92a3ef2cabcc
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_ON BUTTON_RC_PLAY
138 #define BATTERY_OFF BUTTON_POWER
139 #define BATTERY_ON_TXT "PLAY - start"
140 #define BATTERY_OFF_TXT "POWER"
142 #elif CONFIG_KEYPAD == MROBE100_PAD
144 #define BATTERY_ON BUTTON_SELECT
145 #define BATTERY_OFF BUTTON_POWER
146 #define BATTERY_ON_TXT "SELECT - start"
147 #define BATTERY_OFF_TXT "POWER"
149 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
151 #define BATTERY_ON BUTTON_PLAY
152 #define BATTERY_OFF BUTTON_REC
153 #define BATTERY_RC_ON BUTTON_RC_PLAY
154 #define BATTERY_RC_OFF BUTTON_RC_REC
155 #define BATTERY_ON_TXT "PLAY - start"
156 #define BATTERY_OFF_TXT "REC"
158 #elif CONFIG_KEYPAD == COWON_D2_PAD
160 #define BATTERY_OFF BUTTON_POWER
161 #define BATTERY_OFF_TXT "POWER"
163 #elif CONFIG_KEYPAD == IAUDIO67_PAD
165 #define BATTERY_OFF BUTTON_POWER
166 #define BATTERY_OFF_TXT "POWER"
167 #define BATTERY_ON BUTTON_PLAY
168 #define BATTERY_ON_TXT "PLAY - start"
170 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
171 #define BATTERY_ON BUTTON_PLAY
172 #define BATTERY_ON_TXT "PLAY - start"
173 #define BATTERY_OFF BUTTON_BACK
174 #define BATTERY_OFF_TXT "BACK"
176 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
178 #define BATTERY_ON BUTTON_MENU
179 #define BATTERY_OFF BUTTON_POWER
180 #define BATTERY_ON_TXT "MENU - start"
181 #define BATTERY_OFF_TXT "POWER"
183 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
185 #define BATTERY_ON BUTTON_MENU
186 #define BATTERY_OFF BUTTON_POWER
187 #define BATTERY_ON_TXT "MENU - start"
188 #define BATTERY_OFF_TXT "POWER"
190 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
192 #define BATTERY_ON BUTTON_MENU
193 #define BATTERY_OFF BUTTON_POWER
194 #define BATTERY_ON_TXT "MENU - start"
195 #define BATTERY_OFF_TXT "POWER"
197 #elif CONFIG_KEYPAD == ONDAVX747_PAD
199 #define BATTERY_OFF BUTTON_POWER
200 #define BATTERY_OFF_TXT "POWER"
201 #elif CONFIG_KEYPAD == ONDAVX777_PAD
203 #define BATTERY_OFF BUTTON_POWER
204 #define BATTERY_OFF_TXT "POWER"
206 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
208 #define BATTERY_ON BUTTON_LEFT
209 #define BATTERY_OFF BUTTON_RIGHT
210 #define BATTERY_ON_TXT "LEFT"
211 #define BATTERY_OFF_TXT "RIGHT"
213 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
215 #define BATTERY_ON BUTTON_PLAY
216 #define BATTERY_OFF BUTTON_REC
217 #define BATTERY_ON_TXT "PLAY - start"
218 #define BATTERY_OFF_TXT "REC"
220 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
221 #define BATTERY_ON BUTTON_PLAY
222 #define BATTERY_OFF BUTTON_REC
223 #define BATTERY_ON_TXT "PLAY - start"
224 #define BATTERY_OFF_TXT "REC"
226 #else
227 #error No keymap defined!
228 #endif
230 #ifdef HAVE_TOUCHSCREEN
231 #ifndef BATTERY_ON
232 #define BATTERY_ON BUTTON_CENTER
233 #endif
234 #ifndef BATTERY_OFF
235 #define BATTERY_OFF BUTTON_TOPLEFT
236 #endif
237 #ifndef BATTERY_ON_TXT
238 #define BATTERY_ON_TXT "CENTRE - start"
239 #endif
240 #ifndef BATTERY_OFF_TXT
241 #define BATTERY_OFF_TXT "TOPLEFT"
242 #endif
243 #endif
245 /****************************** Plugin Entry Point ****************************/
246 static long start_tick;
248 /* Struct for battery information */
249 static struct batt_info
251 /* the size of the struct elements is optimised to make the struct size
252 * a power of 2 */
253 unsigned secs;
254 int eta;
255 unsigned int voltage;
256 short level;
257 unsigned short flags;
258 } bat[BUF_SIZE/sizeof(struct batt_info)];
260 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
262 static unsigned int thread_id;
263 static struct event_queue thread_q;
264 static bool in_usb_mode;
265 static unsigned int buf_idx;
267 static bool exit_tsr(bool reenter)
269 long button;
270 (void)reenter;
271 rb->lcd_clear_display();
272 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
273 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
274 #ifdef HAVE_LCD_BITMAP
275 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
276 #endif
277 rb->lcd_update();
279 while (1)
281 button = rb->button_get(true);
282 if (IS_SYSEVENT(button))
283 continue;
284 if (button == BATTERY_OFF)
286 rb->queue_post(&thread_q, EV_EXIT, 0);
287 rb->thread_wait(thread_id);
288 /* remove the thread's queue from the broadcast list */
289 rb->queue_delete(&thread_q);
290 return true;
292 else return false;
296 #define BIT_CHARGER 0x1
297 #define BIT_CHARGING 0x2
298 #define BIT_USB_POWER 0x4
300 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
302 /* use long for aligning */
303 static unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
305 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
306 static unsigned int charge_state(void)
308 unsigned int ret = 0;
309 #if CONFIG_CHARGING
310 if (rb->charger_inserted())
311 ret = BIT_CHARGER;
312 #if CONFIG_CHARGING >= CHARGING_MONITOR
313 if (rb->charging_state())
314 ret |= BIT_CHARGING;
315 #endif
316 #endif
317 #ifdef HAVE_USB_POWER
318 if (rb->usb_powered())
319 ret |= BIT_USB_POWER;
320 #endif
321 return ret;
323 #endif
326 static void flush_buffer(void* data)
328 (void)data;
329 int fd;
330 unsigned int i;
332 /* don't access the disk when in usb mode, or when no data is available */
333 if (in_usb_mode || (buf_idx == 0))
334 return;
336 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
337 if (fd < 0)
338 return;
340 for (i = 0; i < buf_idx; i++)
342 rb->fdprintf(fd,
343 "%02d:%02d:%02d, %05d, %03d%%, "
344 "%02d:%02d, %04d, "
345 #if CONFIG_CHARGING
346 " %c"
347 #if CONFIG_CHARGING >= CHARGING_MONITOR
348 ", %c"
349 #endif
350 #endif
351 #ifdef HAVE_USB_POWER
352 ", %c"
353 #endif
354 "\n",
356 HMS(bat[i].secs), bat[i].secs, bat[i].level,
357 bat[i].eta / 60, bat[i].eta % 60,
358 bat[i].voltage
359 #if CONFIG_CHARGING
360 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
361 #if CONFIG_CHARGING >= CHARGING_MONITOR
362 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
363 #endif
364 #endif
365 #ifdef HAVE_USB_POWER
366 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
367 #endif
370 rb->close(fd);
372 buf_idx = 0;
376 static void thread(void)
378 bool exit = false;
379 char *exit_reason = "unknown";
380 long sleep_time = 60 * HZ;
381 struct queue_event ev;
382 int fd;
384 in_usb_mode = false;
385 buf_idx = 0;
387 while (!exit)
389 /* add data to buffer */
390 if (buf_idx < BUF_ELEMENTS)
392 bat[buf_idx].secs = (*rb->current_tick - start_tick) / HZ;
393 bat[buf_idx].level = rb->battery_level();
394 bat[buf_idx].eta = rb->battery_time();
395 bat[buf_idx].voltage = rb->battery_voltage();
396 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
397 bat[buf_idx].flags = charge_state();
398 #endif
399 buf_idx++;
400 rb->register_storage_idle_func(flush_buffer);
403 /* What to do when the measurement buffer is full:
404 1) save our measurements to disk but waste some power doing so?
405 2) throw away measurements to save some power?
406 The choice made here is to save the measurements. It is quite unusual
407 for this to occur because it requires > 16 hours of no disk activity.
409 if (buf_idx == BUF_ELEMENTS) {
410 flush_buffer(NULL);
413 /* sleep some time until next measurement */
414 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
415 switch (ev.id)
417 case SYS_USB_CONNECTED:
418 in_usb_mode = true;
419 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
420 break;
421 case SYS_USB_DISCONNECTED:
422 in_usb_mode = false;
423 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
424 break;
425 case SYS_POWEROFF:
426 exit_reason = "power off";
427 exit = true;
428 break;
429 case EV_EXIT:
430 #ifdef HAVE_LCD_BITMAP
431 rb->splash(HZ, "Exiting battery_bench...");
432 #else
433 rb->splash(HZ, "bench exit");
434 #endif
435 exit_reason = "plugin exit";
436 exit = true;
437 break;
441 /* unregister flush callback and flush to disk */
442 rb->unregister_storage_idle_func(flush_buffer, true);
444 /* log end of bench and exit reason */
445 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
446 if (fd >= 0)
448 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
449 rb->close(fd);
454 #ifdef HAVE_LCD_BITMAP
455 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
457 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
459 int strwdt, strhgt;
460 rb->lcd_getstringsize(str, &strwdt, &strhgt);
461 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
463 #endif
465 enum plugin_status plugin_start(const void* parameter)
467 (void)parameter;
468 int button, fd;
469 bool on = false;
470 start_tick = *rb->current_tick;
471 #ifdef HAVE_LCD_BITMAP
472 int i;
473 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
474 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
475 #endif
476 rb->lcd_clear_display();
478 #ifdef HAVE_LCD_BITMAP
479 rb->lcd_clear_display();
480 rb->lcd_setfont(FONT_SYSFIXED);
482 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
483 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
484 #else
485 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
486 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
487 #endif
488 rb->lcd_update();
490 #ifdef HAVE_REMOTE_LCD
491 rb->lcd_remote_clear_display();
492 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
493 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
494 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
495 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
496 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
497 rb->lcd_remote_update();
498 #endif
502 button = rb->button_get(true);
503 switch (button)
505 case BATTERY_ON:
506 #ifdef BATTERY_RC_ON
507 case BATTERY_RC_ON:
508 #endif
509 on = true;
510 break;
511 case BATTERY_OFF:
512 #ifdef BATTERY_RC_OFF
513 case BATTERY_RC_OFF:
514 #endif
515 return PLUGIN_OK;
517 default:
518 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
519 return PLUGIN_USB_CONNECTED;
521 }while(!on);
523 fd = rb->open(BATTERY_LOG, O_RDONLY);
524 if (fd < 0)
526 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT, 0666);
527 if (fd >= 0)
529 rb->fdprintf(fd,
530 "# This plugin will log your battery performance in a\n"
531 "# file (%s) every minute.\n"
532 "# To properly test your battery:\n"
533 "# 1) Select and playback an album. "
534 "# (Be sure to be more than the player's buffer)\n"
535 "# 2) Set to repeat.\n"
536 "# 3) Let the player run completely out of battery.\n"
537 "# 4) Recharge and copy (or whatever you want) the txt file to "
538 "# your computer.\n"
539 "# Now you can make graphs with the data of the battery log.\n"
540 "# Do not enter another plugin during the test or else the \n"
541 "# logging activity will end.\n\n"
542 "# P.S: You can decide how you will make your tests.\n"
543 "# Just don't open another plugin to be sure that your log "
544 "will continue.\n\n",BATTERY_LOG);
545 rb->fdprintf(fd,
546 "# Battery bench run for %s version %s\n\n"
547 ,MODEL_NAME,rb->rbversion);
549 rb->fdprintf(fd, "# Battery type: %d mAh Buffer Entries: %d\n",
550 rb->global_settings->battery_capacity, (int)BUF_ELEMENTS);
552 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
553 HMS((unsigned)start_tick/HZ));
555 rb->fdprintf(fd,
556 "# Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
557 #if CONFIG_CHARGING
558 ", C:"
559 #endif
560 #if CONFIG_CHARGING >= CHARGING_MONITOR
561 ", S:"
562 #endif
563 #ifdef HAVE_USB_POWER
564 ", U:"
565 #endif
566 "\n");
567 rb->close(fd);
569 else
571 rb->splash(HZ / 2, "Cannot create file!");
572 return PLUGIN_ERROR;
575 else
577 rb->close(fd);
578 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
579 rb->fdprintf(fd, "\n# --File already present. Resuming Benchmark--\n");
580 rb->fdprintf(fd,
581 "# Battery bench run for %s version %s\n\n"
582 ,MODEL_NAME,rb->rbversion);
583 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
584 HMS((unsigned)start_tick/HZ));
585 rb->close(fd);
588 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
589 if ((thread_id = rb->create_thread(thread, thread_stack,
590 sizeof(thread_stack), 0, "Battery Benchmark"
591 IF_PRIO(, PRIORITY_BACKGROUND)
592 IF_COP(, CPU))) == 0)
594 rb->splash(HZ, "Cannot create thread!");
595 return PLUGIN_ERROR;
598 rb->plugin_tsr(exit_tsr);
600 return PLUGIN_OK;