Fix Gigabeat F manual. Thanks to Marianne Arnold for pointing out it was broken.
[kugel-rb.git] / firmware / scroll_engine.c
blob8d84c797e958c30db168a776e191cb8b7244c7e9
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 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
25 #include "config.h"
26 #include "cpu.h"
27 #include "kernel.h"
28 #include "thread.h"
29 #include "usb.h"
30 #include "lcd.h"
31 #include "font.h"
32 #ifdef HAVE_REMOTE_LCD
33 #include "lcd-remote.h"
34 #endif
35 #include "scroll_engine.h"
37 static const char scroll_tick_table[16] = {
38 /* Hz values:
39 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */
40 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3
43 static void scroll_thread(void);
44 static char scroll_stack[DEFAULT_STACK_SIZE*3];
45 static const char scroll_name[] = "scroll";
47 static struct scrollinfo lcd_scroll[LCD_SCROLLABLE_LINES];
49 #ifdef HAVE_REMOTE_LCD
50 struct scrollinfo lcd_remote_scroll[LCD_REMOTE_SCROLLABLE_LINES];
51 struct event_queue scroll_queue;
52 #endif
54 struct scroll_screen_info lcd_scroll_info =
56 .scroll = lcd_scroll,
57 .lines = 0,
58 .ticks = 12,
59 .delay = HZ/2,
60 .bidir_limit = 50,
61 #ifdef HAVE_LCD_BITMAP
62 .step = 6,
63 #endif
64 #ifdef HAVE_LCD_CHARCELLS
65 .jump_scroll_delay = HZ/4,
66 .jump_scroll = 0,
67 #endif
70 #ifdef HAVE_REMOTE_LCD
71 struct scroll_screen_info lcd_remote_scroll_info =
73 .scroll = lcd_remote_scroll,
74 .lines = 0,
75 .ticks = 12,
76 .delay = HZ/2,
77 .bidir_limit = 50,
78 .step = 6,
80 #endif /* HAVE_REMOTE_LCD */
82 void lcd_stop_scroll(void)
84 lcd_scroll_info.lines = 0;
87 /* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
88 void lcd_scroll_stop_line(struct viewport* current_vp, int y)
90 int i = 0;
92 while (i < lcd_scroll_info.lines)
94 if ((lcd_scroll_info.scroll[i].vp == current_vp) &&
95 ((y < 0) || (lcd_scroll_info.scroll[i].y == y)))
97 /* If i is not the last active line in the array, then move
98 the last item to position i */
99 if ((i + 1) != lcd_scroll_info.lines)
101 lcd_scroll_info.scroll[i] = lcd_scroll_info.scroll[lcd_scroll_info.lines-1];
103 lcd_scroll_info.lines--;
105 /* A line can only appear once, so we're done,
106 * unless we are clearing the whole viewport */
107 if (y >= 0)
108 return ;
110 else
112 i++;
117 /* Stop all scrolling lines in the specified viewport */
118 void lcd_scroll_stop(struct viewport* vp)
120 lcd_scroll_stop_line(vp, -1);
123 void lcd_scroll_speed(int speed)
125 lcd_scroll_info.ticks = scroll_tick_table[speed];
128 #if defined(HAVE_LCD_BITMAP)
129 void lcd_scroll_step(int step)
131 lcd_scroll_info.step = step;
133 #endif
135 void lcd_scroll_delay(int ms)
137 lcd_scroll_info.delay = ms / (HZ / 10);
140 void lcd_bidir_scroll(int percent)
142 lcd_scroll_info.bidir_limit = percent;
145 #ifdef HAVE_LCD_CHARCELLS
146 void lcd_jump_scroll(int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
148 lcd_scroll_info.jump_scroll = mode;
151 void lcd_jump_scroll_delay(int ms)
153 lcd_scroll_info.jump_scroll_delay = ms / (HZ / 10);
155 #endif
157 #ifdef HAVE_REMOTE_LCD
158 void lcd_remote_stop_scroll(void)
160 lcd_remote_scroll_info.lines = 0;
163 /* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
164 void lcd_remote_scroll_stop_line(struct viewport* current_vp, int y)
166 int i = 0;
168 while (i < lcd_remote_scroll_info.lines)
170 if ((lcd_remote_scroll_info.scroll[i].vp == current_vp) &&
171 ((y < 0) || (lcd_remote_scroll_info.scroll[i].y == y)))
173 /* If i is not the last active line in the array, then move
174 the last item to position i */
175 if ((i + 1) != lcd_remote_scroll_info.lines)
177 lcd_remote_scroll_info.scroll[i] = lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines-1];
179 lcd_remote_scroll_info.lines--;
181 /* A line can only appear once, so we're done,
182 * unless we are clearing the whole viewport */
183 if (y >= 0)
184 return ;
186 else
188 i++;
193 /* Stop all scrolling lines in the specified viewport */
194 void lcd_remote_scroll_stop(struct viewport* vp)
196 lcd_remote_scroll_stop_line(vp, -1);
199 void lcd_remote_scroll_speed(int speed)
201 lcd_remote_scroll_info.ticks = scroll_tick_table[speed];
204 void lcd_remote_scroll_step(int step)
206 lcd_remote_scroll_info.step = step;
209 void lcd_remote_scroll_delay(int ms)
211 lcd_remote_scroll_info.delay = ms / (HZ / 10);
214 void lcd_remote_bidir_scroll(int percent)
216 lcd_remote_scroll_info.bidir_limit = percent;
219 static void sync_display_ticks(void)
221 lcd_scroll_info.last_scroll =
222 lcd_remote_scroll_info.last_scroll = current_tick;
225 static bool scroll_process_message(int delay)
227 struct queue_event ev;
231 long tick = current_tick;
232 queue_wait_w_tmo(&scroll_queue, &ev, delay);
234 switch (ev.id)
236 case SYS_TIMEOUT:
237 return false;
238 case SYS_USB_CONNECTED:
239 usb_acknowledge(SYS_USB_CONNECTED_ACK);
240 usb_wait_for_disconnect(&scroll_queue);
241 sync_display_ticks();
242 return true;
243 #ifndef SIMULATOR
244 case SYS_REMOTE_PLUGGED:
245 if (!remote_initialized)
246 sync_display_ticks();
247 #endif
250 delay -= current_tick - tick;
252 while (delay > 0);
254 return false;
256 #endif /* HAVE_REMOTE_LCD */
258 static void scroll_thread(void) __attribute__((noreturn));
259 #ifdef HAVE_REMOTE_LCD
261 static void scroll_thread(void)
263 enum
265 SCROLL_LCD = 0x1,
266 SCROLL_LCD_REMOTE = 0x2,
269 sync_display_ticks();
271 while ( 1 )
273 long delay;
274 int scroll;
275 long tick_lcd, tick_remote;
277 tick_lcd = lcd_scroll_info.last_scroll + lcd_scroll_info.ticks;
278 delay = current_tick;
280 if (
281 #ifndef SIMULATOR
282 !remote_initialized ||
283 #endif
284 (tick_remote = lcd_remote_scroll_info.last_scroll +
285 lcd_remote_scroll_info.ticks,
286 TIME_BEFORE(tick_lcd, tick_remote)))
288 scroll = SCROLL_LCD;
289 delay = tick_lcd - delay;
291 /* TIME_BEFORE(tick_remote, tick_lcd) */
292 else if (tick_lcd != tick_remote)
294 scroll = SCROLL_LCD_REMOTE;
295 delay = tick_remote - delay;
297 else
299 scroll = SCROLL_LCD | SCROLL_LCD_REMOTE;
300 delay = tick_lcd - delay;
303 if (scroll_process_message(delay))
304 continue;
306 if (scroll & SCROLL_LCD)
308 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
309 if (lcd_active())
310 #endif
311 lcd_scroll_fn();
312 lcd_scroll_info.last_scroll = current_tick;
315 if (scroll == (SCROLL_LCD | SCROLL_LCD_REMOTE))
316 yield();
318 if (scroll & SCROLL_LCD_REMOTE)
320 lcd_remote_scroll_fn();
321 lcd_remote_scroll_info.last_scroll = current_tick;
325 #else
326 static void scroll_thread(void)
328 while (1)
330 sleep(lcd_scroll_info.ticks);
331 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
332 if (lcd_active())
333 #endif
334 lcd_scroll_fn();
337 #endif /* HAVE_REMOTE_LCD */
339 void scroll_init(void)
341 #ifdef HAVE_REMOTE_LCD
342 queue_init(&scroll_queue, true);
343 #endif
344 create_thread(scroll_thread, scroll_stack,
345 sizeof(scroll_stack), 0, scroll_name
346 IF_PRIO(, PRIORITY_USER_INTERFACE)
347 IF_COP(, CPU));