Fix warning about missing newline at the EOF
[maemo-rb.git] / apps / plugins / battery_bench.c
blobbf40fe175947b178b712c82bc9f09b4ae582a4cc
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 #else
244 #error No keymap defined!
245 #endif
247 #ifdef HAVE_TOUCHSCREEN
248 #ifndef BATTERY_ON
249 #define BATTERY_ON BUTTON_CENTER
250 #endif
251 #ifndef BATTERY_OFF
252 #define BATTERY_OFF BUTTON_TOPLEFT
253 #endif
254 #ifndef BATTERY_ON_TXT
255 #define BATTERY_ON_TXT "CENTRE - start"
256 #endif
257 #ifndef BATTERY_OFF_TXT
258 #define BATTERY_OFF_TXT "TOPLEFT"
259 #endif
260 #endif
262 /****************************** Plugin Entry Point ****************************/
263 static long start_tick;
265 /* Struct for battery information */
266 static struct batt_info
268 /* the size of the struct elements is optimised to make the struct size
269 * a power of 2 */
270 unsigned secs;
271 int eta;
272 unsigned int voltage;
273 short level;
274 unsigned short flags;
275 } bat[BUF_SIZE/sizeof(struct batt_info)];
277 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
279 static unsigned int thread_id;
280 static struct event_queue thread_q SHAREDBSS_ATTR;
281 static bool in_usb_mode;
282 static unsigned int buf_idx;
284 static bool exit_tsr(bool reenter)
286 long button;
287 (void)reenter;
288 rb->lcd_clear_display();
289 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
290 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
291 #ifdef HAVE_LCD_BITMAP
292 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
293 #endif
294 rb->lcd_update();
296 while (1)
298 button = rb->button_get(true);
299 if (IS_SYSEVENT(button))
300 continue;
301 if (button == BATTERY_OFF)
303 rb->queue_post(&thread_q, EV_EXIT, 0);
304 rb->thread_wait(thread_id);
305 /* remove the thread's queue from the broadcast list */
306 rb->queue_delete(&thread_q);
307 return true;
309 else return false;
313 #define BIT_CHARGER 0x1
314 #define BIT_CHARGING 0x2
315 #define BIT_USB_POWER 0x4
317 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
319 /* use long for aligning */
320 static unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
322 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
323 static unsigned int charge_state(void)
325 unsigned int ret = 0;
326 #if CONFIG_CHARGING
327 if (rb->charger_inserted())
328 ret = BIT_CHARGER;
329 #if CONFIG_CHARGING >= CHARGING_MONITOR
330 if (rb->charging_state())
331 ret |= BIT_CHARGING;
332 #endif
333 #endif
334 #ifdef HAVE_USB_POWER
335 if (rb->usb_powered())
336 ret |= BIT_USB_POWER;
337 #endif
338 return ret;
340 #endif
343 static void flush_buffer(void* data)
345 (void)data;
346 int fd;
347 unsigned int i;
349 /* don't access the disk when in usb mode, or when no data is available */
350 if (in_usb_mode || (buf_idx == 0))
351 return;
353 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
354 if (fd < 0)
355 return;
357 for (i = 0; i < buf_idx; i++)
359 rb->fdprintf(fd,
360 "%02d:%02d:%02d, %05d, %03d%%, "
361 "%02d:%02d, %04d, "
362 #if CONFIG_CHARGING
363 " %c"
364 #if CONFIG_CHARGING >= CHARGING_MONITOR
365 ", %c"
366 #endif
367 #endif
368 #ifdef HAVE_USB_POWER
369 ", %c"
370 #endif
371 "\n",
373 HMS(bat[i].secs), bat[i].secs, bat[i].level,
374 bat[i].eta / 60, bat[i].eta % 60,
375 bat[i].voltage
376 #if CONFIG_CHARGING
377 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
378 #if CONFIG_CHARGING >= CHARGING_MONITOR
379 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
380 #endif
381 #endif
382 #ifdef HAVE_USB_POWER
383 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
384 #endif
387 rb->close(fd);
389 buf_idx = 0;
393 static void thread(void)
395 bool exit = false;
396 char *exit_reason = "unknown";
397 long sleep_time = 60 * HZ;
398 struct queue_event ev;
399 int fd;
401 in_usb_mode = false;
402 buf_idx = 0;
404 while (!exit)
406 /* add data to buffer */
407 if (buf_idx < BUF_ELEMENTS)
409 bat[buf_idx].secs = (*rb->current_tick - start_tick) / HZ;
410 bat[buf_idx].level = rb->battery_level();
411 bat[buf_idx].eta = rb->battery_time();
412 bat[buf_idx].voltage = rb->battery_voltage();
413 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
414 bat[buf_idx].flags = charge_state();
415 #endif
416 buf_idx++;
417 #if USING_STORAGE_CALLBACK
418 rb->register_storage_idle_func(flush_buffer);
419 #endif
422 /* What to do when the measurement buffer is full:
423 1) save our measurements to disk but waste some power doing so?
424 2) throw away measurements to save some power?
425 The choice made here is to save the measurements. It is quite unusual
426 for this to occur because it requires > 16 hours of no disk activity.
428 if (buf_idx == BUF_ELEMENTS) {
429 flush_buffer(NULL);
432 /* sleep some time until next measurement */
433 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
434 switch (ev.id)
436 case SYS_USB_CONNECTED:
437 in_usb_mode = true;
438 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
439 break;
440 case SYS_USB_DISCONNECTED:
441 in_usb_mode = false;
442 break;
443 case SYS_POWEROFF:
444 exit_reason = "power off";
445 exit = true;
446 break;
447 case EV_EXIT:
448 #ifdef HAVE_LCD_BITMAP
449 rb->splash(HZ, "Exiting battery_bench...");
450 #else
451 rb->splash(HZ, "bench exit");
452 #endif
453 exit_reason = "plugin exit";
454 exit = true;
455 break;
459 #if USING_STORAGE_CALLBACK
460 /* unregister flush callback and flush to disk */
461 rb->unregister_storage_idle_func(flush_buffer, true);
462 #else
463 flush_buffer(NULL);
464 #endif
466 /* log end of bench and exit reason */
467 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
468 if (fd >= 0)
470 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
471 rb->close(fd);
476 #ifdef HAVE_LCD_BITMAP
477 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
479 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
481 int strwdt, strhgt;
482 rb->lcd_getstringsize(str, &strwdt, &strhgt);
483 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
485 #endif
487 enum plugin_status plugin_start(const void* parameter)
489 (void)parameter;
490 int button, fd;
491 bool on = false;
492 start_tick = *rb->current_tick;
493 #ifdef HAVE_LCD_BITMAP
494 int i;
495 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
496 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
497 #endif
498 rb->lcd_clear_display();
500 #ifdef HAVE_LCD_BITMAP
501 rb->lcd_clear_display();
502 rb->lcd_setfont(FONT_SYSFIXED);
504 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
505 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
506 #else
507 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
508 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
509 #endif
510 rb->lcd_update();
512 #ifdef HAVE_REMOTE_LCD
513 rb->lcd_remote_clear_display();
514 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
515 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
516 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
517 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
518 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
519 rb->lcd_remote_update();
520 #endif
524 button = rb->button_get(true);
525 switch (button)
527 case BATTERY_ON:
528 #ifdef BATTERY_RC_ON
529 case BATTERY_RC_ON:
530 #endif
531 on = true;
532 break;
533 case BATTERY_OFF:
534 #ifdef BATTERY_RC_OFF
535 case BATTERY_RC_OFF:
536 #endif
537 return PLUGIN_OK;
539 default:
540 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
541 return PLUGIN_USB_CONNECTED;
543 }while(!on);
545 fd = rb->open(BATTERY_LOG, O_RDONLY);
546 if (fd < 0)
548 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT, 0666);
549 if (fd >= 0)
551 rb->fdprintf(fd,
552 "# This plugin will log your battery performance in a\n"
553 "# file (%s) every minute.\n"
554 "# To properly test your battery:\n"
555 "# 1) Select and playback an album. "
556 "(Be sure to be more than the player's buffer)\n"
557 "# 2) Set to repeat.\n"
558 "# 3) Let the player run completely out of battery.\n"
559 "# 4) Recharge and copy (or whatever you want) the txt file to "
560 "your computer.\n"
561 "# Now you can make graphs with the data of the battery log.\n"
562 "# Do not enter another plugin during the test or else the \n"
563 "# logging activity will end.\n\n"
564 "# P.S: You can decide how you will make your tests.\n"
565 "# Just don't open another plugin to be sure that your log "
566 "will continue.\n\n",BATTERY_LOG);
567 rb->fdprintf(fd,
568 "# Battery bench run for %s version %s\n\n"
569 ,MODEL_NAME,rb->rbversion);
571 rb->fdprintf(fd, "# Battery type: %d mAh Buffer Entries: %d\n",
572 rb->global_settings->battery_capacity, (int)BUF_ELEMENTS);
574 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
575 HMS((unsigned)start_tick/HZ));
577 rb->fdprintf(fd,
578 "# Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
579 #if CONFIG_CHARGING
580 ", C:"
581 #endif
582 #if CONFIG_CHARGING >= CHARGING_MONITOR
583 ", S:"
584 #endif
585 #ifdef HAVE_USB_POWER
586 ", U:"
587 #endif
588 "\n");
589 rb->close(fd);
591 else
593 rb->splash(HZ / 2, "Cannot create file!");
594 return PLUGIN_ERROR;
597 else
599 rb->close(fd);
600 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
601 rb->fdprintf(fd, "\n# --File already present. Resuming Benchmark--\n");
602 rb->fdprintf(fd,
603 "# Battery bench run for %s version %s\n\n"
604 ,MODEL_NAME,rb->rbversion);
605 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
606 HMS((unsigned)start_tick/HZ));
607 rb->close(fd);
610 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
611 if ((thread_id = rb->create_thread(thread, thread_stack,
612 sizeof(thread_stack), 0, "Battery Benchmark"
613 IF_PRIO(, PRIORITY_BACKGROUND)
614 IF_COP(, CPU))) == 0)
616 rb->splash(HZ, "Cannot create thread!");
617 return PLUGIN_ERROR;
620 rb->plugin_tsr(exit_tsr);
622 return PLUGIN_OK;