summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-charcell.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-charcell.c')
-rw-r--r--firmware/drivers/lcd-charcell.c599
1 files changed, 0 insertions, 599 deletions
diff --git a/firmware/drivers/lcd-charcell.c b/firmware/drivers/lcd-charcell.c
deleted file mode 100644
index b1f0021ff7..0000000000
--- a/firmware/drivers/lcd-charcell.c
+++ /dev/null
@@ -1,599 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 by Jens Arnold
11 * Based on the work of Alan Korr, Kjell Ericson and others
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#include <stdio.h>
24#include "config.h"
25#include "hwcompat.h"
26#include "stdarg.h"
27#include "lcd.h"
28#include "kernel.h"
29#include "thread.h"
30#include "string-extra.h"
31#include <stdlib.h>
32#include "debug.h"
33#include "file.h"
34#include "system.h"
35#include "lcd-charcell.h"
36#include "rbunicode.h"
37#include "scroll_engine.h"
38
39/** definitions **/
40
41#define VARIABLE_XCHARS 16 /* number of software user-definable characters */
42/* There must be mappings for this many characters in the 0xe000 unicode range
43 * in lcd-charset-<target>.c */
44
45#define NO_PATTERN (-1)
46
47static int find_xchar(unsigned long ucs);
48
49/** globals **/
50
51unsigned char lcd_charbuffer[LCD_HEIGHT][LCD_WIDTH]; /* The "frame"buffer */
52static unsigned char lcd_substbuffer[LCD_HEIGHT][LCD_WIDTH];
53struct pattern_info lcd_patterns[MAX_HW_PATTERNS];
54struct cursor_info lcd_cursor;
55
56static unsigned char xfont_variable[VARIABLE_XCHARS][HW_PATTERN_SIZE];
57static bool xfont_variable_locked[VARIABLE_XCHARS];
58static int xspace; /* stores xhcar id of ' ' - often needed */
59
60static struct viewport default_vp =
61 {
62 .x = 0,
63 .y = 0,
64 .width = LCD_WIDTH,
65 .height = LCD_HEIGHT,
66 };
67
68static struct viewport* current_vp = &default_vp;
69
70/* LCD init */
71void lcd_init (void)
72{
73 lcd_init_device();
74 lcd_charset_init();
75 memset(lcd_patterns, 0, sizeof(lcd_patterns));
76 xspace = find_xchar(' ');
77 memset(lcd_charbuffer, xchar_info[xspace].hw_char, sizeof(lcd_charbuffer));
78 scroll_init();
79}
80
81/* Viewports */
82
83void lcd_set_viewport(struct viewport* vp)
84{
85 if (vp == NULL)
86 current_vp = &default_vp;
87 else
88 current_vp = vp;
89
90#if defined(SIMULATOR)
91 /* Force the viewport to be within bounds. If this happens it should
92 * be considered an error - the viewport will not draw as it might be
93 * expected.
94 */
95 if((unsigned) current_vp->x > (unsigned) LCD_WIDTH
96 || (unsigned) current_vp->y > (unsigned) LCD_HEIGHT
97 || current_vp->x + current_vp->width > LCD_WIDTH
98 || current_vp->y + current_vp->height > LCD_HEIGHT)
99 {
100#if !defined(HAVE_VIEWPORT_CLIP)
101 DEBUGF("ERROR: "
102#else
103 DEBUGF("NOTE: "
104#endif
105 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
106 current_vp->x, current_vp->y,
107 current_vp->width, current_vp->height);
108 }
109
110#endif
111}
112
113struct viewport *lcd_get_viewport(bool *is_default)
114{
115 *is_default = (current_vp == &default_vp);
116 return current_vp;
117}
118
119void lcd_update_viewport(void)
120{
121 lcd_update();
122}
123
124void lcd_update_viewport_rect(int x, int y, int width, int height)
125{
126 (void) x;
127 (void) y;
128 (void) width;
129 (void) height;
130 lcd_update();
131}
132
133/** parameter handling **/
134
135int lcd_getwidth(void)
136{
137 return current_vp->width;
138}
139
140int lcd_getheight(void)
141{
142 return current_vp->height;
143}
144
145int lcd_getstringsize(const unsigned char *str, int *w, int *h)
146{
147 int width = utf8length(str);
148
149 if (w)
150 *w = width;
151 if (h)
152 *h = 1;
153
154 return width;
155}
156
157/** low-level functions **/
158
159static int find_xchar(unsigned long ucs)
160{
161 int low = 0;
162 int high = xchar_info_size - 1;
163
164 do
165 {
166 int probe = (low + high) >> 1;
167
168 if (xchar_info[probe].ucs < ucs)
169 low = probe + 1;
170 else if (xchar_info[probe].ucs > ucs)
171 high = probe - 1;
172 else
173 return probe;
174 }
175 while (low <= high);
176
177 /* Not found: return index of no-char symbol (last symbol, hardcoded). */
178 return xchar_info_size - 1;
179}
180
181static int glyph_to_pat(unsigned glyph)
182{
183 int i;
184
185 for (i = 0; i < lcd_pattern_count; i++)
186 if (lcd_patterns[i].glyph == glyph)
187 return i;
188
189 return NO_PATTERN;
190}
191
192static void lcd_free_pat(int pat)
193{
194 int x, y;
195
196 if (pat != NO_PATTERN)
197 {
198 for (x = 0; x < LCD_WIDTH; x++)
199 for (y = 0; y < LCD_HEIGHT; y++)
200 if (pat == lcd_charbuffer[y][x])
201 lcd_charbuffer[y][x] = lcd_substbuffer[y][x];
202
203 if (lcd_cursor.enabled && pat == lcd_cursor.hw_char)
204 lcd_cursor.hw_char = lcd_cursor.subst_char;
205
206 lcd_patterns[pat].count = 0;
207 }
208}
209
210static int lcd_get_free_pat(int xchar)
211{
212 static int last_used_pat = 0;
213
214 int pat = last_used_pat; /* start from last used pattern */
215 int least_pat = pat; /* pattern with least priority */
216 int least_priority = lcd_patterns[pat].priority;
217 int i;
218
219 for (i = 0; i < lcd_pattern_count; i++)
220 {
221 if (++pat >= lcd_pattern_count) /* Keep 'pat' within limits */
222 pat = 0;
223
224 if (lcd_patterns[pat].count == 0)
225 {
226 last_used_pat = pat;
227 return pat;
228 }
229 if (lcd_patterns[pat].priority < least_priority)
230 {
231 least_priority = lcd_patterns[pat].priority;
232 least_pat = pat;
233 }
234 }
235 if (xchar_info[xchar].priority > least_priority) /* prioritized char */
236 {
237 lcd_free_pat(least_pat);
238 last_used_pat = least_pat;
239 return least_pat;
240 }
241 return NO_PATTERN;
242}
243
244static const unsigned char *glyph_to_pattern(unsigned glyph)
245{
246 if (glyph & 0x8000)
247 return xfont_variable[glyph & 0x7fff];
248 else
249 return xfont_fixed[glyph];
250}
251
252static int map_xchar(int xchar, unsigned char *substitute)
253{
254 int pat;
255 unsigned glyph;
256
257 if (xchar_info[xchar].priority > 0) /* soft char */
258 {
259 glyph = xchar_info[xchar].glyph;
260 pat = glyph_to_pat(glyph);
261
262 if (pat == NO_PATTERN) /* not yet mapped */
263 {
264 pat = lcd_get_free_pat(xchar); /* try to map */
265
266 if (pat == NO_PATTERN) /* failed: just use substitute */
267 return xchar_info[xchar].hw_char;
268 else
269 { /* define pattern */
270 lcd_patterns[pat].priority = xchar_info[xchar].priority;
271 lcd_patterns[pat].glyph = glyph;
272 memcpy(lcd_patterns[pat].pattern, glyph_to_pattern(glyph),
273 HW_PATTERN_SIZE);
274 }
275 }
276 lcd_patterns[pat].count++; /* increase reference count */
277 *substitute = xchar_info[xchar].hw_char;
278 return pat;
279 }
280 else /* hardware char */
281 return xchar_info[xchar].hw_char;
282}
283
284static void lcd_putxchar(int x, int y, int xchar)
285{
286 int lcd_char;
287
288 /* Adjust for viewport */
289 x += current_vp->x;
290 y += current_vp->y;
291
292#if defined(HAVE_VIEWPORT_CLIP)
293 if((unsigned)x > (unsigned)LCD_WIDTH || (unsigned)y > (unsigned)LCD_HEIGHT)
294 return;
295#endif
296
297 lcd_char = lcd_charbuffer[y][x];
298
299 if (lcd_char < lcd_pattern_count) /* old char was soft */
300 lcd_patterns[lcd_char].count--; /* decrease old reference count */
301
302 lcd_charbuffer[y][x] = map_xchar(xchar, &lcd_substbuffer[y][x]);
303}
304
305/** user-definable pattern handling **/
306
307unsigned long lcd_get_locked_pattern(void)
308{
309 int i = 0;
310
311 for (i = 0; i < VARIABLE_XCHARS; i++)
312 {
313 if (!xfont_variable_locked[i])
314 {
315 xfont_variable_locked[i] = true;
316 return 0xe000 + i; /* hard-coded */
317 }
318 }
319 return 0;
320}
321
322void lcd_unlock_pattern(unsigned long ucs)
323{
324 int xchar = find_xchar(ucs);
325 unsigned glyph = xchar_info[xchar].glyph;
326
327 if (glyph & 0x8000) /* variable extended char */
328 {
329 lcd_free_pat(glyph_to_pat(glyph));
330 xfont_variable_locked[glyph & 0x7fff] = false;
331 }
332}
333
334void lcd_define_pattern(unsigned long ucs, const char *pattern)
335{
336 int xchar = find_xchar(ucs);
337 unsigned glyph = xchar_info[xchar].glyph;
338 int pat;
339
340 if (glyph & 0x8000) /* variable extended char */
341 {
342 memcpy(xfont_variable[glyph & 0x7fff], pattern, HW_PATTERN_SIZE);
343 pat = glyph_to_pat(glyph);
344 if (pat != NO_PATTERN)
345 memcpy(lcd_patterns[pat].pattern, pattern, HW_PATTERN_SIZE);
346 }
347}
348
349/** output functions **/
350
351/* Clear the whole display */
352void lcd_clear_display(void)
353{
354 int x, y;
355 struct viewport* old_vp = current_vp;
356
357 lcd_scroll_stop();
358 lcd_remove_cursor();
359
360 /* Set the default viewport - required for lcd_putxchar */
361 current_vp = &default_vp;
362
363 for (x = 0; x < LCD_WIDTH; x++)
364 for (y = 0; y < LCD_HEIGHT; y++)
365 lcd_putxchar(x, y, xspace);
366
367 current_vp = old_vp;
368}
369
370/* Clear the current viewport */
371void lcd_clear_viewport(void)
372{
373 int x, y;
374
375 if (current_vp == &default_vp)
376 {
377 lcd_clear_display();
378 }
379 else
380 {
381 /* Remove the cursor if it is within the current viewport */
382 if (lcd_cursor.enabled &&
383 (lcd_cursor.x >= current_vp->x) &&
384 (lcd_cursor.x <= current_vp->x + current_vp->width) &&
385 (lcd_cursor.y >= current_vp->y) &&
386 (lcd_cursor.y <= current_vp->y + current_vp->height))
387 {
388 lcd_remove_cursor();
389 }
390
391 for (x = 0; x < current_vp->width; x++)
392 for (y = 0; y < current_vp->height; y++)
393 lcd_putxchar(x, y, xspace);
394
395 lcd_scroll_stop_viewport(current_vp);
396 }
397}
398
399/* Put an unicode character at the given position */
400void lcd_putc(int x, int y, unsigned long ucs)
401{
402 if ((unsigned)x >= (unsigned)current_vp->width ||
403 (unsigned)y >= (unsigned)current_vp->height)
404 return;
405
406 lcd_putxchar(x, y, find_xchar(ucs));
407}
408
409/* Show cursor (alternating with existing character) at the given position */
410void lcd_put_cursor(int x, int y, unsigned long cursor_ucs)
411{
412 if ((unsigned)x >= (unsigned)current_vp->width ||
413 (unsigned)y >= (unsigned)current_vp->height ||
414 lcd_cursor.enabled)
415 return;
416
417 lcd_cursor.enabled = true;
418 lcd_cursor.visible = false;
419 lcd_cursor.hw_char = map_xchar(find_xchar(cursor_ucs), &lcd_cursor.subst_char);
420 lcd_cursor.x = current_vp->x + x;
421 lcd_cursor.y = current_vp->y + y;
422 lcd_cursor.downcount = 0;
423 lcd_cursor.divider = MAX((HZ/2) / lcd_scroll_info.ticks, 1);
424}
425
426/* Remove the cursor */
427void lcd_remove_cursor(void)
428{
429 if (lcd_cursor.enabled)
430 {
431 if (lcd_cursor.hw_char < lcd_pattern_count) /* soft char, unmap */
432 lcd_patterns[lcd_cursor.hw_char].count--;
433
434 lcd_cursor.enabled = lcd_cursor.visible = false;
435 }
436}
437
438/* Put a string at a given position, skipping first ofs chars */
439static int lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
440{
441 unsigned short ucs;
442 const unsigned char *utf8 = str;
443
444 while (*utf8 && x < current_vp->width)
445 {
446 utf8 = utf8decode(utf8, &ucs);
447
448 if (ofs > 0)
449 {
450 ofs--;
451 continue;
452 }
453 lcd_putxchar(x++, y, find_xchar(ucs));
454 }
455 return x;
456}
457
458/* Put a string at a given position */
459void lcd_putsxy(int x, int y, const unsigned char *str)
460{
461 if ((unsigned)y >= (unsigned)current_vp->height)
462 return;
463
464 lcd_putsxyofs(x, y, 0, str);
465}
466
467/* Formatting version of lcd_putsxy */
468void lcd_putsxyf(int x, int y, const unsigned char *fmt, ...)
469{
470 va_list ap;
471 char buf[256];
472 va_start(ap, fmt);
473 vsnprintf(buf, sizeof (buf), fmt, ap);
474 va_end(ap);
475 lcd_putsxy(x, y, buf);
476}
477
478/*** Line oriented text output ***/
479
480/* Put a string at a given char position, skipping first offset chars */
481void lcd_putsofs(int x, int y, const unsigned char *str, int offset)
482{
483 if ((unsigned)y >= (unsigned)current_vp->height)
484 return;
485
486 /* make sure scrolling is turned off on the line we are updating */
487 lcd_scroll_stop_viewport_rect(current_vp, x, y, current_vp->width - x, 1);
488
489 x = lcd_putsxyofs(x, y, offset, str);
490 while (x < current_vp->width)
491 lcd_putxchar(x++, y, xspace);
492}
493
494
495/* Put a string at a given char position */
496void lcd_puts(int x, int y, const unsigned char *str)
497{
498 lcd_putsofs(x, y, str, 0);
499}
500
501/* Formatting version of lcd_puts */
502void lcd_putsf(int x, int y, const unsigned char *fmt, ...)
503{
504 va_list ap;
505 char buf[256];
506 va_start(ap, fmt);
507 vsnprintf(buf, sizeof (buf), fmt, ap);
508 va_end(ap);
509 lcd_puts(x, y, buf);
510}
511
512/** scrolling **/
513
514bool lcd_puts_scroll_worker(int x, int y, const unsigned char *string,
515 int offset,
516 void (*scroll_func)(struct scrollinfo *), void *data)
517{
518 struct scrollinfo* s;
519 int len;
520
521 if ((unsigned)y >= (unsigned)current_vp->height)
522 return false;
523
524 /* remove any previously scrolling line at the same location */
525 lcd_scroll_stop_viewport_rect(current_vp, x, y, current_vp->width - x, 1);
526
527 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES)
528 return false;
529
530 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
531
532 s->start_tick = current_tick + lcd_scroll_info.delay;
533
534 lcd_putsofs(x, y, string, offset);
535 len = utf8length(string);
536
537 if (current_vp->width - x >= len)
538 return false;
539 /* prepare scroll line */
540 strlcpy(s->linebuffer, string, sizeof s->linebuffer);
541
542 /* scroll bidirectional or forward only depending on the string width */
543 if (lcd_scroll_info.bidir_limit)
544 {
545 s->bidir = len < (current_vp->width) *
546 (100 + lcd_scroll_info.bidir_limit) / 100;
547 }
548 else
549 s->bidir = false;
550
551 s->scroll_func = scroll_func;
552 s->userdata = data;
553
554 s->vp = current_vp;
555 s->x = x;
556 s->y = y;
557 s->height = 1;
558 s->width = current_vp->width - x;
559 s->offset = offset;
560 s->backward = false;
561 lcd_scroll_info.lines++;
562
563 return true;
564}
565
566bool lcd_putsxy_scroll_func(int x, int y, const unsigned char *string,
567 void (*scroll_func)(struct scrollinfo *),
568 void *data, int x_offset)
569{
570 bool retval = false;
571 if (!scroll_func)
572 lcd_putsxyofs(x, y, x_offset, string);
573 else
574 retval = lcd_puts_scroll_worker(x, y, string, x_offset, scroll_func, data);
575
576 return retval;
577}
578
579static void lcd_scroll_fn(struct scrollinfo* s)
580{
581 /* with line == NULL when scrolling stops. This scroller
582 * maintains no userdata so there is nothing left to do */
583 if (!s->line)
584 return;
585 lcd_putsxyofs(s->x, s->y, s->offset, s->line);
586 if (lcd_cursor.enabled)
587 {
588 if (--lcd_cursor.downcount <= 0)
589 {
590 lcd_cursor.downcount = lcd_cursor.divider;
591 lcd_cursor.visible = !lcd_cursor.visible;
592 }
593 }
594}
595
596bool lcd_puts_scroll(int x, int y, const unsigned char *string)
597{
598 return lcd_puts_scroll_worker(x, y, string, 0, lcd_scroll_fn, NULL);
599}