Extract config file saving code to a function; Do not write the NUL character to...
[kugel-rb.git] / apps / plugins / battery_bench.c
blob3f90a72b3e199acc44b7fe40cdd43593bb910075
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 "/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_HDD6330_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 == PHILIPS_SA9200_PAD
192 #define BATTERY_ON BUTTON_MENU
193 #define BATTERY_OFF BUTTON_POWER
194 #define BATTERY_ON_TXT "MENU - start"
195 #define BATTERY_OFF_TXT "POWER"
197 #elif CONFIG_KEYPAD == ONDAVX747_PAD
199 #define BATTERY_OFF BUTTON_POWER
200 #define BATTERY_OFF_TXT "POWER"
201 #elif CONFIG_KEYPAD == ONDAVX777_PAD
203 #define BATTERY_OFF BUTTON_POWER
204 #define BATTERY_OFF_TXT "POWER"
206 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
208 #define BATTERY_ON BUTTON_LEFT
209 #define BATTERY_OFF BUTTON_RIGHT
210 #define BATTERY_ON_TXT "LEFT"
211 #define BATTERY_OFF_TXT "RIGHT"
213 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
215 #define BATTERY_ON BUTTON_PLAY
216 #define BATTERY_OFF BUTTON_REC
217 #define BATTERY_ON_TXT "PLAY - start"
218 #define BATTERY_OFF_TXT "REC"
220 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
221 #define BATTERY_ON BUTTON_PLAY
222 #define BATTERY_OFF BUTTON_REC
223 #define BATTERY_ON_TXT "PLAY - start"
224 #define BATTERY_OFF_TXT "REC"
226 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
227 #define BATTERY_ON BUTTON_PLAY
228 #define BATTERY_OFF BUTTON_REC
229 #define BATTERY_ON_TXT "PLAY - start"
230 #define BATTERY_OFF_TXT "REC"
232 #else
233 #error No keymap defined!
234 #endif
236 #ifdef HAVE_TOUCHSCREEN
237 #ifndef BATTERY_ON
238 #define BATTERY_ON BUTTON_CENTER
239 #endif
240 #ifndef BATTERY_OFF
241 #define BATTERY_OFF BUTTON_TOPLEFT
242 #endif
243 #ifndef BATTERY_ON_TXT
244 #define BATTERY_ON_TXT "CENTRE - start"
245 #endif
246 #ifndef BATTERY_OFF_TXT
247 #define BATTERY_OFF_TXT "TOPLEFT"
248 #endif
249 #endif
251 /****************************** Plugin Entry Point ****************************/
252 static long start_tick;
254 /* Struct for battery information */
255 static struct batt_info
257 /* the size of the struct elements is optimised to make the struct size
258 * a power of 2 */
259 unsigned secs;
260 int eta;
261 unsigned int voltage;
262 short level;
263 unsigned short flags;
264 } bat[BUF_SIZE/sizeof(struct batt_info)];
266 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
268 static unsigned int thread_id;
269 static struct event_queue thread_q;
270 static bool in_usb_mode;
271 static unsigned int buf_idx;
273 static bool exit_tsr(bool reenter)
275 long button;
276 (void)reenter;
277 rb->lcd_clear_display();
278 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
279 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
280 #ifdef HAVE_LCD_BITMAP
281 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
282 #endif
283 rb->lcd_update();
285 while (1)
287 button = rb->button_get(true);
288 if (IS_SYSEVENT(button))
289 continue;
290 if (button == BATTERY_OFF)
292 rb->queue_post(&thread_q, EV_EXIT, 0);
293 rb->thread_wait(thread_id);
294 /* remove the thread's queue from the broadcast list */
295 rb->queue_delete(&thread_q);
296 return true;
298 else return false;
302 #define BIT_CHARGER 0x1
303 #define BIT_CHARGING 0x2
304 #define BIT_USB_POWER 0x4
306 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
308 /* use long for aligning */
309 static unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
311 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
312 static unsigned int charge_state(void)
314 unsigned int ret = 0;
315 #if CONFIG_CHARGING
316 if (rb->charger_inserted())
317 ret = BIT_CHARGER;
318 #if CONFIG_CHARGING >= CHARGING_MONITOR
319 if (rb->charging_state())
320 ret |= BIT_CHARGING;
321 #endif
322 #endif
323 #ifdef HAVE_USB_POWER
324 if (rb->usb_powered())
325 ret |= BIT_USB_POWER;
326 #endif
327 return ret;
329 #endif
332 static void flush_buffer(void* data)
334 (void)data;
335 int fd;
336 unsigned int i;
338 /* don't access the disk when in usb mode, or when no data is available */
339 if (in_usb_mode || (buf_idx == 0))
340 return;
342 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
343 if (fd < 0)
344 return;
346 for (i = 0; i < buf_idx; i++)
348 rb->fdprintf(fd,
349 "%02d:%02d:%02d, %05d, %03d%%, "
350 "%02d:%02d, %04d, "
351 #if CONFIG_CHARGING
352 " %c"
353 #if CONFIG_CHARGING >= CHARGING_MONITOR
354 ", %c"
355 #endif
356 #endif
357 #ifdef HAVE_USB_POWER
358 ", %c"
359 #endif
360 "\n",
362 HMS(bat[i].secs), bat[i].secs, bat[i].level,
363 bat[i].eta / 60, bat[i].eta % 60,
364 bat[i].voltage
365 #if CONFIG_CHARGING
366 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
367 #if CONFIG_CHARGING >= CHARGING_MONITOR
368 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
369 #endif
370 #endif
371 #ifdef HAVE_USB_POWER
372 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
373 #endif
376 rb->close(fd);
378 buf_idx = 0;
382 static void thread(void)
384 bool exit = false;
385 char *exit_reason = "unknown";
386 long sleep_time = 60 * HZ;
387 struct queue_event ev;
388 int fd;
390 in_usb_mode = false;
391 buf_idx = 0;
393 while (!exit)
395 /* add data to buffer */
396 if (buf_idx < BUF_ELEMENTS)
398 bat[buf_idx].secs = (*rb->current_tick - start_tick) / HZ;
399 bat[buf_idx].level = rb->battery_level();
400 bat[buf_idx].eta = rb->battery_time();
401 bat[buf_idx].voltage = rb->battery_voltage();
402 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
403 bat[buf_idx].flags = charge_state();
404 #endif
405 buf_idx++;
406 rb->register_storage_idle_func(flush_buffer);
409 /* What to do when the measurement buffer is full:
410 1) save our measurements to disk but waste some power doing so?
411 2) throw away measurements to save some power?
412 The choice made here is to save the measurements. It is quite unusual
413 for this to occur because it requires > 16 hours of no disk activity.
415 if (buf_idx == BUF_ELEMENTS) {
416 flush_buffer(NULL);
419 /* sleep some time until next measurement */
420 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
421 switch (ev.id)
423 case SYS_USB_CONNECTED:
424 in_usb_mode = true;
425 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
426 break;
427 case SYS_USB_DISCONNECTED:
428 in_usb_mode = false;
429 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
430 break;
431 case SYS_POWEROFF:
432 exit_reason = "power off";
433 exit = true;
434 break;
435 case EV_EXIT:
436 #ifdef HAVE_LCD_BITMAP
437 rb->splash(HZ, "Exiting battery_bench...");
438 #else
439 rb->splash(HZ, "bench exit");
440 #endif
441 exit_reason = "plugin exit";
442 exit = true;
443 break;
447 /* unregister flush callback and flush to disk */
448 rb->unregister_storage_idle_func(flush_buffer, true);
450 /* log end of bench and exit reason */
451 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND, 0666);
452 if (fd >= 0)
454 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
455 rb->close(fd);
460 #ifdef HAVE_LCD_BITMAP
461 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
463 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
465 int strwdt, strhgt;
466 rb->lcd_getstringsize(str, &strwdt, &strhgt);
467 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
469 #endif
471 enum plugin_status plugin_start(const void* parameter)
473 (void)parameter;
474 int button, fd;
475 bool on = false;
476 start_tick = *rb->current_tick;
477 #ifdef HAVE_LCD_BITMAP
478 int i;
479 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
480 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
481 #endif
482 rb->lcd_clear_display();
484 #ifdef HAVE_LCD_BITMAP
485 rb->lcd_clear_display();
486 rb->lcd_setfont(FONT_SYSFIXED);
488 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
489 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
490 #else
491 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
492 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
493 #endif
494 rb->lcd_update();
496 #ifdef HAVE_REMOTE_LCD
497 rb->lcd_remote_clear_display();
498 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
499 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
500 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
501 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
502 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
503 rb->lcd_remote_update();
504 #endif
508 button = rb->button_get(true);
509 switch (button)
511 case BATTERY_ON:
512 #ifdef BATTERY_RC_ON
513 case BATTERY_RC_ON:
514 #endif
515 on = true;
516 break;
517 case BATTERY_OFF:
518 #ifdef BATTERY_RC_OFF
519 case BATTERY_RC_OFF:
520 #endif
521 return PLUGIN_OK;
523 default:
524 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
525 return PLUGIN_USB_CONNECTED;
527 }while(!on);
529 fd = rb->open(BATTERY_LOG, O_RDONLY);
530 if (fd < 0)
532 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT, 0666);
533 if (fd >= 0)
535 rb->fdprintf(fd,
536 "# This plugin will log your battery performance in a\n"
537 "# file (%s) every minute.\n"
538 "# To properly test your battery:\n"
539 "# 1) Select and playback an album. "
540 "# (Be sure to be more than the player's buffer)\n"
541 "# 2) Set to repeat.\n"
542 "# 3) Let the player run completely out of battery.\n"
543 "# 4) Recharge and copy (or whatever you want) the txt file to "
544 "# your computer.\n"
545 "# Now you can make graphs with the data of the battery log.\n"
546 "# Do not enter another plugin during the test or else the \n"
547 "# logging activity will end.\n\n"
548 "# P.S: You can decide how you will make your tests.\n"
549 "# Just don't open another plugin to be sure that your log "
550 "will continue.\n\n",BATTERY_LOG);
551 rb->fdprintf(fd,
552 "# Battery bench run for %s version %s\n\n"
553 ,MODEL_NAME,rb->rbversion);
555 rb->fdprintf(fd, "# Battery type: %d mAh Buffer Entries: %d\n",
556 rb->global_settings->battery_capacity, (int)BUF_ELEMENTS);
558 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
559 HMS((unsigned)start_tick/HZ));
561 rb->fdprintf(fd,
562 "# Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
563 #if CONFIG_CHARGING
564 ", C:"
565 #endif
566 #if CONFIG_CHARGING >= CHARGING_MONITOR
567 ", S:"
568 #endif
569 #ifdef HAVE_USB_POWER
570 ", U:"
571 #endif
572 "\n");
573 rb->close(fd);
575 else
577 rb->splash(HZ / 2, "Cannot create file!");
578 return PLUGIN_ERROR;
581 else
583 rb->close(fd);
584 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
585 rb->fdprintf(fd, "\n# --File already present. Resuming Benchmark--\n");
586 rb->fdprintf(fd,
587 "# Battery bench run for %s version %s\n\n"
588 ,MODEL_NAME,rb->rbversion);
589 rb->fdprintf(fd, "# Rockbox has been running for %02d:%02d:%02d\n",
590 HMS((unsigned)start_tick/HZ));
591 rb->close(fd);
594 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
595 if ((thread_id = rb->create_thread(thread, thread_stack,
596 sizeof(thread_stack), 0, "Battery Benchmark"
597 IF_PRIO(, PRIORITY_BACKGROUND)
598 IF_COP(, CPU))) == 0)
600 rb->splash(HZ, "Cannot create thread!");
601 return PLUGIN_ERROR;
604 rb->plugin_tsr(exit_tsr);
606 return PLUGIN_OK;