move handling of shared manuals (like h100 series) to a new setting in rbutil.ini...
[Rockbox.git] / firmware / drivers / lcd-remote-1bit-v.c
blob6b5b1fb42f00351ce245abe14cbfff7dc47ca9ad
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Richard S. La Charité III
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "config.h"
21 #include "cpu.h"
22 #include "lcd.h"
23 #include "lcd-remote.h"
24 #include "kernel.h"
25 #include "thread.h"
26 #include <string.h>
27 #include <stdlib.h>
28 #include "file.h"
29 #include "debug.h"
30 #include "system.h"
31 #include "font.h"
32 #include "rbunicode.h"
33 #include "bidi.h"
35 #define SCROLLABLE_LINES (((LCD_REMOTE_HEIGHT+4)/5 < 32) ? (LCD_REMOTE_HEIGHT+4)/5 : 32)
37 /*** globals ***/
39 fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH]
40 IBSS_ATTR;
42 static int drawmode = DRMODE_SOLID;
43 static int xmargin = 0;
44 static int ymargin = 0;
45 static int curfont = FONT_SYSFIXED;
47 /* scrolling */
48 static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */
49 static void scroll_thread(void);
50 static long scroll_stack[DEFAULT_STACK_SIZE/sizeof(long)];
51 static const char scroll_name[] = "remote_scroll";
52 static int scroll_ticks = 12; /* # of ticks between updates*/
53 static int scroll_delay = HZ/2; /* ticks delay before start */
54 static int scroll_step = 6; /* pixels per scroll step */
55 static int bidir_limit = 50; /* percent */
56 static struct scrollinfo scroll[SCROLLABLE_LINES];
58 static const char scroll_tick_table[16] = {
59 /* Hz values:
60 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */
61 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3
64 /* remote hotplug */
65 #ifndef SIMULATOR
66 struct event_queue remote_scroll_queue;
67 #endif
69 /*** parameter handling ***/
71 void lcd_remote_set_drawmode(int mode)
73 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
76 int lcd_remote_get_drawmode(void)
78 return drawmode;
81 void lcd_remote_setmargins(int x, int y)
83 xmargin = x;
84 ymargin = y;
87 int lcd_remote_getxmargin(void)
89 return xmargin;
92 int lcd_remote_getymargin(void)
94 return ymargin;
98 void lcd_remote_setfont(int newfont)
100 curfont = newfont;
103 int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h)
105 return font_getstringsize(str, w, h, curfont);
108 /*** low-level drawing functions ***/
110 static void setpixel(int x, int y)
112 lcd_remote_framebuffer[y>>3][x] |= 1 << (y & 7);
115 static void clearpixel(int x, int y)
117 lcd_remote_framebuffer[y>>3][x] &= ~(1 << (y & 7));
120 static void flippixel(int x, int y)
122 lcd_remote_framebuffer[y>>3][x] ^= 1 << (y & 7);
125 static void nopixel(int x, int y)
127 (void)x;
128 (void)y;
131 lcd_remote_pixelfunc_type* const lcd_remote_pixelfuncs[8] = {
132 flippixel, nopixel, setpixel, setpixel,
133 nopixel, clearpixel, nopixel, clearpixel
136 static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits)
137 ICODE_ATTR;
138 static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits)
140 *address ^= bits & mask;
143 static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits)
144 ICODE_ATTR;
145 static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits)
147 *address &= bits | ~mask;
150 static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits)
151 ICODE_ATTR;
152 static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits)
154 *address |= bits & mask;
157 static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits)
158 ICODE_ATTR;
159 static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits)
161 unsigned data = *address;
163 bits ^= data;
164 *address = data ^ (bits & mask);
167 static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
168 ICODE_ATTR;
169 static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
171 *address ^= ~bits & mask;
174 static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
175 ICODE_ATTR;
176 static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
178 *address &= ~(bits & mask);
181 static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
182 ICODE_ATTR;
183 static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
185 *address |= ~bits & mask;
188 static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
189 ICODE_ATTR;
190 static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
192 unsigned data = *address;
194 bits = ~bits ^ data;
195 *address = data ^ (bits & mask);
198 lcd_remote_blockfunc_type* const lcd_remote_blockfuncs[8] = {
199 flipblock, bgblock, fgblock, solidblock,
200 flipinvblock, bginvblock, fginvblock, solidinvblock
203 /*** drawing functions ***/
205 /* Clear the whole display */
206 void lcd_remote_clear_display(void)
208 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
210 memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer);
211 scrolling_lines = 0;
214 /* Set a single pixel */
215 void lcd_remote_drawpixel(int x, int y)
217 if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT))
218 lcd_remote_pixelfuncs[drawmode](x, y);
221 /* Draw a line */
222 void lcd_remote_drawline(int x1, int y1, int x2, int y2)
224 int numpixels;
225 int i;
226 int deltax, deltay;
227 int d, dinc1, dinc2;
228 int x, xinc1, xinc2;
229 int y, yinc1, yinc2;
230 lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode];
232 deltax = abs(x2 - x1);
233 deltay = abs(y2 - y1);
234 xinc2 = 1;
235 yinc2 = 1;
237 if (deltax >= deltay)
239 numpixels = deltax;
240 d = 2 * deltay - deltax;
241 dinc1 = deltay * 2;
242 dinc2 = (deltay - deltax) * 2;
243 xinc1 = 1;
244 yinc1 = 0;
246 else
248 numpixels = deltay;
249 d = 2 * deltax - deltay;
250 dinc1 = deltax * 2;
251 dinc2 = (deltax - deltay) * 2;
252 xinc1 = 0;
253 yinc1 = 1;
255 numpixels++; /* include endpoints */
257 if (x1 > x2)
259 xinc1 = -xinc1;
260 xinc2 = -xinc2;
263 if (y1 > y2)
265 yinc1 = -yinc1;
266 yinc2 = -yinc2;
269 x = x1;
270 y = y1;
272 for (i = 0; i < numpixels; i++)
274 if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT))
275 pfunc(x, y);
277 if (d < 0)
279 d += dinc1;
280 x += xinc1;
281 y += yinc1;
283 else
285 d += dinc2;
286 x += xinc2;
287 y += yinc2;
292 /* Draw a horizontal line (optimised) */
293 void lcd_remote_hline(int x1, int x2, int y)
295 int x;
296 fb_remote_data *dst, *dst_end;
297 unsigned mask;
298 lcd_remote_blockfunc_type *bfunc;
300 /* direction flip */
301 if (x2 < x1)
303 x = x1;
304 x1 = x2;
305 x2 = x;
308 /* nothing to draw? */
309 if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH)
310 || (x2 < 0))
311 return;
313 /* clipping */
314 if (x1 < 0)
315 x1 = 0;
316 if (x2 >= LCD_REMOTE_WIDTH)
317 x2 = LCD_REMOTE_WIDTH-1;
319 bfunc = lcd_remote_blockfuncs[drawmode];
320 dst = &lcd_remote_framebuffer[y>>3][x1];
321 mask = 1 << (y & 7);
323 dst_end = dst + x2 - x1;
325 bfunc(dst++, mask, 0xFFu);
326 while (dst <= dst_end);
329 /* Draw a vertical line (optimised) */
330 void lcd_remote_vline(int x, int y1, int y2)
332 int ny;
333 fb_remote_data *dst;
334 unsigned mask, mask_bottom;
335 lcd_remote_blockfunc_type *bfunc;
337 /* direction flip */
338 if (y2 < y1)
340 ny = y1;
341 y1 = y2;
342 y2 = ny;
345 /* nothing to draw? */
346 if (((unsigned)x >= LCD_REMOTE_WIDTH) || (y1 >= LCD_REMOTE_HEIGHT)
347 || (y2 < 0))
348 return;
350 /* clipping */
351 if (y1 < 0)
352 y1 = 0;
353 if (y2 >= LCD_REMOTE_HEIGHT)
354 y2 = LCD_REMOTE_HEIGHT-1;
356 bfunc = lcd_remote_blockfuncs[drawmode];
357 dst = &lcd_remote_framebuffer[y1>>3][x];
358 ny = y2 - (y1 & ~7);
359 mask = 0xFFu << (y1 & 7);
360 mask_bottom = 0xFFu >> (~ny & 7);
362 for (; ny >= 8; ny -= 8)
364 bfunc(dst, mask, 0xFFu);
365 dst += LCD_REMOTE_WIDTH;
366 mask = 0xFFu;
368 mask &= mask_bottom;
369 bfunc(dst, mask, 0xFFu);
372 /* Draw a rectangular box */
373 void lcd_remote_drawrect(int x, int y, int width, int height)
375 if ((width <= 0) || (height <= 0))
376 return;
378 int x2 = x + width - 1;
379 int y2 = y + height - 1;
381 lcd_remote_vline(x, y, y2);
382 lcd_remote_vline(x2, y, y2);
383 lcd_remote_hline(x, x2, y);
384 lcd_remote_hline(x, x2, y2);
387 /* Fill a rectangular area */
388 void lcd_remote_fillrect(int x, int y, int width, int height)
390 int ny;
391 fb_remote_data *dst, *dst_end;
392 unsigned mask, mask_bottom;
393 unsigned bits = 0;
394 lcd_remote_blockfunc_type *bfunc;
395 bool fillopt = false;
397 /* nothing to draw? */
398 if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH)
399 || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0))
400 return;
402 /* clipping */
403 if (x < 0)
405 width += x;
406 x = 0;
408 if (y < 0)
410 height += y;
411 y = 0;
413 if (x + width > LCD_REMOTE_WIDTH)
414 width = LCD_REMOTE_WIDTH - x;
415 if (y + height > LCD_REMOTE_HEIGHT)
416 height = LCD_REMOTE_HEIGHT - y;
418 if (drawmode & DRMODE_INVERSEVID)
420 if (drawmode & DRMODE_BG)
422 fillopt = true;
425 else
427 if (drawmode & DRMODE_FG)
429 fillopt = true;
430 bits = 0xFFu;
433 bfunc = lcd_remote_blockfuncs[drawmode];
434 dst = &lcd_remote_framebuffer[y>>3][x];
435 ny = height - 1 + (y & 7);
436 mask = 0xFFu << (y & 7);
437 mask_bottom = 0xFFu >> (~ny & 7);
439 for (; ny >= 8; ny -= 8)
441 if (fillopt && (mask == 0xFFu))
442 memset(dst, bits, width);
443 else
445 fb_remote_data *dst_row = dst;
447 dst_end = dst_row + width;
449 bfunc(dst_row++, mask, 0xFFu);
450 while (dst_row < dst_end);
453 dst += LCD_REMOTE_WIDTH;
454 mask = 0xFFu;
456 mask &= mask_bottom;
458 if (fillopt && (mask == 0xFFu))
459 memset(dst, bits, width);
460 else
462 dst_end = dst + width;
464 bfunc(dst++, mask, 0xFFu);
465 while (dst < dst_end);
469 /* About Rockbox' internal bitmap format:
471 * A bitmap contains one bit for every pixel that defines if that pixel is
472 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
473 * at top.
474 * The bytes are stored in row-major order, with byte 0 being top left,
475 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
476 * 0..7, the second row defines pixel row 8..15 etc.
478 * This is the same as the internal lcd hw format. */
480 /* Draw a partial bitmap */
481 void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
482 int stride, int x, int y, int width, int height)
483 ICODE_ATTR;
484 void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
485 int stride, int x, int y, int width, int height)
487 int shift, ny;
488 fb_remote_data *dst, *dst_end;
489 unsigned mask, mask_bottom;
490 lcd_remote_blockfunc_type *bfunc;
492 /* nothing to draw? */
493 if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH)
494 || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0))
495 return;
497 /* clipping */
498 if (x < 0)
500 width += x;
501 src_x -= x;
502 x = 0;
504 if (y < 0)
506 height += y;
507 src_y -= y;
508 y = 0;
510 if (x + width > LCD_REMOTE_WIDTH)
511 width = LCD_REMOTE_WIDTH - x;
512 if (y + height > LCD_REMOTE_HEIGHT)
513 height = LCD_REMOTE_HEIGHT - y;
515 src += stride * (src_y >> 3) + src_x; /* move starting point */
516 src_y &= 7;
517 y -= src_y;
518 dst = &lcd_remote_framebuffer[y>>3][x];
519 shift = y & 7;
520 ny = height - 1 + shift + src_y;
522 bfunc = lcd_remote_blockfuncs[drawmode];
523 mask = 0xFFu << (shift + src_y);
524 mask_bottom = 0xFFu >> (~ny & 7);
526 if (shift == 0)
528 bool copyopt = (drawmode == DRMODE_SOLID);
530 for (; ny >= 8; ny -= 8)
532 if (copyopt && (mask == 0xFFu))
533 memcpy(dst, src, width);
534 else
536 const unsigned char *src_row = src;
537 fb_remote_data *dst_row = dst;
539 dst_end = dst_row + width;
541 bfunc(dst_row++, mask, *src_row++);
542 while (dst_row < dst_end);
545 src += stride;
546 dst += LCD_REMOTE_WIDTH;
547 mask = 0xFFu;
549 mask &= mask_bottom;
551 if (copyopt && (mask == 0xFFu))
552 memcpy(dst, src, width);
553 else
555 dst_end = dst + width;
557 bfunc(dst++, mask, *src++);
558 while (dst < dst_end);
561 else
563 dst_end = dst + width;
566 const unsigned char *src_col = src++;
567 fb_remote_data *dst_col = dst++;
568 unsigned mask_col = mask;
569 unsigned data = 0;
571 for (y = ny; y >= 8; y -= 8)
573 data |= *src_col << shift;
575 if (mask_col & 0xFFu)
577 bfunc(dst_col, mask_col, data);
578 mask_col = 0xFFu;
580 else
581 mask_col >>= 8;
583 src_col += stride;
584 dst_col += LCD_REMOTE_WIDTH;
585 data >>= 8;
587 data |= *src_col << shift;
588 bfunc(dst_col, mask_col & mask_bottom, data);
590 while (dst < dst_end);
594 /* Draw a full bitmap */
595 void lcd_remote_bitmap(const unsigned char *src, int x, int y, int width,
596 int height)
598 lcd_remote_bitmap_part(src, 0, 0, width, x, y, width, height);
601 /* put a string at a given pixel position, skipping first ofs pixel columns */
602 static void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str)
604 unsigned short ch;
605 unsigned short *ucs;
606 struct font* pf = font_get(curfont);
608 ucs = bidi_l2v(str, 1);
610 while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH)
612 int width;
613 const unsigned char *bits;
615 /* get proportional width and glyph bits */
616 width = font_get_width(pf, ch);
618 if (ofs > width)
620 ofs -= width;
621 continue;
624 bits = font_get_bits(pf, ch);
626 lcd_remote_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
627 pf->height);
629 x += width - ofs;
630 ofs = 0;
634 /* put a string at a given pixel position */
635 void lcd_remote_putsxy(int x, int y, const unsigned char *str)
637 lcd_remote_putsxyofs(x, y, 0, str);
640 /*** line oriented text output ***/
642 /* put a string at a given char position */
643 void lcd_remote_puts(int x, int y, const unsigned char *str)
645 lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
648 void lcd_remote_puts_style(int x, int y, const unsigned char *str, int style)
650 lcd_remote_puts_style_offset(x, y, str, style, 0);
653 void lcd_remote_puts_offset(int x, int y, const unsigned char *str, int offset)
655 lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
658 /* put a string at a given char position, style, and pixel position,
659 * skipping first offset pixel columns */
660 void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str,
661 int style, int offset)
663 int xpos,ypos,w,h,xrect;
664 int lastmode = drawmode;
666 /* make sure scrolling is turned off on the line we are updating */
667 scrolling_lines &= ~(1 << y);
669 if(!str || !str[0])
670 return;
672 lcd_remote_getstringsize(str, &w, &h);
673 xpos = xmargin + x*w / utf8length((char *)str);
674 ypos = ymargin + y*h;
675 drawmode = (style & STYLE_INVERT) ?
676 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
677 lcd_remote_putsxyofs(xpos, ypos, offset, str);
678 drawmode ^= DRMODE_INVERSEVID;
679 xrect = xpos + MAX(w - offset, 0);
680 lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h);
681 drawmode = lastmode;
684 /*** scrolling ***/
686 /* Reverse the invert setting of the scrolling line (if any) at given char
687 position. Setting will go into affect next time line scrolls. */
688 void lcd_remote_invertscroll(int x, int y)
690 struct scrollinfo* s;
692 (void)x;
694 if(y>=SCROLLABLE_LINES) return;
696 s = &scroll[y];
697 s->invert = !s->invert;
700 void lcd_remote_stop_scroll(void)
702 scrolling_lines=0;
705 void lcd_remote_scroll_speed(int speed)
707 scroll_ticks = scroll_tick_table[speed];
710 void lcd_remote_scroll_step(int step)
712 scroll_step = step;
715 void lcd_remote_scroll_delay(int ms)
717 scroll_delay = ms / (HZ / 10);
720 void lcd_remote_bidir_scroll(int percent)
722 bidir_limit = percent;
725 void lcd_remote_puts_scroll(int x, int y, const unsigned char *string)
727 lcd_remote_puts_scroll_style(x, y, string, STYLE_DEFAULT);
730 void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int style)
732 lcd_remote_puts_scroll_style_offset(x, y, string, style, 0);
735 void lcd_remote_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
737 lcd_remote_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
740 void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *string,
741 int style, int offset)
743 struct scrollinfo* s;
744 int w, h;
746 if(y>=SCROLLABLE_LINES) return;
748 s = &scroll[y];
750 s->start_tick = current_tick + scroll_delay;
751 s->invert = false;
752 if (style & STYLE_INVERT) {
753 s->invert = true;
754 lcd_remote_puts_style_offset(x,y,string,STYLE_INVERT,offset);
756 else
757 lcd_remote_puts_offset(x,y,string,offset);
759 lcd_remote_getstringsize(string, &w, &h);
761 if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) {
762 /* prepare scroll line */
763 char *end;
765 memset(s->line, 0, sizeof s->line);
766 strcpy(s->line, (char *)string);
768 /* get width */
769 s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h);
771 /* scroll bidirectional or forward only depending on the string
772 width */
773 if ( bidir_limit ) {
774 s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) *
775 (100 + bidir_limit) / 100;
777 else
778 s->bidir = false;
780 if (!s->bidir) { /* add spaces if scrolling in the round */
781 strcat(s->line, " ");
782 /* get new width incl. spaces */
783 s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h);
786 end = strchr(s->line, '\0');
787 strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2);
789 s->len = utf8length((char *)string);
790 s->offset = offset;
791 s->startx = xmargin + x * s->width / s->len;;
792 s->backward = false;
793 scrolling_lines |= (1<<y);
795 else
796 /* force a bit switch-off since it doesn't scroll */
797 scrolling_lines &= ~(1<<y);
800 static void scroll_thread(void)
802 struct font* pf;
803 struct scrollinfo* s;
804 long next_tick = current_tick;
805 long delay = 0;
806 int index;
807 int xpos, ypos;
808 int lastmode;
809 #ifndef SIMULATOR
810 struct event ev;
811 #endif
813 /* initialize scroll struct array */
814 scrolling_lines = 0;
816 while ( 1 ) {
818 #ifdef SIMULATOR
819 sleep(delay);
820 #else
821 if (remote_initialized)
822 queue_wait_w_tmo(&remote_scroll_queue, &ev, delay);
823 else
824 queue_wait(&remote_scroll_queue, &ev);
826 switch (ev.id)
828 case REMOTE_INIT_LCD:
829 lcd_remote_on();
830 lcd_remote_update();
831 break;
833 case REMOTE_DEINIT_LCD:
834 lcd_remote_off();
835 break;
838 delay = next_tick - current_tick - 1;
839 if (delay >= 0)
840 continue;
841 #endif
842 for ( index = 0; index < SCROLLABLE_LINES; index++ ) {
843 /* really scroll? */
844 if ( !(scrolling_lines&(1<<index)) )
845 continue;
847 s = &scroll[index];
849 /* check pause */
850 if (TIME_BEFORE(current_tick, s->start_tick))
851 continue;
853 if (s->backward)
854 s->offset -= scroll_step;
855 else
856 s->offset += scroll_step;
858 pf = font_get(curfont);
859 xpos = s->startx;
860 ypos = ymargin + index * pf->height;
862 if (s->bidir) { /* scroll bidirectional */
863 if (s->offset <= 0) {
864 /* at beginning of line */
865 s->offset = 0;
866 s->backward = false;
867 s->start_tick = current_tick + scroll_delay * 2;
869 if (s->offset >= s->width - (LCD_REMOTE_WIDTH - xpos)) {
870 /* at end of line */
871 s->offset = s->width - (LCD_REMOTE_WIDTH - xpos);
872 s->backward = true;
873 s->start_tick = current_tick + scroll_delay * 2;
876 else {
877 /* scroll forward the whole time */
878 if (s->offset >= s->width)
879 s->offset %= s->width;
882 lastmode = drawmode;
883 drawmode = s->invert ?
884 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
885 lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line);
886 drawmode = lastmode;
887 lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height);
890 next_tick += scroll_ticks;
891 delay = next_tick - current_tick - 1;
892 if (delay < 0)
894 next_tick = current_tick + 1;
895 delay = 0;
900 /* LCD init */
901 void lcd_remote_init(void)
903 #ifndef SIMULATOR
904 /* Call device specific init */
905 lcd_remote_init_device();
906 /* private queue */
907 queue_init(&remote_scroll_queue, false);
908 #endif
909 create_thread(scroll_thread, scroll_stack,
910 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
911 IF_COP(, CPU, false));