Don't try to save settings if none available.
[maemo-rb.git] / firmware / scroll_engine.c
blobbc356a82813ef1cc2ab3f581cafc17750437ae5b
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 "gcc_extensions.h"
27 #include "cpu.h"
28 #include "kernel.h"
29 #include "thread.h"
30 #include "usb.h"
31 #include "lcd.h"
32 #include "font.h"
33 #ifdef HAVE_REMOTE_LCD
34 #include "lcd-remote.h"
35 #endif
36 #include "scroll_engine.h"
38 static const char scroll_tick_table[18] = {
39 /* Hz values [f(x)=100.8/(x+.048)]:
40 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33, 49.2, 96.2 */
41 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3, 2, 1
44 static void scroll_thread(void);
45 static char scroll_stack[DEFAULT_STACK_SIZE*3];
46 static const char scroll_name[] = "scroll";
48 static struct scrollinfo lcd_scroll[LCD_SCROLLABLE_LINES];
50 #ifdef HAVE_REMOTE_LCD
51 static struct scrollinfo lcd_remote_scroll[LCD_REMOTE_SCROLLABLE_LINES];
52 static struct event_queue scroll_queue SHAREDBSS_ATTR;
53 #endif
55 struct scroll_screen_info lcd_scroll_info =
57 .scroll = lcd_scroll,
58 .lines = 0,
59 .ticks = 12,
60 .delay = HZ/2,
61 .bidir_limit = 50,
62 #ifdef HAVE_LCD_BITMAP
63 .step = 6,
64 #endif
65 #ifdef HAVE_LCD_CHARCELLS
66 .jump_scroll_delay = HZ/4,
67 .jump_scroll = 0,
68 #endif
71 #ifdef HAVE_REMOTE_LCD
72 struct scroll_screen_info lcd_remote_scroll_info =
74 .scroll = lcd_remote_scroll,
75 .lines = 0,
76 .ticks = 12,
77 .delay = HZ/2,
78 .bidir_limit = 50,
79 .step = 6,
81 #endif /* HAVE_REMOTE_LCD */
83 void lcd_stop_scroll(void)
85 lcd_scroll_info.lines = 0;
88 /* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
89 void lcd_scroll_stop_line(const struct viewport* current_vp, int y)
91 int i = 0;
93 while (i < lcd_scroll_info.lines)
95 if ((lcd_scroll_info.scroll[i].vp == current_vp) &&
96 ((y < 0) || (lcd_scroll_info.scroll[i].y == y)))
98 /* If i is not the last active line in the array, then move
99 the last item to position i */
100 if ((i + 1) != lcd_scroll_info.lines)
102 lcd_scroll_info.scroll[i] =
103 lcd_scroll_info.scroll[lcd_scroll_info.lines-1];
105 lcd_scroll_info.lines--;
107 /* A line can only appear once, so we're done,
108 * unless we are clearing the whole viewport */
109 if (y >= 0)
110 return ;
112 else
114 i++;
119 /* Stop all scrolling lines in the specified viewport */
120 void lcd_scroll_stop(const struct viewport* vp)
122 lcd_scroll_stop_line(vp, -1);
125 void lcd_scroll_speed(int speed)
127 lcd_scroll_info.ticks = scroll_tick_table[speed];
130 #if defined(HAVE_LCD_BITMAP)
131 void lcd_scroll_step(int step)
133 lcd_scroll_info.step = step;
135 #endif
137 void lcd_scroll_delay(int ms)
139 lcd_scroll_info.delay = ms / (HZ / 10);
142 void lcd_bidir_scroll(int percent)
144 lcd_scroll_info.bidir_limit = percent;
147 #ifdef HAVE_LCD_CHARCELLS
148 void lcd_jump_scroll(int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
150 lcd_scroll_info.jump_scroll = mode;
153 void lcd_jump_scroll_delay(int ms)
155 lcd_scroll_info.jump_scroll_delay = ms / (HZ / 10);
157 #endif
159 #ifdef HAVE_REMOTE_LCD
160 void lcd_remote_stop_scroll(void)
162 lcd_remote_scroll_info.lines = 0;
165 /* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
166 void lcd_remote_scroll_stop_line(const struct viewport* current_vp, int y)
168 int i = 0;
170 while (i < lcd_remote_scroll_info.lines)
172 if ((lcd_remote_scroll_info.scroll[i].vp == current_vp) &&
173 ((y < 0) || (lcd_remote_scroll_info.scroll[i].y == y)))
175 /* If i is not the last active line in the array, then move
176 the last item to position i */
177 if ((i + 1) != lcd_remote_scroll_info.lines)
179 lcd_remote_scroll_info.scroll[i] =
180 lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines-1];
182 lcd_remote_scroll_info.lines--;
184 /* A line can only appear once, so we're done,
185 * unless we are clearing the whole viewport */
186 if (y >= 0)
187 return ;
189 else
191 i++;
196 /* Stop all scrolling lines in the specified viewport */
197 void lcd_remote_scroll_stop(const struct viewport* vp)
199 lcd_remote_scroll_stop_line(vp, -1);
202 void lcd_remote_scroll_speed(int speed)
204 lcd_remote_scroll_info.ticks = scroll_tick_table[speed];
207 void lcd_remote_scroll_step(int step)
209 lcd_remote_scroll_info.step = step;
212 void lcd_remote_scroll_delay(int ms)
214 lcd_remote_scroll_info.delay = ms / (HZ / 10);
217 void lcd_remote_bidir_scroll(int percent)
219 lcd_remote_scroll_info.bidir_limit = percent;
222 static void sync_display_ticks(void)
224 lcd_scroll_info.last_scroll =
225 lcd_remote_scroll_info.last_scroll = current_tick;
228 static bool scroll_process_message(int delay)
230 struct queue_event ev;
234 long tick = current_tick;
235 queue_wait_w_tmo(&scroll_queue, &ev, delay);
237 switch (ev.id)
239 case SYS_TIMEOUT:
240 return false;
241 case SYS_USB_CONNECTED:
242 usb_acknowledge(SYS_USB_CONNECTED_ACK);
243 usb_wait_for_disconnect(&scroll_queue);
244 sync_display_ticks();
245 return true;
246 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
247 case SYS_REMOTE_PLUGGED:
248 if (!remote_initialized)
249 sync_display_ticks();
250 #endif
253 delay -= current_tick - tick;
255 while (delay > 0);
257 return false;
259 #endif /* HAVE_REMOTE_LCD */
261 static void scroll_thread(void) NORETURN_ATTR;
262 #ifdef HAVE_REMOTE_LCD
264 static void scroll_thread(void)
266 enum
268 SCROLL_LCD = 0x1,
269 SCROLL_LCD_REMOTE = 0x2,
272 sync_display_ticks();
274 while ( 1 )
276 long delay;
277 int scroll;
278 long tick_lcd, tick_remote;
280 tick_lcd = lcd_scroll_info.last_scroll + lcd_scroll_info.ticks;
281 delay = current_tick;
283 if (
284 #if (CONFIG_PLATFORM & PLATFORM_NATIVE)
285 !remote_initialized ||
286 #endif
287 (tick_remote = lcd_remote_scroll_info.last_scroll +
288 lcd_remote_scroll_info.ticks,
289 TIME_BEFORE(tick_lcd, tick_remote)))
291 scroll = SCROLL_LCD;
292 delay = tick_lcd - delay;
294 /* TIME_BEFORE(tick_remote, tick_lcd) */
295 else if (tick_lcd != tick_remote)
297 scroll = SCROLL_LCD_REMOTE;
298 delay = tick_remote - delay;
300 else
302 scroll = SCROLL_LCD | SCROLL_LCD_REMOTE;
303 delay = tick_lcd - delay;
306 if (scroll_process_message(delay))
307 continue;
309 if (scroll & SCROLL_LCD)
311 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
312 if (lcd_active())
313 #endif
314 lcd_scroll_fn();
315 lcd_scroll_info.last_scroll = current_tick;
318 if (scroll == (SCROLL_LCD | SCROLL_LCD_REMOTE))
319 yield();
321 if (scroll & SCROLL_LCD_REMOTE)
323 lcd_remote_scroll_fn();
324 lcd_remote_scroll_info.last_scroll = current_tick;
328 #else
329 static void scroll_thread(void)
331 while (1)
333 sleep(lcd_scroll_info.ticks);
334 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
335 if (lcd_active())
336 #endif
337 lcd_scroll_fn();
340 #endif /* HAVE_REMOTE_LCD */
342 void scroll_init(void)
344 #ifdef HAVE_REMOTE_LCD
345 queue_init(&scroll_queue, true);
346 #endif
347 create_thread(scroll_thread, scroll_stack,
348 sizeof(scroll_stack), 0, scroll_name
349 IF_PRIO(, PRIORITY_USER_INTERFACE)
350 IF_COP(, CPU));