Introduce __attribute__((unused)) (#defined to UNUSED_ATTR) to mark possibly unused...
[kugel-rb.git] / apps / plugins / battery_bench.c
bloba73704f39aa235fd62a0c9d944fe149e4f8cca03
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 == COWOND2_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 == ONDAVX747_PAD
185 #define BATTERY_OFF BUTTON_POWER
186 #define BATTERY_OFF_TXT "POWER"
188 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
190 #define BATTERY_ON BUTTON_LEFT
191 #define BATTERY_OFF BUTTON_RIGHT
192 #define BATTERY_ON_TXT "LEFT"
193 #define BATTERY_OFF_TXT "RIGHT"
195 #else
196 #error No keymap defined!
197 #endif
199 #ifdef HAVE_TOUCHSCREEN
200 #ifndef BATTERY_ON
201 #define BATTERY_ON BUTTON_CENTER
202 #endif
203 #ifndef BATTERY_OFF
204 #define BATTERY_OFF BUTTON_TOPLEFT
205 #endif
206 #ifndef BATTERY_ON_TXT
207 #define BATTERY_ON_TXT "CENTRE - start"
208 #endif
209 #ifndef BATTERY_OFF_TXT
210 #define BATTERY_OFF_TXT "TOPLEFT"
211 #endif
212 #endif
214 /****************************** Plugin Entry Point ****************************/
215 int main(void);
216 bool exit_tsr(bool);
217 void thread(void);
220 enum plugin_status plugin_start(UNUSED_ATTR const void* parameter)
223 return main();
226 /* Struct for battery information */
227 struct batt_info
229 /* the size of the struct elements is optimised to make the struct size
230 * a power of 2 */
231 long ticks;
232 int eta;
233 unsigned int voltage;
234 short level;
235 unsigned short flags;
236 } bat[BUF_SIZE/sizeof(struct batt_info)];
238 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
240 static unsigned int thread_id;
241 static struct event_queue thread_q;
242 static bool in_usb_mode;
243 static unsigned int buf_idx;
245 bool exit_tsr(bool reenter)
247 long button;
248 (void)reenter;
249 rb->lcd_clear_display();
250 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
251 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
252 #ifdef HAVE_LCD_BITMAP
253 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
254 #endif
255 rb->lcd_update();
257 while (1)
259 button = rb->button_get(true);
260 if (IS_SYSEVENT(button))
261 continue;
262 if (button == BATTERY_OFF)
264 rb->queue_post(&thread_q, EV_EXIT, 0);
265 rb->thread_wait(thread_id);
266 /* remove the thread's queue from the broadcast list */
267 rb->queue_delete(&thread_q);
268 return true;
270 else return false;
274 #define BIT_CHARGER 0x1
275 #define BIT_CHARGING 0x2
276 #define BIT_USB_POWER 0x4
278 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
280 /* use long for aligning */
281 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
283 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
284 static unsigned int charge_state(void)
286 unsigned int ret = 0;
287 #if CONFIG_CHARGING
288 if (rb->charger_inserted())
289 ret = BIT_CHARGER;
290 #if CONFIG_CHARGING >= CHARGING_MONITOR
291 if (rb->charging_state())
292 ret |= BIT_CHARGING;
293 #endif
294 #endif
295 #ifdef HAVE_USB_POWER
296 if (rb->usb_powered())
297 ret |= BIT_USB_POWER;
298 #endif
299 return ret;
301 #endif
304 static bool flush_buffer(void)
306 int fd, secs;
307 unsigned int i;
309 /* don't access the disk when in usb mode, or when no data is available */
310 if (in_usb_mode || (buf_idx == 0))
312 return false;
315 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
316 if (fd < 0)
318 return false;
321 for (i = 0; i < buf_idx; i++)
323 secs = bat[i].ticks/HZ;
324 rb->fdprintf(fd,
325 "%02d:%02d:%02d, %05d, %03d%%, "
326 "%02d:%02d, %04d, "
327 #if CONFIG_CHARGING
328 " %c"
329 #if CONFIG_CHARGING >= CHARGING_MONITOR
330 ", %c"
331 #endif
332 #endif
333 #ifdef HAVE_USB_POWER
334 ", %c"
335 #endif
336 "\n",
338 HMS(secs), secs, bat[i].level,
339 bat[i].eta / 60, bat[i].eta % 60,
340 bat[i].voltage
341 #if CONFIG_CHARGING
342 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
343 #if CONFIG_CHARGING >= CHARGING_MONITOR
344 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
345 #endif
346 #endif
347 #ifdef HAVE_USB_POWER
348 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
349 #endif
352 rb->close(fd);
354 buf_idx = 0;
355 return true;
359 void thread(void)
361 bool exit = false;
362 char *exit_reason = "unknown";
363 long sleep_time = 60 * HZ;
364 struct queue_event ev;
365 int fd;
367 in_usb_mode = false;
368 buf_idx = 0;
370 while (!exit)
372 /* add data to buffer */
373 if (buf_idx < BUF_ELEMENTS)
375 bat[buf_idx].ticks = *rb->current_tick;
376 bat[buf_idx].level = rb->battery_level();
377 bat[buf_idx].eta = rb->battery_time();
378 bat[buf_idx].voltage = rb->battery_voltage();
379 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
380 bat[buf_idx].flags = charge_state();
381 #endif
382 buf_idx++;
383 rb->register_storage_idle_func(flush_buffer);
386 /* What to do when the measurement buffer is full:
387 1) save our measurements to disk but waste some power doing so?
388 2) throw away measurements to save some power?
389 The choice made here is to save the measurements. It is quite unusual
390 for this to occur because it requires > 16 hours of no disk activity.
392 if (buf_idx == BUF_ELEMENTS) {
393 flush_buffer();
396 /* sleep some time until next measurement */
397 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
398 switch (ev.id)
400 case SYS_USB_CONNECTED:
401 in_usb_mode = true;
402 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
403 break;
404 case SYS_USB_DISCONNECTED:
405 in_usb_mode = false;
406 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
407 break;
408 case SYS_POWEROFF:
409 exit_reason = "power off";
410 exit = true;
411 break;
412 case EV_EXIT:
413 #ifdef HAVE_LCD_BITMAP
414 rb->splash(HZ, "Exiting battery_bench...");
415 #else
416 rb->splash(HZ, "bench exit");
417 #endif
418 exit_reason = "plugin exit";
419 exit = true;
420 break;
424 /* unregister flush callback and flush to disk */
425 rb->unregister_storage_idle_func(flush_buffer, true);
427 /* log end of bench and exit reason */
428 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
429 if (fd >= 0)
431 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
432 rb->close(fd);
437 #ifdef HAVE_LCD_BITMAP
438 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
440 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
442 int strwdt, strhgt;
443 rb->lcd_getstringsize(str, &strwdt, &strhgt);
444 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
446 #endif
448 int main(void)
450 int button, fd;
451 bool on = false;
452 #ifdef HAVE_LCD_BITMAP
453 int i;
454 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
455 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
456 #endif
457 rb->lcd_clear_display();
459 #ifdef HAVE_LCD_BITMAP
460 rb->lcd_clear_display();
461 rb->lcd_setfont(FONT_SYSFIXED);
463 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
464 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
465 #else
466 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
467 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
468 #endif
469 rb->lcd_update();
471 #ifdef HAVE_REMOTE_LCD
472 rb->lcd_remote_clear_display();
473 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
474 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
475 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
476 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
477 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
478 rb->lcd_remote_update();
479 #endif
483 button = rb->button_get(true);
484 switch (button)
486 case BATTERY_ON:
487 #ifdef BATTERY_RC_ON
488 case BATTERY_RC_ON:
489 #endif
490 on = true;
491 break;
492 case BATTERY_OFF:
493 #ifdef BATTERY_RC_OFF
494 case BATTERY_RC_OFF:
495 #endif
496 return PLUGIN_OK;
498 default:
499 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
500 return PLUGIN_USB_CONNECTED;
502 }while(!on);
504 fd = rb->open(BATTERY_LOG, O_RDONLY);
505 if (fd < 0)
507 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
508 if (fd >= 0)
510 rb->fdprintf(fd,
511 "This plugin will log your battery performance in a\n"
512 "file (%s) every minute.\n"
513 "To properly test your battery:\n"
514 "1) Select and playback an album. "
515 "(Be sure to be more than the player's buffer)\n"
516 "2) Set to repeat.\n"
517 "3) Let the player run completely out of battery.\n"
518 "4) Recharge and copy (or whatever you want) the txt file to "
519 "your computer.\n"
520 "Now you can make graphs with the data of the battery log.\n"
521 "Do not enter another plugin during the test or else the "
522 "logging activity will end.\n\n"
523 "P.S: You can decide how you will make your tests.\n"
524 "Just don't open another plugin to be sure that your log "
525 "will continue.\n\n",BATTERY_LOG);
526 rb->fdprintf(fd,
527 "Battery bench run for %s version %s\n\n"
528 ,MODEL_NAME,rb->appsversion);
530 rb->fdprintf(fd,
531 "Battery type: %d mAh Buffer Entries: %d\n"
532 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
533 #if CONFIG_CHARGING
534 ", C:"
535 #endif
536 #if CONFIG_CHARGING >= CHARGING_MONITOR
537 ", S:"
538 #endif
539 #ifdef HAVE_USB_POWER
540 ", U:"
541 #endif
542 "\n"
543 ,rb->global_settings->battery_capacity,
544 (int)BUF_ELEMENTS);
545 rb->close(fd);
547 else
549 rb->splash(HZ / 2, "Cannot create file!");
550 return PLUGIN_ERROR;
553 else
555 rb->close(fd);
556 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
557 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
558 rb->fdprintf(fd,
559 "Battery bench run for %s version %s\n\n"
560 ,MODEL_NAME,rb->appsversion);
561 rb->close(fd);
564 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
565 if ((thread_id = rb->create_thread(thread, thread_stack,
566 sizeof(thread_stack), 0, "Battery Benchmark"
567 IF_PRIO(, PRIORITY_BACKGROUND)
568 IF_COP(, CPU))) == 0)
570 rb->splash(HZ, "Cannot create thread!");
571 return PLUGIN_ERROR;
574 rb->plugin_tsr(exit_tsr);
576 return PLUGIN_OK;