New makefile solution: A single invocation of 'make' to build the entire tree. Fully...
[kugel-rb.git] / apps / plugins / battery_bench.c
blobfff93b2a3a39b2a1b702eb6405d8b22d9942587b
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 ****************************************************************************/
22 #ifndef SIMULATOR /* not for the simulator */
24 #include "version.h"
25 #include "plugin.h"
26 PLUGIN_HEADER
28 #define BATTERY_LOG "/battery_bench.txt"
29 #define BUF_SIZE 16000
31 #define EV_EXIT 1337
33 /* seems to work with 1300, but who knows... */
34 #define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200
36 #if CONFIG_KEYPAD == RECORDER_PAD
38 #define BATTERY_ON BUTTON_PLAY
39 #define BATTERY_OFF BUTTON_OFF
40 #define BATTERY_ON_TXT "PLAY - start"
41 #define BATTERY_OFF_TXT "OFF"
43 #if BUTTON_REMOTE != 0
44 #define BATTERY_RC_ON BUTTON_RC_PLAY
45 #define BATTERY_RC_OFF BUTTON_RC_STOP
46 #endif
48 #elif CONFIG_KEYPAD == ONDIO_PAD
50 #define BATTERY_ON BUTTON_RIGHT
51 #define BATTERY_OFF BUTTON_OFF
52 #define BATTERY_ON_TXT "RIGHT - start"
53 #define BATTERY_OFF_TXT "OFF"
55 #elif CONFIG_KEYPAD == PLAYER_PAD
57 #define BATTERY_ON BUTTON_PLAY
58 #define BATTERY_OFF BUTTON_STOP
59 #define BATTERY_ON_TXT "PLAY - start"
60 #define BATTERY_OFF_TXT "STOP"
62 #define BATTERY_RC_ON BUTTON_RC_PLAY
63 #define BATTERY_RC_OFF BUTTON_RC_STOP
65 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
66 (CONFIG_KEYPAD == IRIVER_H300_PAD)
68 #define BATTERY_ON BUTTON_ON
69 #define BATTERY_RC_ON BUTTON_RC_ON
71 #define BATTERY_OFF BUTTON_OFF
72 #define BATTERY_RC_OFF BUTTON_RC_STOP
74 #define BATTERY_ON_TXT "PLAY - start"
75 #define BATTERY_OFF_TXT "STOP"
77 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
78 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
79 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
81 #define BATTERY_ON BUTTON_PLAY
82 #define BATTERY_OFF BUTTON_MENU
83 #define BATTERY_ON_TXT "PLAY - start"
84 #define BATTERY_OFF_TXT "MENU"
86 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
88 #define BATTERY_ON BUTTON_SELECT
89 #define BATTERY_OFF BUTTON_POWER
90 #define BATTERY_ON_TXT "SELECT - start"
91 #define BATTERY_OFF_TXT "POWER"
93 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
95 #define BATTERY_ON BUTTON_SELECT
96 #define BATTERY_OFF BUTTON_PLAY
97 #define BATTERY_ON_TXT "SELECT - start"
98 #define BATTERY_OFF_TXT "PLAY"
100 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
101 (CONFIG_KEYPAD == SANSA_C200_PAD)
102 #define BATTERY_ON BUTTON_SELECT
103 #define BATTERY_OFF BUTTON_POWER
104 #define BATTERY_ON_TXT "SELECT - start"
105 #define BATTERY_OFF_TXT "POWER"
107 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
109 #define BATTERY_ON BUTTON_PLAY
110 #define BATTERY_OFF BUTTON_POWER
111 #define BATTERY_ON_TXT "PLAY - start"
112 #define BATTERY_OFF_TXT "POWER"
114 #elif CONFIG_KEYPAD == GIGABEAT_PAD
116 #define BATTERY_ON BUTTON_SELECT
117 #define BATTERY_OFF BUTTON_POWER
118 #define BATTERY_ON_TXT "SELECT - start"
119 #define BATTERY_OFF_TXT "POWER"
121 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
123 #define BATTERY_ON BUTTON_SELECT
124 #define BATTERY_OFF BUTTON_BACK
125 #define BATTERY_ON_TXT "SELECT - start"
126 #define BATTERY_OFF_TXT "BACK"
128 #elif CONFIG_KEYPAD == MROBE500_PAD
130 #define BATTERY_ON BUTTON_RC_PLAY
131 #define BATTERY_OFF BUTTON_POWER
132 #define BATTERY_ON_TXT "PLAY - start"
133 #define BATTERY_OFF_TXT "POWER"
135 #elif CONFIG_KEYPAD == MROBE100_PAD
137 #define BATTERY_ON BUTTON_SELECT
138 #define BATTERY_OFF BUTTON_POWER
139 #define BATTERY_ON_TXT "SELECT - start"
140 #define BATTERY_OFF_TXT "POWER"
142 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
144 #define BATTERY_ON BUTTON_PLAY
145 #define BATTERY_OFF BUTTON_REC
146 #define BATTERY_RC_ON BUTTON_RC_PLAY
147 #define BATTERY_RC_OFF BUTTON_RC_REC
148 #define BATTERY_ON_TXT "PLAY - start"
149 #define BATTERY_OFF_TXT "REC"
151 #elif CONFIG_KEYPAD == COWOND2_PAD
153 #define BATTERY_OFF BUTTON_POWER
154 #define BATTERY_OFF_TXT "POWER"
156 #elif CONFIG_KEYPAD == IAUDIO67_PAD
158 #define BATTERY_OFF BUTTON_POWER
159 #define BATTERY_OFF_TXT "POWER"
160 #define BATTERY_ON BUTTON_PLAY
161 #define BATTERY_ON_TXT "PLAY - start"
162 #else
163 #error No keymap defined!
164 #endif
166 #ifdef HAVE_TOUCHSCREEN
167 #ifndef BATTERY_ON
168 #define BATTERY_ON BUTTON_CENTER
169 #endif
170 #ifndef BATTERY_OFF
171 #define BATTERY_OFF BUTTON_TOPLEFT
172 #endif
173 #ifndef BATTERY_ON_TXT
174 #define BATTERY_ON_TXT "CENTRE - start"
175 #endif
176 #ifndef BATTERY_OFF_TXT
177 #define BATTERY_OFF_TXT "TOPLEFT"
178 #endif
179 #endif
181 /****************************** Plugin Entry Point ****************************/
182 static const struct plugin_api* rb;
183 MEM_FUNCTION_WRAPPERS(rb);
184 int main(void);
185 bool exit_tsr(bool);
186 void thread(void);
189 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
191 (void)parameter;
192 rb = api;
194 return main();
197 /* Struct for battery information */
198 struct batt_info
200 /* the size of the struct elements is optimised to make the struct size
201 * a power of 2 */
202 long ticks;
203 int eta;
204 unsigned int voltage;
205 short level;
206 unsigned short flags;
207 } bat[BUF_SIZE/sizeof(struct batt_info)];
209 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
211 static struct thread_entry *thread_id;
212 static struct event_queue thread_q;
213 static bool in_usb_mode;
214 static unsigned int buf_idx;
216 bool exit_tsr(bool reenter)
218 (void)reenter;
219 rb->lcd_clear_display();
220 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
221 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
222 #ifdef HAVE_LCD_BITMAP
223 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
224 #endif
225 rb->lcd_update();
227 if (rb->button_get(true) == BATTERY_OFF)
229 rb->queue_post(&thread_q, EV_EXIT, 0);
230 rb->thread_wait(thread_id);
231 /* remove the thread's queue from the broadcast list */
232 rb->queue_delete(&thread_q);
233 return true;
235 else return false;
238 #define BIT_CHARGER 0x1
239 #define BIT_CHARGING 0x2
240 #define BIT_USB_POWER 0x4
242 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
244 /* use long for aligning */
245 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
247 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
248 static unsigned int charge_state(void)
250 unsigned int ret = 0;
251 #if CONFIG_CHARGING
252 if (rb->charger_inserted())
253 ret = BIT_CHARGER;
254 #if CONFIG_CHARGING == CHARGING_MONITOR
255 if (rb->charging_state())
256 ret |= BIT_CHARGING;
257 #endif
258 #endif
259 #ifdef HAVE_USB_POWER
260 if (rb->usb_powered())
261 ret |= BIT_USB_POWER;
262 #endif
263 return ret;
265 #endif
268 static bool flush_buffer(void)
270 int fd, secs;
271 unsigned int i;
273 /* don't access the disk when in usb mode, or when no data is available */
274 if (in_usb_mode || (buf_idx == 0))
276 return false;
279 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
280 if (fd < 0)
282 return false;
285 for (i = 0; i < buf_idx; i++)
287 secs = bat[i].ticks/HZ;
288 rb->fdprintf(fd,
289 "%02d:%02d:%02d, %05d, %03d%%, "
290 "%02d:%02d, %04d, "
291 #if CONFIG_CHARGING
292 " %c"
293 #if CONFIG_CHARGING == CHARGING_MONITOR
294 ", %c"
295 #endif
296 #endif
297 #ifdef HAVE_USB_POWER
298 ", %c"
299 #endif
300 "\n",
302 HMS(secs), secs, bat[i].level,
303 bat[i].eta / 60, bat[i].eta % 60,
304 bat[i].voltage
305 #if CONFIG_CHARGING
306 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
307 #if CONFIG_CHARGING == CHARGING_MONITOR
308 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
309 #endif
310 #endif
311 #ifdef HAVE_USB_POWER
312 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
313 #endif
316 rb->close(fd);
318 buf_idx = 0;
319 return true;
323 void thread(void)
325 bool exit = false;
326 char *exit_reason = "unknown";
327 long sleep_time = 60 * HZ;
328 struct queue_event ev;
329 int fd;
331 in_usb_mode = false;
332 buf_idx = 0;
334 while (!exit)
336 /* add data to buffer */
337 if (buf_idx < BUF_ELEMENTS)
339 bat[buf_idx].ticks = *rb->current_tick;
340 bat[buf_idx].level = rb->battery_level();
341 bat[buf_idx].eta = rb->battery_time();
342 bat[buf_idx].voltage = rb->battery_voltage();
343 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
344 bat[buf_idx].flags = charge_state();
345 #endif
346 buf_idx++;
347 rb->register_storage_idle_func(flush_buffer);
350 /* What to do when the measurement buffer is full:
351 1) save our measurements to disk but waste some power doing so?
352 2) throw away measurements to save some power?
353 The choice made here is to save the measurements. It is quite unusual
354 for this to occur because it requires > 16 hours of no disk activity.
356 if (buf_idx == BUF_ELEMENTS) {
357 flush_buffer();
360 /* sleep some time until next measurement */
361 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
362 switch (ev.id)
364 case SYS_USB_CONNECTED:
365 in_usb_mode = true;
366 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
367 break;
368 case SYS_USB_DISCONNECTED:
369 in_usb_mode = false;
370 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
371 break;
372 case SYS_POWEROFF:
373 exit_reason = "power off";
374 exit = true;
375 break;
376 case EV_EXIT:
377 #ifdef HAVE_LCD_BITMAP
378 rb->splash(HZ, "Exiting battery_bench...");
379 #else
380 rb->splash(HZ, "bench exit");
381 #endif
382 exit_reason = "plugin exit";
383 exit = true;
384 break;
388 /* unregister flush callback and flush to disk */
389 rb->unregister_storage_idle_func(flush_buffer, true);
391 /* log end of bench and exit reason */
392 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
393 if (fd >= 0)
395 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
396 rb->close(fd);
401 #ifdef HAVE_LCD_BITMAP
402 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
404 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
406 int strwdt, strhgt;
407 rb->lcd_getstringsize(str, &strwdt, &strhgt);
408 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
410 #endif
412 int main(void)
414 int button, fd;
415 bool on = false;
416 #ifdef HAVE_LCD_BITMAP
417 int i;
418 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
419 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
420 #endif
421 rb->lcd_clear_display();
423 #ifdef HAVE_LCD_BITMAP
424 rb->lcd_clear_display();
425 rb->lcd_setfont(FONT_SYSFIXED);
427 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
428 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
429 #else
430 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
431 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
432 #endif
433 rb->lcd_update();
435 #ifdef HAVE_REMOTE_LCD
436 rb->lcd_remote_clear_display();
437 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
438 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
439 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
440 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
441 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
442 rb->lcd_remote_update();
443 #endif
447 button = rb->button_get(true);
448 switch (button)
450 case BATTERY_ON:
451 #ifdef BATTERY_RC_ON
452 case BATTERY_RC_ON:
453 #endif
454 on = true;
455 break;
456 case BATTERY_OFF:
457 #ifdef BATTERY_RC_OFF
458 case BATTERY_RC_OFF:
459 #endif
460 return PLUGIN_OK;
462 default:
463 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
464 return PLUGIN_USB_CONNECTED;
466 }while(!on);
468 fd = rb->open(BATTERY_LOG, O_RDONLY);
469 if (fd < 0)
471 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
472 if (fd >= 0)
474 rb->fdprintf(fd,
475 "This plugin will log your battery performance in a\n"
476 "file (%s) every minute.\n"
477 "To properly test your battery:\n"
478 "1) Select and playback an album. "
479 "(Be sure to be more than the player's buffer)\n"
480 "2) Set to repeat.\n"
481 "3) Let the player run completely out of battery.\n"
482 "4) Recharge and copy (or whatever you want) the txt file to "
483 "your computer.\n"
484 "Now you can make graphs with the data of the battery log.\n"
485 "Do not enter another plugin during the test or else the "
486 "logging activity will end.\n\n"
487 "P.S: You can decide how you will make your tests.\n"
488 "Just don't open another plugin to be sure that your log "
489 "will continue.\n\n",BATTERY_LOG);
490 rb->fdprintf(fd,
491 "Battery bench run for %s version %s\n\n"
492 ,MODEL_NAME,rb->appsversion);
494 rb->fdprintf(fd,
495 "Battery type: %d mAh Buffer Entries: %d\n"
496 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
497 #if CONFIG_CHARGING
498 ", C:"
499 #endif
500 #if CONFIG_CHARGING == CHARGING_MONITOR
501 ", S:"
502 #endif
503 #ifdef HAVE_USB_POWER
504 ", U:"
505 #endif
506 "\n"
507 ,rb->global_settings->battery_capacity,
508 (int)BUF_ELEMENTS);
509 rb->close(fd);
511 else
513 rb->splash(HZ / 2, "Cannot create file!");
514 return PLUGIN_ERROR;
517 else
519 rb->close(fd);
520 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
521 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
522 rb->fdprintf(fd,
523 "Battery bench run for %s version %s\n\n"
524 ,MODEL_NAME,rb->appsversion);
525 rb->close(fd);
528 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
529 if ((thread_id = rb->create_thread(thread, thread_stack,
530 sizeof(thread_stack), 0, "Battery Benchmark"
531 IF_PRIO(, PRIORITY_BACKGROUND)
532 IF_COP(, CPU))) == NULL)
534 rb->splash(HZ, "Cannot create thread!");
535 return PLUGIN_ERROR;
538 rb->plugin_tsr(exit_tsr);
540 return PLUGIN_OK;
543 #endif /* SIMULATOR */