make the dialog box asking about replacing an up-to-date bootloader less confusing.
[Rockbox.git] / apps / plugins / battery_bench.c
blobdfe9632f7ba9e8cf1b1cc0cc40c6e1e5ea07277f
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 #endif
120 /****************************** Plugin Entry Point ****************************/
121 static struct plugin_api* rb;
122 MEM_FUNCTION_WRAPPERS(rb);
123 int main(void);
124 bool exit_tsr(bool);
125 void thread(void);
128 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
130 (void)parameter;
131 rb = api;
133 return main();
136 bool thread_stopped = false;
138 /* Struct for battery information */
139 struct batt_info
141 /* the size of the struct elements is optimised to make the struct size
142 * a power of 2 */
143 long ticks;
144 int eta;
145 unsigned int voltage;
146 short level;
147 unsigned short flags;
148 } bat[BUF_SIZE/sizeof(struct batt_info)];
150 struct event_queue thread_q;
152 bool exit_tsr(bool reenter)
154 bool exit = true;
155 (void)reenter;
156 rb->lcd_clear_display();
157 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
158 rb->lcd_puts_scroll(0, 1, "Press OFF to cancel the test");
159 #ifdef HAVE_LCD_BITMAP
160 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
161 #endif
162 rb->lcd_update();
164 if (rb->button_get(true) != BATTERY_OFF)
165 exit = false;
166 if (exit)
168 rb->queue_post(&thread_q, EV_EXIT, 0);
169 while (!thread_stopped)
170 rb->yield();
171 /* remove the thread's queue from the broadcast list */
172 rb->queue_delete(&thread_q);
173 return true;
175 else return false;
178 #define BIT_CHARGER 0x1
179 #define BIT_CHARGING 0x2
180 #define BIT_USB_POWER 0x4
182 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
184 /* use long for aligning */
185 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
187 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
188 unsigned int charge_state(void)
190 unsigned int ret = 0;
191 #if CONFIG_CHARGING
192 if(rb->charger_inserted())
193 ret = BIT_CHARGER;
194 #if CONFIG_CHARGING == CHARGING_MONITOR
195 if(rb->charging_state())
196 ret |= BIT_CHARGING;
197 #endif
198 #endif
199 #ifdef HAVE_USB_POWER
200 if(rb->usb_powered())
201 ret |= BIT_USB_POWER;
202 #endif
203 return ret;
205 #endif
207 void thread(void)
209 bool got_info = false, timeflag = false, in_usb_mode = false;
210 int fd, buffelements, tick = 1, i = 0, skipped = 0, exit = 0;
211 int fst = 0, lst = 0; /* first and last skipped tick */
212 unsigned int last_voltage = 0;
213 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
214 unsigned int last_state = 0;
215 #endif
216 long sleep_time = 5 * HZ;
218 struct queue_event ev;
220 buffelements = sizeof(bat)/sizeof(struct batt_info);
222 #ifndef HAVE_FLASH_STORAGE
223 if(rb->global_settings->disk_spindown > 1)
224 sleep_time = (rb->global_settings->disk_spindown - 1) * HZ;
225 #endif
229 if(!in_usb_mode && got_info &&
230 (exit || timeflag || rb->ata_disk_is_active()) )
232 int last, secs, j, temp = skipped;
234 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
235 if(fd < 0)
236 exit = 1;
237 else
241 if(skipped)
243 last = buffelements;
244 fst /= HZ;
245 lst /= HZ;
246 rb->fdprintf(fd,"-Skipped %d measurements from "
247 "%02d:%02d:%02d to %02d:%02d:%02d-\n",skipped,
248 HMS(fst),HMS(lst));
249 skipped = 0;
251 else
253 last = i;
254 i = 0;
257 for(j = i; j < last; j++)
259 secs = bat[j].ticks/HZ;
260 rb->fdprintf(fd,
261 "%02d:%02d:%02d, %05d, %03d%%, "
262 "%02d:%02d, %04d, %04d"
263 #if CONFIG_CHARGING
264 ", %c"
265 #if CONFIG_CHARGING == CHARGING_MONITOR
266 ", %c"
267 #endif
268 #endif
269 #ifdef HAVE_USB_POWER
270 ", %c"
271 #endif
272 "\n",
274 HMS(secs), secs, bat[j].level,
275 bat[j].eta / 60, bat[j].eta % 60,
276 bat[j].voltage,
277 temp + 1 + (j-i)
278 #if CONFIG_CHARGING
279 ,(bat[j].flags & BIT_CHARGER)?'A':'-'
280 #if CONFIG_CHARGING == CHARGING_MONITOR
281 ,(bat[j].flags & BIT_CHARGING)?'C':'-'
282 #endif
283 #endif
284 #ifdef HAVE_USB_POWER
285 ,(bat[j].flags & BIT_USB_POWER)?'U':'-'
286 #endif
289 if(!j % 100 && !j) /* yield() at every 100 writes */
290 rb->yield();
292 temp += j - i;
294 }while(i != 0);
296 rb->close(fd);
297 tick = *rb->current_tick;
298 got_info = false;
299 timeflag = false;
302 else
304 unsigned int current_voltage;
306 #if CONFIG_CODEC == SWCODEC
307 !rb->pcm_is_playing()
308 #else
309 !rb->mp3_is_playing()
310 #endif
311 && (*rb->current_tick - tick) > DISK_SPINDOWN_TIMEOUT * HZ)
312 timeflag = true;
314 if(last_voltage != (current_voltage=rb->battery_voltage())
315 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
316 || last_state != charge_state()
317 #endif
320 if(i == buffelements)
322 if(!skipped++)
323 fst = bat[0].ticks;
324 i = 0;
326 else if(skipped)
328 skipped++;
329 lst = bat[i].ticks;
331 bat[i].ticks = *rb->current_tick;
332 bat[i].level = rb->battery_level();
333 bat[i].eta = rb->battery_time();
334 last_voltage = bat[i].voltage = current_voltage;
335 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
336 bat[i].flags = last_state = charge_state();
337 #endif
338 i++;
339 got_info = true;
344 if(exit)
346 if(exit == 2)
347 rb->splash(HZ,
348 #ifdef HAVE_LCD_BITMAP
349 "Exiting battery_bench...");
350 #else
351 "bench exit");
352 #endif
353 thread_stopped = true;
354 return;
357 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
358 switch (ev.id)
360 case SYS_USB_CONNECTED:
361 in_usb_mode = true;
362 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
363 break;
364 case SYS_USB_DISCONNECTED:
365 in_usb_mode = false;
366 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
367 break;
368 case SYS_POWEROFF:
369 exit = 1;
370 break;
371 case EV_EXIT:
372 exit = 2;
373 break;
375 } while (1);
380 #ifdef HAVE_LCD_BITMAP
381 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
383 void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
385 int strwdt, strhgt;
386 rb->lcd_getstringsize(str, &strwdt, &strhgt);
387 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
389 #endif
391 int main(void)
393 int button, fd;
394 bool on = false;
395 #ifdef HAVE_LCD_BITMAP
396 int i;
397 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
398 "for more info", BATTERY_ON_TXT, BATTERY_OFF_TXT };
399 #endif
400 rb->lcd_clear_display();
402 #ifdef HAVE_LCD_BITMAP
403 rb->lcd_clear_display();
404 rb->lcd_setfont(FONT_SYSFIXED);
406 for(i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
407 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
408 #else
409 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
410 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
411 #endif
412 rb->lcd_update();
414 #ifdef HAVE_REMOTE_LCD
415 rb->lcd_remote_clear_display();
416 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
417 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
418 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
419 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
420 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
421 rb->lcd_remote_update();
422 #endif
426 button = rb->button_get(true);
427 switch(button)
429 case BATTERY_ON:
430 #ifdef BATTERY_RC_ON
431 case BATTERY_RC_ON:
432 #endif
433 on = true;
434 break;
435 case BATTERY_OFF:
436 #ifdef BATTERY_RC_OFF
437 case BATTERY_RC_OFF:
438 #endif
439 return PLUGIN_OK;
441 default: if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
442 return PLUGIN_USB_CONNECTED;
444 }while(!on);
446 fd = rb->open(BATTERY_LOG, O_RDONLY);
447 if(fd < 0)
449 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
450 if(fd >= 0)
452 rb->fdprintf(fd,
453 "This plugin will log your battery performance in a\n"
454 "file (%s) every time the disk is accessed (or every hour).\n"
455 "To properly test your battery:\n"
456 "1) Select and playback an album. "
457 "(Be sure to be more than the player's buffer)\n"
458 "2) Set to repeat.\n"
459 "3) Let the player run completely out of battery.\n"
460 "4) Recharge and copy (or whatever you want) the txt file to "
461 "your computer.\n"
462 "Now you can make graphs with the data of the battery log.\n"
463 "Do not enter another plugin during the test or else the "
464 "logging activity will end.\n\n"
465 "P.S: You can decide how you will make your tests.\n"
466 "Just don't open another plugin to be sure that your log "
467 "will continue.\n"
468 "M/DA (Measurements per Disk Activity) shows how many times\n"
469 "data was logged in the buffer between Disk Activity.\n\n"
470 "Battery type: %d mAh Buffer Entries: %d\n"
471 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:,"
472 " M/DA:"
473 #if CONFIG_CHARGING
474 ", C:"
475 #endif
476 #if CONFIG_CHARGING == CHARGING_MONITOR
477 ", S:"
478 #endif
479 #ifdef HAVE_USB_POWER
480 ", U:"
481 #endif
482 "\n"
483 ,BATTERY_LOG,rb->global_settings->battery_capacity,
484 BUF_SIZE / (unsigned)sizeof(struct batt_info));
485 rb->close(fd);
487 else
489 rb->splash(HZ / 2, "Cannot create file!");
490 return PLUGIN_ERROR;
493 else
495 rb->close(fd);
496 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
497 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
498 rb->close(fd);
501 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
502 if(rb->create_thread(thread, thread_stack,
503 sizeof(thread_stack), 0, "Battery Benchmark"
504 IF_PRIO(, PRIORITY_BACKGROUND)
505 IF_COP(, CPU)) == NULL)
507 rb->splash(HZ, "Cannot create thread!");
508 return PLUGIN_ERROR;
511 rb->plugin_tsr(exit_tsr);
513 return PLUGIN_OK;
516 #endif