My Devcon 2008 contribution: port for Philips GoGear HDD1630 (PP5022-based). Current...
[Rockbox.git] / firmware / scroll_engine.c
blobfac104e6814271136a28777ee1091dc89706b0f2
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 by Michael Sevakis
12 * LCD scrolling driver and scheduler
14 * Much collected and combined from the various Rockbox LCD drivers.
16 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "config.h"
24 #include "cpu.h"
25 #include "kernel.h"
26 #include "thread.h"
27 #include "usb.h"
28 #include "lcd.h"
29 #include "font.h"
30 #ifdef HAVE_REMOTE_LCD
31 #include "lcd-remote.h"
32 #endif
33 #include "scroll_engine.h"
35 static const char scroll_tick_table[16] = {
36 /* Hz values:
37 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */
38 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3
41 static void scroll_thread(void);
42 static char scroll_stack[DEFAULT_STACK_SIZE*3];
43 static const char scroll_name[] = "scroll";
45 static struct scrollinfo lcd_scroll[LCD_SCROLLABLE_LINES];
47 #ifdef HAVE_REMOTE_LCD
48 struct scrollinfo lcd_remote_scroll[LCD_REMOTE_SCROLLABLE_LINES];
49 struct event_queue scroll_queue;
50 #endif
52 struct scroll_screen_info lcd_scroll_info =
54 .scroll = lcd_scroll,
55 .lines = 0,
56 .ticks = 12,
57 .delay = HZ/2,
58 .bidir_limit = 50,
59 #ifdef HAVE_LCD_BITMAP
60 .step = 6,
61 #endif
62 #ifdef HAVE_LCD_CHARCELLS
63 .jump_scroll_delay = HZ/4,
64 .jump_scroll = 0,
65 #endif
68 #ifdef HAVE_REMOTE_LCD
69 struct scroll_screen_info lcd_remote_scroll_info =
71 .scroll = lcd_remote_scroll,
72 .lines = 0,
73 .ticks = 12,
74 .delay = HZ/2,
75 .bidir_limit = 50,
76 .step = 6,
78 #endif /* HAVE_REMOTE_LCD */
80 void lcd_stop_scroll(void)
82 lcd_scroll_info.lines = 0;
85 /* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
86 void lcd_scroll_stop_line(struct viewport* current_vp, int y)
88 int i = 0;
90 while (i < lcd_scroll_info.lines)
92 if ((lcd_scroll_info.scroll[i].vp == current_vp) &&
93 ((y < 0) || (lcd_scroll_info.scroll[i].y == y)))
95 /* If i is not the last active line in the array, then move
96 the last item to position i */
97 if ((i + 1) != lcd_scroll_info.lines)
99 lcd_scroll_info.scroll[i] = lcd_scroll_info.scroll[lcd_scroll_info.lines-1];
101 lcd_scroll_info.lines--;
103 /* A line can only appear once, so we're done. */
104 return ;
106 else
108 i++;
113 /* Stop all scrolling lines in the specified viewport */
114 void lcd_scroll_stop(struct viewport* vp)
116 lcd_scroll_stop_line(vp, -1);
119 void lcd_scroll_speed(int speed)
121 lcd_scroll_info.ticks = scroll_tick_table[speed];
124 #if defined(HAVE_LCD_BITMAP)
125 void lcd_scroll_step(int step)
127 lcd_scroll_info.step = step;
129 #endif
131 void lcd_scroll_delay(int ms)
133 lcd_scroll_info.delay = ms / (HZ / 10);
136 void lcd_bidir_scroll(int percent)
138 lcd_scroll_info.bidir_limit = percent;
141 #ifdef HAVE_LCD_CHARCELLS
142 void lcd_jump_scroll(int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
144 lcd_scroll_info.jump_scroll = mode;
147 void lcd_jump_scroll_delay(int ms)
149 lcd_scroll_info.jump_scroll_delay = ms / (HZ / 10);
151 #endif
153 #ifdef HAVE_REMOTE_LCD
154 void lcd_remote_stop_scroll(void)
156 lcd_remote_scroll_info.lines = 0;
159 /* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
160 void lcd_remote_scroll_stop_line(struct viewport* current_vp, int y)
162 int i = 0;
164 while (i < lcd_remote_scroll_info.lines)
166 if ((lcd_remote_scroll_info.scroll[i].vp == current_vp) &&
167 ((y < 0) || (lcd_remote_scroll_info.scroll[i].y == y)))
169 /* If i is not the last active line in the array, then move
170 the last item to position i */
171 if ((i + 1) != lcd_remote_scroll_info.lines)
173 lcd_remote_scroll_info.scroll[i] = lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines-1];
175 lcd_remote_scroll_info.lines--;
177 /* A line can only appear once, so we're done. */
178 return ;
180 else
182 i++;
187 /* Stop all scrolling lines in the specified viewport */
188 void lcd_remote_scroll_stop(struct viewport* vp)
190 lcd_remote_scroll_stop_line(vp, -1);
193 void lcd_remote_scroll_speed(int speed)
195 lcd_remote_scroll_info.ticks = scroll_tick_table[speed];
198 void lcd_remote_scroll_step(int step)
200 lcd_remote_scroll_info.step = step;
203 void lcd_remote_scroll_delay(int ms)
205 lcd_remote_scroll_info.delay = ms / (HZ / 10);
208 void lcd_remote_bidir_scroll(int percent)
210 lcd_remote_scroll_info.bidir_limit = percent;
213 static void sync_display_ticks(void)
215 lcd_scroll_info.last_scroll =
216 lcd_remote_scroll_info.last_scroll = current_tick;
219 static bool scroll_process_message(int delay)
221 struct queue_event ev;
225 long tick = current_tick;
226 queue_wait_w_tmo(&scroll_queue, &ev, delay);
228 switch (ev.id)
230 case SYS_TIMEOUT:
231 return false;
232 case SYS_USB_CONNECTED:
233 usb_acknowledge(SYS_USB_CONNECTED_ACK);
234 usb_wait_for_disconnect(&scroll_queue);
235 sync_display_ticks();
236 return true;
237 #ifndef SIMULATOR
238 case SYS_REMOTE_PLUGGED:
239 if (!remote_initialized)
240 sync_display_ticks();
241 #endif
244 delay -= current_tick - tick;
246 while (delay > 0);
248 return false;
250 #endif /* HAVE_REMOTE_LCD */
252 static void scroll_thread(void) __attribute__((noreturn));
253 #ifdef HAVE_REMOTE_LCD
255 static void scroll_thread(void)
257 enum
259 SCROLL_LCD = 0x1,
260 SCROLL_LCD_REMOTE = 0x2,
263 sync_display_ticks();
265 while ( 1 )
267 long delay;
268 int scroll;
269 long tick_lcd, tick_remote;
271 tick_lcd = lcd_scroll_info.last_scroll + lcd_scroll_info.ticks;
272 delay = current_tick;
274 if (
275 #ifndef SIMULATOR
276 !remote_initialized ||
277 #endif
278 (tick_remote = lcd_remote_scroll_info.last_scroll +
279 lcd_remote_scroll_info.ticks,
280 TIME_BEFORE(tick_lcd, tick_remote)))
282 scroll = SCROLL_LCD;
283 delay = tick_lcd - delay;
285 /* TIME_BEFORE(tick_remote, tick_lcd) */
286 else if (tick_lcd != tick_remote)
288 scroll = SCROLL_LCD_REMOTE;
289 delay = tick_remote - delay;
291 else
293 scroll = SCROLL_LCD | SCROLL_LCD_REMOTE;
294 delay = tick_lcd - delay;
297 if (scroll_process_message(delay))
298 continue;
300 if (scroll & SCROLL_LCD)
302 #ifdef HAVE_LCD_ENABLE
303 if (lcd_enabled())
304 #endif
305 lcd_scroll_fn();
306 lcd_scroll_info.last_scroll = current_tick;
309 if (scroll == (SCROLL_LCD | SCROLL_LCD_REMOTE))
310 yield();
312 if (scroll & SCROLL_LCD_REMOTE)
314 lcd_remote_scroll_fn();
315 lcd_remote_scroll_info.last_scroll = current_tick;
319 #else
320 static void scroll_thread(void)
322 while (1)
324 sleep(lcd_scroll_info.ticks);
325 #ifdef HAVE_LCD_ENABLE
326 if (lcd_enabled())
327 #endif
328 lcd_scroll_fn();
331 #endif /* HAVE_REMOTE_LCD */
333 void scroll_init(void)
335 #ifdef HAVE_REMOTE_LCD
336 queue_init(&scroll_queue, true);
337 #endif
338 create_thread(scroll_thread, scroll_stack,
339 sizeof(scroll_stack), 0, scroll_name
340 IF_PRIO(, PRIORITY_USER_INTERFACE)
341 IF_COP(, CPU));