1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
32 #ifdef HAVE_REMOTE_LCD
33 #include "lcd-remote.h"
35 #include "scroll_engine.h"
37 static const char scroll_tick_table
[16] = {
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
;
54 struct scroll_screen_info lcd_scroll_info
=
61 #ifdef HAVE_LCD_BITMAP
64 #ifdef HAVE_LCD_CHARCELLS
65 .jump_scroll_delay
= HZ
/4,
70 #ifdef HAVE_REMOTE_LCD
71 struct scroll_screen_info lcd_remote_scroll_info
=
73 .scroll
= lcd_remote_scroll
,
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(const struct viewport
* current_vp
, int y
)
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
] =
102 lcd_scroll_info
.scroll
[lcd_scroll_info
.lines
-1];
104 lcd_scroll_info
.lines
--;
106 /* A line can only appear once, so we're done,
107 * unless we are clearing the whole viewport */
118 /* Stop all scrolling lines in the specified viewport */
119 void lcd_scroll_stop(const struct viewport
* vp
)
121 lcd_scroll_stop_line(vp
, -1);
124 void lcd_scroll_speed(int speed
)
126 lcd_scroll_info
.ticks
= scroll_tick_table
[speed
];
129 #if defined(HAVE_LCD_BITMAP)
130 void lcd_scroll_step(int step
)
132 lcd_scroll_info
.step
= step
;
136 void lcd_scroll_delay(int ms
)
138 lcd_scroll_info
.delay
= ms
/ (HZ
/ 10);
141 void lcd_bidir_scroll(int percent
)
143 lcd_scroll_info
.bidir_limit
= percent
;
146 #ifdef HAVE_LCD_CHARCELLS
147 void lcd_jump_scroll(int mode
) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
149 lcd_scroll_info
.jump_scroll
= mode
;
152 void lcd_jump_scroll_delay(int ms
)
154 lcd_scroll_info
.jump_scroll_delay
= ms
/ (HZ
/ 10);
158 #ifdef HAVE_REMOTE_LCD
159 void lcd_remote_stop_scroll(void)
161 lcd_remote_scroll_info
.lines
= 0;
164 /* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
165 void lcd_remote_scroll_stop_line(const struct viewport
* current_vp
, int y
)
169 while (i
< lcd_remote_scroll_info
.lines
)
171 if ((lcd_remote_scroll_info
.scroll
[i
].vp
== current_vp
) &&
172 ((y
< 0) || (lcd_remote_scroll_info
.scroll
[i
].y
== y
)))
174 /* If i is not the last active line in the array, then move
175 the last item to position i */
176 if ((i
+ 1) != lcd_remote_scroll_info
.lines
)
178 lcd_remote_scroll_info
.scroll
[i
] =
179 lcd_remote_scroll_info
.scroll
[lcd_remote_scroll_info
.lines
-1];
181 lcd_remote_scroll_info
.lines
--;
183 /* A line can only appear once, so we're done,
184 * unless we are clearing the whole viewport */
195 /* Stop all scrolling lines in the specified viewport */
196 void lcd_remote_scroll_stop(const struct viewport
* vp
)
198 lcd_remote_scroll_stop_line(vp
, -1);
201 void lcd_remote_scroll_speed(int speed
)
203 lcd_remote_scroll_info
.ticks
= scroll_tick_table
[speed
];
206 void lcd_remote_scroll_step(int step
)
208 lcd_remote_scroll_info
.step
= step
;
211 void lcd_remote_scroll_delay(int ms
)
213 lcd_remote_scroll_info
.delay
= ms
/ (HZ
/ 10);
216 void lcd_remote_bidir_scroll(int percent
)
218 lcd_remote_scroll_info
.bidir_limit
= percent
;
221 static void sync_display_ticks(void)
223 lcd_scroll_info
.last_scroll
=
224 lcd_remote_scroll_info
.last_scroll
= current_tick
;
227 static bool scroll_process_message(int delay
)
229 struct queue_event ev
;
233 long tick
= current_tick
;
234 queue_wait_w_tmo(&scroll_queue
, &ev
, delay
);
240 case SYS_USB_CONNECTED
:
241 usb_acknowledge(SYS_USB_CONNECTED_ACK
);
242 usb_wait_for_disconnect(&scroll_queue
);
243 sync_display_ticks();
245 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
246 case SYS_REMOTE_PLUGGED
:
247 if (!remote_initialized
)
248 sync_display_ticks();
252 delay
-= current_tick
- tick
;
258 #endif /* HAVE_REMOTE_LCD */
260 static void scroll_thread(void) __attribute__((noreturn
));
261 #ifdef HAVE_REMOTE_LCD
263 static void scroll_thread(void)
268 SCROLL_LCD_REMOTE
= 0x2,
271 sync_display_ticks();
277 long tick_lcd
, tick_remote
;
279 tick_lcd
= lcd_scroll_info
.last_scroll
+ lcd_scroll_info
.ticks
;
280 delay
= current_tick
;
283 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
284 !remote_initialized
||
286 (tick_remote
= lcd_remote_scroll_info
.last_scroll
+
287 lcd_remote_scroll_info
.ticks
,
288 TIME_BEFORE(tick_lcd
, tick_remote
)))
291 delay
= tick_lcd
- delay
;
293 /* TIME_BEFORE(tick_remote, tick_lcd) */
294 else if (tick_lcd
!= tick_remote
)
296 scroll
= SCROLL_LCD_REMOTE
;
297 delay
= tick_remote
- delay
;
301 scroll
= SCROLL_LCD
| SCROLL_LCD_REMOTE
;
302 delay
= tick_lcd
- delay
;
305 if (scroll_process_message(delay
))
308 if (scroll
& SCROLL_LCD
)
310 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
314 lcd_scroll_info
.last_scroll
= current_tick
;
317 if (scroll
== (SCROLL_LCD
| SCROLL_LCD_REMOTE
))
320 if (scroll
& SCROLL_LCD_REMOTE
)
322 lcd_remote_scroll_fn();
323 lcd_remote_scroll_info
.last_scroll
= current_tick
;
328 static void scroll_thread(void)
332 sleep(lcd_scroll_info
.ticks
);
333 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
339 #endif /* HAVE_REMOTE_LCD */
341 void scroll_init(void)
343 #ifdef HAVE_REMOTE_LCD
344 queue_init(&scroll_queue
, true);
346 create_thread(scroll_thread
, scroll_stack
,
347 sizeof(scroll_stack
), 0, scroll_name
348 IF_PRIO(, PRIORITY_USER_INTERFACE
)