Add 2008 to the copyright notice.
[Rockbox.git] / apps / plugins / battery_bench.c
blob91352089844d11d7a17955218aaafc7201e18bcf
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 #endif
134 /****************************** Plugin Entry Point ****************************/
135 static struct plugin_api* rb;
136 MEM_FUNCTION_WRAPPERS(rb);
137 int main(void);
138 bool exit_tsr(bool);
139 void thread(void);
142 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
144 (void)parameter;
145 rb = api;
147 return main();
150 /* Struct for battery information */
151 struct batt_info
153 /* the size of the struct elements is optimised to make the struct size
154 * a power of 2 */
155 long ticks;
156 int eta;
157 unsigned int voltage;
158 short level;
159 unsigned short flags;
160 } bat[BUF_SIZE/sizeof(struct batt_info)];
162 struct thread_entry *thread_id;
163 struct event_queue thread_q;
165 bool exit_tsr(bool reenter)
167 bool exit = true;
168 (void)reenter;
169 rb->lcd_clear_display();
170 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
171 rb->lcd_puts_scroll(0, 1, "Press OFF to cancel the test");
172 #ifdef HAVE_LCD_BITMAP
173 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
174 #endif
175 rb->lcd_update();
177 if (rb->button_get(true) != BATTERY_OFF)
178 exit = false;
179 if (exit)
181 rb->queue_post(&thread_q, EV_EXIT, 0);
182 rb->thread_wait(thread_id);
183 /* remove the thread's queue from the broadcast list */
184 rb->queue_delete(&thread_q);
185 return true;
187 else return false;
190 #define BIT_CHARGER 0x1
191 #define BIT_CHARGING 0x2
192 #define BIT_USB_POWER 0x4
194 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
196 /* use long for aligning */
197 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
199 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
200 unsigned int charge_state(void)
202 unsigned int ret = 0;
203 #if CONFIG_CHARGING
204 if(rb->charger_inserted())
205 ret = BIT_CHARGER;
206 #if CONFIG_CHARGING == CHARGING_MONITOR
207 if(rb->charging_state())
208 ret |= BIT_CHARGING;
209 #endif
210 #endif
211 #ifdef HAVE_USB_POWER
212 if(rb->usb_powered())
213 ret |= BIT_USB_POWER;
214 #endif
215 return ret;
217 #endif
219 void thread(void)
221 bool got_info = false, timeflag = false, in_usb_mode = false;
222 int fd, buffelements, tick = 1, i = 0, skipped = 0, exit = 0;
223 int fst = 0, lst = 0; /* first and last skipped tick */
224 unsigned int last_voltage = 0;
225 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
226 unsigned int last_state = 0;
227 #endif
228 long sleep_time = 5 * HZ;
230 struct queue_event ev;
232 buffelements = sizeof(bat)/sizeof(struct batt_info);
234 #ifndef HAVE_FLASH_STORAGE
235 if(rb->global_settings->disk_spindown > 1)
236 sleep_time = (rb->global_settings->disk_spindown - 1) * HZ;
237 #endif
241 if(!in_usb_mode && got_info &&
242 (exit || timeflag || rb->ata_disk_is_active()) )
244 int last, secs, j, temp = skipped;
246 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
247 if(fd < 0)
248 exit = 1;
249 else
253 if(skipped)
255 last = buffelements;
256 fst /= HZ;
257 lst /= HZ;
258 rb->fdprintf(fd,"-Skipped %d measurements from "
259 "%02d:%02d:%02d to %02d:%02d:%02d-\n",skipped,
260 HMS(fst),HMS(lst));
261 skipped = 0;
263 else
265 last = i;
266 i = 0;
269 for(j = i; j < last; j++)
271 secs = bat[j].ticks/HZ;
272 rb->fdprintf(fd,
273 "%02d:%02d:%02d, %05d, %03d%%, "
274 "%02d:%02d, %04d, %04d"
275 #if CONFIG_CHARGING
276 ", %c"
277 #if CONFIG_CHARGING == CHARGING_MONITOR
278 ", %c"
279 #endif
280 #endif
281 #ifdef HAVE_USB_POWER
282 ", %c"
283 #endif
284 "\n",
286 HMS(secs), secs, bat[j].level,
287 bat[j].eta / 60, bat[j].eta % 60,
288 bat[j].voltage,
289 temp + 1 + (j-i)
290 #if CONFIG_CHARGING
291 ,(bat[j].flags & BIT_CHARGER)?'A':'-'
292 #if CONFIG_CHARGING == CHARGING_MONITOR
293 ,(bat[j].flags & BIT_CHARGING)?'C':'-'
294 #endif
295 #endif
296 #ifdef HAVE_USB_POWER
297 ,(bat[j].flags & BIT_USB_POWER)?'U':'-'
298 #endif
301 if(!j % 100 && !j) /* yield() at every 100 writes */
302 rb->yield();
304 temp += j - i;
306 }while(i != 0);
308 rb->close(fd);
309 tick = *rb->current_tick;
310 got_info = false;
311 timeflag = false;
314 else
316 unsigned int current_voltage;
318 #if CONFIG_CODEC == SWCODEC
319 !rb->pcm_is_playing()
320 #else
321 !rb->mp3_is_playing()
322 #endif
323 && (*rb->current_tick - tick) > DISK_SPINDOWN_TIMEOUT * HZ)
324 timeflag = true;
326 if(last_voltage != (current_voltage=rb->battery_voltage())
327 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
328 || last_state != charge_state()
329 #endif
332 if(i == buffelements)
334 if(!skipped++)
335 fst = bat[0].ticks;
336 i = 0;
338 else if(skipped)
340 skipped++;
341 lst = bat[i].ticks;
343 bat[i].ticks = *rb->current_tick;
344 bat[i].level = rb->battery_level();
345 bat[i].eta = rb->battery_time();
346 last_voltage = bat[i].voltage = current_voltage;
347 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
348 bat[i].flags = last_state = charge_state();
349 #endif
350 i++;
351 got_info = true;
356 if(exit)
358 if(exit == 2)
359 rb->splash(HZ,
360 #ifdef HAVE_LCD_BITMAP
361 "Exiting battery_bench...");
362 #else
363 "bench exit");
364 #endif
365 return;
368 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
369 switch (ev.id)
371 case SYS_USB_CONNECTED:
372 in_usb_mode = true;
373 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
374 break;
375 case SYS_USB_DISCONNECTED:
376 in_usb_mode = false;
377 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
378 break;
379 case SYS_POWEROFF:
380 exit = 1;
381 break;
382 case EV_EXIT:
383 exit = 2;
384 break;
386 } while (1);
390 #ifdef HAVE_LCD_BITMAP
391 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
393 void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
395 int strwdt, strhgt;
396 rb->lcd_getstringsize(str, &strwdt, &strhgt);
397 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
399 #endif
401 int main(void)
403 int button, fd;
404 bool on = false;
405 #ifdef HAVE_LCD_BITMAP
406 int i;
407 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
408 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT };
409 #endif
410 rb->lcd_clear_display();
412 #ifdef HAVE_LCD_BITMAP
413 rb->lcd_clear_display();
414 rb->lcd_setfont(FONT_SYSFIXED);
416 for(i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
417 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
418 #else
419 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
420 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
421 #endif
422 rb->lcd_update();
424 #ifdef HAVE_REMOTE_LCD
425 rb->lcd_remote_clear_display();
426 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
427 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
428 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
429 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
430 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
431 rb->lcd_remote_update();
432 #endif
436 button = rb->button_get(true);
437 switch(button)
439 case BATTERY_ON:
440 #ifdef BATTERY_RC_ON
441 case BATTERY_RC_ON:
442 #endif
443 on = true;
444 break;
445 case BATTERY_OFF:
446 #ifdef BATTERY_RC_OFF
447 case BATTERY_RC_OFF:
448 #endif
449 return PLUGIN_OK;
451 default: if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
452 return PLUGIN_USB_CONNECTED;
454 }while(!on);
456 fd = rb->open(BATTERY_LOG, O_RDONLY);
457 if(fd < 0)
459 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
460 if(fd >= 0)
462 rb->fdprintf(fd,
463 "This plugin will log your battery performance in a\n"
464 "file (%s) every time the disk is accessed (or every hour).\n"
465 "To properly test your battery:\n"
466 "1) Select and playback an album. "
467 "(Be sure to be more than the player's buffer)\n"
468 "2) Set to repeat.\n"
469 "3) Let the player run completely out of battery.\n"
470 "4) Recharge and copy (or whatever you want) the txt file to "
471 "your computer.\n"
472 "Now you can make graphs with the data of the battery log.\n"
473 "Do not enter another plugin during the test or else the "
474 "logging activity will end.\n\n"
475 "P.S: You can decide how you will make your tests.\n"
476 "Just don't open another plugin to be sure that your log "
477 "will continue.\n"
478 "M/DA (Measurements per Disk Activity) shows how many times\n"
479 "data was logged in the buffer between Disk Activity.\n\n"
480 "Battery type: %d mAh Buffer Entries: %d\n"
481 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:,"
482 " M/DA:"
483 #if CONFIG_CHARGING
484 ", C:"
485 #endif
486 #if CONFIG_CHARGING == CHARGING_MONITOR
487 ", S:"
488 #endif
489 #ifdef HAVE_USB_POWER
490 ", U:"
491 #endif
492 "\n"
493 ,BATTERY_LOG,rb->global_settings->battery_capacity,
494 BUF_SIZE / (unsigned)sizeof(struct batt_info));
495 rb->close(fd);
497 else
499 rb->splash(HZ / 2, "Cannot create file!");
500 return PLUGIN_ERROR;
503 else
505 rb->close(fd);
506 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
507 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
508 rb->close(fd);
511 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
512 if((thread_id = rb->create_thread(thread, thread_stack,
513 sizeof(thread_stack), 0, "Battery Benchmark"
514 IF_PRIO(, PRIORITY_BACKGROUND)
515 IF_COP(, CPU))) == NULL)
517 rb->splash(HZ, "Cannot create thread!");
518 return PLUGIN_ERROR;
521 rb->plugin_tsr(exit_tsr);
523 return PLUGIN_OK;
526 #endif