blob: 200695b5d64bb3d93ca3ceb15e1ccc68200797cf [file] [log] [blame]
Michael Sevakis58fc2792007-07-28 08:12:05 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 by Michael Sevakis
11 *
12 * LCD scrolling driver and scheduler
13 *
14 * Much collected and combined from the various Rockbox LCD drivers.
15 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000016 * 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.
Michael Sevakis58fc2792007-07-28 08:12:05 +000020 *
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
23 *
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"
36
37static 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
41};
42
43static void scroll_thread(void);
44static char scroll_stack[DEFAULT_STACK_SIZE*3];
45static const char scroll_name[] = "scroll";
46
Bertrik Sikkendb2d61f2008-04-20 10:24:15 +000047static struct scrollinfo lcd_scroll[LCD_SCROLLABLE_LINES];
Michael Sevakis58fc2792007-07-28 08:12:05 +000048
49#ifdef HAVE_REMOTE_LCD
50struct scrollinfo lcd_remote_scroll[LCD_REMOTE_SCROLLABLE_LINES];
Michael Sevakis84f5c5c2007-10-16 22:00:51 +000051struct event_queue scroll_queue;
Michael Sevakis58fc2792007-07-28 08:12:05 +000052#endif
53
54struct scroll_screen_info lcd_scroll_info =
55{
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
68};
69
70#ifdef HAVE_REMOTE_LCD
71struct scroll_screen_info lcd_remote_scroll_info =
72{
73 .scroll = lcd_remote_scroll,
74 .lines = 0,
75 .ticks = 12,
76 .delay = HZ/2,
77 .bidir_limit = 50,
78 .step = 6,
79};
80#endif /* HAVE_REMOTE_LCD */
81
82void lcd_stop_scroll(void)
83{
84 lcd_scroll_info.lines = 0;
85}
86
Dave Chapman945c8a22008-01-07 20:34:11 +000087/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
88void lcd_scroll_stop_line(struct viewport* current_vp, int y)
89{
90 int i = 0;
91
92 while (i < lcd_scroll_info.lines)
93 {
94 if ((lcd_scroll_info.scroll[i].vp == current_vp) &&
95 ((y < 0) || (lcd_scroll_info.scroll[i].y == y)))
96 {
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)
100 {
101 lcd_scroll_info.scroll[i] = lcd_scroll_info.scroll[lcd_scroll_info.lines-1];
102 }
103 lcd_scroll_info.lines--;
104
105 /* A line can only appear once, so we're done. */
106 return ;
107 }
108 else
109 {
110 i++;
111 }
112 }
113}
114
115/* Stop all scrolling lines in the specified viewport */
116void lcd_scroll_stop(struct viewport* vp)
117{
118 lcd_scroll_stop_line(vp, -1);
119}
120
Michael Sevakis58fc2792007-07-28 08:12:05 +0000121void lcd_scroll_speed(int speed)
122{
123 lcd_scroll_info.ticks = scroll_tick_table[speed];
124}
125
126#if defined(HAVE_LCD_BITMAP)
Michael Sevakis58fc2792007-07-28 08:12:05 +0000127void lcd_scroll_step(int step)
128{
129 lcd_scroll_info.step = step;
130}
131#endif
132
133void lcd_scroll_delay(int ms)
134{
135 lcd_scroll_info.delay = ms / (HZ / 10);
136}
137
138void lcd_bidir_scroll(int percent)
139{
140 lcd_scroll_info.bidir_limit = percent;
141}
142
143#ifdef HAVE_LCD_CHARCELLS
144void lcd_jump_scroll(int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
145{
146 lcd_scroll_info.jump_scroll = mode;
147}
148
149void lcd_jump_scroll_delay(int ms)
150{
151 lcd_scroll_info.jump_scroll_delay = ms / (HZ / 10);
152}
153#endif
154
155#ifdef HAVE_REMOTE_LCD
Michael Sevakis58fc2792007-07-28 08:12:05 +0000156void lcd_remote_stop_scroll(void)
157{
158 lcd_remote_scroll_info.lines = 0;
159}
160
Dave Chapman945c8a22008-01-07 20:34:11 +0000161/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
162void lcd_remote_scroll_stop_line(struct viewport* current_vp, int y)
163{
164 int i = 0;
165
166 while (i < lcd_remote_scroll_info.lines)
167 {
168 if ((lcd_remote_scroll_info.scroll[i].vp == current_vp) &&
169 ((y < 0) || (lcd_remote_scroll_info.scroll[i].y == y)))
170 {
171 /* If i is not the last active line in the array, then move
172 the last item to position i */
173 if ((i + 1) != lcd_remote_scroll_info.lines)
174 {
175 lcd_remote_scroll_info.scroll[i] = lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines-1];
176 }
177 lcd_remote_scroll_info.lines--;
178
179 /* A line can only appear once, so we're done. */
180 return ;
181 }
182 else
183 {
184 i++;
185 }
186 }
187}
188
189/* Stop all scrolling lines in the specified viewport */
190void lcd_remote_scroll_stop(struct viewport* vp)
191{
192 lcd_remote_scroll_stop_line(vp, -1);
193}
194
Michael Sevakis58fc2792007-07-28 08:12:05 +0000195void lcd_remote_scroll_speed(int speed)
196{
197 lcd_remote_scroll_info.ticks = scroll_tick_table[speed];
198}
199
200void lcd_remote_scroll_step(int step)
201{
202 lcd_remote_scroll_info.step = step;
203}
204
205void lcd_remote_scroll_delay(int ms)
206{
207 lcd_remote_scroll_info.delay = ms / (HZ / 10);
208}
209
210void lcd_remote_bidir_scroll(int percent)
211{
212 lcd_remote_scroll_info.bidir_limit = percent;
213}
214
215static void sync_display_ticks(void)
216{
217 lcd_scroll_info.last_scroll =
218 lcd_remote_scroll_info.last_scroll = current_tick;
219}
220
221static bool scroll_process_message(int delay)
222{
Michael Sevakisa9b2fb52007-10-16 01:25:17 +0000223 struct queue_event ev;
Michael Sevakis58fc2792007-07-28 08:12:05 +0000224
225 do
226 {
227 long tick = current_tick;
228 queue_wait_w_tmo(&scroll_queue, &ev, delay);
229
230 switch (ev.id)
231 {
232 case SYS_TIMEOUT:
233 return false;
234 case SYS_USB_CONNECTED:
235 usb_acknowledge(SYS_USB_CONNECTED_ACK);
236 usb_wait_for_disconnect(&scroll_queue);
237 sync_display_ticks();
238 return true;
239#ifndef SIMULATOR
240 case SYS_REMOTE_PLUGGED:
241 if (!remote_initialized)
242 sync_display_ticks();
243#endif
244 }
245
246 delay -= current_tick - tick;
247 }
248 while (delay > 0);
249
250 return false;
251}
252#endif /* HAVE_REMOTE_LCD */
253
254static void scroll_thread(void) __attribute__((noreturn));
255#ifdef HAVE_REMOTE_LCD
256
257static void scroll_thread(void)
258{
259 enum
260 {
261 SCROLL_LCD = 0x1,
262 SCROLL_LCD_REMOTE = 0x2,
263 };
264
265 sync_display_ticks();
266
267 while ( 1 )
268 {
269 long delay;
270 int scroll;
271 long tick_lcd, tick_remote;
272
273 tick_lcd = lcd_scroll_info.last_scroll + lcd_scroll_info.ticks;
274 delay = current_tick;
275
276 if (
277#ifndef SIMULATOR
278 !remote_initialized ||
279#endif
280 (tick_remote = lcd_remote_scroll_info.last_scroll +
281 lcd_remote_scroll_info.ticks,
282 TIME_BEFORE(tick_lcd, tick_remote)))
283 {
284 scroll = SCROLL_LCD;
285 delay = tick_lcd - delay;
286 }
287 /* TIME_BEFORE(tick_remote, tick_lcd) */
288 else if (tick_lcd != tick_remote)
289 {
290 scroll = SCROLL_LCD_REMOTE;
291 delay = tick_remote - delay;
292 }
293 else
294 {
295 scroll = SCROLL_LCD | SCROLL_LCD_REMOTE;
296 delay = tick_lcd - delay;
297 }
298
299 if (scroll_process_message(delay))
300 continue;
301
302 if (scroll & SCROLL_LCD)
303 {
304#ifdef HAVE_LCD_ENABLE
305 if (lcd_enabled())
306#endif
307 lcd_scroll_fn();
308 lcd_scroll_info.last_scroll = current_tick;
309 }
310
311 if (scroll == (SCROLL_LCD | SCROLL_LCD_REMOTE))
312 yield();
313
314 if (scroll & SCROLL_LCD_REMOTE)
315 {
316 lcd_remote_scroll_fn();
317 lcd_remote_scroll_info.last_scroll = current_tick;
318 }
319 }
320}
321#else
322static void scroll_thread(void)
323{
324 while (1)
325 {
326 sleep(lcd_scroll_info.ticks);
327#ifdef HAVE_LCD_ENABLE
328 if (lcd_enabled())
329#endif
330 lcd_scroll_fn();
331 }
332}
333#endif /* HAVE_REMOTE_LCD */
334
335void scroll_init(void)
336{
337#ifdef HAVE_REMOTE_LCD
338 queue_init(&scroll_queue, true);
339#endif
340 create_thread(scroll_thread, scroll_stack,
Michael Sevakisa9b2fb52007-10-16 01:25:17 +0000341 sizeof(scroll_stack), 0, scroll_name
Michael Sevakis58fc2792007-07-28 08:12:05 +0000342 IF_PRIO(, PRIORITY_USER_INTERFACE)
Michael Sevakisa9b2fb52007-10-16 01:25:17 +0000343 IF_COP(, CPU));
Michael Sevakis58fc2792007-07-28 08:12:05 +0000344}