Fix red in bootloaders
[maemo-rb.git] / apps / plugins / battery_bench.c
blobaed9c77317f8454760b76180e2ccb43f0f0762fd
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 #else
189 #error No keymap defined!
190 #endif
192 #ifdef HAVE_TOUCHSCREEN
193 #ifndef BATTERY_ON
194 #define BATTERY_ON BUTTON_CENTER
195 #endif
196 #ifndef BATTERY_OFF
197 #define BATTERY_OFF BUTTON_TOPLEFT
198 #endif
199 #ifndef BATTERY_ON_TXT
200 #define BATTERY_ON_TXT "CENTRE - start"
201 #endif
202 #ifndef BATTERY_OFF_TXT
203 #define BATTERY_OFF_TXT "TOPLEFT"
204 #endif
205 #endif
207 /****************************** Plugin Entry Point ****************************/
208 int main(void);
209 bool exit_tsr(bool);
210 void thread(void);
213 enum plugin_status plugin_start(const void* parameter)
215 (void)parameter;
217 return main();
220 /* Struct for battery information */
221 struct batt_info
223 /* the size of the struct elements is optimised to make the struct size
224 * a power of 2 */
225 long ticks;
226 int eta;
227 unsigned int voltage;
228 short level;
229 unsigned short flags;
230 } bat[BUF_SIZE/sizeof(struct batt_info)];
232 #define BUF_ELEMENTS (sizeof(bat)/sizeof(struct batt_info))
234 static unsigned int thread_id;
235 static struct event_queue thread_q;
236 static bool in_usb_mode;
237 static unsigned int buf_idx;
239 bool exit_tsr(bool reenter)
241 long button;
242 (void)reenter;
243 rb->lcd_clear_display();
244 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
245 rb->lcd_puts_scroll(0, 1, "Press " BATTERY_OFF_TXT " to cancel the test");
246 #ifdef HAVE_LCD_BITMAP
247 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
248 #endif
249 rb->lcd_update();
251 while (1)
253 button = rb->button_get(true);
254 if (IS_SYSEVENT(button))
255 continue;
256 if (button == BATTERY_OFF)
258 rb->queue_post(&thread_q, EV_EXIT, 0);
259 rb->thread_wait(thread_id);
260 /* remove the thread's queue from the broadcast list */
261 rb->queue_delete(&thread_q);
262 return true;
264 else return false;
268 #define BIT_CHARGER 0x1
269 #define BIT_CHARGING 0x2
270 #define BIT_USB_POWER 0x4
272 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
274 /* use long for aligning */
275 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
277 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
278 static unsigned int charge_state(void)
280 unsigned int ret = 0;
281 #if CONFIG_CHARGING
282 if (rb->charger_inserted())
283 ret = BIT_CHARGER;
284 #if CONFIG_CHARGING >= CHARGING_MONITOR
285 if (rb->charging_state())
286 ret |= BIT_CHARGING;
287 #endif
288 #endif
289 #ifdef HAVE_USB_POWER
290 if (rb->usb_powered())
291 ret |= BIT_USB_POWER;
292 #endif
293 return ret;
295 #endif
298 static bool flush_buffer(void)
300 int fd, secs;
301 unsigned int i;
303 /* don't access the disk when in usb mode, or when no data is available */
304 if (in_usb_mode || (buf_idx == 0))
306 return false;
309 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
310 if (fd < 0)
312 return false;
315 for (i = 0; i < buf_idx; i++)
317 secs = bat[i].ticks/HZ;
318 rb->fdprintf(fd,
319 "%02d:%02d:%02d, %05d, %03d%%, "
320 "%02d:%02d, %04d, "
321 #if CONFIG_CHARGING
322 " %c"
323 #if CONFIG_CHARGING >= CHARGING_MONITOR
324 ", %c"
325 #endif
326 #endif
327 #ifdef HAVE_USB_POWER
328 ", %c"
329 #endif
330 "\n",
332 HMS(secs), secs, bat[i].level,
333 bat[i].eta / 60, bat[i].eta % 60,
334 bat[i].voltage
335 #if CONFIG_CHARGING
336 , (bat[i].flags & BIT_CHARGER) ? 'A' : '-'
337 #if CONFIG_CHARGING >= CHARGING_MONITOR
338 , (bat[i].flags & BIT_CHARGING) ? 'C' : '-'
339 #endif
340 #endif
341 #ifdef HAVE_USB_POWER
342 , (bat[i].flags & BIT_USB_POWER) ? 'U' : '-'
343 #endif
346 rb->close(fd);
348 buf_idx = 0;
349 return true;
353 void thread(void)
355 bool exit = false;
356 char *exit_reason = "unknown";
357 long sleep_time = 60 * HZ;
358 struct queue_event ev;
359 int fd;
361 in_usb_mode = false;
362 buf_idx = 0;
364 while (!exit)
366 /* add data to buffer */
367 if (buf_idx < BUF_ELEMENTS)
369 bat[buf_idx].ticks = *rb->current_tick;
370 bat[buf_idx].level = rb->battery_level();
371 bat[buf_idx].eta = rb->battery_time();
372 bat[buf_idx].voltage = rb->battery_voltage();
373 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
374 bat[buf_idx].flags = charge_state();
375 #endif
376 buf_idx++;
377 rb->register_storage_idle_func(flush_buffer);
380 /* What to do when the measurement buffer is full:
381 1) save our measurements to disk but waste some power doing so?
382 2) throw away measurements to save some power?
383 The choice made here is to save the measurements. It is quite unusual
384 for this to occur because it requires > 16 hours of no disk activity.
386 if (buf_idx == BUF_ELEMENTS) {
387 flush_buffer();
390 /* sleep some time until next measurement */
391 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
392 switch (ev.id)
394 case SYS_USB_CONNECTED:
395 in_usb_mode = true;
396 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
397 break;
398 case SYS_USB_DISCONNECTED:
399 in_usb_mode = false;
400 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
401 break;
402 case SYS_POWEROFF:
403 exit_reason = "power off";
404 exit = true;
405 break;
406 case EV_EXIT:
407 #ifdef HAVE_LCD_BITMAP
408 rb->splash(HZ, "Exiting battery_bench...");
409 #else
410 rb->splash(HZ, "bench exit");
411 #endif
412 exit_reason = "plugin exit";
413 exit = true;
414 break;
418 /* unregister flush callback and flush to disk */
419 rb->unregister_storage_idle_func(flush_buffer, true);
421 /* log end of bench and exit reason */
422 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
423 if (fd >= 0)
425 rb->fdprintf(fd, "--Battery bench ended, reason: %s--\n", exit_reason);
426 rb->close(fd);
431 #ifdef HAVE_LCD_BITMAP
432 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
434 static void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
436 int strwdt, strhgt;
437 rb->lcd_getstringsize(str, &strwdt, &strhgt);
438 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
440 #endif
442 int main(void)
444 int button, fd;
445 bool on = false;
446 #ifdef HAVE_LCD_BITMAP
447 int i;
448 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
449 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT " - quit" };
450 #endif
451 rb->lcd_clear_display();
453 #ifdef HAVE_LCD_BITMAP
454 rb->lcd_clear_display();
455 rb->lcd_setfont(FONT_SYSFIXED);
457 for (i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
458 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
459 #else
460 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
461 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
462 #endif
463 rb->lcd_update();
465 #ifdef HAVE_REMOTE_LCD
466 rb->lcd_remote_clear_display();
467 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
468 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
469 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
470 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
471 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
472 rb->lcd_remote_update();
473 #endif
477 button = rb->button_get(true);
478 switch (button)
480 case BATTERY_ON:
481 #ifdef BATTERY_RC_ON
482 case BATTERY_RC_ON:
483 #endif
484 on = true;
485 break;
486 case BATTERY_OFF:
487 #ifdef BATTERY_RC_OFF
488 case BATTERY_RC_OFF:
489 #endif
490 return PLUGIN_OK;
492 default:
493 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
494 return PLUGIN_USB_CONNECTED;
496 }while(!on);
498 fd = rb->open(BATTERY_LOG, O_RDONLY);
499 if (fd < 0)
501 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
502 if (fd >= 0)
504 rb->fdprintf(fd,
505 "This plugin will log your battery performance in a\n"
506 "file (%s) every minute.\n"
507 "To properly test your battery:\n"
508 "1) Select and playback an album. "
509 "(Be sure to be more than the player's buffer)\n"
510 "2) Set to repeat.\n"
511 "3) Let the player run completely out of battery.\n"
512 "4) Recharge and copy (or whatever you want) the txt file to "
513 "your computer.\n"
514 "Now you can make graphs with the data of the battery log.\n"
515 "Do not enter another plugin during the test or else the "
516 "logging activity will end.\n\n"
517 "P.S: You can decide how you will make your tests.\n"
518 "Just don't open another plugin to be sure that your log "
519 "will continue.\n\n",BATTERY_LOG);
520 rb->fdprintf(fd,
521 "Battery bench run for %s version %s\n\n"
522 ,MODEL_NAME,rb->appsversion);
524 rb->fdprintf(fd,
525 "Battery type: %d mAh Buffer Entries: %d\n"
526 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:"
527 #if CONFIG_CHARGING
528 ", C:"
529 #endif
530 #if CONFIG_CHARGING >= CHARGING_MONITOR
531 ", S:"
532 #endif
533 #ifdef HAVE_USB_POWER
534 ", U:"
535 #endif
536 "\n"
537 ,rb->global_settings->battery_capacity,
538 (int)BUF_ELEMENTS);
539 rb->close(fd);
541 else
543 rb->splash(HZ / 2, "Cannot create file!");
544 return PLUGIN_ERROR;
547 else
549 rb->close(fd);
550 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
551 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
552 rb->fdprintf(fd,
553 "Battery bench run for %s version %s\n\n"
554 ,MODEL_NAME,rb->appsversion);
555 rb->close(fd);
558 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
559 if ((thread_id = rb->create_thread(thread, thread_stack,
560 sizeof(thread_stack), 0, "Battery Benchmark"
561 IF_PRIO(, PRIORITY_BACKGROUND)
562 IF_COP(, CPU))) == 0)
564 rb->splash(HZ, "Cannot create thread!");
565 return PLUGIN_ERROR;
568 rb->plugin_tsr(exit_tsr);
570 return PLUGIN_OK;