Introduce Rockbox Utility to the manual as automated installation option. Only rather...
[Rockbox.git] / apps / plugins / battery_bench.c
blob43bfc7255f658122027316fb5c17e3a219c9efa7
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
39 #if BUTTON_REMOTE != 0
40 #define BATTERY_RC_ON BUTTON_RC_PLAY
41 #define BATTERY_RC_OFF BUTTON_RC_STOP
42 #endif
44 #elif CONFIG_KEYPAD == ONDIO_PAD
46 #define BATTERY_ON BUTTON_RIGHT
47 #define BATTERY_OFF BUTTON_OFF
49 #elif CONFIG_KEYPAD == PLAYER_PAD
51 #define BATTERY_ON BUTTON_PLAY
52 #define BATTERY_RC_ON BUTTON_RC_PLAY
54 #define BATTERY_OFF BUTTON_STOP
55 #define BATTERY_RC_OFF BUTTON_RC_STOP
57 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
58 (CONFIG_KEYPAD == IRIVER_H300_PAD)
60 #define BATTERY_ON BUTTON_ON
61 #define BATTERY_RC_ON BUTTON_RC_ON
63 #define BATTERY_OFF BUTTON_OFF
64 #define BATTERY_RC_OFF BUTTON_RC_STOP
66 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
67 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
68 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
70 #define BATTERY_ON BUTTON_PLAY
71 #define BATTERY_OFF BUTTON_MENU
73 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
75 #define BATTERY_ON BUTTON_SELECT
76 #define BATTERY_OFF BUTTON_PLAY
78 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
80 #define BATTERY_ON BUTTON_SELECT
81 #define BATTERY_OFF BUTTON_PLAY
83 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
84 (CONFIG_KEYPAD == SANSA_C200_PAD)
85 #define BATTERY_ON BUTTON_SELECT
86 #define BATTERY_OFF BUTTON_POWER
88 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
90 #define BATTERY_ON BUTTON_PLAY
91 #define BATTERY_OFF BUTTON_POWER
93 #elif CONFIG_KEYPAD == GIGABEAT_PAD
95 #define BATTERY_ON BUTTON_SELECT
96 #define BATTERY_OFF BUTTON_POWER
98 #endif
101 /****************************** Plugin Entry Point ****************************/
102 static struct plugin_api* rb;
103 MEM_FUNCTION_WRAPPERS(rb);
104 int main(void);
105 bool exit_tsr(bool);
106 void thread(void);
109 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
111 (void)parameter;
112 rb = api;
114 return main();
117 bool thread_stopped = false;
119 /* Struct for battery information */
120 struct batt_info
122 /* the size of the struct elements is optimised to make the struct size
123 * a power of 2 */
124 long ticks;
125 int eta;
126 unsigned int voltage;
127 short level;
128 unsigned short flags;
129 } bat[BUF_SIZE/sizeof(struct batt_info)];
131 struct event_queue thread_q;
133 bool exit_tsr(bool reenter)
135 bool exit = true;
136 (void)reenter;
137 rb->lcd_clear_display();
138 rb->lcd_puts_scroll(0, 0, "Batt.Bench is currently running.");
139 rb->lcd_puts_scroll(0, 1, "Press OFF to cancel the test");
140 #ifdef HAVE_LCD_BITMAP
141 rb->lcd_puts_scroll(0, 2, "Anything else will resume");
142 #endif
143 rb->lcd_update();
145 if (rb->button_get(true) != BATTERY_OFF)
146 exit = false;
147 if (exit)
149 rb->queue_post(&thread_q, EV_EXIT, 0);
150 while (!thread_stopped)
151 rb->yield();
152 /* remove the thread's queue from the broadcast list */
153 rb->queue_delete(&thread_q);
154 return true;
156 else return false;
159 #define BIT_CHARGER 0x1
160 #define BIT_CHARGING 0x2
161 #define BIT_USB_POWER 0x4
163 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
165 /* use long for aligning */
166 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
168 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
169 unsigned int charge_state(void)
171 unsigned int ret = 0;
172 #if CONFIG_CHARGING
173 if(rb->charger_inserted())
174 ret = BIT_CHARGER;
175 #if CONFIG_CHARGING == CHARGING_MONITOR
176 if(rb->charging_state())
177 ret |= BIT_CHARGING;
178 #endif
179 #endif
180 #ifdef HAVE_USB_POWER
181 if(rb->usb_powered())
182 ret |= BIT_USB_POWER;
183 #endif
184 return ret;
186 #endif
188 void thread(void)
190 bool got_info = false, timeflag = false, in_usb_mode = false;
191 int fd, buffelements, tick = 1, i = 0, skipped = 0, exit = 0;
192 int fst = 0, lst = 0; /* first and last skipped tick */
193 unsigned int last_voltage = 0;
194 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
195 unsigned int last_state = 0;
196 #endif
197 long sleep_time = 5 * HZ;
199 struct event ev;
201 buffelements = sizeof(bat)/sizeof(struct batt_info);
203 #ifndef HAVE_FLASH_STORAGE
204 if(rb->global_settings->disk_spindown > 1)
205 sleep_time = (rb->global_settings->disk_spindown - 1) * HZ;
206 #endif
210 if(!in_usb_mode && got_info &&
211 (exit || timeflag || rb->ata_disk_is_active()) )
213 int last, secs, j, temp = skipped;
215 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
216 if(fd < 0)
217 exit = 1;
218 else
222 if(skipped)
224 last = buffelements;
225 fst /= HZ;
226 lst /= HZ;
227 rb->fdprintf(fd,"-Skipped %d measurements from "
228 "%02d:%02d:%02d to %02d:%02d:%02d-\n",skipped,
229 HMS(fst),HMS(lst));
230 skipped = 0;
232 else
234 last = i;
235 i = 0;
238 for(j = i; j < last; j++)
240 secs = bat[j].ticks/HZ;
241 rb->fdprintf(fd,
242 "%02d:%02d:%02d, %05d, %03d%%, "
243 "%02d:%02d, %04d, %04d"
244 #if CONFIG_CHARGING
245 ", %c"
246 #if CONFIG_CHARGING == CHARGING_MONITOR
247 ", %c"
248 #endif
249 #endif
250 #ifdef HAVE_USB_POWER
251 ", %c"
252 #endif
253 "\n",
255 HMS(secs), secs, bat[j].level,
256 bat[j].eta / 60, bat[j].eta % 60,
257 bat[j].voltage,
258 temp + 1 + (j-i)
259 #if CONFIG_CHARGING
260 ,(bat[j].flags & BIT_CHARGER)?'A':'-'
261 #if CONFIG_CHARGING == CHARGING_MONITOR
262 ,(bat[j].flags & BIT_CHARGING)?'C':'-'
263 #endif
264 #endif
265 #ifdef HAVE_USB_POWER
266 ,(bat[j].flags & BIT_USB_POWER)?'U':'-'
267 #endif
270 if(!j % 100 && !j) /* yield() at every 100 writes */
271 rb->yield();
273 temp += j - i;
275 }while(i != 0);
277 rb->close(fd);
278 tick = *rb->current_tick;
279 got_info = false;
280 timeflag = false;
283 else
285 unsigned int current_voltage;
287 #if CONFIG_CODEC == SWCODEC
288 !rb->pcm_is_playing()
289 #else
290 !rb->mp3_is_playing()
291 #endif
292 && (*rb->current_tick - tick) > DISK_SPINDOWN_TIMEOUT * HZ)
293 timeflag = true;
295 if(last_voltage != (current_voltage=rb->battery_voltage())
296 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
297 || last_state != charge_state()
298 #endif
301 if(i == buffelements)
303 if(!skipped++)
304 fst = bat[0].ticks;
305 i = 0;
307 else if(skipped)
309 skipped++;
310 lst = bat[i].ticks;
312 bat[i].ticks = *rb->current_tick;
313 bat[i].level = rb->battery_level();
314 bat[i].eta = rb->battery_time();
315 last_voltage = bat[i].voltage = current_voltage;
316 #if CONFIG_CHARGING || defined(HAVE_USB_POWER)
317 bat[i].flags = last_state = charge_state();
318 #endif
319 i++;
320 got_info = true;
325 if(exit)
327 if(exit == 2)
328 rb->splash(HZ,
329 #ifdef HAVE_LCD_BITMAP
330 "Exiting battery_bench...");
331 #else
332 "bench exit");
333 #endif
334 thread_stopped = true;
335 rb->remove_thread(NULL); /* Suicide. Never returns. */
338 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
339 switch (ev.id)
341 case SYS_USB_CONNECTED:
342 in_usb_mode = true;
343 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
344 break;
345 case SYS_USB_DISCONNECTED:
346 in_usb_mode = false;
347 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
348 break;
349 case SYS_POWEROFF:
350 exit = 1;
351 break;
352 case EV_EXIT:
353 exit = 2;
354 break;
356 } while (1);
361 #ifdef HAVE_LCD_BITMAP
362 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
364 void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
366 int strwdt, strhgt;
367 rb->lcd_getstringsize(str, &strwdt, &strhgt);
368 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
370 #endif
372 int main(void)
374 int button, fd;
375 bool on = false;
376 #ifdef HAVE_LCD_BITMAP
377 int i;
378 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
379 "for more info", "PLAY - start", "OFF - quit" };
380 #endif
381 rb->lcd_clear_display();
383 #ifdef HAVE_LCD_BITMAP
384 rb->lcd_clear_display();
385 rb->lcd_setfont(FONT_SYSFIXED);
387 for(i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
388 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
389 #else
390 rb->lcd_puts_scroll(0, 0, "Batt.Bench.");
391 rb->lcd_puts_scroll(0, 1, "PLAY/STOP");
392 #endif
393 rb->lcd_update();
395 #ifdef HAVE_REMOTE_LCD
396 rb->lcd_remote_clear_display();
397 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
398 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
399 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
400 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
401 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
402 rb->lcd_remote_update();
403 #endif
407 button = rb->button_get(true);
408 switch(button)
410 case BATTERY_ON:
411 #ifdef BATTERY_RC_ON
412 case BATTERY_RC_ON:
413 #endif
414 on = true;
415 break;
416 case BATTERY_OFF:
417 #ifdef BATTERY_RC_OFF
418 case BATTERY_RC_OFF:
419 #endif
420 return PLUGIN_OK;
422 default: if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
423 return PLUGIN_USB_CONNECTED;
425 }while(!on);
427 fd = rb->open(BATTERY_LOG, O_RDONLY);
428 if(fd < 0)
430 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
431 if(fd >= 0)
433 rb->fdprintf(fd,
434 "This plugin will log your battery performance in a\n"
435 "file (%s) every time the disk is accessed (or every hour).\n"
436 "To properly test your battery:\n"
437 "1) Select and playback an album. "
438 "(Be sure to be more than the player's buffer)\n"
439 "2) Set to repeat.\n"
440 "3) Let the player run completely out of battery.\n"
441 "4) Recharge and copy (or whatever you want) the txt file to "
442 "your computer.\n"
443 "Now you can make graphs with the data of the battery log.\n"
444 "Do not enter another plugin during the test or else the "
445 "logging activity will end.\n\n"
446 "P.S: You can decide how you will make your tests.\n"
447 "Just don't open another plugin to be sure that your log "
448 "will continue.\n"
449 "M/DA (Measurements per Disk Activity) shows how many times\n"
450 "data was logged in the buffer between Disk Activity.\n\n"
451 "Battery type: %d mAh Buffer Entries: %d\n"
452 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:,"
453 " M/DA:"
454 #if CONFIG_CHARGING
455 ", C:"
456 #endif
457 #if CONFIG_CHARGING == CHARGING_MONITOR
458 ", S:"
459 #endif
460 #ifdef HAVE_USB_POWER
461 ", U:"
462 #endif
463 "\n"
464 ,BATTERY_LOG,rb->global_settings->battery_capacity,
465 BUF_SIZE / (unsigned)sizeof(struct batt_info));
466 rb->close(fd);
468 else
470 rb->splash(HZ / 2, "Cannot create file!");
471 return PLUGIN_ERROR;
474 else
476 rb->close(fd);
477 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
478 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
479 rb->close(fd);
482 rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
483 if(rb->create_thread(thread, thread_stack,
484 sizeof(thread_stack), "Battery Benchmark"
485 IF_PRIO(, PRIORITY_BACKGROUND)
486 IF_COP(, CPU, false)) == NULL)
488 rb->splash(HZ, "Cannot create thread!");
489 return PLUGIN_ERROR;
492 rb->plugin_tsr(exit_tsr);
494 return PLUGIN_OK;
497 #endif