grr.. typo
[Rockbox.git] / apps / plugins / battery_bench.c
blobad45d6562dca96438f6392765ed294cd9ed6ad96
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
11 * Copyright (C) 2006 Alexander Spyridakis, Hristo Kovachev
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
20 #ifndef SIMULATOR /* not for the simulator */
22 #include "plugin.h"
23 PLUGIN_HEADER
25 #define BATTERY_LOG "/battery_bench.txt"
26 #define BUF_SIZE 16000
27 #define DISK_SPINDOWN_TIMEOUT 3600
29 #define EV_EXIT 1337
31 /* seems to work with 1300, but who knows... */
32 #define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200
34 #if CONFIG_KEYPAD == RECORDER_PAD
36 #define BATTERY_ON BUTTON_PLAY
37 #define BATTERY_OFF BUTTON_OFF
38 #define BATTERY_ON_TXT "PLAY - start"
39 #define BATTERY_OFF_TXT "OFF - quit"
41 #if BUTTON_REMOTE != 0
42 #define BATTERY_RC_ON BUTTON_RC_PLAY
43 #define BATTERY_RC_OFF BUTTON_RC_STOP
44 #endif
46 #elif CONFIG_KEYPAD == ONDIO_PAD
48 #define BATTERY_ON BUTTON_RIGHT
49 #define BATTERY_OFF BUTTON_OFF
50 #define BATTERY_ON_TXT "RIGHT - start"
51 #define BATTERY_OFF_TXT "OFF - quit"
53 #elif CONFIG_KEYPAD == PLAYER_PAD
55 #define BATTERY_ON BUTTON_PLAY
56 #define BATTERY_OFF BUTTON_STOP
58 #define BATTERY_RC_ON BUTTON_RC_PLAY
59 #define BATTERY_RC_OFF BUTTON_RC_STOP
61 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
62 (CONFIG_KEYPAD == IRIVER_H300_PAD)
64 #define BATTERY_ON BUTTON_ON
65 #define BATTERY_RC_ON BUTTON_RC_ON
67 #define BATTERY_OFF BUTTON_OFF
68 #define BATTERY_RC_OFF BUTTON_RC_STOP
70 #define BATTERY_ON_TXT "PLAY - start"
71 #define BATTERY_OFF_TXT "STOP - quit"
73 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
74 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
75 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
77 #define BATTERY_ON BUTTON_PLAY
78 #define BATTERY_OFF BUTTON_MENU
79 #define BATTERY_ON_TXT "PLAY - start"
80 #define BATTERY_OFF_TXT "MENU - quit"
82 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
84 #define BATTERY_ON BUTTON_SELECT
85 #define BATTERY_OFF BUTTON_POWER
86 #define BATTERY_ON_TXT "SELECT - start"
87 #define BATTERY_OFF_TXT "POWER - quit"
89 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
91 #define BATTERY_ON BUTTON_SELECT
92 #define BATTERY_OFF BUTTON_PLAY
93 #define BATTERY_ON_TXT "SELECT - start"
94 #define BATTERY_OFF_TXT "PLAY - quit"
96 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
97 (CONFIG_KEYPAD == SANSA_C200_PAD)
98 #define BATTERY_ON BUTTON_SELECT
99 #define BATTERY_OFF BUTTON_POWER
100 #define BATTERY_ON_TXT "SELECT - start"
101 #define BATTERY_OFF_TXT "POWER - quit"
103 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
105 #define BATTERY_ON BUTTON_PLAY
106 #define BATTERY_OFF BUTTON_POWER
107 #define BATTERY_ON_TXT "PLAY - start"
108 #define BATTERY_OFF_TXT "POWER - quit"
110 #elif CONFIG_KEYPAD == GIGABEAT_PAD
112 #define BATTERY_ON BUTTON_SELECT
113 #define BATTERY_OFF BUTTON_POWER
114 #define BATTERY_ON_TXT "SELECT - start"
115 #define BATTERY_OFF_TXT "POWER - quit"
117 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
119 #define BATTERY_ON BUTTON_SELECT
120 #define BATTERY_OFF BUTTON_BACK
121 #define BATTERY_ON_TXT "SELECT - start"
122 #define BATTERY_OFF_TXT "BACK - quit"
124 #elif CONFIG_KEYPAD == MROBE500_PAD
126 #define BATTERY_ON BUTTON_RC_PLAY
127 #define BATTERY_OFF BUTTON_POWER
128 #define BATTERY_ON_TXT "PLAY - start"
129 #define BATTERY_OFF_TXT "POWER - quit"
131 #elif CONFIG_KEYPAD == MROBE100_PAD
133 #define BATTERY_ON BUTTON_SELECT
134 #define BATTERY_OFF BUTTON_POWER
135 #define BATTERY_ON_TXT "SELECT - start"
136 #define BATTERY_OFF_TXT "POWER - quit"
138 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
140 #define BATTERY_ON BUTTON_PLAY
141 #define BATTERY_OFF BUTTON_REC
142 #define BATTERY_RC_ON BUTTON_RC_PLAY
143 #define BATTERY_RC_OFF BUTTON_RC_REC
144 #define BATTERY_ON_TXT "PLAY - start"
145 #define BATTERY_OFF_TXT "REC - quit"
147 #elif CONFIG_KEYPAD == COWOND2_PAD
149 #define BATTERY_ON BUTTON_MENU
150 #define BATTERY_OFF BUTTON_POWER
151 #define BATTERY_ON_TXT "MENU - start"
152 #define BATTERY_OFF_TXT "POWER - quit"
154 #else
155 #error No keymap defined!
156 #endif
159 /****************************** Plugin Entry Point ****************************/
160 static struct plugin_api* rb;
161 MEM_FUNCTION_WRAPPERS(rb);
162 int main(void);
163 bool exit_tsr(bool);
164 void thread(void);
167 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
169 (void)parameter;
170 rb = api;
172 return main();
175 /* Struct for battery information */
176 struct batt_info
178 /* the size of the struct elements is optimised to make the struct size
179 * a power of 2 */
180 long ticks;
181 int eta;
182 unsigned int voltage;
183 short level;
184 unsigned short flags;
185 } bat[BUF_SIZE/sizeof(struct batt_info)];
187 struct thread_entry *thread_id;
188 struct event_queue thread_q;
190 bool exit_tsr(bool reenter)
192 bool exit = true;
193 (void)reenter;
194 rb->lcd_clear_display();
195 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
196 rb->lcd_puts_scroll(0, 1, "Press OFF to cancel the test");
197 #ifdef HAVE_LCD_BITMAP
198 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
199 #endif
200 rb->lcd_update();
202 if (rb->button_get(true) != BATTERY_OFF)
203 exit = false;
204 if (exit)
206 rb->queue_post(&thread_q, EV_EXIT, 0);
207 rb->thread_wait(thread_id);
208 /* remove the thread's queue from the broadcast list */
209 rb->queue_delete(&thread_q);
210 return true;
212 else return false;
215 #define BIT_CHARGER 0x1
216 #define BIT_CHARGING 0x2
217 #define BIT_USB_POWER 0x4
219 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
221 /* use long for aligning */
222 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
224 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
225 unsigned int charge_state(void)
227 unsigned int ret = 0;
228 #if CONFIG_CHARGING
229 if(rb->charger_inserted())
230 ret = BIT_CHARGER;
231 #if CONFIG_CHARGING == CHARGING_MONITOR
232 if(rb->charging_state())
233 ret |= BIT_CHARGING;
234 #endif
235 #endif
236 #ifdef HAVE_USB_POWER
237 if(rb->usb_powered())
238 ret |= BIT_USB_POWER;
239 #endif
240 return ret;
242 #endif
244 void thread(void)
246 bool got_info = false, timeflag = false, in_usb_mode = false;
247 int fd, buffelements, tick = 1, i = 0, skipped = 0, exit = 0;
248 int fst = 0, lst = 0; /* first and last skipped tick */
249 unsigned int last_voltage = 0;
250 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
251 unsigned int last_state = 0;
252 #endif
253 long sleep_time = 5 * HZ;
255 struct queue_event ev;
257 buffelements = sizeof(bat)/sizeof(struct batt_info);
259 #ifndef HAVE_FLASH_STORAGE
260 if(rb->global_settings->disk_spindown > 1)
261 sleep_time = (rb->global_settings->disk_spindown - 1) * HZ;
262 #endif
266 if(!in_usb_mode && got_info &&
267 (exit || timeflag || rb->ata_disk_is_active()) )
269 int last, secs, j, temp = skipped;
271 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
272 if(fd < 0)
273 exit = 1;
274 else
278 if(skipped)
280 last = buffelements;
281 fst /= HZ;
282 lst /= HZ;
283 rb->fdprintf(fd,"-Skipped %d measurements from "
284 "%02d:%02d:%02d to %02d:%02d:%02d-\n",skipped,
285 HMS(fst),HMS(lst));
286 skipped = 0;
288 else
290 last = i;
291 i = 0;
294 for(j = i; j < last; j++)
296 secs = bat[j].ticks/HZ;
297 rb->fdprintf(fd,
298 "%02d:%02d:%02d, %05d, %03d%%, "
299 "%02d:%02d, %04d, %04d"
300 #if CONFIG_CHARGING
301 ", %c"
302 #if CONFIG_CHARGING == CHARGING_MONITOR
303 ", %c"
304 #endif
305 #endif
306 #ifdef HAVE_USB_POWER
307 ", %c"
308 #endif
309 "\n",
311 HMS(secs), secs, bat[j].level,
312 bat[j].eta / 60, bat[j].eta % 60,
313 bat[j].voltage,
314 temp + 1 + (j-i)
315 #if CONFIG_CHARGING
316 ,(bat[j].flags & BIT_CHARGER)?'A':'-'
317 #if CONFIG_CHARGING == CHARGING_MONITOR
318 ,(bat[j].flags & BIT_CHARGING)?'C':'-'
319 #endif
320 #endif
321 #ifdef HAVE_USB_POWER
322 ,(bat[j].flags & BIT_USB_POWER)?'U':'-'
323 #endif
326 if(!j % 100 && !j) /* yield() at every 100 writes */
327 rb->yield();
329 temp += j - i;
331 }while(i != 0);
333 rb->close(fd);
334 tick = *rb->current_tick;
335 got_info = false;
336 timeflag = false;
339 else
341 unsigned int current_voltage;
343 #if CONFIG_CODEC == SWCODEC
344 !rb->pcm_is_playing()
345 #else
346 !rb->mp3_is_playing()
347 #endif
348 && (*rb->current_tick - tick) > DISK_SPINDOWN_TIMEOUT * HZ)
349 timeflag = true;
351 if(last_voltage != (current_voltage=rb->battery_voltage())
352 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
353 || last_state != charge_state()
354 #endif
357 if(i == buffelements)
359 if(!skipped++)
360 fst = bat[0].ticks;
361 i = 0;
363 else if(skipped)
365 skipped++;
366 lst = bat[i].ticks;
368 bat[i].ticks = *rb->current_tick;
369 bat[i].level = rb->battery_level();
370 bat[i].eta = rb->battery_time();
371 last_voltage = bat[i].voltage = current_voltage;
372 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
373 bat[i].flags = last_state = charge_state();
374 #endif
375 i++;
376 got_info = true;
381 if(exit)
383 if(exit == 2)
384 rb->splash(HZ,
385 #ifdef HAVE_LCD_BITMAP
386 "Exiting battery_bench...");
387 #else
388 "bench exit");
389 #endif
390 return;
393 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
394 switch (ev.id)
396 case SYS_USB_CONNECTED:
397 in_usb_mode = true;
398 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
399 break;
400 case SYS_USB_DISCONNECTED:
401 in_usb_mode = false;
402 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
403 break;
404 case SYS_POWEROFF:
405 exit = 1;
406 break;
407 case EV_EXIT:
408 exit = 2;
409 break;
411 } while (1);
415 #ifdef HAVE_LCD_BITMAP
416 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
418 void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
420 int strwdt, strhgt;
421 rb->lcd_getstringsize(str, &strwdt, &strhgt);
422 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
424 #endif
426 int main(void)
428 int button, fd;
429 bool on = false;
430 #ifdef HAVE_LCD_BITMAP
431 int i;
432 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
433 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT };
434 #endif
435 rb->lcd_clear_display();
437 #ifdef HAVE_LCD_BITMAP
438 rb->lcd_clear_display();
439 rb->lcd_setfont(FONT_SYSFIXED);
441 for(i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
442 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
443 #else
444 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
445 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
446 #endif
447 rb->lcd_update();
449 #ifdef HAVE_REMOTE_LCD
450 rb->lcd_remote_clear_display();
451 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
452 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
453 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
454 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
455 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
456 rb->lcd_remote_update();
457 #endif
461 button = rb->button_get(true);
462 switch(button)
464 case BATTERY_ON:
465 #ifdef BATTERY_RC_ON
466 case BATTERY_RC_ON:
467 #endif
468 on = true;
469 break;
470 case BATTERY_OFF:
471 #ifdef BATTERY_RC_OFF
472 case BATTERY_RC_OFF:
473 #endif
474 return PLUGIN_OK;
476 default: if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
477 return PLUGIN_USB_CONNECTED;
479 }while(!on);
481 fd = rb->open(BATTERY_LOG, O_RDONLY);
482 if(fd < 0)
484 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
485 if(fd >= 0)
487 rb->fdprintf(fd,
488 "This plugin will log your battery performance in a\n"
489 "file (%s) every time the disk is accessed (or every hour).\n"
490 "To properly test your battery:\n"
491 "1) Select and playback an album. "
492 "(Be sure to be more than the player's buffer)\n"
493 "2) Set to repeat.\n"
494 "3) Let the player run completely out of battery.\n"
495 "4) Recharge and copy (or whatever you want) the txt file to "
496 "your computer.\n"
497 "Now you can make graphs with the data of the battery log.\n"
498 "Do not enter another plugin during the test or else the "
499 "logging activity will end.\n\n"
500 "P.S: You can decide how you will make your tests.\n"
501 "Just don't open another plugin to be sure that your log "
502 "will continue.\n"
503 "M/DA (Measurements per Disk Activity) shows how many times\n"
504 "data was logged in the buffer between Disk Activity.\n\n"
505 "Battery type: %d mAh Buffer Entries: %d\n"
506 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:,"
507 " M/DA:"
508 #if CONFIG_CHARGING
509 ", C:"
510 #endif
511 #if CONFIG_CHARGING == CHARGING_MONITOR
512 ", S:"
513 #endif
514 #ifdef HAVE_USB_POWER
515 ", U:"
516 #endif
517 "\n"
518 ,BATTERY_LOG,rb->global_settings->battery_capacity,
519 BUF_SIZE / (unsigned)sizeof(struct batt_info));
520 rb->close(fd);
522 else
524 rb->splash(HZ / 2, "Cannot create file!");
525 return PLUGIN_ERROR;
528 else
530 rb->close(fd);
531 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
532 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
533 rb->close(fd);
536 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
537 if((thread_id = rb->create_thread(thread, thread_stack,
538 sizeof(thread_stack), 0, "Battery Benchmark"
539 IF_PRIO(, PRIORITY_BACKGROUND)
540 IF_COP(, CPU))) == NULL)
542 rb->splash(HZ, "Cannot create thread!");
543 return PLUGIN_ERROR;
546 rb->plugin_tsr(exit_tsr);
548 return PLUGIN_OK;
551 #endif