More iPod 3G work from Seven Le Mesle
[Rockbox.git] / apps / plugins / battery_bench.c
blob1e77c64f7136e5aff5b95983f44eebfb1bc0bbd1
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
35 #define BATTERY_ON BUTTON_PLAY
36 #define BATTERY_OFF BUTTON_OFF
38 #elif CONFIG_KEYPAD == ONDIO_PAD
39 #define BATTERY_ON BUTTON_RIGHT
40 #define BATTERY_OFF BUTTON_OFF
42 #elif CONFIG_KEYPAD == PLAYER_PAD
43 #define BATTERY_ON BUTTON_ON
44 #define BATTERY_OFF BUTTON_STOP
46 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
47 (CONFIG_KEYPAD == IRIVER_H300_PAD)
49 #define BATTERY_ON BUTTON_ON
50 #define BATTERY_RC_ON BUTTON_RC_ON
52 #define BATTERY_OFF BUTTON_OFF
53 #define BATTERY_RC_OFF BUTTON_RC_STOP
55 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
56 (CONFIG_KEYPAD == IPOD_3G_PAD)
58 #define BATTERY_ON BUTTON_PLAY
59 #define BATTERY_OFF BUTTON_MENU
61 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
63 #define BATTERY_ON BUTTON_SELECT
64 #define BATTERY_OFF BUTTON_PLAY
66 #endif
69 /****************************** Plugin Entry Point ****************************/
70 static struct plugin_api* rb;
71 int main(void);
72 void exit_tsr(void);
73 void thread(void);
76 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
78 (void)parameter;
79 rb = api;
81 return main();
84 struct
86 int id;
87 bool ended;
88 } s_thread;
90 /* Struct for battery information */
91 struct batt_info
93 int ticks, level, eta;
94 unsigned int voltage;
95 } bat[BUF_SIZE/sizeof(struct batt_info)];
97 struct event_queue thread_q;
99 void exit_tsr(void)
101 rb->queue_post(&thread_q, EV_EXIT, NULL);
102 while (!s_thread.ended)
103 rb->yield();
104 /* remove the thread's queue from the broadcast list */
105 rb->queue_delete(&thread_q);
108 #define BIT_CHARGER 0x1000
109 #define BIT_CHARGING 0x2000
110 #define BIT_USB_POWER 0x4000
112 #define HMS(x) (x)/3600,((x)%3600)/60,((x)%3600)%60
114 /* use long for aligning */
115 unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
117 #if defined(HAVE_CHARGING) || defined(HAVE_USB_POWER)
118 unsigned int charge_state(void)
120 unsigned int ret = 0;
121 #ifdef HAVE_CHARGING
122 if(rb->charger_inserted())
123 ret = BIT_CHARGER;
124 #ifdef HAVE_CHARGE_STATE
125 if(rb->charging_state())
126 ret |= BIT_CHARGING;
127 #endif
128 #endif
129 #ifdef HAVE_USB_POWER
130 if(rb->usb_powered())
131 ret |= BIT_USB_POWER;
132 #endif
133 return ret;
135 #endif
137 void thread(void)
139 bool got_info = false, timeflag = false, in_usb_mode = false;
140 int fd, buffelements, tick = 1, i = 0, skipped = 0, exit = 0;
141 int fst = 0, lst = 0; /* first and last skipped tick */
142 unsigned int last_voltage = 0;
143 #if defined(HAVE_CHARGING) || defined(HAVE_USB_POWER)
144 unsigned int last_state = 0;
145 #endif
146 long sleep_time;
148 struct event ev;
150 buffelements = sizeof(bat)/sizeof(struct batt_info);
152 sleep_time = (rb->global_settings->disk_spindown > 1) ?
153 (rb->global_settings->disk_spindown - 1) * HZ : 5 * HZ;
157 if(!in_usb_mode && got_info &&
158 (exit || timeflag || rb->ata_disk_is_active()) )
160 int last, secs, j, temp = skipped;
162 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT | O_APPEND);
163 if(fd < 0)
164 exit = 1;
165 else
169 if(skipped)
171 last = buffelements;
172 fst /= HZ;
173 lst /= HZ;
174 rb->fdprintf(fd,"-Skipped %d measurements from "
175 "%02d:%02d:%02d to %02d:%02d:%02d-\n",skipped,
176 HMS(fst),HMS(lst));
177 skipped = 0;
179 else
181 last = i;
182 i = 0;
185 for(j = i; j < last; j++)
187 secs = bat[j].ticks/HZ;
188 rb->fdprintf(fd,
189 "%02d:%02d:%02d, %05d, %03d%%, "
190 "%02d:%02d, %04d, %04d"
191 #ifdef HAVE_CHARGING
192 ", %c"
193 #ifdef HAVE_CHARGE_STATE
194 ", %c"
195 #endif
196 #endif
197 #ifdef HAVE_USB_POWER
198 ", %c"
199 #endif
200 "\n",
202 HMS(secs), secs, bat[j].level,
203 bat[j].eta / 60, bat[j].eta % 60,
204 #if defined(HAVE_CHARGING) || defined(HAVE_USB_POWER)
205 (bat[j].voltage &
206 (~(BIT_CHARGER|BIT_CHARGING|BIT_USB_POWER)))
207 *10,
208 #else
209 bat[j].voltage * 10,
210 #endif
211 temp + 1 + (j-i)
212 #ifdef HAVE_CHARGING
213 ,(bat[j].voltage & BIT_CHARGER)?'A':'-'
214 #ifdef HAVE_CHARGE_STATE
215 ,(bat[j].voltage & BIT_CHARGING)?'C':'-'
216 #endif
217 #endif
218 #ifdef HAVE_USB_POWER
219 ,(bat[j].voltage & BIT_USB_POWER)?'U':'-'
220 #endif
223 if(!j % 100 && !j) /* yield() at every 100 writes */
224 rb->yield();
226 temp += j - i;
228 }while(i != 0);
230 rb->close(fd);
231 tick = *rb->current_tick;
232 got_info = false;
233 timeflag = false;
236 else
238 unsigned int current_voltage;
240 #if CONFIG_CODEC == SWCODEC
241 !rb->pcm_is_playing()
242 #else
243 !rb->mp3_is_playing()
244 #endif
245 && (*rb->current_tick - tick) > DISK_SPINDOWN_TIMEOUT * HZ)
246 timeflag = true;
248 if(last_voltage != (current_voltage=rb->battery_voltage())
249 #if defined(HAVE_CHARGING) || defined(HAVE_USB_POWER)
250 || last_state != charge_state()
251 #endif
254 if(i == buffelements)
256 if(!skipped++)
257 fst = bat[0].ticks;
258 i = 0;
260 else if(skipped)
262 skipped++;
263 lst = bat[i].ticks;
265 bat[i].ticks = *rb->current_tick;
266 bat[i].level = rb->battery_level();
267 bat[i].eta = rb->battery_time();
268 last_voltage = bat[i].voltage = current_voltage;
269 #if defined(HAVE_CHARGING) || defined(HAVE_USB_POWER)
270 bat[i].voltage |= last_state = charge_state();
271 #endif
272 i++;
273 got_info = true;
278 if(exit)
280 if(exit == 2)
281 rb->splash(HZ,true,
282 #ifdef HAVE_LCD_BITMAP
283 "Exiting battery_bench...");
284 #else
285 "bench exit");
286 #endif
287 s_thread.ended = true;
288 rb->remove_thread(s_thread.id);
289 rb->yield(); /* exit the thread, this yield() won't return */
292 rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
293 switch (ev.id)
295 case SYS_USB_CONNECTED:
296 in_usb_mode = true;
297 rb->usb_acknowledge(SYS_USB_CONNECTED_ACK);
298 break;
299 case SYS_USB_DISCONNECTED:
300 in_usb_mode = false;
301 rb->usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
302 break;
303 case SYS_POWEROFF:
304 exit = 1;
305 break;
306 case EV_EXIT:
307 exit = 2;
308 break;
310 } while (1);
315 #ifdef HAVE_LCD_BITMAP
316 typedef void (*plcdfunc)(int x, int y, const unsigned char *str);
318 void put_centered_str(const char* str, plcdfunc putsxy, int lcd_width, int line)
320 int strwdt, strhgt;
321 rb->lcd_getstringsize(str, &strwdt, &strhgt);
322 putsxy((lcd_width - strwdt)/2, line*(strhgt), str);
324 #endif
326 int main(void)
328 int button, fd;
329 bool on = false;
330 #ifdef HAVE_LCD_BITMAP
331 const char *msgs[] = { "Battery Benchmark","Check file", BATTERY_LOG,
332 "for more info", "PLAY - start", "OFF - quit" };
333 #endif
334 rb->lcd_clear_display();
336 #ifdef HAVE_LCD_BITMAP
337 int i;
339 rb->lcd_clear_display();
340 rb->lcd_setfont(FONT_SYSFIXED);
342 for(i = 0; i<(int)(sizeof(msgs)/sizeof(char *)); i++)
343 put_centered_str(msgs[i],rb->lcd_putsxy,LCD_WIDTH,i+1);
345 rb->lcd_update();
346 #ifdef HAVE_REMOTE_LCD
347 rb->lcd_remote_clear_display();
348 put_centered_str(msgs[0],rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,0);
349 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-2],
350 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,1);
351 put_centered_str(msgs[sizeof(msgs)/sizeof(char*)-1],
352 rb->lcd_remote_putsxy,LCD_REMOTE_WIDTH,2);
353 rb->lcd_remote_update();
354 #endif
356 #else
357 rb->lcd_puts_scroll(0, 1, "Batt.Bench.");
358 rb->lcd_puts_scroll(0, 2, "PLAY/STOP");
359 #endif
363 button = rb->button_get(true);
364 switch(button)
366 case BATTERY_ON:
367 #ifdef BATTERY_RC_ON
368 case BATTERY_RC_ON:
369 #endif
370 on = true;
371 break;
372 case BATTERY_OFF:
373 #ifdef BATTERY_RC_OFF
374 case BATTERY_RC_OFF:
375 #endif
376 return PLUGIN_OK;
378 default: if(rb->default_event_handler(button) == SYS_USB_CONNECTED)
379 return PLUGIN_USB_CONNECTED;
381 }while(!on);
383 fd = rb->open(BATTERY_LOG, O_RDONLY);
384 if(fd < 0)
386 fd = rb->open(BATTERY_LOG, O_RDWR | O_CREAT);
387 if(fd >= 0)
389 rb->fdprintf(fd,
390 "This plugin will log your battery performance in a\n"
391 "file (%s) every time the disk is accessed (or every hour).\n"
392 "To properly test your battery:\n"
393 "1) Select and playback an album. "
394 "(Be sure to be more than the player's buffer)\n"
395 "2) Set to repeat.\n"
396 "3) Let the player run completely out of battery.\n"
397 "4) Recharge and copy (or whatever you want) the txt file to "
398 "your computer.\n"
399 "Now you can make graphs with the data of the battery log.\n"
400 "Do not enter another plugin during the test or else the "
401 "logging activity will end.\n\n"
402 "P.S: You can decide how you will make your tests.\n"
403 "Just don't open another plugin to be sure that your log "
404 "will continue.\n"
405 "M/DA (Measurements per Disk Activity) shows how many times\n"
406 "data was logged in the buffer between Disk Activity.\n\n"
407 "Battery type: %d mAh Buffer Entries: %d\n"
408 " Time:, Seconds:, Level:, Time Left:, Voltage[mV]:,"
409 " M/DA:"
410 #ifdef HAVE_CHARGING
411 ", C:"
412 #endif
413 #ifdef HAVE_CHARGE_STATE
414 ", S:"
415 #endif
416 #ifdef HAVE_USB_POWER
417 ", U:"
418 #endif
419 "\n"
420 ,BATTERY_LOG,rb->global_settings->battery_capacity,
421 BUF_SIZE / sizeof(struct batt_info));
422 rb->close(fd);
424 else
426 rb->splash(HZ / 2, true, "Cannot create file!");
427 return PLUGIN_ERROR;
430 else
432 rb->close(fd);
433 fd = rb->open(BATTERY_LOG, O_RDWR | O_APPEND);
434 rb->fdprintf(fd, "\n--File already present. Resuming Benchmark--\n");
435 rb->close(fd);
438 rb->queue_init(&thread_q); /* put the thread's queue in the bcast list */
439 rb->memset(&s_thread, 0, sizeof(s_thread)); /* zero the struct */
440 s_thread.id = rb->create_thread(thread, thread_stack,
441 sizeof(thread_stack), "Battery Benchmark");
442 rb->plugin_tsr(exit_tsr);
444 return PLUGIN_OK;
447 #endif