Use a more natural guard for the callback definition
[kugel-rb.git] / apps / plugins / battery_bench.c
blobe4e399ff7bd8fbc89c29691a3e2f34434c59ab8c
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 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
208 #define BATTERY_ON BUTTON_PLAY
209 #define BATTERY_OFF BUTTON_REC
210 #define BATTERY_ON_TXT "PLAY - start"
211 #define BATTERY_OFF_TXT "REC"
213 #else
214 #error No keymap defined!
215 #endif
217 #ifdef HAVE_TOUCHSCREEN
218 #ifndef BATTERY_ON
219 #define BATTERY_ON BUTTON_CENTER
220 #endif
221 #ifndef BATTERY_OFF
222 #define BATTERY_OFF BUTTON_TOPLEFT
223 #endif
224 #ifndef BATTERY_ON_TXT
225 #define BATTERY_ON_TXT "CENTRE - start"
226 #endif
227 #ifndef BATTERY_OFF_TXT
228 #define BATTERY_OFF_TXT "TOPLEFT"
229 #endif
230 #endif
232 /****************************** Plugin Entry Point ****************************/
233 int main(void);
234 bool exit_tsr(bool);
235 void thread(void);
238 enum plugin_status plugin_start(const void* parameter)
240 (void)parameter;
242 return main();
245 /* Struct for battery information */
246 struct batt_info
248 /* the size of the struct elements is optimised to make the struct size
249 * a power of 2 */
250 long ticks;
251 int eta;
252 unsigned int voltage;
253 short level;
254 unsigned short flags;
255 } bat[BUF_SIZE/sizeof(struct batt_info)];
257 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
259 static unsigned int thread_id;
260 static struct event_queue thread_q;
261 static bool in_usb_mode;
262 static unsigned int buf_idx;
264 bool exit_tsr(bool reenter)
266 long button;
267 (void)reenter;
268 rb->lcd_clear_display();
269 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
270 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
271 #ifdef HAVE_LCD_BITMAP
272 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
273 #endif
274 rb->lcd_update();
276 while (1)
278 button = rb->button_get(true);
279 if (IS_SYSEVENT(button))
280 continue;
281 if (button == BATTERY_OFF)
283 rb->queue_post(&thread_q, EV_EXIT, 0);
284 rb->thread_wait(thread_id);
285 /* remove the thread's queue from the broadcast list */
286 rb->queue_delete(&thread_q);
287 return true;
289 else return false;
293 #define BIT_CHARGER 0x1
294 #define BIT_CHARGING 0x2
295 #define BIT_USB_POWER 0x4
297 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
299 /* use long for aligning */
300 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
302 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
303 static unsigned int charge_state(void)
305 unsigned int ret = 0;
306 #if CONFIG_CHARGING
307 if (rb->charger_inserted())
308 ret = BIT_CHARGER;
309 #if CONFIG_CHARGING >= CHARGING_MONITOR
310 if (rb->charging_state())
311 ret |= BIT_CHARGING;
312 #endif
313 #endif
314 #ifdef HAVE_USB_POWER
315 if (rb->usb_powered())
316 ret |= BIT_USB_POWER;
317 #endif
318 return ret;
320 #endif
323 static void flush_buffer(void* data)
325 (void)data;
326 int fd, secs;
327 unsigned int i;
329 /* don't access the disk when in usb mode, or when no data is available */
330 if (in_usb_mode || (buf_idx == 0))
331 return;
333 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
334 if (fd < 0)
335 return;
337 for (i = 0; i < buf_idx; i++)
339 secs = bat[i].ticks/HZ;
340 rb->fdprintf(fd,
341 "%02d:%02d:%02d, %05d, %03d%%, "
342 "%02d:%02d, %04d, "
343 #if CONFIG_CHARGING
344 " %c"
345 #if CONFIG_CHARGING >= CHARGING_MONITOR
346 ", %c"
347 #endif
348 #endif
349 #ifdef HAVE_USB_POWER
350 ", %c"
351 #endif
352 "\n",
354 HMS(secs), secs, bat[i].level,
355 bat[i].eta / 60, bat[i].eta % 60,
356 bat[i].voltage
357 #if CONFIG_CHARGING
358 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
359 #if CONFIG_CHARGING >= CHARGING_MONITOR
360 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
361 #endif
362 #endif
363 #ifdef HAVE_USB_POWER
364 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
365 #endif
368 rb->close(fd);
370 buf_idx = 0;
374 void thread(void)
376 bool exit = false;
377 char *exit_reason = "unknown";
378 long sleep_time = 60 * HZ;
379 struct queue_event ev;
380 int fd;
382 in_usb_mode = false;
383 buf_idx = 0;
385 while (!exit)
387 /* add data to buffer */
388 if (buf_idx < BUF_ELEMENTS)
390 bat[buf_idx].ticks = *rb->current_tick;
391 bat[buf_idx].level = rb->battery_level();
392 bat[buf_idx].eta = rb->battery_time();
393 bat[buf_idx].voltage = rb->battery_voltage();
394 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
395 bat[buf_idx].flags = charge_state();
396 #endif
397 buf_idx++;
398 rb->register_storage_idle_func(flush_buffer);
401 /* What to do when the measurement buffer is full:
402 1) save our measurements to disk but waste some power doing so?
403 2) throw away measurements to save some power?
404 The choice made here is to save the measurements. It is quite unusual
405 for this to occur because it requires > 16 hours of no disk activity.
407 if (buf_idx == BUF_ELEMENTS) {
408 flush_buffer(NULL);
411 /* sleep some time until next measurement */
412 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
413 switch (ev.id)
415 case SYS_USB_CONNECTED:
416 in_usb_mode = true;
417 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
418 break;
419 case SYS_USB_DISCONNECTED:
420 in_usb_mode = false;
421 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
422 break;
423 case SYS_POWEROFF:
424 exit_reason = "power off";
425 exit = true;
426 break;
427 case EV_EXIT:
428 #ifdef HAVE_LCD_BITMAP
429 rb->splash(HZ, "Exiting battery_bench...");
430 #else
431 rb->splash(HZ, "bench exit");
432 #endif
433 exit_reason = "plugin exit";
434 exit = true;
435 break;
439 /* unregister flush callback and flush to disk */
440 rb->unregister_storage_idle_func(flush_buffer, true);
442 /* log end of bench and exit reason */
443 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
444 if (fd >= 0)
446 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
447 rb->close(fd);
452 #ifdef HAVE_LCD_BITMAP
453 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
455 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
457 int strwdt, strhgt;
458 rb->lcd_getstringsize(str, &strwdt, &strhgt);
459 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
461 #endif
463 int main(void)
465 int button, fd;
466 bool on = false;
467 #ifdef HAVE_LCD_BITMAP
468 int i;
469 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
470 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
471 #endif
472 rb->lcd_clear_display();
474 #ifdef HAVE_LCD_BITMAP
475 rb->lcd_clear_display();
476 rb->lcd_setfont(FONT_SYSFIXED);
478 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
479 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
480 #else
481 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
482 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
483 #endif
484 rb->lcd_update();
486 #ifdef HAVE_REMOTE_LCD
487 rb->lcd_remote_clear_display();
488 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
489 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
490 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
491 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
492 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
493 rb->lcd_remote_update();
494 #endif
498 button = rb->button_get(true);
499 switch (button)
501 case BATTERY_ON:
502 #ifdef BATTERY_RC_ON
503 case BATTERY_RC_ON:
504 #endif
505 on = true;
506 break;
507 case BATTERY_OFF:
508 #ifdef BATTERY_RC_OFF
509 case BATTERY_RC_OFF:
510 #endif
511 return PLUGIN_OK;
513 default:
514 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
515 return PLUGIN_USB_CONNECTED;
517 }while(!on);
519 fd = rb->open(BATTERY_LOG, O_RDONLY);
520 if (fd < 0)
522 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
523 if (fd >= 0)
525 rb->fdprintf(fd,
526 "This plugin will log your battery performance in a\n"
527 "file (%s) every minute.\n"
528 "To properly test your battery:\n"
529 "1) Select and playback an album. "
530 "(Be sure to be more than the player's buffer)\n"
531 "2) Set to repeat.\n"
532 "3) Let the player run completely out of battery.\n"
533 "4) Recharge and copy (or whatever you want) the txt file to "
534 "your computer.\n"
535 "Now you can make graphs with the data of the battery log.\n"
536 "Do not enter another plugin during the test or else the "
537 "logging activity will end.\n\n"
538 "P.S: You can decide how you will make your tests.\n"
539 "Just don't open another plugin to be sure that your log "
540 "will continue.\n\n",BATTERY_LOG);
541 rb->fdprintf(fd,
542 "Battery bench run for %s version %s\n\n"
543 ,MODEL_NAME,rb->appsversion);
545 rb->fdprintf(fd,
546 "Battery type: %d mAh Buffer Entries: %d\n"
547 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
548 #if CONFIG_CHARGING
549 ", C:"
550 #endif
551 #if CONFIG_CHARGING >= CHARGING_MONITOR
552 ", S:"
553 #endif
554 #ifdef HAVE_USB_POWER
555 ", U:"
556 #endif
557 "\n"
558 ,rb->global_settings->battery_capacity,
559 (int)BUF_ELEMENTS);
560 rb->close(fd);
562 else
564 rb->splash(HZ / 2, "Cannot create file!");
565 return PLUGIN_ERROR;
568 else
570 rb->close(fd);
571 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
572 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
573 rb->fdprintf(fd,
574 "Battery bench run for %s version %s\n\n"
575 ,MODEL_NAME,rb->appsversion);
576 rb->close(fd);
579 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
580 if ((thread_id = rb->create_thread(thread, thread_stack,
581 sizeof(thread_stack), 0, "Battery Benchmark"
582 IF_PRIO(, PRIORITY_BACKGROUND)
583 IF_COP(, CPU))) == 0)
585 rb->splash(HZ, "Cannot create thread!");
586 return PLUGIN_ERROR;
589 rb->plugin_tsr(exit_tsr);
591 return PLUGIN_OK;