1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Jens Arnold
12 * Rockbox driver for 2bit vertically interleaved remote LCDs
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
24 #include "lcd-remote.h"
34 #include "rbunicode.h"
36 #include "lcd-remote-target.h"
38 #define SCROLLABLE_LINES (((LCD_REMOTE_HEIGHT+4)/5 < 32) ? (LCD_REMOTE_HEIGHT+4)/5 : 32)
42 fb_remote_data lcd_remote_framebuffer
[LCD_REMOTE_FBHEIGHT
][LCD_REMOTE_FBWIDTH
]
45 static const fb_remote_data patterns
[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
47 static fb_remote_data
* remote_backdrop
= NULL
;
48 static long remote_backdrop_offset IDATA_ATTR
= 0;
50 static unsigned fg_pattern IDATA_ATTR
= 0xFFFF; /* initially black */
51 static unsigned bg_pattern IDATA_ATTR
= 0x0000; /* initially white */
52 static int drawmode
= DRMODE_SOLID
;
53 static int xmargin
= 0;
54 static int ymargin
= 0;
55 static int curfont
= FONT_SYSFIXED
;
58 static volatile int scrolling_lines
=0; /* Bitpattern of which lines are scrolling */
59 static void scroll_thread(void);
60 static long scroll_stack
[DEFAULT_STACK_SIZE
/sizeof(long)];
61 static const char scroll_name
[] = "remote_scroll";
62 static int scroll_ticks
= 12; /* # of ticks between updates*/
63 static int scroll_delay
= HZ
/2; /* ticks delay before start */
64 static int scroll_step
= 6; /* pixels per scroll step */
65 static int bidir_limit
= 50; /* percent */
66 static struct scrollinfo scroll
[SCROLLABLE_LINES
];
68 static const char scroll_tick_table
[16] = {
70 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */
71 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3
76 struct event_queue remote_scroll_queue
;
79 /*** parameter handling ***/
80 unsigned lcd_remote_color_to_native(unsigned color
)
82 unsigned r
= (color
& 0xf800) >> 10;
83 unsigned g
= (color
& 0x07e0) >> 5;
84 unsigned b
= (color
& 0x001f) << 2;
87 * |Y'| = |0.299000 0.587000 0.114000| |G|
90 return (5*r
+ 9*g
+ b
) >> 8;
93 void lcd_remote_set_drawmode(int mode
)
95 drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
98 int lcd_remote_get_drawmode(void)
103 void lcd_remote_set_foreground(unsigned brightness
)
105 fg_pattern
= patterns
[brightness
& 3];
108 unsigned lcd_remote_get_foreground(void)
110 return (~fg_pattern
>> 7) & 3;
113 void lcd_remote_set_background(unsigned brightness
)
115 bg_pattern
= patterns
[brightness
& 3];
118 unsigned lcd_remote_get_background(void)
120 return (~bg_pattern
>> 7) & 3;
123 void lcd_remote_set_drawinfo(int mode
, unsigned fg_brightness
,
124 unsigned bg_brightness
)
126 lcd_remote_set_drawmode(mode
);
127 lcd_remote_set_foreground(fg_brightness
);
128 lcd_remote_set_background(bg_brightness
);
131 void lcd_remote_setmargins(int x
, int y
)
137 int lcd_remote_getxmargin(void)
142 int lcd_remote_getymargin(void)
147 void lcd_remote_setfont(int newfont
)
152 int lcd_remote_getstringsize(const unsigned char *str
, int *w
, int *h
)
154 return font_getstringsize(str
, w
, h
, curfont
);
157 /*** low-level drawing functions ***/
159 static void setpixel(int x
, int y
)
161 unsigned mask
= 0x0101 << (y
& 7);
162 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
163 unsigned data
= *address
;
165 *address
= data
^ ((data
^ fg_pattern
) & mask
);
168 static void clearpixel(int x
, int y
)
170 unsigned mask
= 0x0101 << (y
& 7);
171 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
172 unsigned data
= *address
;
174 *address
= data
^ ((data
^ bg_pattern
) & mask
);
177 static void clearimgpixel(int x
, int y
)
179 unsigned mask
= 0x0101 << (y
& 7);
180 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
181 unsigned data
= *address
;
183 *address
= data
^ ((data
^ *(fb_remote_data
*)((long)address
184 + remote_backdrop_offset
)) & mask
);
187 static void flippixel(int x
, int y
)
189 unsigned mask
= 0x0101 << (y
& 7);
190 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
195 static void nopixel(int x
, int y
)
201 lcd_remote_pixelfunc_type
* const lcd_remote_pixelfuncs_bgcolor
[8] = {
202 flippixel
, nopixel
, setpixel
, setpixel
,
203 nopixel
, clearpixel
, nopixel
, clearpixel
206 lcd_remote_pixelfunc_type
* const lcd_remote_pixelfuncs_backdrop
[8] = {
207 flippixel
, nopixel
, setpixel
, setpixel
,
208 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
211 lcd_remote_pixelfunc_type
* const *lcd_remote_pixelfuncs
= lcd_remote_pixelfuncs_bgcolor
;
213 /* 'mask' and 'bits' contain 2 bits per pixel */
214 static void flipblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
216 static void flipblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
218 *address
^= bits
& mask
;
221 static void bgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
223 static void bgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
225 unsigned data
= *address
;
227 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
230 static void bgimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
232 static void bgimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
234 unsigned data
= *address
;
236 *address
= data
^ ((data
^ *(fb_remote_data
*)((long)address
237 + remote_backdrop_offset
)) & mask
& ~bits
);
240 static void fgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
242 static void fgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
244 unsigned data
= *address
;
246 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
249 static void solidblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
251 static void solidblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
253 unsigned data
= *address
;
254 unsigned bgp
= bg_pattern
;
256 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
257 *address
= data
^ ((data
^ bits
) & mask
);
260 static void solidimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
262 static void solidimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
264 unsigned data
= *address
;
265 unsigned bgp
= *(fb_remote_data
*)((long)address
+ remote_backdrop_offset
);
267 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
268 *address
= data
^ ((data
^ bits
) & mask
);
271 static void flipinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
273 static void flipinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
275 *address
^= ~bits
& mask
;
278 static void bginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
280 static void bginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
282 unsigned data
= *address
;
284 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
287 static void bgimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
289 static void bgimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
291 unsigned data
= *address
;
293 *address
= data
^ ((data
^ *(fb_remote_data
*)((long)address
294 + remote_backdrop_offset
)) & mask
& bits
);
297 static void fginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
299 static void fginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
301 unsigned data
= *address
;
303 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
306 static void solidinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
308 static void solidinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
310 unsigned data
= *address
;
311 unsigned fgp
= fg_pattern
;
313 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
314 *address
= data
^ ((data
^ bits
) & mask
);
317 static void solidimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
319 static void solidimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
321 unsigned data
= *address
;
322 unsigned fgp
= fg_pattern
;
324 bits
= fgp
^ ((fgp
^ *(fb_remote_data
*)((long)address
325 + remote_backdrop_offset
)) & bits
);
326 *address
= data
^ ((data
^ bits
) & mask
);
329 lcd_remote_blockfunc_type
* const lcd_remote_blockfuncs_bgcolor
[8] = {
330 flipblock
, bgblock
, fgblock
, solidblock
,
331 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
334 lcd_remote_blockfunc_type
* const lcd_remote_blockfuncs_backdrop
[8] = {
335 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
336 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
339 lcd_remote_blockfunc_type
* const *lcd_remote_blockfuncs
= lcd_remote_blockfuncs_bgcolor
;
342 void lcd_remote_set_backdrop(fb_remote_data
* backdrop
)
344 remote_backdrop
= backdrop
;
347 remote_backdrop_offset
= (long)backdrop
- (long)lcd_remote_framebuffer
;
348 lcd_remote_pixelfuncs
= lcd_remote_pixelfuncs_backdrop
;
349 lcd_remote_blockfuncs
= lcd_remote_blockfuncs_backdrop
;
353 remote_backdrop_offset
= 0;
354 lcd_remote_pixelfuncs
= lcd_remote_pixelfuncs_bgcolor
;
355 lcd_remote_blockfuncs
= lcd_remote_blockfuncs_bgcolor
;
359 fb_remote_data
* lcd_remote_get_backdrop(void)
361 return remote_backdrop
;
364 static inline void setblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
366 unsigned data
= *address
;
369 *address
= data
^ (bits
& mask
);
372 /*** drawing functions ***/
374 /* Clear the whole display */
375 void lcd_remote_clear_display(void)
377 if (drawmode
& DRMODE_INVERSEVID
)
379 memset(lcd_remote_framebuffer
, fg_pattern
,
380 sizeof lcd_remote_framebuffer
);
385 memcpy(lcd_remote_framebuffer
, remote_backdrop
,
386 sizeof lcd_remote_framebuffer
);
388 memset(lcd_remote_framebuffer
, bg_pattern
,
389 sizeof lcd_remote_framebuffer
);
394 /* Set a single pixel */
395 void lcd_remote_drawpixel(int x
, int y
)
397 if (((unsigned)x
< LCD_REMOTE_WIDTH
) && ((unsigned)y
< LCD_REMOTE_HEIGHT
))
398 lcd_remote_pixelfuncs
[drawmode
](x
, y
);
402 void lcd_remote_drawline(int x1
, int y1
, int x2
, int y2
)
410 lcd_remote_pixelfunc_type
*pfunc
= lcd_remote_pixelfuncs
[drawmode
];
412 deltax
= abs(x2
- x1
);
413 deltay
= abs(y2
- y1
);
417 if (deltax
>= deltay
)
420 d
= 2 * deltay
- deltax
;
422 dinc2
= (deltay
- deltax
) * 2;
429 d
= 2 * deltax
- deltay
;
431 dinc2
= (deltax
- deltay
) * 2;
435 numpixels
++; /* include endpoints */
452 for (i
= 0; i
< numpixels
; i
++)
454 if (((unsigned)x
< LCD_REMOTE_WIDTH
) && ((unsigned)y
< LCD_REMOTE_HEIGHT
))
472 /* Draw a horizontal line (optimised) */
473 void lcd_remote_hline(int x1
, int x2
, int y
)
476 fb_remote_data
*dst
, *dst_end
;
478 lcd_remote_blockfunc_type
*bfunc
;
488 /* nothing to draw? */
489 if (((unsigned)y
>= LCD_REMOTE_HEIGHT
) || (x1
>= LCD_REMOTE_WIDTH
)
496 if (x2
>= LCD_REMOTE_WIDTH
)
497 x2
= LCD_REMOTE_WIDTH
-1;
499 bfunc
= lcd_remote_blockfuncs
[drawmode
];
500 dst
= &lcd_remote_framebuffer
[y
>>3][x1
];
501 mask
= 0x0101 << (y
& 7);
503 dst_end
= dst
+ x2
- x1
;
505 bfunc(dst
++, mask
, 0xFFFFu
);
506 while (dst
<= dst_end
);
509 /* Draw a vertical line (optimised) */
510 void lcd_remote_vline(int x
, int y1
, int y2
)
514 unsigned mask
, mask_bottom
;
515 lcd_remote_blockfunc_type
*bfunc
;
525 /* nothing to draw? */
526 if (((unsigned)x
>= LCD_REMOTE_WIDTH
) || (y1
>= LCD_REMOTE_HEIGHT
)
533 if (y2
>= LCD_REMOTE_HEIGHT
)
534 y2
= LCD_REMOTE_HEIGHT
-1;
536 bfunc
= lcd_remote_blockfuncs
[drawmode
];
537 dst
= &lcd_remote_framebuffer
[y1
>>3][x
];
539 mask
= (0xFFu
<< (y1
& 7)) & 0xFFu
;
541 mask_bottom
= 0xFFu
>> (~ny
& 7);
542 mask_bottom
|= mask_bottom
<< 8;
544 for (; ny
>= 8; ny
-= 8)
546 bfunc(dst
, mask
, 0xFFFFu
);
547 dst
+= LCD_REMOTE_WIDTH
;
551 bfunc(dst
, mask
, 0xFFFFu
);
554 /* Draw a rectangular box */
555 void lcd_remote_drawrect(int x
, int y
, int width
, int height
)
557 if ((width
<= 0) || (height
<= 0))
560 int x2
= x
+ width
- 1;
561 int y2
= y
+ height
- 1;
563 lcd_remote_vline(x
, y
, y2
);
564 lcd_remote_vline(x2
, y
, y2
);
565 lcd_remote_hline(x
, x2
, y
);
566 lcd_remote_hline(x
, x2
, y2
);
569 /* Fill a rectangular area */
570 void lcd_remote_fillrect(int x
, int y
, int width
, int height
)
573 fb_remote_data
*dst
, *dst_end
;
574 unsigned mask
, mask_bottom
;
576 lcd_remote_blockfunc_type
*bfunc
;
577 bool fillopt
= false;
579 /* nothing to draw? */
580 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_REMOTE_WIDTH
)
581 || (y
>= LCD_REMOTE_HEIGHT
) || (x
+ width
<= 0) || (y
+ height
<= 0))
595 if (x
+ width
> LCD_REMOTE_WIDTH
)
596 width
= LCD_REMOTE_WIDTH
- x
;
597 if (y
+ height
> LCD_REMOTE_HEIGHT
)
598 height
= LCD_REMOTE_HEIGHT
- y
;
600 if (drawmode
& DRMODE_INVERSEVID
)
602 if ((drawmode
& DRMODE_BG
) && !remote_backdrop
)
610 if (drawmode
& DRMODE_FG
)
616 bfunc
= lcd_remote_blockfuncs
[drawmode
];
617 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
618 ny
= height
- 1 + (y
& 7);
619 mask
= (0xFFu
<< (y
& 7)) & 0xFFu
;
621 mask_bottom
= 0xFFu
>> (~ny
& 7);
622 mask_bottom
|= mask_bottom
<< 8;
624 for (; ny
>= 8; ny
-= 8)
626 if (fillopt
&& (mask
== 0xFFFFu
))
627 memset16(dst
, bits
, width
);
630 fb_remote_data
*dst_row
= dst
;
632 dst_end
= dst_row
+ width
;
634 bfunc(dst_row
++, mask
, 0xFFFFu
);
635 while (dst_row
< dst_end
);
638 dst
+= LCD_REMOTE_WIDTH
;
643 if (fillopt
&& (mask
== 0xFFFFu
))
644 memset16(dst
, bits
, width
);
647 dst_end
= dst
+ width
;
649 bfunc(dst
++, mask
, 0xFFFFu
);
650 while (dst
< dst_end
);
654 /* About Rockbox' internal monochrome bitmap format:
656 * A bitmap contains one bit for every pixel that defines if that pixel is
657 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
659 * The bytes are stored in row-major order, with byte 0 being top left,
660 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
661 * 0..7, the second row defines pixel row 8..15 etc.
663 * This is similar to the internal lcd hw format. */
665 /* Draw a partial monochrome bitmap */
666 void lcd_remote_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
667 int stride
, int x
, int y
, int width
, int height
)
669 void lcd_remote_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
670 int stride
, int x
, int y
, int width
, int height
)
673 fb_remote_data
*dst
, *dst_end
;
674 unsigned data
, mask
, mask_bottom
;
675 lcd_remote_blockfunc_type
*bfunc
;
677 /* nothing to draw? */
678 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_REMOTE_WIDTH
)
679 || (y
>= LCD_REMOTE_HEIGHT
) || (x
+ width
<= 0) || (y
+ height
<= 0))
695 if (x
+ width
> LCD_REMOTE_WIDTH
)
696 width
= LCD_REMOTE_WIDTH
- x
;
697 if (y
+ height
> LCD_REMOTE_HEIGHT
)
698 height
= LCD_REMOTE_HEIGHT
- y
;
700 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
703 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
705 ny
= height
- 1 + shift
+ src_y
;
707 bfunc
= lcd_remote_blockfuncs
[drawmode
];
708 mask
= 0xFFu
<< (shift
+ src_y
);
709 /* not byte-doubled here because shift+src_y can be > 7 */
710 mask_bottom
= 0xFFu
>> (~ny
& 7);
711 mask_bottom
|= mask_bottom
<< 8;
718 for (; ny
>= 8; ny
-= 8)
720 const unsigned char *src_row
= src
;
721 fb_remote_data
*dst_row
= dst
;
723 dst_end
= dst_row
+ width
;
727 bfunc(dst_row
++, mask
, data
| (data
<< 8));
729 while (dst_row
< dst_end
);
732 dst
+= LCD_REMOTE_WIDTH
;
737 dst_end
= dst
+ width
;
741 bfunc(dst
++, mask
, data
| (data
<< 8));
743 while (dst
< dst_end
);
749 dst_end
= dst
+ width
;
752 const unsigned char *src_col
= src
++;
753 fb_remote_data
*dst_col
= dst
++;
754 unsigned mask_col
= mask
& 0xFFu
;
756 mask_col
|= mask_col
<< 8;
759 for (y
= ny
; y
>= 8; y
-= 8)
761 data
|= *src_col
<< shift
;
765 ddata
= data
& 0xFFu
;
766 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
771 mask_col
= (mask
>> 8) & 0xFFu
;
772 mask_col
|= mask_col
<< 8;
776 dst_col
+= LCD_REMOTE_WIDTH
;
779 data
|= *src_col
<< shift
;
780 mask_col
&= mask_bottom
;
781 ddata
= data
& 0xFFu
;
782 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
784 while (dst
< dst_end
);
788 /* Draw a full monochrome bitmap */
789 void lcd_remote_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
,
792 lcd_remote_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
795 /* About Rockbox' internal native bitmap format:
797 * A bitmap contains one bit in each byte of a pair of bytes for every pixel.
798 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte
799 * are arranged vertically, LSB at top.
800 * The pairs of bytes are stored as shorts, in row-major order, with word 0
801 * being top left, word 1 2nd from left etc. The first row of words defines
802 * pixel rows 0..7, the second row defines pixel row 8..15 etc.
804 * This is the same as the internal lcd hw format. */
806 /* Draw a partial native bitmap */
807 void lcd_remote_bitmap_part(const fb_remote_data
*src
, int src_x
, int src_y
,
808 int stride
, int x
, int y
, int width
, int height
)
810 void lcd_remote_bitmap_part(const fb_remote_data
*src
, int src_x
, int src_y
,
811 int stride
, int x
, int y
, int width
, int height
)
814 fb_remote_data
*dst
, *dst_end
;
815 unsigned mask
, mask_bottom
;
817 /* nothing to draw? */
818 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_REMOTE_WIDTH
)
819 || (y
>= LCD_REMOTE_HEIGHT
) || (x
+ width
<= 0) || (y
+ height
<= 0))
835 if (x
+ width
> LCD_REMOTE_WIDTH
)
836 width
= LCD_REMOTE_WIDTH
- x
;
837 if (y
+ height
> LCD_REMOTE_HEIGHT
)
838 height
= LCD_REMOTE_HEIGHT
- y
;
840 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
843 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
845 ny
= height
- 1 + shift
+ src_y
;
847 mask
= 0xFFu
<< (shift
+ src_y
);
848 /* not byte-doubled here because shift+src_y can be > 7 */
849 mask_bottom
= 0xFFu
>> (~ny
& 7);
850 mask_bottom
|= mask_bottom
<< 8;
857 for (; ny
>= 8; ny
-= 8)
860 memcpy(dst
, src
, width
* sizeof(fb_remote_data
));
863 const fb_remote_data
*src_row
= src
;
864 fb_remote_data
*dst_row
= dst
;
866 dst_end
= dst_row
+ width
;
868 setblock(dst_row
++, mask
, *src_row
++);
869 while (dst_row
< dst_end
);
872 dst
+= LCD_REMOTE_WIDTH
;
878 memcpy(dst
, src
, width
* sizeof(fb_remote_data
));
881 dst_end
= dst
+ width
;
883 setblock(dst
++, mask
, *src
++);
884 while (dst
< dst_end
);
889 unsigned datamask
= (0xFFu
<< shift
) & 0xFFu
;
891 datamask
|= datamask
<< 8;
893 dst_end
= dst
+ width
;
896 const fb_remote_data
*src_col
= src
++;
897 fb_remote_data
*dst_col
= dst
++;
898 unsigned mask_col
= mask
& 0xFFu
;
899 unsigned data
, olddata
= 0;
901 mask_col
|= mask_col
<< 8;
903 for (y
= ny
; y
>= 8; y
-= 8)
905 data
= *src_col
<< shift
;
909 setblock(dst_col
, mask_col
,
910 olddata
^((olddata
^ data
) & datamask
));
915 mask_col
= (mask
<< 8) & 0xFFu
;
916 mask_col
|= mask_col
<< 8;
919 dst_col
+= LCD_REMOTE_WIDTH
;
922 data
= *src_col
<< shift
;
923 setblock(dst_col
, mask_col
& mask_bottom
,
924 olddata
^((olddata
^ data
) & datamask
));
926 while (dst
< dst_end
);
930 /* Draw a full native bitmap */
931 void lcd_remote_bitmap(const fb_remote_data
*src
, int x
, int y
, int width
,
934 lcd_remote_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
937 /* put a string at a given pixel position, skipping first ofs pixel columns */
938 static void lcd_remote_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
942 struct font
* pf
= font_get(curfont
);
944 ucs
= bidi_l2v(str
, 1);
946 while ((ch
= *ucs
++) != 0 && x
< LCD_REMOTE_WIDTH
)
949 const unsigned char *bits
;
951 /* get proportional width and glyph bits */
952 width
= font_get_width(pf
, ch
);
960 bits
= font_get_bits(pf
, ch
);
962 lcd_remote_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
970 /* put a string at a given pixel position */
971 void lcd_remote_putsxy(int x
, int y
, const unsigned char *str
)
973 lcd_remote_putsxyofs(x
, y
, 0, str
);
976 /*** line oriented text output ***/
978 /* put a string at a given char position */
979 void lcd_remote_puts(int x
, int y
, const unsigned char *str
)
981 lcd_remote_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
984 void lcd_remote_puts_style(int x
, int y
, const unsigned char *str
, int style
)
986 lcd_remote_puts_style_offset(x
, y
, str
, style
, 0);
989 void lcd_remote_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
991 lcd_remote_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
994 /* put a string at a given char position, style, and pixel position,
995 * skipping first offset pixel columns */
996 void lcd_remote_puts_style_offset(int x
, int y
, const unsigned char *str
,
997 int style
, int offset
)
999 int xpos
,ypos
,w
,h
,xrect
;
1000 int lastmode
= drawmode
;
1002 /* make sure scrolling is turned off on the line we are updating */
1003 scrolling_lines
&= ~(1 << y
);
1008 lcd_remote_getstringsize(str
, &w
, &h
);
1009 xpos
= xmargin
+ x
*w
/ utf8length((char *)str
);
1010 ypos
= ymargin
+ y
*h
;
1011 drawmode
= (style
& STYLE_INVERT
) ?
1012 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1013 lcd_remote_putsxyofs(xpos
, ypos
, offset
, str
);
1014 drawmode
^= DRMODE_INVERSEVID
;
1015 xrect
= xpos
+ MAX(w
- offset
, 0);
1016 lcd_remote_fillrect(xrect
, ypos
, LCD_REMOTE_WIDTH
- xrect
, h
);
1017 drawmode
= lastmode
;
1022 /* Reverse the invert setting of the scrolling line (if any) at given char
1023 position. Setting will go into affect next time line scrolls. */
1024 void lcd_remote_invertscroll(int x
, int y
)
1026 struct scrollinfo
* s
;
1030 if(y
>=SCROLLABLE_LINES
) return;
1033 s
->invert
= !s
->invert
;
1036 void lcd_remote_stop_scroll(void)
1041 void lcd_remote_scroll_speed(int speed
)
1043 scroll_ticks
= scroll_tick_table
[speed
];
1046 void lcd_remote_scroll_step(int step
)
1051 void lcd_remote_scroll_delay(int ms
)
1053 scroll_delay
= ms
/ (HZ
/ 10);
1056 void lcd_remote_bidir_scroll(int percent
)
1058 bidir_limit
= percent
;
1061 void lcd_remote_puts_scroll(int x
, int y
, const unsigned char *string
)
1063 lcd_remote_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
1066 void lcd_remote_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
1068 lcd_remote_puts_scroll_style_offset(x
, y
, string
, style
, 0);
1071 void lcd_remote_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
1073 lcd_remote_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
1076 void lcd_remote_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
1077 int style
, int offset
)
1079 struct scrollinfo
* s
;
1082 if(y
>=SCROLLABLE_LINES
) return;
1086 s
->start_tick
= current_tick
+ scroll_delay
;
1088 if (style
& STYLE_INVERT
) {
1090 lcd_remote_puts_style_offset(x
,y
,string
,STYLE_INVERT
,offset
);
1093 lcd_remote_puts_offset(x
,y
,string
,offset
);
1095 lcd_remote_getstringsize(string
, &w
, &h
);
1097 if (LCD_REMOTE_WIDTH
- x
* 8 - xmargin
< w
) {
1098 /* prepare scroll line */
1101 memset(s
->line
, 0, sizeof s
->line
);
1102 strcpy(s
->line
, (char *)string
);
1105 s
->width
= lcd_remote_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1107 /* scroll bidirectional or forward only depending on the string
1109 if ( bidir_limit
) {
1110 s
->bidir
= s
->width
< (LCD_REMOTE_WIDTH
- xmargin
) *
1111 (100 + bidir_limit
) / 100;
1116 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1117 strcat(s
->line
, " ");
1118 /* get new width incl. spaces */
1119 s
->width
= lcd_remote_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1122 end
= strchr(s
->line
, '\0');
1123 strncpy(end
, (char *)string
, LCD_REMOTE_WIDTH
/2);
1125 s
->len
= utf8length((char *)string
);
1127 s
->startx
= xmargin
+ x
* s
->width
/ s
->len
;;
1128 s
->backward
= false;
1129 scrolling_lines
|= (1<<y
);
1132 /* force a bit switch-off since it doesn't scroll */
1133 scrolling_lines
&= ~(1<<y
);
1136 static void scroll_thread(void)
1139 struct scrollinfo
* s
;
1144 long next_tick
= current_tick
;
1149 /* initialize scroll struct array */
1150 scrolling_lines
= 0;
1157 if (remote_initialized
)
1158 queue_wait_w_tmo(&remote_scroll_queue
, &ev
, delay
);
1160 queue_wait(&remote_scroll_queue
, &ev
);
1164 case REMOTE_INIT_LCD
:
1166 lcd_remote_update();
1169 case REMOTE_DEINIT_LCD
:
1174 delay
= next_tick
- current_tick
- 1;
1179 for ( index
= 0; index
< SCROLLABLE_LINES
; index
++ ) {
1180 /* really scroll? */
1181 if ( !(scrolling_lines
&(1<<index
)) )
1187 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1191 s
->offset
-= scroll_step
;
1193 s
->offset
+= scroll_step
;
1195 pf
= font_get(curfont
);
1197 ypos
= ymargin
+ index
* pf
->height
;
1199 if (s
->bidir
) { /* scroll bidirectional */
1200 if (s
->offset
<= 0) {
1201 /* at beginning of line */
1203 s
->backward
= false;
1204 s
->start_tick
= current_tick
+ scroll_delay
* 2;
1206 if (s
->offset
>= s
->width
- (LCD_REMOTE_WIDTH
- xpos
)) {
1207 /* at end of line */
1208 s
->offset
= s
->width
- (LCD_REMOTE_WIDTH
- xpos
);
1210 s
->start_tick
= current_tick
+ scroll_delay
* 2;
1214 /* scroll forward the whole time */
1215 if (s
->offset
>= s
->width
)
1216 s
->offset
%= s
->width
;
1219 lastmode
= drawmode
;
1220 drawmode
= s
->invert
?
1221 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1222 lcd_remote_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
1223 drawmode
= lastmode
;
1224 lcd_remote_update_rect(xpos
, ypos
, LCD_REMOTE_WIDTH
- xpos
, pf
->height
);
1228 next_tick
+= scroll_ticks
;
1229 delay
= next_tick
- current_tick
- 1;
1232 next_tick
= current_tick
+ 1;
1239 void lcd_remote_init(void)
1242 /* Call device specific init */
1243 lcd_remote_init_device();
1245 queue_init(&remote_scroll_queue
, false);
1247 create_thread(scroll_thread
, scroll_stack
,
1248 sizeof(scroll_stack
), scroll_name
IF_PRIO(, PRIORITY_USER_INTERFACE
)
1249 IF_COP(, CPU
, false));