Commit FS#9617 - Keymaps for Plugins fuze by Thomas Martitz.
[kugel-rb.git] / apps / plugins / stopwatch.c
blobd53937acb2ae9c9f90475cfefc25c139bc096dc0
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 /* FIXME: Use PLUGIN_APPS_DIR */
36 #define STOPWATCH_FILE ROCKBOX_DIR "/apps/stopwatch.dat"
38 /* variable button definitions */
39 #if CONFIG_KEYPAD == RECORDER_PAD
40 #define STOPWATCH_QUIT BUTTON_OFF
41 #define STOPWATCH_START_STOP BUTTON_PLAY
42 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
43 #define STOPWATCH_LAP_TIMER BUTTON_ON
44 #define STOPWATCH_SCROLL_UP BUTTON_UP
45 #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
53 #elif CONFIG_KEYPAD == ONDIO_PAD
54 #define STOPWATCH_QUIT BUTTON_OFF
55 #define STOPWATCH_START_STOP BUTTON_RIGHT
56 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
57 #define STOPWATCH_LAP_TIMER BUTTON_MENU
58 #define STOPWATCH_SCROLL_UP BUTTON_UP
59 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
60 #elif CONFIG_KEYPAD == PLAYER_PAD
61 #define STOPWATCH_QUIT BUTTON_MENU
62 #define STOPWATCH_START_STOP BUTTON_PLAY
63 #define STOPWATCH_RESET_TIMER BUTTON_STOP
64 #define STOPWATCH_LAP_TIMER BUTTON_ON
65 #define STOPWATCH_SCROLL_UP BUTTON_RIGHT
66 #define STOPWATCH_SCROLL_DOWN BUTTON_LEFT
67 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
68 (CONFIG_KEYPAD == IRIVER_H300_PAD)
69 #define STOPWATCH_QUIT BUTTON_OFF
70 #define STOPWATCH_START_STOP BUTTON_SELECT
71 #define STOPWATCH_RESET_TIMER BUTTON_DOWN
72 #define STOPWATCH_LAP_TIMER BUTTON_ON
73 #define STOPWATCH_SCROLL_UP BUTTON_RIGHT
74 #define STOPWATCH_SCROLL_DOWN BUTTON_LEFT
76 #define STOPWATCH_RC_QUIT BUTTON_RC_STOP
78 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
79 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
80 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
81 #define STOPWATCH_QUIT BUTTON_MENU
82 #define STOPWATCH_START_STOP BUTTON_SELECT
83 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
84 #define STOPWATCH_LAP_TIMER BUTTON_RIGHT
85 #define STOPWATCH_SCROLL_UP BUTTON_SCROLL_FWD
86 #define STOPWATCH_SCROLL_DOWN BUTTON_SCROLL_BACK
87 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
88 #define STOPWATCH_QUIT BUTTON_PLAY
89 #define STOPWATCH_START_STOP BUTTON_MODE
90 #define STOPWATCH_RESET_TIMER BUTTON_EQ
91 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
92 #define STOPWATCH_SCROLL_UP BUTTON_UP
93 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
94 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
95 #define STOPWATCH_QUIT BUTTON_POWER
96 #define STOPWATCH_START_STOP BUTTON_PLAY
97 #define STOPWATCH_RESET_TIMER BUTTON_REC
98 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
99 #define STOPWATCH_SCROLL_UP BUTTON_UP
100 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
101 #elif CONFIG_KEYPAD == GIGABEAT_PAD
102 #define STOPWATCH_QUIT BUTTON_POWER
103 #define STOPWATCH_START_STOP BUTTON_SELECT
104 #define STOPWATCH_RESET_TIMER BUTTON_A
105 #define STOPWATCH_LAP_TIMER BUTTON_MENU
106 #define STOPWATCH_SCROLL_UP BUTTON_UP
107 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
109 /* FIXME: e200 could use scrollwheel */
110 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
111 (CONFIG_KEYPAD == SANSA_C200_PAD) || \
112 (CONFIG_KEYPAD == SANSA_CLIP_PAD) || \
113 (CONFIG_KEYPAD == SANSA_M200_PAD)
114 #define STOPWATCH_QUIT BUTTON_POWER
115 #define STOPWATCH_START_STOP BUTTON_RIGHT
116 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
117 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
118 #define STOPWATCH_SCROLL_UP BUTTON_UP
119 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
121 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
122 #define STOPWATCH_QUIT BUTTON_POWER
123 #define STOPWATCH_START_STOP BUTTON_RIGHT
124 #define STOPWATCH_RESET_TIMER BUTTON_LEFT
125 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
126 /* FIXME: ipods scroll other way around, investigate */
127 #define STOPWATCH_SCROLL_UP BUTTON_SCROLL_BACK
128 #define STOPWATCH_SCROLL_DOWN BUTTON_SCROLL_FWD
130 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
131 #define STOPWATCH_QUIT BUTTON_POWER
132 #define STOPWATCH_START_STOP BUTTON_PLAY
133 #define STOPWATCH_RESET_TIMER BUTTON_REW
134 #define STOPWATCH_LAP_TIMER BUTTON_FF
135 #define STOPWATCH_SCROLL_UP BUTTON_SCROLL_UP
136 #define STOPWATCH_SCROLL_DOWN BUTTON_SCROLL_DOWN
137 #elif CONFIG_KEYPAD == MROBE500_PAD
138 #define STOPWATCH_QUIT BUTTON_POWER
139 #define STOPWATCH_START_STOP BUTTON_RC_HEART
140 #define STOPWATCH_RESET_TIMER BUTTON_RC_MODE
141 #define STOPWATCH_LAP_TIMER BUTTON_RC_PLAY
142 #define STOPWATCH_SCROLL_UP BUTTON_RIGHT
143 #define STOPWATCH_SCROLL_DOWN BUTTON_LEFT
144 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
145 #define STOPWATCH_QUIT BUTTON_BACK
146 #define STOPWATCH_START_STOP BUTTON_PLAY
147 #define STOPWATCH_RESET_TIMER BUTTON_MENU
148 #define STOPWATCH_LAP_TIMER BUTTON_SELECT
149 #define STOPWATCH_SCROLL_UP BUTTON_UP
150 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
151 #elif CONFIG_KEYPAD == MROBE100_PAD
152 #define STOPWATCH_QUIT BUTTON_POWER
153 #define STOPWATCH_START_STOP BUTTON_SELECT
154 #define STOPWATCH_RESET_TIMER BUTTON_DISPLAY
155 #define STOPWATCH_LAP_TIMER BUTTON_MENU
156 #define STOPWATCH_SCROLL_UP BUTTON_UP
157 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
158 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
159 #define STOPWATCH_QUIT BUTTON_RC_REC
160 #define STOPWATCH_START_STOP BUTTON_RC_PLAY
161 #define STOPWATCH_RESET_TIMER BUTTON_RC_REW
162 #define STOPWATCH_LAP_TIMER BUTTON_RC_FF
163 #define STOPWATCH_SCROLL_UP BUTTON_RC_VOL_UP
164 #define STOPWATCH_SCROLL_DOWN BUTTON_RC_VOL_DOWN
165 #define STOPWATCH_RC_QUIT BUTTON_REC
166 #elif CONFIG_KEYPAD == COWOND2_PAD
167 #define STOPWATCH_QUIT BUTTON_POWER
168 #elif CONFIG_KEYPAD == IAUDIO67_PAD
169 #define STOPWATCH_QUIT BUTTON_MENU
170 #define STOPWATCH_START_STOP BUTTON_PLAY
171 #define STOPWATCH_RESET_TIMER BUTTON_STOP
172 #define STOPWATCH_LAP_TIMER BUTTON_LEFT
173 #define STOPWATCH_SCROLL_UP BUTTON_VOLUP
174 #define STOPWATCH_SCROLL_DOWN BUTTON_VOLDOWN
175 #define STOPWATCH_RC_QUIT BUTTON_POWER
176 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
177 #define STOPWATCH_QUIT BUTTON_BACK
178 #define STOPWATCH_START_STOP BUTTON_PLAY
179 #define STOPWATCH_RESET_TIMER BUTTON_SELECT
180 #define STOPWATCH_LAP_TIMER BUTTON_CUSTOM
181 #define STOPWATCH_SCROLL_UP BUTTON_UP
182 #define STOPWATCH_SCROLL_DOWN BUTTON_DOWN
183 #else
184 #error No keymap defined!
185 #endif
187 #ifdef HAVE_TOUCHSCREEN
188 #ifndef STOPWATCH_QUIT
189 #define STOPWATCH_QUIT BUTTON_TOPLEFT
190 #endif
191 #ifndef STOPWATCH_START_STOP
192 #define STOPWATCH_START_STOP BUTTON_CENTER
193 #endif
194 #ifndef STOPWATCH_RESET_TIMER
195 #define STOPWATCH_RESET_TIMER BUTTON_MIDRIGHT
196 #endif
197 #ifndef STOPWATCH_LAP_TIMER
198 #define STOPWATCH_LAP_TIMER BUTTON_MIDLEFT
199 #endif
200 #ifndef STOPWATCH_SCROLL_UP
201 #define STOPWATCH_SCROLL_UP BUTTON_TOPMIDDLE
202 #endif
203 #ifndef STOPWATCH_SCROLL_DOWN
204 #define STOPWATCH_SCROLL_DOWN BUTTON_BOTTOMMIDDLE
205 #endif
206 #endif
208 static const struct plugin_api* rb;
210 static int stopwatch = 0;
211 static long start_at = 0;
212 static int prev_total = 0;
213 static bool counting = false;
214 static int curr_lap = 0;
215 static int lap_scroll = 0;
216 static int lap_start;
217 static int lap_times[MAX_LAPS];
219 static void ticks_to_string(int ticks,int lap,int buflen, char * buf)
221 int hours, minutes, seconds, cs;
223 hours = ticks / (HZ * 3600);
224 ticks -= (HZ * hours * 3600);
225 minutes = ticks / (HZ * 60);
226 ticks -= (HZ * minutes * 60);
227 seconds = ticks / HZ;
228 ticks -= (HZ * seconds);
229 cs = ticks;
230 if (!lap)
232 rb->snprintf(buf, buflen,
233 "%2d:%02d:%02d.%02d",
234 hours, minutes, seconds, cs);
236 else
239 if (lap > 1)
241 int last_ticks, last_hours, last_minutes, last_seconds, last_cs;
242 last_ticks = lap_times[(lap-1)%MAX_LAPS] - lap_times[(lap-2)%MAX_LAPS];
243 last_hours = last_ticks / (HZ * 3600);
244 last_ticks -= (HZ * last_hours * 3600);
245 last_minutes = last_ticks / (HZ * 60);
246 last_ticks -= (HZ * last_minutes * 60);
247 last_seconds = last_ticks / HZ;
248 last_ticks -= (HZ * last_seconds);
249 last_cs = last_ticks;
251 rb->snprintf(buf, buflen,
252 "%2d %2d:%02d:%02d.%02d [%2d:%02d:%02d.%02d]",
253 lap, hours, minutes, seconds, cs, last_hours,
254 last_minutes, last_seconds, last_cs);
256 else
258 rb->snprintf(buf, buflen,
259 "%2d %2d:%02d:%02d.%02d",
260 lap, hours, minutes, seconds, cs);
266 * Load saved stopwatch state, if exists.
268 void load_stopwatch(void)
270 int fd;
272 fd = rb->open(STOPWATCH_FILE, O_RDONLY);
274 if (fd < 0)
276 return;
279 /* variable stopwatch isn't saved/loaded, because it is only used
280 * temporarily in main loop
283 rb->read(fd, &start_at, sizeof(start_at));
284 rb->read(fd, &prev_total, sizeof(prev_total));
285 rb->read(fd, &counting, sizeof(counting));
286 rb->read(fd, &curr_lap, sizeof(curr_lap));
287 rb->read(fd, &lap_scroll, sizeof(lap_scroll));
288 rb->read(fd, &lap_start, sizeof(lap_start));
289 rb->read(fd, lap_times, sizeof(lap_times));
291 if (counting && start_at > *rb->current_tick)
293 /* Stopwatch started in the future? Unlikely; probably started on a
294 * previous session and powered off in-between. We'll keep
295 * everything intact (user can clear manually) but stop the
296 * stopwatch to avoid negative timing.
298 start_at = 0;
299 counting = false;
302 rb->close(fd);
306 * Save stopwatch state.
308 void save_stopwatch(void)
310 int fd;
312 fd = rb->open(STOPWATCH_FILE, O_CREAT|O_WRONLY|O_TRUNC);
314 if (fd < 0)
316 return;
319 /* variable stopwatch isn't saved/loaded, because it is only used
320 * temporarily in main loop
323 rb->write(fd, &start_at, sizeof(start_at));
324 rb->write(fd, &prev_total, sizeof(prev_total));
325 rb->write(fd, &counting, sizeof(counting));
326 rb->write(fd, &curr_lap, sizeof(curr_lap));
327 rb->write(fd, &lap_scroll, sizeof(lap_scroll));
328 rb->write(fd, &lap_start, sizeof(lap_start));
329 rb->write(fd, lap_times, sizeof(lap_times));
331 rb->close(fd);
334 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
336 char buf[32];
337 int button;
338 int lap;
339 int done = false;
340 bool update_lap = true;
341 int lines;
343 (void)parameter;
344 rb = api;
346 #ifdef HAVE_LCD_BITMAP
347 int h;
348 rb->lcd_setfont(FONT_UI);
349 rb->lcd_getstringsize("M", NULL, &h);
350 lines = (LCD_HEIGHT / h) - (LAP_Y);
351 #else
352 lines = 1;
353 #endif
355 load_stopwatch();
357 rb->lcd_clear_display();
359 while (!done)
361 if (counting)
363 stopwatch = prev_total + *rb->current_tick - start_at;
365 else
367 stopwatch = prev_total;
370 ticks_to_string(stopwatch,0,32,buf);
371 rb->lcd_puts(0, TIMER_Y, buf);
373 if(update_lap)
375 lap_start = curr_lap - lap_scroll;
376 for (lap = lap_start; lap > lap_start - lines; lap--)
378 if (lap > 0)
380 ticks_to_string(lap_times[(lap-1)%MAX_LAPS],lap,32,buf);
381 rb->lcd_puts_scroll(0, LAP_Y + lap_start - lap, buf);
383 else
385 rb->lcd_puts(0, LAP_Y + lap_start - lap,
386 " ");
389 update_lap = false;
392 rb->lcd_update();
394 if (! counting)
396 button = rb->button_get(true);
398 else
400 button = rb->button_get_w_tmo(10);
402 /* Make sure that the jukebox isn't powered off
403 automatically */
404 rb->reset_poweroff_timer();
406 switch (button)
409 /* exit */
410 #ifdef STOPWATCH_RC_QUIT
411 case STOPWATCH_RC_QUIT:
412 #endif
413 case STOPWATCH_QUIT:
414 save_stopwatch();
415 done = true;
416 break;
418 /* Stop/Start toggle */
419 case STOPWATCH_START_STOP:
420 counting = ! counting;
421 if (counting)
423 start_at = *rb->current_tick;
424 stopwatch = prev_total + *rb->current_tick - start_at;
426 else
428 prev_total += *rb->current_tick - start_at;
429 stopwatch = prev_total;
431 break;
433 /* Reset timer */
434 case STOPWATCH_RESET_TIMER:
435 if (!counting)
437 prev_total = 0;
438 curr_lap = 0;
439 update_lap = true;
441 break;
443 /* Lap timer */
444 case STOPWATCH_LAP_TIMER:
445 lap_times[curr_lap%MAX_LAPS] = stopwatch;
446 curr_lap++;
447 update_lap = true;
448 break;
450 /* Scroll Lap timer up */
451 case STOPWATCH_SCROLL_UP:
452 if (lap_scroll > 0)
454 lap_scroll --;
455 update_lap = true;
457 break;
459 /* Scroll Lap timer down */
460 case STOPWATCH_SCROLL_DOWN:
461 if ((lap_scroll < curr_lap - lines) &&
462 (lap_scroll < (MAX_LAPS - lines)) )
464 lap_scroll ++;
465 update_lap = true;
467 break;
469 default:
470 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
471 return PLUGIN_USB_CONNECTED;
472 break;
475 return PLUGIN_OK;