Bump plugin API version. This should have been done in r24587. Also, because the...
[kugel-rb.git] / apps / plugins / battery_bench.c
blob57545c210644684e588ba08b74006c486b18b6ed
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"
25 PLUGIN_HEADER
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_SA9200_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 == ONDAVX747_PAD
192 #define BATTERY_OFF BUTTON_POWER
193 #define BATTERY_OFF_TXT "POWER"
194 #elif CONFIG_KEYPAD == ONDAVX777_PAD
196 #define BATTERY_OFF BUTTON_POWER
197 #define BATTERY_OFF_TXT "POWER"
199 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
201 #define BATTERY_ON BUTTON_LEFT
202 #define BATTERY_OFF BUTTON_RIGHT
203 #define BATTERY_ON_TXT "LEFT"
204 #define BATTERY_OFF_TXT "RIGHT"
206 #else
207 #error No keymap defined!
208 #endif
210 #ifdef HAVE_TOUCHSCREEN
211 #ifndef BATTERY_ON
212 #define BATTERY_ON BUTTON_CENTER
213 #endif
214 #ifndef BATTERY_OFF
215 #define BATTERY_OFF BUTTON_TOPLEFT
216 #endif
217 #ifndef BATTERY_ON_TXT
218 #define BATTERY_ON_TXT "CENTRE - start"
219 #endif
220 #ifndef BATTERY_OFF_TXT
221 #define BATTERY_OFF_TXT "TOPLEFT"
222 #endif
223 #endif
225 /****************************** Plugin Entry Point ****************************/
226 int main(void);
227 bool exit_tsr(bool);
228 void thread(void);
231 enum plugin_status plugin_start(const void* parameter)
233 (void)parameter;
235 return main();
238 /* Struct for battery information */
239 struct batt_info
241 /* the size of the struct elements is optimised to make the struct size
242 * a power of 2 */
243 long ticks;
244 int eta;
245 unsigned int voltage;
246 short level;
247 unsigned short flags;
248 } bat[BUF_SIZE/sizeof(struct batt_info)];
250 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
252 static unsigned int thread_id;
253 static struct event_queue thread_q;
254 static bool in_usb_mode;
255 static unsigned int buf_idx;
257 bool exit_tsr(bool reenter)
259 long button;
260 (void)reenter;
261 rb->lcd_clear_display();
262 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
263 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
264 #ifdef HAVE_LCD_BITMAP
265 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
266 #endif
267 rb->lcd_update();
269 while (1)
271 button = rb->button_get(true);
272 if (IS_SYSEVENT(button))
273 continue;
274 if (button == BATTERY_OFF)
276 rb->queue_post(&thread_q, EV_EXIT, 0);
277 rb->thread_wait(thread_id);
278 /* remove the thread's queue from the broadcast list */
279 rb->queue_delete(&thread_q);
280 return true;
282 else return false;
286 #define BIT_CHARGER 0x1
287 #define BIT_CHARGING 0x2
288 #define BIT_USB_POWER 0x4
290 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
292 /* use long for aligning */
293 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
295 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
296 static unsigned int charge_state(void)
298 unsigned int ret = 0;
299 #if CONFIG_CHARGING
300 if (rb->charger_inserted())
301 ret = BIT_CHARGER;
302 #if CONFIG_CHARGING >= CHARGING_MONITOR
303 if (rb->charging_state())
304 ret |= BIT_CHARGING;
305 #endif
306 #endif
307 #ifdef HAVE_USB_POWER
308 if (rb->usb_powered())
309 ret |= BIT_USB_POWER;
310 #endif
311 return ret;
313 #endif
316 static void flush_buffer(void* data)
318 (void)data;
319 int fd, secs;
320 unsigned int i;
322 /* don't access the disk when in usb mode, or when no data is available */
323 if (in_usb_mode || (buf_idx == 0))
324 return;
326 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
327 if (fd < 0)
328 return;
330 for (i = 0; i < buf_idx; i++)
332 secs = bat[i].ticks/HZ;
333 rb->fdprintf(fd,
334 "%02d:%02d:%02d, %05d, %03d%%, "
335 "%02d:%02d, %04d, "
336 #if CONFIG_CHARGING
337 " %c"
338 #if CONFIG_CHARGING >= CHARGING_MONITOR
339 ", %c"
340 #endif
341 #endif
342 #ifdef HAVE_USB_POWER
343 ", %c"
344 #endif
345 "\n",
347 HMS(secs), secs, bat[i].level,
348 bat[i].eta / 60, bat[i].eta % 60,
349 bat[i].voltage
350 #if CONFIG_CHARGING
351 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
352 #if CONFIG_CHARGING >= CHARGING_MONITOR
353 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
354 #endif
355 #endif
356 #ifdef HAVE_USB_POWER
357 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
358 #endif
361 rb->close(fd);
363 buf_idx = 0;
367 void thread(void)
369 bool exit = false;
370 char *exit_reason = "unknown";
371 long sleep_time = 60 * HZ;
372 struct queue_event ev;
373 int fd;
375 in_usb_mode = false;
376 buf_idx = 0;
378 while (!exit)
380 /* add data to buffer */
381 if (buf_idx < BUF_ELEMENTS)
383 bat[buf_idx].ticks = *rb->current_tick;
384 bat[buf_idx].level = rb->battery_level();
385 bat[buf_idx].eta = rb->battery_time();
386 bat[buf_idx].voltage = rb->battery_voltage();
387 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
388 bat[buf_idx].flags = charge_state();
389 #endif
390 buf_idx++;
391 rb->register_storage_idle_func(flush_buffer);
394 /* What to do when the measurement buffer is full:
395 1) save our measurements to disk but waste some power doing so?
396 2) throw away measurements to save some power?
397 The choice made here is to save the measurements. It is quite unusual
398 for this to occur because it requires > 16 hours of no disk activity.
400 if (buf_idx == BUF_ELEMENTS) {
401 flush_buffer(NULL);
404 /* sleep some time until next measurement */
405 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
406 switch (ev.id)
408 case SYS_USB_CONNECTED:
409 in_usb_mode = true;
410 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
411 break;
412 case SYS_USB_DISCONNECTED:
413 in_usb_mode = false;
414 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
415 break;
416 case SYS_POWEROFF:
417 exit_reason = "power off";
418 exit = true;
419 break;
420 case EV_EXIT:
421 #ifdef HAVE_LCD_BITMAP
422 rb->splash(HZ, "Exiting battery_bench...");
423 #else
424 rb->splash(HZ, "bench exit");
425 #endif
426 exit_reason = "plugin exit";
427 exit = true;
428 break;
432 /* unregister flush callback and flush to disk */
433 rb->unregister_storage_idle_func(flush_buffer, true);
435 /* log end of bench and exit reason */
436 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
437 if (fd >= 0)
439 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
440 rb->close(fd);
445 #ifdef HAVE_LCD_BITMAP
446 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
448 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
450 int strwdt, strhgt;
451 rb->lcd_getstringsize(str, &strwdt, &strhgt);
452 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
454 #endif
456 int main(void)
458 int button, fd;
459 bool on = false;
460 #ifdef HAVE_LCD_BITMAP
461 int i;
462 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
463 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
464 #endif
465 rb->lcd_clear_display();
467 #ifdef HAVE_LCD_BITMAP
468 rb->lcd_clear_display();
469 rb->lcd_setfont(FONT_SYSFIXED);
471 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
472 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
473 #else
474 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
475 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
476 #endif
477 rb->lcd_update();
479 #ifdef HAVE_REMOTE_LCD
480 rb->lcd_remote_clear_display();
481 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
482 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
483 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
484 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
485 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
486 rb->lcd_remote_update();
487 #endif
491 button = rb->button_get(true);
492 switch (button)
494 case BATTERY_ON:
495 #ifdef BATTERY_RC_ON
496 case BATTERY_RC_ON:
497 #endif
498 on = true;
499 break;
500 case BATTERY_OFF:
501 #ifdef BATTERY_RC_OFF
502 case BATTERY_RC_OFF:
503 #endif
504 return PLUGIN_OK;
506 default:
507 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
508 return PLUGIN_USB_CONNECTED;
510 }while(!on);
512 fd = rb->open(BATTERY_LOG, O_RDONLY);
513 if (fd < 0)
515 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
516 if (fd >= 0)
518 rb->fdprintf(fd,
519 "This plugin will log your battery performance in a\n"
520 "file (%s) every minute.\n"
521 "To properly test your battery:\n"
522 "1) Select and playback an album. "
523 "(Be sure to be more than the player's buffer)\n"
524 "2) Set to repeat.\n"
525 "3) Let the player run completely out of battery.\n"
526 "4) Recharge and copy (or whatever you want) the txt file to "
527 "your computer.\n"
528 "Now you can make graphs with the data of the battery log.\n"
529 "Do not enter another plugin during the test or else the "
530 "logging activity will end.\n\n"
531 "P.S: You can decide how you will make your tests.\n"
532 "Just don't open another plugin to be sure that your log "
533 "will continue.\n\n",BATTERY_LOG);
534 rb->fdprintf(fd,
535 "Battery bench run for %s version %s\n\n"
536 ,MODEL_NAME,rb->appsversion);
538 rb->fdprintf(fd,
539 "Battery type: %d mAh Buffer Entries: %d\n"
540 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
541 #if CONFIG_CHARGING
542 ", C:"
543 #endif
544 #if CONFIG_CHARGING >= CHARGING_MONITOR
545 ", S:"
546 #endif
547 #ifdef HAVE_USB_POWER
548 ", U:"
549 #endif
550 "\n"
551 ,rb->global_settings->battery_capacity,
552 (int)BUF_ELEMENTS);
553 rb->close(fd);
555 else
557 rb->splash(HZ / 2, "Cannot create file!");
558 return PLUGIN_ERROR;
561 else
563 rb->close(fd);
564 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
565 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
566 rb->fdprintf(fd,
567 "Battery bench run for %s version %s\n\n"
568 ,MODEL_NAME,rb->appsversion);
569 rb->close(fd);
572 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
573 if ((thread_id = rb->create_thread(thread, thread_stack,
574 sizeof(thread_stack), 0, "Battery Benchmark"
575 IF_PRIO(, PRIORITY_BACKGROUND)
576 IF_COP(, CPU))) == 0)
578 rb->splash(HZ, "Cannot create thread!");
579 return PLUGIN_ERROR;
582 rb->plugin_tsr(exit_tsr);
584 return PLUGIN_OK;