Fix 'make fullinstall'
[kugel-rb.git] / apps / plugins / stopwatch.c
blob19ccc5006da715efbcf787ea5c989babd84d4009
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004 Mike Holden
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
24 PLUGIN_HEADER
26 #ifdef HAVE_LCD_BITMAP
27 #define TIMER_Y 1
28 #else
29 #define TIMER_Y 0
30 #endif
32 #define LAP_Y TIMER_Y+1
33 #define MAX_LAPS 64
35 #define STOPWATCH_FILE ROCKBOX_DIR "/apps/stopwatch.dat"
37 /* variable button definitions */
38 #if CONFIG_KEYPAD == RECORDER_PAD
39 #define STOPWATCH_QUIT BUTTON_OFF
40 #define STOPWATCH_START_STOP BUTTON_PLAY
41 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
42 #define STOPWATCH_LAP_TIMER BUTTON_ON
43 #define STOPWATCH_SCROLL_UP BUTTON_UP
44 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
46 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
47 #define STOPWATCH_QUIT BUTTON_OFF
48 #define STOPWATCH_START_STOP BUTTON_SELECT
49 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
50 #define STOPWATCH_LAP_TIMER BUTTON_ON
51 #define STOPWATCH_SCROLL_UP BUTTON_UP
52 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
54 #elif CONFIG_KEYPAD == ONDIO_PAD
55 #define STOPWATCH_QUIT BUTTON_OFF
56 #define STOPWATCH_START_STOP BUTTON_RIGHT
57 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
58 #define STOPWATCH_LAP_TIMER BUTTON_MENU
59 #define STOPWATCH_SCROLL_UP BUTTON_UP
60 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
62 #elif CONFIG_KEYPAD == PLAYER_PAD
63 #define STOPWATCH_QUIT BUTTON_MENU
64 #define STOPWATCH_START_STOP BUTTON_PLAY
65 #define STOPWATCH_RESET_TIMER BUTTON_STOP
66 #define STOPWATCH_LAP_TIMER BUTTON_ON
67 #define STOPWATCH_SCROLL_UP BUTTON_RIGHT
68 #define STOPWATCH_SCROLL_DOWN BUTTON_LEFT
70 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
71 (CONFIG_KEYPAD == IRIVER_H300_PAD)
72 #define STOPWATCH_QUIT BUTTON_OFF
73 #define STOPWATCH_START_STOP BUTTON_SELECT
74 #define STOPWATCH_RESET_TIMER BUTTON_DOWN
75 #define STOPWATCH_LAP_TIMER BUTTON_ON
76 #define STOPWATCH_SCROLL_UP BUTTON_RIGHT
77 #define STOPWATCH_SCROLL_DOWN BUTTON_LEFT
78 #define STOPWATCH_RC_QUIT BUTTON_RC_STOP
80 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
81 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
82 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
83 #define STOPWATCH_QUIT BUTTON_MENU
84 #define STOPWATCH_START_STOP BUTTON_SELECT
85 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
86 #define STOPWATCH_LAP_TIMER BUTTON_RIGHT
87 #define STOPWATCH_SCROLL_UP BUTTON_SCROLL_FWD
88 #define STOPWATCH_SCROLL_DOWN BUTTON_SCROLL_BACK
90 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
91 #define STOPWATCH_QUIT BUTTON_PLAY
92 #define STOPWATCH_START_STOP BUTTON_MODE
93 #define STOPWATCH_RESET_TIMER BUTTON_EQ
94 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
95 #define STOPWATCH_SCROLL_UP BUTTON_UP
96 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
98 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
99 #define STOPWATCH_QUIT BUTTON_POWER
100 #define STOPWATCH_START_STOP BUTTON_PLAY
101 #define STOPWATCH_RESET_TIMER BUTTON_REC
102 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
103 #define STOPWATCH_SCROLL_UP BUTTON_UP
104 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
106 #elif CONFIG_KEYPAD == GIGABEAT_PAD
107 #define STOPWATCH_QUIT BUTTON_POWER
108 #define STOPWATCH_START_STOP BUTTON_SELECT
109 #define STOPWATCH_RESET_TIMER BUTTON_A
110 #define STOPWATCH_LAP_TIMER BUTTON_MENU
111 #define STOPWATCH_SCROLL_UP BUTTON_UP
112 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
114 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
115 (CONFIG_KEYPAD == SANSA_C200_PAD) || \
116 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
117 (CONFIG_KEYPAD == SANSA_M200_PAD)
118 #define STOPWATCH_QUIT BUTTON_POWER
119 #define STOPWATCH_START_STOP BUTTON_RIGHT
120 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
121 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
122 #define STOPWATCH_SCROLL_UP BUTTON_UP
123 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
125 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
126 #define STOPWATCH_QUIT (BUTTON_HOME|BUTTON_REPEAT)
127 #define STOPWATCH_START_STOP BUTTON_RIGHT
128 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
129 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
130 #define STOPWATCH_SCROLL_UP BUTTON_SCROLL_BACK
131 #define STOPWATCH_SCROLL_DOWN BUTTON_SCROLL_FWD
133 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
134 #define STOPWATCH_QUIT BUTTON_POWER
135 #define STOPWATCH_START_STOP BUTTON_PLAY
136 #define STOPWATCH_RESET_TIMER BUTTON_REW
137 #define STOPWATCH_LAP_TIMER BUTTON_FF
138 #define STOPWATCH_SCROLL_UP BUTTON_SCROLL_UP
139 #define STOPWATCH_SCROLL_DOWN BUTTON_SCROLL_DOWN
141 #elif CONFIG_KEYPAD == MROBE500_PAD
142 #define STOPWATCH_QUIT BUTTON_POWER
143 #define STOPWATCH_START_STOP BUTTON_RC_HEART
144 #define STOPWATCH_RESET_TIMER BUTTON_RC_MODE
145 #define STOPWATCH_LAP_TIMER BUTTON_RC_PLAY
146 #define STOPWATCH_SCROLL_UP BUTTON_RIGHT
147 #define STOPWATCH_SCROLL_DOWN BUTTON_LEFT
149 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
150 #define STOPWATCH_QUIT BUTTON_BACK
151 #define STOPWATCH_START_STOP BUTTON_PLAY
152 #define STOPWATCH_RESET_TIMER BUTTON_MENU
153 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
154 #define STOPWATCH_SCROLL_UP BUTTON_UP
155 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
157 #elif CONFIG_KEYPAD == MROBE100_PAD
158 #define STOPWATCH_QUIT BUTTON_POWER
159 #define STOPWATCH_START_STOP BUTTON_SELECT
160 #define STOPWATCH_RESET_TIMER BUTTON_DISPLAY
161 #define STOPWATCH_LAP_TIMER BUTTON_MENU
162 #define STOPWATCH_SCROLL_UP BUTTON_UP
163 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
165 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
166 #define STOPWATCH_QUIT BUTTON_RC_REC
167 #define STOPWATCH_START_STOP BUTTON_RC_PLAY
168 #define STOPWATCH_RESET_TIMER BUTTON_RC_REW
169 #define STOPWATCH_LAP_TIMER BUTTON_RC_FF
170 #define STOPWATCH_SCROLL_UP BUTTON_RC_VOL_UP
171 #define STOPWATCH_SCROLL_DOWN BUTTON_RC_VOL_DOWN
172 #define STOPWATCH_RC_QUIT BUTTON_REC
174 #elif CONFIG_KEYPAD == COWOND2_PAD
175 #define STOPWATCH_QUIT BUTTON_POWER
177 #elif CONFIG_KEYPAD == IAUDIO67_PAD
178 #define STOPWATCH_QUIT BUTTON_MENU
179 #define STOPWATCH_START_STOP BUTTON_PLAY
180 #define STOPWATCH_RESET_TIMER BUTTON_STOP
181 #define STOPWATCH_LAP_TIMER BUTTON_LEFT
182 #define STOPWATCH_SCROLL_UP BUTTON_VOLUP
183 #define STOPWATCH_SCROLL_DOWN BUTTON_VOLDOWN
184 #define STOPWATCH_RC_QUIT BUTTON_POWER
186 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
187 #define STOPWATCH_QUIT BUTTON_BACK
188 #define STOPWATCH_START_STOP BUTTON_PLAY
189 #define STOPWATCH_RESET_TIMER BUTTON_SELECT
190 #define STOPWATCH_LAP_TIMER BUTTON_CUSTOM
191 #define STOPWATCH_SCROLL_UP BUTTON_UP
192 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
194 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
195 #define STOPWATCH_QUIT BUTTON_POWER
196 #define STOPWATCH_START_STOP BUTTON_SELECT
197 #define STOPWATCH_RESET_TIMER BUTTON_MENU
198 #define STOPWATCH_LAP_TIMER BUTTON_VIEW
199 #define STOPWATCH_SCROLL_UP BUTTON_UP
200 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
202 #elif CONFIG_KEYPAD == ONDAVX747_PAD
203 #define STOPWATCH_QUIT BUTTON_POWER
205 #else
206 #error No keymap defined!
207 #endif
209 #ifdef HAVE_TOUCHSCREEN
210 #ifndef STOPWATCH_QUIT
211 #define STOPWATCH_QUIT BUTTON_TOPLEFT
212 #endif
213 #ifndef STOPWATCH_START_STOP
214 #define STOPWATCH_START_STOP BUTTON_CENTER
215 #endif
216 #ifndef STOPWATCH_RESET_TIMER
217 #define STOPWATCH_RESET_TIMER BUTTON_MIDRIGHT
218 #endif
219 #ifndef STOPWATCH_LAP_TIMER
220 #define STOPWATCH_LAP_TIMER BUTTON_MIDLEFT
221 #endif
222 #ifndef STOPWATCH_SCROLL_UP
223 #define STOPWATCH_SCROLL_UP BUTTON_TOPMIDDLE
224 #endif
225 #ifndef STOPWATCH_SCROLL_DOWN
226 #define STOPWATCH_SCROLL_DOWN BUTTON_BOTTOMMIDDLE
227 #endif
228 #endif
230 static int stopwatch = 0;
231 static long start_at = 0;
232 static int prev_total = 0;
233 static bool counting = false;
234 static int curr_lap = 0;
235 static int lap_scroll = 0;
236 static int lap_start;
237 static int lap_times[MAX_LAPS];
239 static void ticks_to_string(int ticks,int lap,int buflen, char * buf)
241 int hours, minutes, seconds, cs;
243 hours = ticks / (HZ * 3600);
244 ticks -= (HZ * hours * 3600);
245 minutes = ticks / (HZ * 60);
246 ticks -= (HZ * minutes * 60);
247 seconds = ticks / HZ;
248 ticks -= (HZ * seconds);
249 cs = ticks;
250 if (!lap)
252 rb->snprintf(buf, buflen,
253 "%2d:%02d:%02d.%02d",
254 hours, minutes, seconds, cs);
256 else
259 if (lap > 1)
261 int last_ticks, last_hours, last_minutes, last_seconds, last_cs;
262 last_ticks = lap_times[(lap-1)%MAX_LAPS] - lap_times[(lap-2)%MAX_LAPS];
263 last_hours = last_ticks / (HZ * 3600);
264 last_ticks -= (HZ * last_hours * 3600);
265 last_minutes = last_ticks / (HZ * 60);
266 last_ticks -= (HZ * last_minutes * 60);
267 last_seconds = last_ticks / HZ;
268 last_ticks -= (HZ * last_seconds);
269 last_cs = last_ticks;
271 rb->snprintf(buf, buflen,
272 "%2d %2d:%02d:%02d.%02d [%2d:%02d:%02d.%02d]",
273 lap, hours, minutes, seconds, cs, last_hours,
274 last_minutes, last_seconds, last_cs);
276 else
278 rb->snprintf(buf, buflen,
279 "%2d %2d:%02d:%02d.%02d",
280 lap, hours, minutes, seconds, cs);
286 * Load saved stopwatch state, if exists.
288 void load_stopwatch(void)
290 int fd;
292 fd = rb->open(STOPWATCH_FILE, O_RDONLY);
294 if (fd < 0)
296 return;
299 /* variable stopwatch isn't saved/loaded, because it is only used
300 * temporarily in main loop
303 rb->read(fd, &start_at, sizeof(start_at));
304 rb->read(fd, &prev_total, sizeof(prev_total));
305 rb->read(fd, &counting, sizeof(counting));
306 rb->read(fd, &curr_lap, sizeof(curr_lap));
307 rb->read(fd, &lap_scroll, sizeof(lap_scroll));
308 rb->read(fd, &lap_start, sizeof(lap_start));
309 rb->read(fd, lap_times, sizeof(lap_times));
311 if (counting && start_at > *rb->current_tick)
313 /* Stopwatch started in the future? Unlikely; probably started on a
314 * previous session and powered off in-between. We'll keep
315 * everything intact (user can clear manually) but stop the
316 * stopwatch to avoid negative timing.
318 start_at = 0;
319 counting = false;
322 rb->close(fd);
326 * Save stopwatch state.
328 void save_stopwatch(void)
330 int fd;
332 fd = rb->open(STOPWATCH_FILE, O_CREAT|O_WRONLY|O_TRUNC);
334 if (fd < 0)
336 return;
339 /* variable stopwatch isn't saved/loaded, because it is only used
340 * temporarily in main loop
343 rb->write(fd, &start_at, sizeof(start_at));
344 rb->write(fd, &prev_total, sizeof(prev_total));
345 rb->write(fd, &counting, sizeof(counting));
346 rb->write(fd, &curr_lap, sizeof(curr_lap));
347 rb->write(fd, &lap_scroll, sizeof(lap_scroll));
348 rb->write(fd, &lap_start, sizeof(lap_start));
349 rb->write(fd, lap_times, sizeof(lap_times));
351 rb->close(fd);
354 enum plugin_status plugin_start(const void* parameter)
356 char buf[32];
357 int button;
358 int lap;
359 int done = false;
360 bool update_lap = true;
361 int lines;
363 (void)parameter;
365 #ifdef HAVE_LCD_BITMAP
366 int h;
367 rb->lcd_setfont(FONT_UI);
368 rb->lcd_getstringsize("M", NULL, &h);
369 lines = (LCD_HEIGHT / h) - (LAP_Y);
370 #else
371 lines = 1;
372 #endif
374 load_stopwatch();
376 rb->lcd_clear_display();
378 while (!done)
380 if (counting)
382 stopwatch = prev_total + *rb->current_tick - start_at;
384 else
386 stopwatch = prev_total;
389 ticks_to_string(stopwatch,0,32,buf);
390 rb->lcd_puts(0, TIMER_Y, buf);
392 if(update_lap)
394 lap_start = curr_lap - lap_scroll;
395 for (lap = lap_start; lap > lap_start - lines; lap--)
397 if (lap > 0)
399 ticks_to_string(lap_times[(lap-1)%MAX_LAPS],lap,32,buf);
400 rb->lcd_puts_scroll(0, LAP_Y + lap_start - lap, buf);
402 else
404 rb->lcd_puts(0, LAP_Y + lap_start - lap,
405 " ");
408 update_lap = false;
411 rb->lcd_update();
413 if (! counting)
415 button = rb->button_get(true);
417 else
419 button = rb->button_get_w_tmo(10);
421 /* Make sure that the jukebox isn't powered off
422 automatically */
423 rb->reset_poweroff_timer();
425 switch (button)
428 /* exit */
429 #ifdef STOPWATCH_RC_QUIT
430 case STOPWATCH_RC_QUIT:
431 #endif
432 case STOPWATCH_QUIT:
433 save_stopwatch();
434 done = true;
435 break;
437 /* Stop/Start toggle */
438 case STOPWATCH_START_STOP:
439 counting = ! counting;
440 if (counting)
442 start_at = *rb->current_tick;
443 stopwatch = prev_total + *rb->current_tick - start_at;
445 else
447 prev_total += *rb->current_tick - start_at;
448 stopwatch = prev_total;
450 break;
452 /* Reset timer */
453 case STOPWATCH_RESET_TIMER:
454 if (!counting)
456 prev_total = 0;
457 curr_lap = 0;
458 update_lap = true;
460 break;
462 /* Lap timer */
463 case STOPWATCH_LAP_TIMER:
464 lap_times[curr_lap%MAX_LAPS] = stopwatch;
465 curr_lap++;
466 update_lap = true;
467 break;
469 /* Scroll Lap timer up */
470 case STOPWATCH_SCROLL_UP:
471 if (lap_scroll > 0)
473 lap_scroll --;
474 update_lap = true;
476 break;
478 /* Scroll Lap timer down */
479 case STOPWATCH_SCROLL_DOWN:
480 if ((lap_scroll < curr_lap - lines) &&
481 (lap_scroll < (MAX_LAPS - lines)) )
483 lap_scroll ++;
484 update_lap = true;
486 break;
488 default:
489 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
490 return PLUGIN_USB_CONNECTED;
491 break;
494 return PLUGIN_OK;