summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-player.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-player.c')
-rw-r--r--firmware/drivers/lcd-player.c830
1 files changed, 0 insertions, 830 deletions
diff --git a/firmware/drivers/lcd-player.c b/firmware/drivers/lcd-player.c
deleted file mode 100644
index dd99246611..0000000000
--- a/firmware/drivers/lcd-player.c
+++ /dev/null
@@ -1,830 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "config.h"
20#include "hwcompat.h"
21
22#ifdef HAVE_LCD_CHARCELLS
23
24#include "lcd.h"
25#include "kernel.h"
26#include "thread.h"
27#include <string.h>
28#include <stdlib.h>
29#include "file.h"
30#include "debug.h"
31#include "system.h"
32#include "font.h"
33#include "lcd-player-charset.h"
34#include "rbunicode.h"
35
36/*** definitions ***/
37
38#define OLD_LCD_CONTRAST_SET ((char)0xA8)
39#define OLD_LCD_CRAM ((char)0xB0) /* Characters */
40#define OLD_LCD_PRAM ((char)0x80) /* Patterns */
41#define OLD_LCD_IRAM ((char)0xE0) /* Icons */
42
43#define NEW_LCD_CONTRAST_SET ((char)0x50)
44#define NEW_LCD_CRAM ((char)0x80) /* Characters */
45#define NEW_LCD_PRAM ((char)0xC0) /* Patterns */
46#define NEW_LCD_IRAM ((char)0x40) /* Icons */
47#define NEW_LCD_FUNCTION_SET ((char)0x10)
48#define NEW_LCD_POWER_SAVE_MODE_OSC_CONTROL_SET ((char)0x0c)
49#define NEW_LCD_POWER_CONTROL_REGISTER_SET ((char)0x20)
50#define NEW_LCD_DISPLAY_CONTROL_SET ((char)0x28)
51
52#define LCD_CURSOR(x,y) ((char)(lcd_cram+((y)*16+(x))))
53#define LCD_ICON(i) ((char)(lcd_iram+i))
54
55#define SCROLLABLE_LINES 2
56
57#define SCROLL_MODE_OFF 0
58#define SCROLL_MODE_PAUSE 1
59#define SCROLL_MODE_RUN 2
60
61extern unsigned short new_lcd_rocklatin1_to_xlcd[];
62extern unsigned short old_lcd_rocklatin1_to_xlcd[];
63extern const unsigned char lcd_player_extended_lcd_to_rocklatin1[];
64extern unsigned char extended_font_player[NO_EXTENDED_LCD_CHARS][8];
65
66/*** generic code ***/
67
68#define MAX_CURSOR_CHARS 8
69struct cursorinfo {
70 int len;
71 char text[MAX_CURSOR_CHARS];
72 int textpos;
73 int y_pos;
74 int x_pos;
75 int divider;
76 int downcount;
77} cursor;
78
79static void scroll_thread(void);
80static char scroll_stack[DEFAULT_STACK_SIZE];
81static const char scroll_name[] = "scroll";
82static int scroll_ticks = 12; /* # of ticks between updates */
83static int scroll_delay = HZ/2; /* delay before starting scroll */
84static int jump_scroll_delay = HZ/4; /* delay between jump scroll jumps */
85static int scroll_spacing = 3; /* spaces between end and start of text */
86static int bidir_limit = 50; /* percent */
87static int jump_scroll = 0; /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
88
89static struct scrollinfo scroll[SCROLLABLE_LINES];
90
91static char extended_chars_mapped[NO_EXTENDED_LCD_CHARS];
92static char extended_pattern_content[8]; /* Which char is mapped in pattern */
93static char extended_pattern_usage[8]; /* Counting number of times used */
94static char pattern_size; /* Last pattern, 3 for old LCD, 7 for new LCD */
95
96static bool new_lcd;
97
98unsigned short *lcd_ascii;
99static char lcd_contrast_set;
100static char lcd_cram;
101static char lcd_pram;
102static char lcd_iram;
103
104unsigned short buffer_xlcd[11][2];
105unsigned short buffer_lcd_mirror[11][2];
106
107#ifdef SIMULATOR
108unsigned char hardware_buffer_lcd[11][2];
109#endif
110
111#define NO_CHAR -1
112
113static void lcd_free_pat(int map_ch)
114{
115 int x, y;
116 unsigned char substitute_char;
117
118 int pat;
119 pat=extended_chars_mapped[map_ch];
120 if (pat!=NO_CHAR) {
121
122 substitute_char=lcd_player_extended_lcd_to_rocklatin1[map_ch];
123
124 /* TODO: use a define for the screen width! */
125 for (x=0; x<11; x++) {
126 /* TODO: use a define for the screen height! */
127 for (y=0; y<2; y++) {
128 if (map_ch==lcd_ascii[buffer_xlcd[x][y]]-512) {
129 buffer_xlcd[x][y]=substitute_char;
130 buffer_lcd_mirror[x][y]=substitute_char;
131#ifdef SIMULATOR
132 hardware_buffer_lcd[x][y]=substitute_char;
133#else
134 lcd_write_command_e(LCD_CURSOR(x, y), substitute_char);
135#endif
136 }
137 }
138 }
139 extended_chars_mapped[map_ch]=NO_CHAR;
140 extended_pattern_content[pat]=NO_CHAR;
141 extended_pattern_usage[pat]=0;
142 }
143#ifdef SIMULATOR
144 lcd_update();
145#endif
146}
147
148static int lcd_get_free_pat(int ch)
149{
150 int pat;
151 int last_pat=0;
152 static int last_used_pat=0;
153 int loop;
154
155 pat=last_used_pat;
156 for (loop=0; loop<=pattern_size; loop++) {
157 pat=(pat+1)&pattern_size; /* Keep 'pat' within limits */
158 if (extended_pattern_usage[pat]==0) {
159 int map_ch=extended_pattern_content[pat];
160 if (map_ch != NO_CHAR) {
161 extended_chars_mapped[map_ch]=NO_CHAR;
162 extended_pattern_content[pat]=NO_CHAR;
163 }
164 last_used_pat=pat;
165 return pat;
166 }
167 if (extended_pattern_content[pat]>extended_pattern_content[last_pat])
168 last_pat=pat;
169 }
170 if (ch<32) { /* Prioritized char */
171 /* Remove last_pat */
172 lcd_free_pat(extended_pattern_content[last_pat]);
173 last_used_pat=last_pat;
174 return last_pat;
175 }
176 return NO_CHAR;
177
178}
179
180void xlcd_update(void)
181{
182 int x, y;
183 for (x=0; x<11; x++) {
184 for (y=0; y<2; y++) {
185 unsigned short ch=buffer_xlcd[x][y];
186 unsigned char hw_ch=0xff;
187 if (ch==buffer_lcd_mirror[x][y])
188 continue; /* No need to redraw */
189 buffer_lcd_mirror[x][y]=ch;
190 if (ch>=256 && ch<512) {
191 hw_ch=ch-256;
192 } else {
193 int map_ch=lcd_ascii[ch];
194 if (map_ch<512) {
195 hw_ch=map_ch;
196 }
197 else {
198 map_ch=map_ch-512;
199 if (extended_chars_mapped[map_ch]!=NO_CHAR) {
200 hw_ch=extended_chars_mapped[map_ch];
201 extended_pattern_usage[hw_ch]++;
202 }
203 else {
204 int pat;
205 pat=lcd_get_free_pat(map_ch);
206 if (pat<0) {
207 /* Find substitute char */
208 map_ch=
209 lcd_player_extended_lcd_to_rocklatin1[map_ch];
210 hw_ch=lcd_ascii[map_ch];
211 } else {
212#ifdef DEBUG
213 if (extended_pattern_usage[pat]!=0) {
214 DEBUGF("***Pattern %d is not zero!\n", pat);
215 }
216#endif
217 extended_chars_mapped[map_ch]=pat;
218 extended_pattern_content[pat]=map_ch;
219 extended_pattern_usage[pat]=1;
220 lcd_define_hw_pattern(pat*8,
221 extended_font_player[map_ch],
222 8);
223 hw_ch=pat;
224 }
225 }
226 }
227 }
228#ifdef SIMULATOR
229 hardware_buffer_lcd[x][y]=hw_ch;
230#else
231 lcd_write_command_e(LCD_CURSOR(x,y), hw_ch);
232#endif
233 }
234 }
235 lcd_update();
236}
237
238bool lcdx_putc(int x, int y, unsigned short ch)
239{
240 int lcd_char;
241 if (buffer_xlcd[x][y]==ch)
242 return false; /* Same char, ignore any update */
243 lcd_char=lcd_ascii[buffer_xlcd[x][y]];
244 if (lcd_char>=512) {
245 /* The removed char is a defined pattern, count down the reference. */
246 extended_pattern_usage[(int)extended_chars_mapped[lcd_char-512]]--;
247#ifdef DEBUG
248 if (extended_pattern_usage[(int)extended_chars_mapped[lcd_char]]<0) {
249 DEBUGF("**** Mapped char %02x is less than 0!\n", lcd_char);
250 }
251#endif
252 }
253
254 buffer_xlcd[x][y]=ch;
255
256 lcd_char=lcd_ascii[ch];
257 if (lcd_char>=256)
258 return true; /* Caller shall call xlcd_update() when done */
259
260 buffer_lcd_mirror[x][y]=lcd_char;
261#ifdef SIMULATOR
262 hardware_buffer_lcd[x][y]=lcd_char;
263#else
264 lcd_write_command_e(LCD_CURSOR(x, y), lcd_char);
265#endif
266 return false;
267}
268
269void lcd_clear_display(void)
270{
271 int i;
272 bool update=false;
273 lcd_stop_scroll();
274 cursor.len=0; /* Stop cursor */
275 for (i=0;i<22;i++)
276 update|=lcdx_putc(i%11, i/11, ' ');
277 if (update)
278 xlcd_update();
279}
280
281static void lcd_puts_cont_scroll(int x, int y, const unsigned char *string)
282{
283 bool update=false;
284
285 for (; *string && x<11; x++)
286 {
287 /* We should check if char is over 256 */
288 update|=lcdx_putc(x, y, *(unsigned char*)string++);
289 }
290
291 for (; x<11; x++)
292 update|=lcdx_putc(x, y, ' ');
293 if (update)
294 xlcd_update();
295#ifdef SIMULATOR
296 lcd_update();
297#endif
298}
299void lcd_puts(int x, int y, const unsigned char *string)
300{
301 int i=0;
302 unsigned short ucs;
303 const unsigned char *utf8 = string;
304 unsigned char tmp[12];
305
306 while (*utf8 && i<11) {
307 utf8 = utf8decode(utf8, &ucs);
308 if (ucs < 256)
309 tmp[i++] = ucs;
310 else
311 tmp[i++] = '?';
312 }
313
314 tmp[i] = 0;
315
316 scroll[y].mode=SCROLL_MODE_OFF;
317 return lcd_puts_cont_scroll(x, y, tmp);
318}
319
320void lcd_put_cursor(int x, int y, char cursor_char)
321{
322 if (cursor.len == 0) {
323 cursor.text[0]=buffer_xlcd[x][y];
324 cursor.text[1]=cursor_char;
325 cursor.len=2;
326 cursor.textpos=0;
327 cursor.y_pos=y;
328 cursor.x_pos=x;
329 cursor.downcount=0;
330 cursor.divider=4;
331 }
332}
333
334void lcd_remove_cursor(void)
335{
336 if (cursor.len!=0) {
337 bool up;
338 cursor.len=0;
339 up = lcdx_putc(cursor.x_pos, cursor.y_pos, cursor.text[0]);
340#ifdef SIMULATOR
341 if(up)
342 lcd_update();
343#endif
344 }
345}
346
347void lcd_putc(int x, int y, unsigned short ch)
348{
349 bool update;
350 if (x<0 || y<0) {
351 return;
352 }
353 update=lcdx_putc(x, y, ch);
354
355 if (update)
356 xlcd_update();
357}
358
359unsigned char lcd_get_locked_pattern(void)
360{
361 unsigned char pat=1;
362 while (pat<LAST_RESERVED_CHAR) {
363 if (lcd_ascii[pat]==RESERVED_CHAR) {
364 lcd_ascii[pat]=0x200+pat;
365 return pat;
366 }
367 pat++;
368 }
369 return 0;
370}
371
372void lcd_unlock_pattern(unsigned char pat)
373{
374 lcd_ascii[pat]=RESERVED_CHAR;
375 lcd_free_pat(pat);
376}
377
378void lcd_define_pattern(int pat, const char *pattern)
379{
380 int i;
381 for (i=0; i<7; i++) {
382 extended_font_player[pat][i]=pattern[i];
383 }
384 if (extended_chars_mapped[pat]!=NO_CHAR) {
385 lcd_define_hw_pattern(extended_chars_mapped[pat]*8, pattern, 7);
386 }
387}
388
389#ifndef SIMULATOR
390void lcd_define_hw_pattern (int which,const char *pattern,int length)
391{
392 lcd_write_command(lcd_pram | which);
393 lcd_write_data(pattern, length);
394}
395
396void lcd_double_height(bool on)
397{
398 if(new_lcd)
399 lcd_write_command(on?9:8);
400}
401
402static const char icon_pos[] =
403{
404 0, 0, 0, 0, /* Battery */
405 2, /* USB */
406 3, /* Play */
407 4, /* Record */
408 5, /* Pause */
409 5, /* Audio */
410 6, /* Repeat */
411 7, /* 1 */
412 9, /* Volume */
413 9, /* Volume 1 */
414 9, /* Volume 2 */
415 10, /* Volume 3 */
416 10, /* Volume 4 */
417 10, /* Volume 5 */
418 10, /* Param */
419};
420
421static const char icon_mask[] =
422{
423 0x02, 0x08, 0x04, 0x10, /* Battery */
424 0x04, /* USB */
425 0x10, /* Play */
426 0x10, /* Record */
427 0x02, /* Pause */
428 0x10, /* Audio */
429 0x02, /* Repeat */
430 0x01, /* 1 */
431 0x04, /* Volume */
432 0x02, /* Volume 1 */
433 0x01, /* Volume 2 */
434 0x08, /* Volume 3 */
435 0x04, /* Volume 4 */
436 0x01, /* Volume 5 */
437 0x10, /* Param */
438};
439
440void lcd_icon(int icon, bool enable)
441{
442 static unsigned char icon_mirror[11] = {0};
443 int pos, mask;
444
445 pos = icon_pos[icon];
446 mask = icon_mask[icon];
447
448 if(enable)
449 icon_mirror[pos] |= mask;
450 else
451 icon_mirror[pos] &= ~mask;
452
453 lcd_write_command_e(LCD_ICON(pos), icon_mirror[pos]);
454}
455
456int lcd_default_contrast(void)
457{
458 return 30;
459}
460
461void lcd_set_contrast(int val)
462{
463 lcd_write_command_e(lcd_contrast_set, 31 - val);
464}
465#endif /* SIMULATOR */
466
467void lcd_init (void)
468{
469 unsigned char data_vector[64];
470
471 (void)data_vector;
472
473 new_lcd = is_new_player();
474 memset(extended_chars_mapped, NO_CHAR, sizeof(extended_chars_mapped));
475 memset(extended_pattern_content, NO_CHAR,sizeof(extended_pattern_content));
476 memset(extended_pattern_usage, 0, sizeof(extended_pattern_usage));
477
478 if(new_lcd) {
479 lcd_ascii = new_lcd_rocklatin1_to_xlcd;
480 lcd_contrast_set = NEW_LCD_CONTRAST_SET;
481 lcd_cram = NEW_LCD_CRAM;
482 lcd_pram = NEW_LCD_PRAM;
483 lcd_iram = NEW_LCD_IRAM;
484 pattern_size=7; /* Last pattern, 7 for new LCD */
485
486#ifndef SIMULATOR
487 /* LCD init for cold start */
488 PBCR2 &= 0xff00; /* Set PB0..PB3 to GPIO */
489 or_b(0x0f, &PBIORL); /* ... output */
490 or_b(0x0f, &PBDRL); /* ... and high */
491
492 lcd_write_command(NEW_LCD_FUNCTION_SET + 1); /* CGRAM selected */
493 lcd_write_command_e(NEW_LCD_CONTRAST_SET, 0x08);
494 lcd_write_command(NEW_LCD_POWER_SAVE_MODE_OSC_CONTROL_SET + 2);
495 /* oscillator on */
496 lcd_write_command(NEW_LCD_POWER_CONTROL_REGISTER_SET + 7);
497 /* opamp buffer + voltage booster on*/
498
499 memset(data_vector, 0x20, 64);
500 lcd_write_command(NEW_LCD_CRAM); /* Set DDRAM address */
501 lcd_write_data(data_vector, 64); /* all spaces */
502
503 memset(data_vector, 0, 64);
504 lcd_write_command(NEW_LCD_PRAM); /* Set CGRAM address */
505 lcd_write_data(data_vector, 64); /* zero out */
506 lcd_write_command(NEW_LCD_IRAM); /* Set ICONRAM address */
507 lcd_write_data(data_vector, 16); /* zero out */
508
509 lcd_write_command(NEW_LCD_DISPLAY_CONTROL_SET + 1); /* display on */
510#endif /* !SIMULATOR */
511 }
512 else {
513 lcd_ascii = old_lcd_rocklatin1_to_xlcd;
514 lcd_contrast_set = OLD_LCD_CONTRAST_SET;
515 lcd_cram = OLD_LCD_CRAM;
516 lcd_pram = OLD_LCD_PRAM;
517 lcd_iram = OLD_LCD_IRAM;
518 pattern_size=3; /* Last pattern, 3 for old LCD */
519
520#ifndef SIMULATOR
521#if 1
522 /* LCD init for cold start */
523 PBCR2 &= 0xff00; /* Set PB0..PB3 to GPIO */
524 or_b(0x0f, &PBIORL); /* ... output */
525 or_b(0x0f, &PBDRL); /* ... and high */
526
527 lcd_write_command(0x61);
528 lcd_write_command(0x42);
529 lcd_write_command(0x57);
530
531 memset(data_vector, 0x24, 13);
532 lcd_write_command(OLD_LCD_CRAM); /* Set DDRAM address */
533 lcd_write_data(data_vector, 13); /* all spaces */
534 lcd_write_command(OLD_LCD_CRAM + 0x10);
535 lcd_write_data(data_vector, 13);
536 lcd_write_command(OLD_LCD_CRAM + 0x20);
537 lcd_write_data(data_vector, 13);
538
539 memset(data_vector, 0, 32);
540 lcd_write_command(OLD_LCD_PRAM); /* Set CGRAM address */
541 lcd_write_data(data_vector, 32); /* zero out */
542 lcd_write_command(OLD_LCD_IRAM); /* Set ICONRAM address */
543 lcd_write_data(data_vector, 13); /* zero out */
544 lcd_write_command(OLD_LCD_IRAM + 0x10);
545 lcd_write_data(data_vector, 13);
546
547 lcd_write_command(0x31);
548#else
549 /* archos look-alike code, left here for reference. As soon as the
550 * rockbox version is confirmed working, this will go away */
551 {
552 int i;
553
554 PBCR2 &= 0xc000;
555 PBIOR |= 0x000f;
556 PBDR |= 0x0002;
557 PBDR |= 0x0001;
558 PBDR |= 0x0004;
559 PBDR |= 0x0008;
560
561 for (i=0; i<200; i++) asm volatile ("nop"); /* wait 100 us */
562
563 PBDR &= 0xfffd; /* CS low (assert) */
564
565 for (i=0; i<100; i++) asm volatile ("nop"); /* wait 50 us */
566
567 lcd_write_command(0x61);
568 lcd_write_command(0x42);
569 lcd_write_command(0x57);
570
571 memset(data_vector, 0x24, 13);
572 lcd_write_command(0xb0); /* Set DDRAM address */
573 lcd_write_data(data_vector, 13); /* all spaces */
574 lcd_write_command(0xc0);
575 lcd_write_data(data_vector, 13);
576 lcd_write_command(0xd0);
577 lcd_write_data(data_vector, 13);
578
579 memset(data_vector, 0, 32);
580 lcd_write_command(0x80); /* Set CGRAM address */
581 lcd_write_data(data_vector, 32); /* zero out */
582 lcd_write_command(0xe0); /* Set ICONRAM address */
583 lcd_write_data(data_vector, 13); /* zero out */
584 lcd_write_command(0xf0);
585 lcd_write_data(data_vector, 13);
586
587 for (i=0; i<300000; i++) asm volatile ("nop"); /* wait 150 ms */
588
589 lcd_write_command(0x31);
590 lcd_write_command_e(0xa8, 0); /* Set contrast control */
591 }
592#endif
593#endif /* !SIMULATOR */
594 }
595
596 lcd_set_contrast(lcd_default_contrast());
597
598 create_thread(scroll_thread, scroll_stack,
599 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)
600 IF_COP(, CPU, false));
601}
602
603void lcd_jump_scroll (int mode) /* 0=off, 1=once, ..., JUMP_SCROLL_ALWAYS */
604{
605 jump_scroll=mode;
606}
607
608void lcd_bidir_scroll(int percent)
609{
610 bidir_limit = percent;
611}
612
613void lcd_puts_scroll(int x, int y, const unsigned char* string )
614{
615 struct scrollinfo* s;
616 int i=0;
617 unsigned short ucs;
618 const unsigned char *utf8 = string;
619 unsigned char tmp[utf8length(string)+1];
620
621 while (*utf8) {
622 utf8 = utf8decode(utf8, &ucs);
623 if (ucs < 256)
624 tmp[i++] = ucs;
625 else
626 tmp[i++] = '?';
627 }
628
629 tmp[i] = 0;
630
631
632 s = &scroll[y];
633
634 lcd_puts_cont_scroll(x,y,tmp);
635 s->textlen = strlen(tmp);
636
637 if ( s->textlen > 11-x ) {
638 s->mode = SCROLL_MODE_RUN;
639 s->scroll_start_tick = current_tick + scroll_delay;
640 s->offset=0;
641 s->startx=x;
642 s->starty=y;
643 s->direction=+1;
644 s->jump_scroll=0;
645 s->jump_scroll_steps=0;
646 if (jump_scroll && jump_scroll_delay<scroll_ticks*(s->textlen-11+x)) {
647 s->jump_scroll_steps=11-x;
648 s->jump_scroll=jump_scroll;
649 }
650 strncpy(s->text,tmp,sizeof s->text);
651 s->turn_offset=-1;
652 if (bidir_limit && (s->textlen < ((11-x)*(100+bidir_limit))/100)) {
653 s->turn_offset=s->textlen+x-11;
654 }
655 else {
656 for (i=0; i<scroll_spacing &&
657 s->textlen<(int)sizeof(s->text); i++) {
658 s->text[s->textlen++]=' ';
659 }
660 }
661 if (s->textlen<(int)sizeof(s->text))
662 s->text[s->textlen]=' ';
663 s->text[sizeof s->text - 1] = 0;
664 }
665 else
666 s->mode = SCROLL_MODE_OFF;
667}
668
669void lcd_stop_scroll(void)
670{
671 struct scrollinfo* s;
672 int index;
673
674 for ( index = 0; index < SCROLLABLE_LINES; index++ ) {
675 s = &scroll[index];
676 if ( s->mode == SCROLL_MODE_RUN ||
677 s->mode == SCROLL_MODE_PAUSE ) {
678 /* restore scrolled row */
679 lcd_puts(s->startx, s->starty, s->text);
680 }
681 }
682
683 lcd_update();
684}
685
686static const char scroll_tick_table[16] = {
687 /* Hz values:
688 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */
689 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3
690};
691
692void lcd_scroll_speed(int speed)
693{
694 scroll_ticks = scroll_tick_table[speed];
695}
696
697void lcd_scroll_delay(int ms)
698{
699 scroll_delay = ms / (HZ / 10);
700}
701
702void lcd_jump_scroll_delay(int ms)
703{
704 jump_scroll_delay = ms / (HZ / 10);
705}
706
707static void scroll_thread(void)
708{
709 struct scrollinfo* s;
710 int index;
711 int i, o;
712 bool update;
713
714 /* initialize scroll struct array */
715 for (index = 0; index < SCROLLABLE_LINES; index++) {
716 scroll[index].mode = SCROLL_MODE_OFF;
717 }
718
719 while ( 1 ) {
720
721 update = false;
722
723 for ( index = 0; index < SCROLLABLE_LINES; index++ ) {
724 s = &scroll[index];
725 if ( s->mode == SCROLL_MODE_RUN ) {
726 if ( TIME_AFTER(current_tick, s->scroll_start_tick) ) {
727 char buffer[12];
728 int jumping_scroll=s->jump_scroll;
729 update = true;
730 if (s->jump_scroll) {
731
732 /* Find new position to start jump scroll by
733 * finding last white space within
734 * jump_scroll_steps */
735 int i;
736 o = s->offset = s->offset + s->jump_scroll_steps;
737 for (i = 0; i < s->jump_scroll_steps; i++, o--) {
738 if (o < s->textlen &&
739 ((0x20 <= s->text[o] && s->text[o] <= 0x2f) || s->text[o] == '_'))
740 {
741 s->offset = o;
742 break;
743 }
744 }
745
746 s->scroll_start_tick = current_tick +
747 jump_scroll_delay;
748 /* Eat space */
749 while (s->offset < s->textlen &&
750 ((0x20 <= s->text[s->offset] && s->text[s->offset] <= 0x2f) ||
751 s->text[s->offset] == '_')) {
752 s->offset++;
753 }
754 if (s->offset >= s->textlen) {
755 s->offset=0;
756 s->scroll_start_tick = current_tick +
757 scroll_delay;
758 if (s->jump_scroll != JUMP_SCROLL_ALWAYS) {
759 s->jump_scroll--;
760 s->direction=1;
761 }
762 }
763 } else {
764 if ( s->offset < s->textlen-1 ) {
765 s->offset+=s->direction;
766 if (s->offset==0) {
767 s->direction=+1;
768 s->scroll_start_tick = current_tick +
769 scroll_delay;
770 } else {
771 if (s->offset == s->turn_offset) {
772 s->direction=-1;
773 s->scroll_start_tick = current_tick +
774 scroll_delay;
775 }
776 }
777 }
778 else {
779 s->offset = 0;
780 }
781 }
782
783 i=0;
784 o=s->offset;
785 while (i<11) {
786 buffer[i++]=s->text[o++];
787 if (o==s->textlen /* || (jump_scroll && buffer[i-1] == ' ') */)
788 break;
789 }
790 o=0;
791 if (s->turn_offset == -1 && !jumping_scroll) {
792 while (i<11) {
793 buffer[i++]=s->text[o++];
794 }
795 } else {
796 while (i<11) {
797 buffer[i++]=' ';
798 }
799 }
800 buffer[11]=0;
801
802 lcd_puts_cont_scroll(s->startx, s->starty, buffer);
803 }
804 }
805 if (cursor.len>0) {
806 if (cursor.downcount--<0) {
807 cursor.downcount=cursor.divider;
808 cursor.textpos++;
809 if (cursor.textpos>=cursor.len)
810 cursor.textpos=0;
811#ifdef SIMULATOR
812 lcdx_putc(cursor.x_pos, cursor.y_pos,
813 cursor.text[cursor.textpos]);
814 update=true;
815#else
816 update|=lcdx_putc(cursor.x_pos, cursor.y_pos,
817 cursor.text[cursor.textpos]);
818#endif
819 }
820 }
821 if (update) {
822 lcd_update();
823 }
824 }
825
826 sleep(scroll_ticks);
827 }
828}
829
830#endif /* HAVE_LCD_CHARCELLS */