1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
23 #include "lcd-remote.h"
32 #include "rbunicode.h"
37 #define LCD_REMOTE_CNTL_ADC_NORMAL 0xa0
38 #define LCD_REMOTE_CNTL_ADC_REVERSE 0xa1
39 #define LCD_REMOTE_CNTL_SHL_NORMAL 0xc0
40 #define LCD_REMOTE_CNTL_SHL_REVERSE 0xc8
41 #define LCD_REMOTE_CNTL_DISPLAY_ON_OFF 0xae
42 #define LCD_REMOTE_CNTL_ENTIRE_ON_OFF 0xa4
43 #define LCD_REMOTE_CNTL_REVERSE_ON_OFF 0xa6
44 #define LCD_REMOTE_CNTL_NOP 0xe3
45 #define LCD_REMOTE_CNTL_POWER_CONTROL 0x2b
46 #define LCD_REMOTE_CNTL_SELECT_REGULATOR 0x20
47 #define LCD_REMOTE_CNTL_SELECT_BIAS 0xa2
48 #define LCD_REMOTE_CNTL_SELECT_VOLTAGE 0x81
49 #define LCD_REMOTE_CNTL_INIT_LINE 0x40
50 #define LCD_REMOTE_CNTL_SET_PAGE_ADDRESS 0xB0
52 #define LCD_REMOTE_CNTL_HIGHCOL 0x10 /* Upper column address */
53 #define LCD_REMOTE_CNTL_LOWCOL 0x00 /* Lower column address */
55 #define CS_LO and_l(~0x00000004, &GPIO1_OUT)
56 #define CS_HI or_l(0x00000004, &GPIO1_OUT)
57 #define CLK_LO and_l(~0x10000000, &GPIO_OUT)
58 #define CLK_HI or_l(0x10000000, &GPIO_OUT)
59 #define DATA_LO and_l(~0x00040000, &GPIO1_OUT)
60 #define DATA_HI or_l(0x00040000, &GPIO1_OUT)
61 #define RS_LO and_l(~0x00010000, &GPIO_OUT)
62 #define RS_HI or_l(0x00010000, &GPIO_OUT)
64 #define SCROLLABLE_LINES 13
68 fb_remote_data lcd_remote_framebuffer
[LCD_REMOTE_HEIGHT
/8][LCD_REMOTE_WIDTH
]
71 static int drawmode
= DRMODE_SOLID
;
72 static int xmargin
= 0;
73 static int ymargin
= 0;
74 static int curfont
= FONT_SYSFIXED
;
77 static int xoffset
; /* needed for flip */
79 /* timeout counter for deasserting /CS after access, <0 means not counting */
80 static int cs_countdown IDATA_ATTR
= 0;
81 #define CS_TIMEOUT (HZ/10)
83 #ifdef HAVE_REMOTE_LCD_TICKING
84 /* If set to true, will prevent "ticking" to headphones. */
85 static bool emireduce
= false;
86 static int byte_delay
= 0;
90 static struct event_queue remote_scroll_queue
;
91 #define REMOTE_INIT_LCD 1
92 #define REMOTE_DEINIT_LCD 2
94 static bool remote_initialized
= false;
95 static int _remote_type
= REMOTETYPE_UNPLUGGED
;
97 /* cached settings values */
98 static bool cached_invert
= false;
99 static bool cached_flip
= false;
100 static int cached_contrast
= DEFAULT_REMOTE_CONTRAST_SETTING
;
104 static volatile int scrolling_lines
=0; /* Bitpattern of which lines are scrolling */
105 static void scroll_thread(void);
106 static long scroll_stack
[DEFAULT_STACK_SIZE
/sizeof(long)];
107 static const char scroll_name
[] = "remote_scroll";
108 static int scroll_ticks
= 12; /* # of ticks between updates*/
109 static int scroll_delay
= HZ
/2; /* ticks delay before start */
110 static int scroll_step
= 6; /* pixels per scroll step */
111 static int bidir_limit
= 50; /* percent */
112 static struct scrollinfo scroll
[SCROLLABLE_LINES
];
114 static const char scroll_tick_table
[16] = {
116 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */
117 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3
120 /*** driver routines ***/
124 #ifdef HAVE_REMOTE_LCD_TICKING
125 static inline void _byte_delay(int delay
)
128 "move.l %[dly], %%d0 \n"
141 #endif /* HAVE_REMOTE_LCD_TICKING */
143 /* Standard low-level byte writer. Requires CLK low on entry */
144 static inline void _write_byte(unsigned data
)
147 "move.l (%[gpo1]), %%d0 \n" /* Get current state of data line */
148 "and.l %[dbit], %%d0 \n"
149 "beq.s 1f \n" /* and set it as previous-state bit */
150 "bset #8, %[data] \n"
152 "move.l %[data], %%d0 \n" /* Compute the 'bit derivative', i.e. a value */
153 "lsr.l #1, %%d0 \n" /* with 1's where the data changes from the */
154 "eor.l %%d0, %[data] \n" /* previous state, and 0's where it doesn't */
155 "swap %[data] \n" /* Shift data to upper byte */
156 "lsl.l #8, %[data] \n"
158 "lsl.l #1,%[data] \n" /* Shift out MSB */
160 "eor.l %[dbit], (%[gpo1]) \n" /* 1: flip DATA */
162 "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK */
163 "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK */
165 "lsl.l #1,%[data] \n" /* ..unrolled.. */
167 "eor.l %[dbit], (%[gpo1]) \n"
169 "eor.l %[cbit], (%[gpo0]) \n"
170 "eor.l %[cbit], (%[gpo0]) \n"
172 "lsl.l #1,%[data] \n"
174 "eor.l %[dbit], (%[gpo1]) \n"
176 "eor.l %[cbit], (%[gpo0]) \n"
177 "eor.l %[cbit], (%[gpo0]) \n"
179 "lsl.l #1,%[data] \n"
181 "eor.l %[dbit], (%[gpo1]) \n"
183 "eor.l %[cbit], (%[gpo0]) \n"
184 "eor.l %[cbit], (%[gpo0]) \n"
186 "lsl.l #1,%[data] \n"
188 "eor.l %[dbit], (%[gpo1]) \n"
190 "eor.l %[cbit], (%[gpo0]) \n"
191 "eor.l %[cbit], (%[gpo0]) \n"
193 "lsl.l #1,%[data] \n"
195 "eor.l %[dbit], (%[gpo1]) \n"
197 "eor.l %[cbit], (%[gpo0]) \n"
198 "eor.l %[cbit], (%[gpo0]) \n"
200 "lsl.l #1,%[data] \n"
202 "eor.l %[dbit], (%[gpo1]) \n"
204 "eor.l %[cbit], (%[gpo0]) \n"
205 "eor.l %[cbit], (%[gpo0]) \n"
207 "lsl.l #1,%[data] \n"
209 "eor.l %[dbit], (%[gpo1]) \n"
211 "eor.l %[cbit], (%[gpo0]) \n"
212 "eor.l %[cbit], (%[gpo0]) \n"
216 [gpo0
]"a"(&GPIO_OUT
),
217 [cbit
]"d"(0x10000000),
218 [gpo1
]"a"(&GPIO1_OUT
),
219 [dbit
]"d"(0x00040000)
225 /* Fast low-level byte writer. Don't use with high CPU clock.
226 * Requires CLK low on entry */
227 static inline void _write_fast(unsigned data
)
230 "move.w %%sr,%%d3 \n" /* Get current interrupt level */
231 "move.w #0x2700,%%sr \n" /* Disable interrupts */
233 "move.l (%[gpo1]), %%d0 \n" /* Get current state of data port */
234 "move.l %%d0, %%d1 \n"
235 "and.l %[dbit], %%d1 \n" /* Check current state of data line */
236 "beq.s 1f \n" /* and set it as previous-state bit */
237 "bset #8, %[data] \n"
239 "move.l %[data], %%d1 \n" /* Compute the 'bit derivative', i.e. a value */
240 "lsr.l #1, %%d1 \n" /* with 1's where the data changes from the */
241 "eor.l %%d1, %[data] \n" /* previous state, and 0's where it doesn't */
242 "swap %[data] \n" /* Shift data to upper byte */
243 "lsl.l #8, %[data] \n"
245 "move.l (%[gpo0]), %%d1 \n" /* Get current state of clock port */
246 "move.l %[cbit], %%d2 \n" /* Precalculate opposite state of clock line */
247 "eor.l %%d1, %%d2 \n"
249 "lsl.l #1,%[data] \n" /* Shift out MSB */
251 "eor.l %[dbit], %%d0 \n" /* 1: flip data bit */
252 "move.l %%d0, (%[gpo1]) \n" /* and output new DATA state */
254 "move.l %%d2, (%[gpo0]) \n" /* Set CLK */
255 "move.l %%d1, (%[gpo0]) \n" /* Reset CLK */
257 "lsl.l #1,%[data] \n" /* ..unrolled.. */
259 "eor.l %[dbit], %%d0 \n"
260 "move.l %%d0, (%[gpo1]) \n"
262 "move.l %%d2, (%[gpo0]) \n"
263 "move.l %%d1, (%[gpo0]) \n"
265 "lsl.l #1,%[data] \n"
267 "eor.l %[dbit], %%d0 \n"
268 "move.l %%d0, (%[gpo1]) \n"
270 "move.l %%d2, (%[gpo0]) \n"
271 "move.l %%d1, (%[gpo0]) \n"
273 "lsl.l #1,%[data] \n"
275 "eor.l %[dbit], %%d0 \n"
276 "move.l %%d0, (%[gpo1]) \n"
278 "move.l %%d2, (%[gpo0]) \n"
279 "move.l %%d1, (%[gpo0]) \n"
281 "lsl.l #1,%[data] \n"
283 "eor.l %[dbit], %%d0 \n"
284 "move.l %%d0, (%[gpo1]) \n"
286 "move.l %%d2, (%[gpo0]) \n"
287 "move.l %%d1, (%[gpo0]) \n"
289 "lsl.l #1,%[data] \n"
291 "eor.l %[dbit], %%d0 \n"
292 "move.l %%d0, (%[gpo1]) \n"
294 "move.l %%d2, (%[gpo0]) \n"
295 "move.l %%d1, (%[gpo0]) \n"
297 "lsl.l #1,%[data] \n"
299 "eor.l %[dbit], %%d0 \n"
300 "move.l %%d0, (%[gpo1]) \n"
302 "move.l %%d2, (%[gpo0]) \n"
303 "move.l %%d1, (%[gpo0]) \n"
305 "lsl.l #1,%[data] \n"
307 "eor.l %[dbit], %%d0 \n"
308 "move.l %%d0, (%[gpo1]) \n"
310 "move.l %%d2, (%[gpo0]) \n"
311 "move.l %%d1, (%[gpo0]) \n"
313 "move.w %%d3, %%sr \n" /* Restore interrupt level */
317 [gpo0
]"a"(&GPIO_OUT
),
318 [cbit
]"i"(0x10000000),
319 [gpo1
]"a"(&GPIO1_OUT
),
320 [dbit
]"d"(0x00040000)
322 "d0", "d1", "d2", "d3"
326 void lcd_remote_write_command(int cmd
)
333 #ifdef HAVE_REMOTE_LCD_TICKING
334 _byte_delay(byte_delay
- 148);
337 cs_countdown
= CS_TIMEOUT
;
340 void lcd_remote_write_command_ex(int cmd
, int data
)
347 #ifdef HAVE_REMOTE_LCD_TICKING
348 _byte_delay(byte_delay
- 148);
351 #ifdef HAVE_REMOTE_LCD_TICKING
352 _byte_delay(byte_delay
- 148);
355 cs_countdown
= CS_TIMEOUT
;
358 void lcd_remote_write_data(const unsigned char* p_bytes
, int count
) ICODE_ATTR
;
359 void lcd_remote_write_data(const unsigned char* p_bytes
, int count
)
361 const unsigned char *p_end
= p_bytes
+ count
;
367 /* This is safe as long as lcd_remote_write_data() isn't called from within
369 if (cpu_frequency
< 50000000)
371 while (p_bytes
< p_end
)
373 _write_fast(*p_bytes
++);
374 #ifdef HAVE_REMOTE_LCD_TICKING
375 _byte_delay(byte_delay
- 87);
381 while (p_bytes
< p_end
)
383 _write_byte(*p_bytes
++);
384 #ifdef HAVE_REMOTE_LCD_TICKING
385 _byte_delay(byte_delay
- 148);
390 cs_countdown
= CS_TIMEOUT
;
392 #endif /* !SIMULATOR */
394 /*** hardware configuration ***/
396 int lcd_remote_default_contrast(void)
398 return DEFAULT_REMOTE_CONTRAST_SETTING
;
403 #ifdef HAVE_REMOTE_LCD_TICKING
404 void lcd_remote_emireduce(bool state
)
410 void lcd_remote_powersave(bool on
)
412 if (remote_initialized
)
414 lcd_remote_write_command(LCD_REMOTE_CNTL_DISPLAY_ON_OFF
| (on
? 0 : 1));
415 lcd_remote_write_command(LCD_REMOTE_CNTL_ENTIRE_ON_OFF
| (on
? 1 : 0));
419 void lcd_remote_set_contrast(int val
)
421 cached_contrast
= val
;
422 if (remote_initialized
)
423 lcd_remote_write_command_ex(LCD_REMOTE_CNTL_SELECT_VOLTAGE
, val
);
426 void lcd_remote_set_invert_display(bool yesno
)
428 cached_invert
= yesno
;
429 if (remote_initialized
)
430 lcd_remote_write_command(LCD_REMOTE_CNTL_REVERSE_ON_OFF
| (yesno
?1:0));
433 /* turn the display upside down (call lcd_remote_update() afterwards) */
434 void lcd_remote_set_flip(bool yesno
)
440 if (remote_initialized
)
442 lcd_remote_write_command(LCD_REMOTE_CNTL_ADC_NORMAL
);
443 lcd_remote_write_command(LCD_REMOTE_CNTL_SHL_NORMAL
);
448 xoffset
= 132 - LCD_REMOTE_WIDTH
;
449 if (remote_initialized
)
451 lcd_remote_write_command(LCD_REMOTE_CNTL_ADC_REVERSE
);
452 lcd_remote_write_command(LCD_REMOTE_CNTL_SHL_REVERSE
);
457 /* The actual LCD init */
458 static void remote_lcd_init(void)
462 lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_BIAS
| 0x0);
464 lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL
| 0x5);
466 lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL
| 0x6);
468 lcd_remote_write_command(LCD_REMOTE_CNTL_POWER_CONTROL
| 0x7);
470 lcd_remote_write_command(LCD_REMOTE_CNTL_SELECT_REGULATOR
| 0x4); // 0x4 Select regulator @ 5.0 (default);
474 lcd_remote_write_command(LCD_REMOTE_CNTL_INIT_LINE
| 0x0); // init line
475 lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS
| 0x0); // page address
476 lcd_remote_write_command_ex(0x10, 0x00); // Column MSB + LSB
478 lcd_remote_write_command(LCD_REMOTE_CNTL_DISPLAY_ON_OFF
| 1);
480 remote_initialized
= true;
482 lcd_remote_set_flip(cached_flip
);
483 lcd_remote_set_contrast(cached_contrast
);
484 lcd_remote_set_invert_display(cached_invert
);
487 bool remote_detect(void)
489 return (GPIO_READ
& 0x40000000)?false:true;
492 int remote_type(void)
497 /* Monitor remote hotswap */
498 static void remote_tick(void)
500 static bool last_status
= false;
501 static int countdown
= 0;
502 static int init_delay
= 0;
507 current_status
= remote_detect();
508 /* Only report when the status has changed */
509 if (current_status
!= last_status
)
511 last_status
= current_status
;
512 countdown
= current_status
? 20*HZ
: 1;
516 /* Count down until it gets negative */
522 if (!(countdown
% 8))
524 /* Determine which type of remote it is */
525 level
= set_irq_level(HIGHEST_IRQ_LEVEL
);
526 val
= adc_scan(ADC_REMOTEDETECT
);
527 set_irq_level(level
);
529 if (val
< ADCVAL_H100_LCD_REMOTE_HOLD
)
531 if (val
< ADCVAL_H100_LCD_REMOTE
)
532 if (val
< ADCVAL_H300_LCD_REMOTE
)
533 _remote_type
= REMOTETYPE_H300_LCD
; /* hold off */
535 _remote_type
= REMOTETYPE_H100_LCD
; /* hold off */
537 if (val
< ADCVAL_H300_LCD_REMOTE_HOLD
)
538 _remote_type
= REMOTETYPE_H300_LCD
; /* hold on */
540 _remote_type
= REMOTETYPE_H100_LCD
; /* hold on */
542 if (--init_delay
<= 0)
544 queue_post(&remote_scroll_queue
, REMOTE_INIT_LCD
, 0);
550 _remote_type
= REMOTETYPE_H300_NONLCD
; /* hold on or off */
558 _remote_type
= REMOTETYPE_UNPLUGGED
;
560 queue_post(&remote_scroll_queue
, REMOTE_DEINIT_LCD
, 0);
565 /* handle chip select timeout */
566 if (cs_countdown
>= 0)
568 if (cs_countdown
== 0)
571 #endif /* !SIMULATOR */
576 void lcd_remote_init(void)
578 create_thread(scroll_thread
, scroll_stack
,
579 sizeof(scroll_stack
), scroll_name
IF_PRIO(, PRIORITY_USER_INTERFACE
));
581 #else /* !SIMULATOR */
583 /* Initialise ports and kick off monitor */
584 void lcd_remote_init(void)
586 #ifdef IRIVER_H300_SERIES
587 or_l(0x10010000, &GPIO_FUNCTION
); /* GPIO16: RS
590 or_l(0x00040006, &GPIO1_FUNCTION
); /* GPO33: Backlight
593 or_l(0x10010000, &GPIO_ENABLE
);
594 or_l(0x00040006, &GPIO1_ENABLE
);
596 or_l(0x10010800, &GPIO_FUNCTION
); /* GPIO11: Backlight
600 or_l(0x00040004, &GPIO1_FUNCTION
); /* GPIO34: CS
602 or_l(0x10010800, &GPIO_ENABLE
);
603 or_l(0x00040004, &GPIO1_ENABLE
);
605 lcd_remote_clear_display();
608 queue_init(&remote_scroll_queue
, false);
609 tick_add_task(remote_tick
);
610 create_thread(scroll_thread
, scroll_stack
,
611 sizeof(scroll_stack
), scroll_name
IF_PRIO(, PRIORITY_USER_INTERFACE
));
614 /*** update functions ***/
616 /* Update the display.
617 This must be called after all other LCD functions that change the display. */
618 void lcd_remote_update(void) ICODE_ATTR
;
619 void lcd_remote_update(void)
623 if (!remote_initialized
)
626 #ifdef HAVE_REMOTE_LCD_TICKING
627 /* Adjust byte delay for emi reduction. */
628 byte_delay
= emireduce
? cpu_frequency
/ 197600 + 28: 0;
631 /* Copy display bitmap to hardware */
632 for (y
= 0; y
< LCD_REMOTE_HEIGHT
/8; y
++)
634 lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS
| y
);
635 lcd_remote_write_command(LCD_REMOTE_CNTL_HIGHCOL
| ((xoffset
>> 4) & 0xf));
636 lcd_remote_write_command(LCD_REMOTE_CNTL_LOWCOL
| (xoffset
& 0xf));
637 lcd_remote_write_data(lcd_remote_framebuffer
[y
], LCD_REMOTE_WIDTH
);
641 /* Update a fraction of the display. */
642 void lcd_remote_update_rect(int, int, int, int) ICODE_ATTR
;
643 void lcd_remote_update_rect(int x
, int y
, int width
, int height
)
647 if (!remote_initialized
)
650 /* The Y coordinates have to work on even 8 pixel rows */
651 ymax
= (y
+ height
-1) >> 3;
654 if(x
+ width
> LCD_REMOTE_WIDTH
)
655 width
= LCD_REMOTE_WIDTH
- x
;
657 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
658 if(ymax
>= LCD_REMOTE_HEIGHT
/8)
659 ymax
= LCD_REMOTE_HEIGHT
/8-1;
661 #ifdef HAVE_REMOTE_LCD_TICKING
662 /* Adjust byte delay for emi reduction */
663 byte_delay
= emireduce
? cpu_frequency
/ 197600 + 28: 0;
666 /* Copy specified rectange bitmap to hardware */
667 for (; y
<= ymax
; y
++)
669 lcd_remote_write_command(LCD_REMOTE_CNTL_SET_PAGE_ADDRESS
| y
);
670 lcd_remote_write_command(LCD_REMOTE_CNTL_HIGHCOL
| (((x
+xoffset
) >> 4) & 0xf));
671 lcd_remote_write_command(LCD_REMOTE_CNTL_LOWCOL
| ((x
+xoffset
) & 0xf));
672 lcd_remote_write_data(&lcd_remote_framebuffer
[y
][x
], width
);
675 #endif /* !SIMULATOR */
677 /*** parameter handling ***/
679 void lcd_remote_set_drawmode(int mode
)
681 drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
684 int lcd_remote_get_drawmode(void)
689 void lcd_remote_setmargins(int x
, int y
)
695 int lcd_remote_getxmargin(void)
700 int lcd_remote_getymargin(void)
706 void lcd_remote_setfont(int newfont
)
711 int lcd_remote_getstringsize(const unsigned char *str
, int *w
, int *h
)
713 return font_getstringsize(str
, w
, h
, curfont
);
716 /*** low-level drawing functions ***/
718 static void setpixel(int x
, int y
)
720 lcd_remote_framebuffer
[y
>>3][x
] |= 1 << (y
& 7);
723 static void clearpixel(int x
, int y
)
725 lcd_remote_framebuffer
[y
>>3][x
] &= ~(1 << (y
& 7));
728 static void flippixel(int x
, int y
)
730 lcd_remote_framebuffer
[y
>>3][x
] ^= 1 << (y
& 7);
733 static void nopixel(int x
, int y
)
739 lcd_remote_pixelfunc_type
* const lcd_remote_pixelfuncs
[8] = {
740 flippixel
, nopixel
, setpixel
, setpixel
,
741 nopixel
, clearpixel
, nopixel
, clearpixel
744 static void flipblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
746 static void flipblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
748 *address
^= bits
& mask
;
751 static void bgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
753 static void bgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
755 *address
&= bits
| ~mask
;
758 static void fgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
760 static void fgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
762 *address
|= bits
& mask
;
765 static void solidblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
767 static void solidblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
769 unsigned data
= *address
;
772 *address
= data
^ (bits
& mask
);
775 static void flipinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
777 static void flipinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
779 *address
^= ~bits
& mask
;
782 static void bginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
784 static void bginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
786 *address
&= ~(bits
& mask
);
789 static void fginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
791 static void fginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
793 *address
|= ~bits
& mask
;
796 static void solidinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
798 static void solidinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
800 unsigned data
= *address
;
803 *address
= data
^ (bits
& mask
);
806 lcd_remote_blockfunc_type
* const lcd_remote_blockfuncs
[8] = {
807 flipblock
, bgblock
, fgblock
, solidblock
,
808 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
811 /*** drawing functions ***/
813 /* Clear the whole display */
814 void lcd_remote_clear_display(void)
816 unsigned bits
= (drawmode
& DRMODE_INVERSEVID
) ? 0xFFu
: 0;
818 memset(lcd_remote_framebuffer
, bits
, sizeof lcd_remote_framebuffer
);
822 /* Set a single pixel */
823 void lcd_remote_drawpixel(int x
, int y
)
825 if (((unsigned)x
< LCD_REMOTE_WIDTH
) && ((unsigned)y
< LCD_REMOTE_HEIGHT
))
826 lcd_remote_pixelfuncs
[drawmode
](x
, y
);
830 void lcd_remote_drawline(int x1
, int y1
, int x2
, int y2
)
838 lcd_remote_pixelfunc_type
*pfunc
= lcd_remote_pixelfuncs
[drawmode
];
840 deltax
= abs(x2
- x1
);
841 deltay
= abs(y2
- y1
);
845 if (deltax
>= deltay
)
848 d
= 2 * deltay
- deltax
;
850 dinc2
= (deltay
- deltax
) * 2;
857 d
= 2 * deltax
- deltay
;
859 dinc2
= (deltax
- deltay
) * 2;
863 numpixels
++; /* include endpoints */
880 for (i
= 0; i
< numpixels
; i
++)
882 if (((unsigned)x
< LCD_REMOTE_WIDTH
) && ((unsigned)y
< LCD_REMOTE_HEIGHT
))
900 /* Draw a horizontal line (optimised) */
901 void lcd_remote_hline(int x1
, int x2
, int y
)
904 fb_remote_data
*dst
, *dst_end
;
906 lcd_remote_blockfunc_type
*bfunc
;
916 /* nothing to draw? */
917 if (((unsigned)y
>= LCD_REMOTE_HEIGHT
) || (x1
>= LCD_REMOTE_WIDTH
)
924 if (x2
>= LCD_REMOTE_WIDTH
)
925 x2
= LCD_REMOTE_WIDTH
-1;
927 bfunc
= lcd_remote_blockfuncs
[drawmode
];
928 dst
= &lcd_remote_framebuffer
[y
>>3][x1
];
931 dst_end
= dst
+ x2
- x1
;
933 bfunc(dst
++, mask
, 0xFFu
);
934 while (dst
<= dst_end
);
937 /* Draw a vertical line (optimised) */
938 void lcd_remote_vline(int x
, int y1
, int y2
)
942 unsigned mask
, mask_bottom
;
943 lcd_remote_blockfunc_type
*bfunc
;
953 /* nothing to draw? */
954 if (((unsigned)x
>= LCD_REMOTE_WIDTH
) || (y1
>= LCD_REMOTE_HEIGHT
)
961 if (y2
>= LCD_REMOTE_HEIGHT
)
962 y2
= LCD_REMOTE_HEIGHT
-1;
964 bfunc
= lcd_remote_blockfuncs
[drawmode
];
965 dst
= &lcd_remote_framebuffer
[y1
>>3][x
];
967 mask
= 0xFFu
<< (y1
& 7);
968 mask_bottom
= 0xFFu
>> (~ny
& 7);
970 for (; ny
>= 8; ny
-= 8)
972 bfunc(dst
, mask
, 0xFFu
);
973 dst
+= LCD_REMOTE_WIDTH
;
977 bfunc(dst
, mask
, 0xFFu
);
980 /* Draw a rectangular box */
981 void lcd_remote_drawrect(int x
, int y
, int width
, int height
)
983 if ((width
<= 0) || (height
<= 0))
986 int x2
= x
+ width
- 1;
987 int y2
= y
+ height
- 1;
989 lcd_remote_vline(x
, y
, y2
);
990 lcd_remote_vline(x2
, y
, y2
);
991 lcd_remote_hline(x
, x2
, y
);
992 lcd_remote_hline(x
, x2
, y2
);
995 /* Fill a rectangular area */
996 void lcd_remote_fillrect(int x
, int y
, int width
, int height
)
999 fb_remote_data
*dst
, *dst_end
;
1000 unsigned mask
, mask_bottom
;
1002 lcd_remote_blockfunc_type
*bfunc
;
1003 bool fillopt
= false;
1005 /* nothing to draw? */
1006 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_REMOTE_WIDTH
)
1007 || (y
>= LCD_REMOTE_HEIGHT
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1021 if (x
+ width
> LCD_REMOTE_WIDTH
)
1022 width
= LCD_REMOTE_WIDTH
- x
;
1023 if (y
+ height
> LCD_REMOTE_HEIGHT
)
1024 height
= LCD_REMOTE_HEIGHT
- y
;
1026 if (drawmode
& DRMODE_INVERSEVID
)
1028 if (drawmode
& DRMODE_BG
)
1035 if (drawmode
& DRMODE_FG
)
1041 bfunc
= lcd_remote_blockfuncs
[drawmode
];
1042 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
1043 ny
= height
- 1 + (y
& 7);
1044 mask
= 0xFFu
<< (y
& 7);
1045 mask_bottom
= 0xFFu
>> (~ny
& 7);
1047 for (; ny
>= 8; ny
-= 8)
1049 if (fillopt
&& (mask
== 0xFFu
))
1050 memset(dst
, bits
, width
);
1053 fb_remote_data
*dst_row
= dst
;
1055 dst_end
= dst_row
+ width
;
1057 bfunc(dst_row
++, mask
, 0xFFu
);
1058 while (dst_row
< dst_end
);
1061 dst
+= LCD_REMOTE_WIDTH
;
1064 mask
&= mask_bottom
;
1066 if (fillopt
&& (mask
== 0xFFu
))
1067 memset(dst
, bits
, width
);
1070 dst_end
= dst
+ width
;
1072 bfunc(dst
++, mask
, 0xFFu
);
1073 while (dst
< dst_end
);
1077 /* About Rockbox' internal bitmap format:
1079 * A bitmap contains one bit for every pixel that defines if that pixel is
1080 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
1082 * The bytes are stored in row-major order, with byte 0 being top left,
1083 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
1084 * 0..7, the second row defines pixel row 8..15 etc.
1086 * This is the same as the internal lcd hw format. */
1088 /* Draw a partial bitmap */
1089 void lcd_remote_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
1090 int stride
, int x
, int y
, int width
, int height
)
1092 void lcd_remote_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
1093 int stride
, int x
, int y
, int width
, int height
)
1096 fb_remote_data
*dst
, *dst_end
;
1097 unsigned mask
, mask_bottom
;
1098 lcd_remote_blockfunc_type
*bfunc
;
1100 /* nothing to draw? */
1101 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_REMOTE_WIDTH
)
1102 || (y
>= LCD_REMOTE_HEIGHT
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1118 if (x
+ width
> LCD_REMOTE_WIDTH
)
1119 width
= LCD_REMOTE_WIDTH
- x
;
1120 if (y
+ height
> LCD_REMOTE_HEIGHT
)
1121 height
= LCD_REMOTE_HEIGHT
- y
;
1123 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
1126 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
1128 ny
= height
- 1 + shift
+ src_y
;
1130 bfunc
= lcd_remote_blockfuncs
[drawmode
];
1131 mask
= 0xFFu
<< (shift
+ src_y
);
1132 mask_bottom
= 0xFFu
>> (~ny
& 7);
1136 bool copyopt
= (drawmode
== DRMODE_SOLID
);
1138 for (; ny
>= 8; ny
-= 8)
1140 if (copyopt
&& (mask
== 0xFFu
))
1141 memcpy(dst
, src
, width
);
1144 const unsigned char *src_row
= src
;
1145 fb_remote_data
*dst_row
= dst
;
1147 dst_end
= dst_row
+ width
;
1149 bfunc(dst_row
++, mask
, *src_row
++);
1150 while (dst_row
< dst_end
);
1154 dst
+= LCD_REMOTE_WIDTH
;
1157 mask
&= mask_bottom
;
1159 if (copyopt
&& (mask
== 0xFFu
))
1160 memcpy(dst
, src
, width
);
1163 dst_end
= dst
+ width
;
1165 bfunc(dst
++, mask
, *src
++);
1166 while (dst
< dst_end
);
1171 dst_end
= dst
+ width
;
1174 const unsigned char *src_col
= src
++;
1175 fb_remote_data
*dst_col
= dst
++;
1176 unsigned mask_col
= mask
;
1179 for (y
= ny
; y
>= 8; y
-= 8)
1181 data
|= *src_col
<< shift
;
1183 if (mask_col
& 0xFFu
)
1185 bfunc(dst_col
, mask_col
, data
);
1192 dst_col
+= LCD_REMOTE_WIDTH
;
1195 data
|= *src_col
<< shift
;
1196 bfunc(dst_col
, mask_col
& mask_bottom
, data
);
1198 while (dst
< dst_end
);
1202 /* Draw a full bitmap */
1203 void lcd_remote_bitmap(const unsigned char *src
, int x
, int y
, int width
,
1206 lcd_remote_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
1209 /* put a string at a given pixel position, skipping first ofs pixel columns */
1210 static void lcd_remote_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
1213 unsigned short *ucs
;
1214 struct font
* pf
= font_get(curfont
);
1216 ucs
= bidi_l2v(str
, 1);
1218 while ((ch
= *ucs
++) != 0 && x
< LCD_REMOTE_WIDTH
)
1221 const unsigned char *bits
;
1223 /* get proportional width and glyph bits */
1224 width
= font_get_width(pf
, ch
);
1232 bits
= font_get_bits(pf
, ch
);
1234 lcd_remote_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
1242 /* put a string at a given pixel position */
1243 void lcd_remote_putsxy(int x
, int y
, const unsigned char *str
)
1245 lcd_remote_putsxyofs(x
, y
, 0, str
);
1248 /*** line oriented text output ***/
1250 /* put a string at a given char position */
1251 void lcd_remote_puts(int x
, int y
, const unsigned char *str
)
1253 lcd_remote_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
1256 void lcd_remote_puts_style(int x
, int y
, const unsigned char *str
, int style
)
1258 lcd_remote_puts_style_offset(x
, y
, str
, style
, 0);
1261 void lcd_remote_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
1263 lcd_remote_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
1266 /* put a string at a given char position, style, and pixel position,
1267 * skipping first offset pixel columns */
1268 void lcd_remote_puts_style_offset(int x
, int y
, const unsigned char *str
,
1269 int style
, int offset
)
1271 int xpos
,ypos
,w
,h
,xrect
;
1272 int lastmode
= drawmode
;
1274 /* make sure scrolling is turned off on the line we are updating */
1275 scrolling_lines
&= ~(1 << y
);
1280 lcd_remote_getstringsize(str
, &w
, &h
);
1281 xpos
= xmargin
+ x
*w
/ utf8length((char *)str
);
1282 ypos
= ymargin
+ y
*h
;
1283 drawmode
= (style
& STYLE_INVERT
) ?
1284 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1285 lcd_remote_putsxyofs(xpos
, ypos
, offset
, str
);
1286 drawmode
^= DRMODE_INVERSEVID
;
1287 xrect
= xpos
+ MAX(w
- offset
, 0);
1288 lcd_remote_fillrect(xrect
, ypos
, LCD_REMOTE_WIDTH
- xrect
, h
);
1289 drawmode
= lastmode
;
1294 /* Reverse the invert setting of the scrolling line (if any) at given char
1295 position. Setting will go into affect next time line scrolls. */
1296 void lcd_remote_invertscroll(int x
, int y
)
1298 struct scrollinfo
* s
;
1303 s
->invert
= !s
->invert
;
1306 void lcd_remote_stop_scroll(void)
1311 void lcd_remote_scroll_speed(int speed
)
1313 scroll_ticks
= scroll_tick_table
[speed
];
1316 void lcd_remote_scroll_step(int step
)
1321 void lcd_remote_scroll_delay(int ms
)
1323 scroll_delay
= ms
/ (HZ
/ 10);
1326 void lcd_remote_bidir_scroll(int percent
)
1328 bidir_limit
= percent
;
1331 void lcd_remote_puts_scroll(int x
, int y
, const unsigned char *string
)
1333 lcd_remote_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
1336 void lcd_remote_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
1338 lcd_remote_puts_scroll_style_offset(x
, y
, string
, style
, 0);
1341 void lcd_remote_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
1343 lcd_remote_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
1346 void lcd_remote_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
1347 int style
, int offset
)
1349 struct scrollinfo
* s
;
1354 s
->start_tick
= current_tick
+ scroll_delay
;
1356 if (style
& STYLE_INVERT
) {
1358 lcd_remote_puts_style_offset(x
,y
,string
,STYLE_INVERT
,offset
);
1361 lcd_remote_puts_offset(x
,y
,string
,offset
);
1363 lcd_remote_getstringsize(string
, &w
, &h
);
1365 if (LCD_REMOTE_WIDTH
- x
* 8 - xmargin
< w
) {
1366 /* prepare scroll line */
1369 memset(s
->line
, 0, sizeof s
->line
);
1370 strcpy(s
->line
, (char *)string
);
1373 s
->width
= lcd_remote_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1375 /* scroll bidirectional or forward only depending on the string
1377 if ( bidir_limit
) {
1378 s
->bidir
= s
->width
< (LCD_REMOTE_WIDTH
- xmargin
) *
1379 (100 + bidir_limit
) / 100;
1384 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1385 strcat(s
->line
, " ");
1386 /* get new width incl. spaces */
1387 s
->width
= lcd_remote_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1390 end
= strchr(s
->line
, '\0');
1391 strncpy(end
, (char *)string
, LCD_REMOTE_WIDTH
/2);
1393 s
->len
= utf8length((char *)string
);
1395 s
->startx
= xmargin
+ x
* s
->width
/ s
->len
;;
1396 s
->backward
= false;
1397 scrolling_lines
|= (1<<y
);
1400 /* force a bit switch-off since it doesn't scroll */
1401 scrolling_lines
&= ~(1<<y
);
1404 static void scroll_thread(void)
1407 struct scrollinfo
* s
;
1408 long next_tick
= current_tick
;
1417 /* initialize scroll struct array */
1418 scrolling_lines
= 0;
1425 if (remote_initialized
)
1426 queue_wait_w_tmo(&remote_scroll_queue
, &ev
, delay
);
1428 queue_wait(&remote_scroll_queue
, &ev
);
1432 case REMOTE_INIT_LCD
:
1434 lcd_remote_update();
1437 case REMOTE_DEINIT_LCD
:
1440 remote_initialized
= false;
1444 delay
= next_tick
- current_tick
- 1;
1448 for ( index
= 0; index
< SCROLLABLE_LINES
; index
++ ) {
1449 /* really scroll? */
1450 if ( !(scrolling_lines
&(1<<index
)) )
1456 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1460 s
->offset
-= scroll_step
;
1462 s
->offset
+= scroll_step
;
1464 pf
= font_get(curfont
);
1466 ypos
= ymargin
+ index
* pf
->height
;
1468 if (s
->bidir
) { /* scroll bidirectional */
1469 if (s
->offset
<= 0) {
1470 /* at beginning of line */
1472 s
->backward
= false;
1473 s
->start_tick
= current_tick
+ scroll_delay
* 2;
1475 if (s
->offset
>= s
->width
- (LCD_REMOTE_WIDTH
- xpos
)) {
1476 /* at end of line */
1477 s
->offset
= s
->width
- (LCD_REMOTE_WIDTH
- xpos
);
1479 s
->start_tick
= current_tick
+ scroll_delay
* 2;
1483 /* scroll forward the whole time */
1484 if (s
->offset
>= s
->width
)
1485 s
->offset
%= s
->width
;
1488 lastmode
= drawmode
;
1489 drawmode
= s
->invert
?
1490 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1491 lcd_remote_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
1492 drawmode
= lastmode
;
1493 lcd_remote_update_rect(xpos
, ypos
, LCD_REMOTE_WIDTH
- xpos
, pf
->height
);
1496 next_tick
+= scroll_ticks
;
1497 delay
= next_tick
- current_tick
- 1;
1500 next_tick
= current_tick
+ 1;