Changed lcd_drawrect() to use upper left corner and height/width as parameters
[kugel-rb/myfork.git] / firmware / drivers / lcd.c
blob4bdecd41f572201aef1c15cb24f1e17526788139
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Alan Korr
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "config.h"
21 #include "lcd.h"
22 #include "kernel.h"
23 #include "thread.h"
24 #include <string.h>
25 #include <stdlib.h>
26 #include "file.h"
27 #include "debug.h"
28 #include "system.h"
30 #ifdef LOADABLE_FONTS
31 #include "ajf.h"
32 #include "panic.h"
33 #endif
35 #if defined(SIMULATOR)
36 #include "sim_icons.h"
37 #endif
40 /*** definitions ***/
42 #define LCDR (PBDR_ADDR+1)
44 #ifdef HAVE_LCD_CHARCELLS
46 #define LCD_DS 1 // PB0 = 1 --- 0001 --- LCD-DS
47 #define LCD_CS 2 // PB1 = 1 --- 0010 --- /LCD-CS
48 #define LCD_SD 4 // PB2 = 1 --- 0100 --- LCD-SD
49 #define LCD_SC 8 // PB3 = 1 --- 1000 --- LCD-SC
50 #ifdef HAVE_NEW_CHARCELL_LCD
51 # define LCD_CONTRAST_SET ((char)0x50)
52 # define LCD_CRAM ((char)0x80) /* Characters */
53 # define LCD_PRAM ((char)0xC0) /* Patterns */
54 # define LCD_IRAM ((char)0x40) /* Icons */
55 #else
56 # define LCD_CONTRAST_SET ((char)0xA8)
57 # define LCD_CRAM ((char)0xB0) /* Characters */
58 # define LCD_PRAM ((char)0x80) /* Patterns */
59 # define LCD_IRAM ((char)0xE0) /* Icons */
60 #endif
61 #define LCD_CURSOR(x,y) ((char)(LCD_CRAM+((y)*16+(x))))
62 #define LCD_ICON(i) ((char)(LCD_IRAM+i))
64 #elif HAVE_LCD_BITMAP
66 #define LCD_SD 1 // PB0 = 1 --- 0001
67 #define LCD_SC 2 // PB1 = 1 --- 0010
68 #define LCD_RS 4 // PB2 = 1 --- 0100
69 #define LCD_CS 8 // PB3 = 1 --- 1000
70 #define LCD_DS LCD_RS
72 #define LCD_SET_LOWER_COLUMN_ADDRESS ((char)0x00)
73 #define LCD_SET_HIGHER_COLUMN_ADDRESS ((char)0x10)
74 #define LCD_SET_INTERNAL_REGULATOR_RESISTOR_RATIO ((char)0x20)
75 #define LCD_SET_POWER_CONTROL_REGISTER ((char)0x28)
76 #define LCD_SET_DISPLAY_START_LINE ((char)0x40)
77 #define LCD_SET_CONTRAST_CONTROL_REGISTER ((char)0x81)
78 #define LCD_SET_SEGMENT_REMAP ((char)0xA0)
79 #define LCD_SET_LCD_BIAS ((char)0xA2)
80 #define LCD_SET_ENTIRE_DISPLAY_OFF ((char)0xA4)
81 #define LCD_SET_ENTIRE_DISPLAY_ON ((char)0xA5)
82 #define LCD_SET_NORMAL_DISPLAY ((char)0xA6)
83 #define LCD_SET_REVERSE_DISPLAY ((char)0xA7)
84 #define LCD_SET_INDICATOR_OFF ((char)0xAC)
85 #define LCD_SET_INDICATOR_ON ((char)0xAD)
86 #define LCD_SET_DISPLAY_OFF ((char)0xAE)
87 #define LCD_SET_DISPLAY_ON ((char)0xAF)
88 #define LCD_SET_PAGE_ADDRESS ((char)0xB0)
89 #define LCD_SET_COM_OUTPUT_SCAN_DIRECTION ((char)0xC0)
90 #define LCD_SET_DISPLAY_OFFSET ((char)0xD3)
91 #define LCD_SET_READ_MODIFY_WRITE_MODE ((char)0xE0)
92 #define LCD_SOFTWARE_RESET ((char)0xE2)
93 #define LCD_NOP ((char)0xE3)
94 #define LCD_SET_END_OF_READ_MODIFY_WRITE_MODE ((char)0xEE)
96 /* LCD command codes */
97 #define LCD_CNTL_RESET 0xe2 // Software reset
98 #define LCD_CNTL_POWER 0x2f // Power control
99 #define LCD_CNTL_CONTRAST 0x81 // Contrast
100 #define LCD_CNTL_OUTSCAN 0xc8 // Output scan direction
101 #define LCD_CNTL_SEGREMAP 0xa1 // Segment remap
102 #define LCD_CNTL_DISPON 0xaf // Display on
104 #define LCD_CNTL_PAGE 0xb0 // Page address
105 #define LCD_CNTL_HIGHCOL 0x10 // Upper column address
106 #define LCD_CNTL_LOWCOL 0x00 // Lower column address
109 #endif /* CHARCELL or BITMAP */
112 /*** generic code ***/
114 struct scrollinfo {
115 char text[MAX_PATH];
116 char line[32];
117 int textlen;
118 int offset;
119 int startx;
120 int starty;
121 int space;
124 static void scroll_thread(void);
125 static char scroll_stack[DEFAULT_STACK_SIZE];
126 static char scroll_name[] = "scroll";
127 static char scroll_speed = 8; /* updates per second */
128 static char scroll_spacing = 3; /* spaces between end and start of text */
131 static struct scrollinfo scroll; /* only one scroll line at the moment */
132 static int scroll_count = 0;
134 #ifndef SIMULATOR
136 * About /CS,DS,SC,SD
137 * ------------------
139 * LCD on JBP and JBR uses a SPI protocol to receive orders (SDA and SCK lines)
141 * - /CS -> Chip Selection line :
142 * 0 : LCD chipset is activated.
143 * - DS -> Data Selection line, latched at the rising edge
144 * of the 8th serial clock (*) :
145 * 0 : instruction register,
146 * 1 : data register;
147 * - SC -> Serial Clock line (SDA).
148 * - SD -> Serial Data line (SCK), latched at the rising edge
149 * of each serial clock (*).
151 * _ _
152 * /CS \ /
153 * \______________________________________________________/
154 * _____ ____ ____ ____ ____ ____ ____ ____ ____ _____
155 * SD \/ D7 \/ D6 \/ D5 \/ D4 \/ D3 \/ D2 \/ D1 \/ D0 \/
156 * _____/\____/\____/\____/\____/\____/\____/\____/\____/\_____
158 * _____ _ _ _ _ _ _ _ ________
159 * SC \ * \ * \ * \ * \ * \ * \ * \ *
160 * \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
161 * _ _________________________________________________________
162 * DS \/
163 * _/\_________________________________________________________
168 * The only way to do logical operations in an atomic way
169 * on SH1 is using :
171 * or.b/and.b/tst.b/xor.b #imm,@(r0,gbr)
173 * but GCC doesn't generate them at all so some assembly
174 * codes are needed here.
176 * The Global Base Register gbr is expected to be zero
177 * and r0 is the address of one register in the on-chip
178 * peripheral module.
182 #define ASM_IMPLEMENTATION
184 static void lcd_write(bool command, int byte) __attribute__ ((section (".icode")));
185 static void lcd_write(bool command, int byte)
187 #ifdef ASM_IMPLEMENTATION
189 asm("and.b %0, @(r0,gbr)"
191 : /* %0 */ "I"(~(LCD_CS|LCD_DS|LCD_SD|LCD_SC)),
192 /* %1 */ "z"(LCDR));
194 if (command)
195 asm ("shll8 %0\n"
196 "0: \n\t"
197 "and.b %2,@(r0,gbr)\n\t"
198 "shll %0\n\t"
199 "bf 1f\n\t"
200 "or.b %3,@(r0,gbr)\n"
201 "1: \n\t"
202 "or.b %4,@(r0,gbr)\n"
203 "add #-1,%1\n\t"
204 "cmp/pl %1\n\t"
205 "bt 0b"
207 : /* %0 */ "r"(((unsigned)byte)<<16),
208 /* %1 */ "r"(8),
209 /* %2 */ "I"(~(LCD_SC|LCD_SD|LCD_DS)),
210 /* %3 */ "I"(LCD_SD),
211 /* %4 */ "I"(LCD_SC),
212 /* %5 */ "z"(LCDR));
213 else
214 #if 0
215 asm ("shll8 %0\n"
216 "0: \n\t"
217 "and.b %2, @(r0,gbr)\n\t"
218 "shll %0\n\t"
219 "bf 1f\n\t"
220 "or.b %3, @(r0,gbr)\n"
221 "1: \n\t"
222 "or.b %4, @(r0,gbr)\n"
223 "add #-1, %1\n\t"
224 "cmp/pl %1\n\t"
225 "bt 0b"
227 : /* %0 */ "r"(((unsigned)byte)<<16),
228 /* %1 */ "r"(8),
229 /* %2 */ "I"(~(LCD_SC|LCD_SD)),
230 /* %3 */ "I"(LCD_SD|LCD_DS),
231 /* %4 */ "I"(LCD_SC|LCD_DS),
232 /* %5 */ "z"(LCDR));
233 #else
234 asm ("shll8 %0\n"
235 "0: \n\t"
236 "and.b %2, @(r0,gbr)\n\t"
237 "shll %0\n\t"
238 "bf 1f\n\t"
239 "or.b %3, @(r0,gbr)\n"
240 "1: \n\t"
241 "or.b %4, @(r0,gbr)\n"
242 "and.b %2, @(r0,gbr)\n\t"
243 "shll %0\n\t"
244 "bf 1f\n\t"
245 "or.b %3, @(r0,gbr)\n"
246 "1: \n\t"
247 "or.b %4, @(r0,gbr)\n"
248 "and.b %2, @(r0,gbr)\n\t"
249 "shll %0\n\t"
250 "bf 1f\n\t"
251 "or.b %3, @(r0,gbr)\n"
252 "1: \n\t"
253 "or.b %4, @(r0,gbr)\n"
254 "and.b %2, @(r0,gbr)\n\t"
255 "shll %0\n\t"
256 "bf 1f\n\t"
257 "or.b %3, @(r0,gbr)\n"
258 "1: \n\t"
259 "or.b %4, @(r0,gbr)\n"
260 "and.b %2, @(r0,gbr)\n\t"
261 "shll %0\n\t"
262 "bf 1f\n\t"
263 "or.b %3, @(r0,gbr)\n"
264 "1: \n\t"
265 "or.b %4, @(r0,gbr)\n"
266 "and.b %2, @(r0,gbr)\n\t"
267 "shll %0\n\t"
268 "bf 1f\n\t"
269 "or.b %3, @(r0,gbr)\n"
270 "1: \n\t"
271 "or.b %4, @(r0,gbr)\n"
272 "and.b %2, @(r0,gbr)\n\t"
273 "shll %0\n\t"
274 "bf 1f\n\t"
275 "or.b %3, @(r0,gbr)\n"
276 "1: \n\t"
277 "or.b %4, @(r0,gbr)\n"
278 "and.b %2, @(r0,gbr)\n\t"
279 "shll %0\n\t"
280 "bf 1f\n\t"
281 "or.b %3, @(r0,gbr)\n"
282 "1: \n\t"
283 "or.b %4, @(r0,gbr)\n"
285 : /* %0 */ "r"(((unsigned)byte)<<16),
286 /* %1 */ "r"(8),
287 /* %2 */ "I"(~(LCD_SC|LCD_SD)),
288 /* %3 */ "I"(LCD_SD|LCD_DS),
289 /* %4 */ "I"(LCD_SC|LCD_DS),
290 /* %5 */ "z"(LCDR));
291 #endif
293 asm("or.b %0, @(r0,gbr)"
295 : /* %0 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC),
296 /* %1 */ "z"(LCDR));
298 #else
300 int i;
301 char on,off;
303 PBDR &= ~LCD_CS; /* enable lcd chip select */
305 if ( command ) {
306 on=~(LCD_SD|LCD_SC|LCD_DS);
307 off=LCD_SC;
309 else {
310 on=~(LCD_SD|LCD_SC);
311 off=LCD_SC|LCD_DS;
314 /* clock out each bit, MSB first */
315 for (i=0x80;i;i>>=1)
317 PBDR &= on;
318 if (i & byte)
319 PBDR |= LCD_SD;
320 PBDR |= off;
323 PBDR |= LCD_CS; /* disable lcd chip select */
325 #endif /* ASM_IMPLEMENTATION */
326 #endif /* !SIMULATOR */
328 /*** model specific code */
330 #ifdef HAVE_LCD_CHARCELLS
332 #ifdef HAVE_NEW_CHARCELL_LCD
334 static const unsigned char lcd_ascii[] = {
335 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
336 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
337 0x10,0x11,0x05,0x13,0x14,0x15,0x16,0x17,
338 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
339 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
340 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
341 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
342 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
343 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
344 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
345 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
346 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
347 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
348 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
349 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
350 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
351 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
352 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
353 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
354 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
355 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
356 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
357 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,
358 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
359 0x41,0x41,0x41,0x41,0x41,0x41,0x20,0x43,
360 0x45,0x45,0x45,0x45,0x49,0x49,0x49,0x49,
361 0x44,0x4e,0x4f,0x4f,0x4f,0x4f,0x4f,0x20,
362 0x20,0x55,0x55,0x55,0x55,0x59,0x20,0x20,
363 0x61,0x61,0x61,0x61,0x61,0x61,0x20,0x63,
364 0x65,0x65,0x65,0x65,0x69,0x69,0x69,0x69,
365 0x6f,0x6e,0x6f,0x6f,0x6f,0x6f,0x6f,0x20,
366 0x20,0x75,0x75,0x75,0x75,0x79,0x20,0x79
369 #else
371 static const unsigned char lcd_ascii[] = {
372 0x00,0x01,0x02,0x03,0x00,0x84,0x85,0x89,
373 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
374 0xec,0xe3,0xe2,0xe1,0xe0,0xdf,0x15,0x00,
375 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
376 0x24,0x25,0x26,0x37,0x06,0x29,0x2a,0x2b,
377 0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,
378 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,
379 0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,
380 0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,
381 0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,
382 0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,
383 0x5c,0x5d,0x5e,0xa9,0x33,0xce,0x00,0x15,
384 0x00,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,
385 0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,
386 0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,
387 0x7c,0x7d,0x7e,0x24,0x24,0x24,0x24,0x24,
388 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
389 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
390 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
391 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
392 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
393 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
394 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,
395 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
396 0x45,0x45,0x45,0x45,0x45,0x45,0x24,0x47,
397 0x49,0x49,0x49,0x49,0x4d,0x4d,0x4d,0x4d,
398 0x48,0x52,0x53,0x53,0x53,0x53,0x53,0x24,
399 0x24,0x59,0x59,0x59,0x59,0x5d,0x24,0x24,
400 0x65,0x65,0x65,0x65,0x65,0x65,0x24,0x67,
401 0x69,0x69,0x69,0x69,0x6d,0x6d,0x6d,0x6d,
402 0x73,0x72,0x73,0x73,0x73,0x73,0x73,0x24,
403 0x24,0x79,0x79,0x79,0x79,0x7d,0x24,0x7d
405 #endif /* HAVE_NEW_CHARCELL_LCD */
407 #ifndef SIMULATOR
408 void lcd_clear_display(void)
410 int i;
411 lcd_write(true,LCD_CURSOR(0,0));
412 for (i=0;i<32;i++)
413 lcd_write(false,lcd_ascii[' ']);
416 void lcd_puts(int x, int y, unsigned char *string)
418 lcd_write(true,LCD_CURSOR(x,y));
419 while (*string && x++<11)
420 lcd_write(false,lcd_ascii[*(unsigned char*)string++]);
423 void lcd_define_pattern (int which,char *pattern,int length)
425 int i;
426 lcd_write(true,LCD_PRAM|which);
427 for (i=0;i<length;i++)
428 lcd_write(false,pattern[i]);
431 void lcd_double_height(bool on)
433 lcd_write(true,on?9:8);
436 static char icon_pos[] =
438 0, 0, 0, 0, /* Battery */
439 2, /* USB */
440 3, /* Play */
441 4, /* Record */
442 5, /* Pause */
443 5, /* Audio */
444 6, /* Repeat */
445 7, /* 1 */
446 9, /* Volume */
447 9, /* Volume 1 */
448 9, /* Volume 2 */
449 10, /* Volume 3 */
450 10, /* Volume 4 */
451 10, /* Volume 5 */
452 10, /* Param */
455 static char icon_mask[] =
457 0x02, 0x08, 0x04, 0x10, /* Battery */
458 0x04, /* USB */
459 0x10, /* Play */
460 0x10, /* Record */
461 0x02, /* Pause */
462 0x10, /* Audio */
463 0x02, /* Repeat */
464 0x01, /* 1 */
465 0x04, /* Volume */
466 0x02, /* Volume 1 */
467 0x01, /* Volume 2 */
468 0x08, /* Volume 3 */
469 0x04, /* Volume 4 */
470 0x01, /* Volume 5 */
471 0x10, /* Param */
474 void lcd_icon(int icon, bool enable)
476 static unsigned char icon_mirror[11] = {0};
477 int pos, mask;
479 pos = icon_pos[icon];
480 mask = icon_mask[icon];
482 lcd_write(true, LCD_ICON(pos));
484 if(enable)
485 icon_mirror[pos] |= mask;
486 else
487 icon_mirror[pos] &= ~mask;
489 lcd_write(false, icon_mirror[pos]);
491 #endif /* !SIMULATOR */
493 #endif /* HAVE_LCD_CHARCELLS */
495 #if defined(SIMULATOR) && defined(HAVE_LCD_CHARCELLS)
496 void lcd_icon(int icon, bool enable)
498 sim_lcd_icon(icon, enable);
500 #endif
502 #if defined(HAVE_LCD_CHARCELLS) || defined(SIMULATOR) /* not BITMAP */
503 void lcd_init (void)
505 create_thread(scroll_thread, scroll_stack,
506 sizeof(scroll_stack), scroll_name);
507 #if defined(LOADABLE_FONTS) && defined(SIMULATOR)
508 lcd_init_fonts();
509 #endif
511 #endif
513 #ifdef SIMULATOR
514 void lcd_set_contrast(int val)
516 val = val;
518 #else
519 #ifdef HAVE_LCD_BITMAP
520 void lcd_set_contrast(int val)
522 lcd_write(true, LCD_CNTL_CONTRAST);
523 lcd_write(true, val);
525 #else
526 void lcd_set_contrast(int val)
528 lcd_write(true, LCD_CONTRAST_SET);
529 lcd_write(false, 31-val);
531 #endif
532 #endif
534 #if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR) /* not CHARCELLS */
537 * All bitmaps have this format:
538 * Bits within a byte are arranged veritcally, LSB at top.
539 * Bytes are stored in column-major format, with byte 0 at top left,
540 * byte 1 is 2nd from top, etc. Bytes following left-most column
541 * starts 2nd left column, etc.
543 * Note: The HW takes bitmap bytes in row-major order.
545 * Memory copy of display bitmap
547 unsigned char lcd_framebuffer[LCD_WIDTH][LCD_HEIGHT/8] __attribute__ ((section (".idata")));
549 static int font=0;
550 static int xmargin=0;
551 static int ymargin=0;
554 * ASCII character generation tables
556 * This contains only the printable characters (0x20-0x7f).
557 * Each element in this table is a character pattern bitmap.
559 #define ASCII_MIN 0x20 /* First char in table */
560 #define ASCII_MAX 0x7f /* Last char in table */
562 extern unsigned char char_gen_6x8[][5];
563 extern unsigned char char_gen_8x12[][14];
564 extern unsigned char char_gen_12x16[][22];
566 /* All zeros and ones bitmaps for area filling */
567 static unsigned char zeros[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00 };
569 static unsigned char ones[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
570 0xff, 0xff };
571 static char fonts[] = { 6,8,12 };
572 static char fontheight[] = { 8,12,16 };
574 #ifndef SIMULATOR
577 * Initialize LCD
579 void lcd_init (void)
581 /* Initialize PB0-3 as output pins */
582 PBCR2 &= 0xff00; /* MD = 00 */
583 PBIOR |= 0x000f; /* IOR = 1 */
585 lcd_clear_display();
586 lcd_update();
587 create_thread(scroll_thread, scroll_stack,
588 sizeof(scroll_stack), scroll_name);
592 * Update the display.
593 * This must be called after all other LCD functions that change the display.
595 void lcd_update (void) __attribute__ ((section (".icode")));
596 void lcd_update (void)
598 int x, y;
600 /* Copy display bitmap to hardware */
601 for (y = 0; y < LCD_HEIGHT/8; y++)
603 lcd_write (true, LCD_CNTL_PAGE | (y & 0xf));
604 lcd_write (true, LCD_CNTL_HIGHCOL);
605 lcd_write (true, LCD_CNTL_LOWCOL);
607 for (x = 0; x < LCD_WIDTH; x++)
608 lcd_write (false, lcd_framebuffer[x][y]);
613 * Update a fraction of the display.
615 void lcd_update_rect (int, int, int, int) __attribute__ ((section (".icode")));
616 void lcd_update_rect (int x_start, int y,
617 int width, int height)
619 int ymax;
620 int xmax;
621 int x;
623 /* The Y coordinates have to work on even 8 pixel rows */
624 ymax = (y + height)/8;
625 y /= 8;
627 xmax = x_start + width;
629 if(xmax > LCD_WIDTH)
630 xmax = LCD_WIDTH;
631 if(ymax >= LCD_HEIGHT/8)
632 ymax = LCD_HEIGHT/8-1;
634 /* Copy specified rectange bitmap to hardware */
635 for (; y <= ymax; y++)
637 lcd_write (true, LCD_CNTL_PAGE | (y & 0xf));
638 lcd_write (true, LCD_CNTL_HIGHCOL | ((x_start>>4) & 0xf));
639 lcd_write (true, LCD_CNTL_LOWCOL | (x_start & 0xf));
641 for (x = x_start; x < xmax; x++)
642 lcd_write (false, lcd_framebuffer[x][y]);
646 #endif /* SIMULATOR */
649 * Clear the display
651 void lcd_clear_display (void)
653 #if defined(SIMULATOR) && defined(HAVE_LCD_CHARCELLS)
654 /* Clear just the text portion of the display */
655 int x, y;
656 for (y = 8; y <= (32 + 7); ++y)
658 for (x = 0; x < LCD_WIDTH; x++)
659 CLEAR_PIXEL(x, y);
661 /* this function is being used when simulating a charcell LCD and
662 then we update immediately */
663 lcd_update();
664 #else
665 memset (lcd_framebuffer, 0, sizeof lcd_framebuffer);
666 #endif
669 void lcd_setfont(int newfont)
671 font = newfont;
674 void lcd_setmargins(int x, int y)
676 xmargin = x;
677 ymargin = y;
680 int lcd_getxmargin(void)
682 return xmargin;
685 int lcd_getymargin(void)
687 return ymargin;
692 #ifdef LOADABLE_FONTS
694 static unsigned char* _font = NULL;
696 int lcd_init_fonts(void)
698 if (!_font)
699 _font = ajf_read_font("/system.ajf");
701 if (!_font)
703 lcd_putsxy(0,0,"No font", 0);
704 return -1;
707 return 0;
710 void lcd_setldfont(unsigned char* f)
712 _font = f;
715 unsigned char* lcd_getcurrentldfont()
717 if (!_font)
718 panicf("No font loaded!");
719 return _font;
723 * Return width and height of a string with a given font.
725 int lcd_getstringsize(unsigned char *str, unsigned char* font, int *w, int *h)
727 int width=0;
728 int height=0;
729 unsigned char ch;
731 if (!font)
732 panicf("No font specified");
734 while((ch = *str++))
736 int dw,dh;
737 ajf_get_charsize(ch, font, &dw, &dh);
738 if (dh>height)
739 height = dh;
740 width+=dw;
742 *w = width;
743 *h = height;
745 return width;
749 * Put a string at specified bit position
752 void lcd_putsldfxy(int x, int y, unsigned char *str)
754 unsigned char ch;
755 int nx;
756 int ny=8;
757 int lcd_x = x;
758 int lcd_y = y;
759 if (!_font)
761 lcd_putsxy(0,0,"No font", 0);
762 return;
764 ny = (int)_font[2];
765 while (((ch = *str++) != '\0'))
767 unsigned char *char_buf = ajf_get_charbuf(ch, _font, &nx, &ny);
768 if (!char_buf)
770 char_buf = ajf_get_charbuf('?', _font, &nx, &ny);
771 if (!char_buf)
772 panicf("Bad font");
774 if(lcd_x + nx > LCD_WIDTH)
775 break;
777 lcd_bitmap (&char_buf[0], lcd_x, lcd_y, nx, ny, true);
778 lcd_x += nx;
781 #endif
784 #ifdef LCD_PROPFONTS
786 extern unsigned char char_dw_8x8_prop[][9];
789 * Return width and height of a given font.
791 int lcd_getstringsize(unsigned char *str, unsigned int font, int *w, int *h)
793 int width=0;
794 int height=0;
795 unsigned char ch, byte;
796 (void)font;
798 while((ch = *str++)) {
799 /* Limit to char generation table */
800 if (ch < ASCII_MIN)
801 /* replace unsupported letters with question marks */
802 ch = ' '-ASCII_MIN;
803 else
804 ch -= ASCII_MIN;
806 byte = char_dw_8x8_prop[ch][8];
807 width += (byte>>4) + 1;
808 if((byte & 0x0f) > height)
809 height = byte & 0x0f;
812 *w = width;
813 *h = height;
815 return width;
819 * Put a string at specified bit position
822 void lcd_putspropxy(int x, int y, unsigned char *str, int thisfont)
824 unsigned int ch;
825 int nx;
826 int ny=8;
827 unsigned char *src;
828 int lcd_x = x;
829 int lcd_y = y;
831 (void)thisfont;
833 while (((ch = *str++) != '\0'))
835 /* Limit to char generation table */
836 if (ch < ASCII_MIN)
837 /* replace unsupported letters with question marks */
838 ch = ' '-ASCII_MIN;
839 else
840 ch -= ASCII_MIN;
842 nx = char_dw_8x8_prop[ch][8] >> 4;
844 if(lcd_x + nx > LCD_WIDTH)
845 break;
847 src = char_dw_8x8_prop[ch];
848 lcd_clearrect (lcd_x+nx, lcd_y, 1, ny);
849 lcd_bitmap (src, lcd_x, lcd_y, nx, ny, true);
851 lcd_x += nx+1;
855 #endif
858 * Put a string at specified character position
860 void lcd_puts(int x, int y, unsigned char *str)
862 #if defined(SIMULATOR) && defined(HAVE_LCD_CHARCELLS)
863 /* We make the simulator truncate the string if it reaches the right edge,
864 as otherwise it'll wrap. The real target doesn't wrap. */
866 char buffer[12];
867 if(strlen(str)+x > 11 ) {
868 strncpy(buffer, str, sizeof buffer);
869 buffer[11-x]=0;
870 str = buffer;
872 xmargin = 0;
873 ymargin = 8;
874 #endif
876 if(!str || !str[0])
877 return;
879 #ifdef LCD_PROPFONTS
880 lcd_putspropxy( xmargin + x*fonts[font],
881 ymargin + y*fontheight[font],
882 str, font );
883 #elif LOADABLE_FONTS
885 int w,h;
886 lcd_getstringsize(str,_font,&w,&h);
887 lcd_putsldfxy( xmargin + x*w/strlen(str), ymargin + y*h, str );
889 #else
890 lcd_putsxy( xmargin + x*fonts[font],
891 ymargin + y*fontheight[font],
892 str, font );
893 #endif
894 #if defined(SIMULATOR) && defined(HAVE_LCD_CHARCELLS)
895 /* this function is being used when simulating a charcell LCD and
896 then we update immediately */
897 lcd_update();
898 #endif
903 * Put a string at specified bit position
905 void lcd_putsxy(int x, int y, unsigned char *str, int thisfont)
907 #ifdef LCD_PROPFONTS
908 lcd_putspropxy(x,y,str,thisfont);
909 #else
911 int nx = fonts[thisfont];
912 int ny = fontheight[thisfont];
913 int ch;
914 unsigned char *src;
915 int lcd_x = x;
916 int lcd_y = y;
918 #ifdef LOADABLE_FONTS
919 if ( _font ) {
920 lcd_putsldfxy(x,y,str);
921 return;
923 #endif
925 while (((ch = *str++) != '\0') && (lcd_x + nx < LCD_WIDTH))
927 if (lcd_y + ny > LCD_HEIGHT)
928 return;
930 /* Limit to char generation table */
931 if ((ch < ASCII_MIN) || (ch > ASCII_MAX))
932 /* replace unsupported letters with question marks */
933 ch = '?' - ASCII_MIN;
934 else
935 ch -= ASCII_MIN;
937 if (thisfont == 2)
938 src = char_gen_12x16[ch];
939 else if (thisfont == 1)
940 src = char_gen_8x12[ch];
941 else
942 src = char_gen_6x8[ch];
944 lcd_bitmap (src, lcd_x, lcd_y, nx-1, ny, true);
945 lcd_bitmap (zeros, lcd_x+nx-1, lcd_y, 1, ny, true);
947 lcd_x += nx;
950 #endif
954 * Display a bitmap at (x, y), size (nx, ny)
955 * clear is true to clear destination area first
957 void lcd_bitmap (unsigned char *src, int x, int y, int nx, int ny,
958 bool clear) __attribute__ ((section (".icode")));
959 void lcd_bitmap (unsigned char *src, int x, int y, int nx, int ny,
960 bool clear)
962 unsigned char *dst;
963 unsigned char *dst2;
964 unsigned int data, mask, mask2, mask3, mask4;
965 int shift;
967 if (((unsigned)x >= LCD_WIDTH) || ((unsigned)y >= LCD_HEIGHT))
968 return;
969 if (((unsigned)(x + nx)) >= LCD_WIDTH)
970 nx = LCD_WIDTH - x;
971 if (((unsigned)(y + ny)) >= LCD_HEIGHT)
972 ny = LCD_HEIGHT - y;
974 shift = y & 7;
975 dst2 = &lcd_framebuffer[x][y/8];
976 ny += shift;
978 /* Calculate bit masks */
979 mask4 = ~(0xfe << ((ny-1) & 7));
980 if (clear)
982 mask = ~(0xff << shift);
983 mask2 = 0;
984 mask3 = ~mask4;
985 if (ny <= 8)
986 mask3 |= mask;
988 else
989 mask = mask2 = mask3 = 0xff;
991 /* Loop for each column */
992 for (x = 0; x < nx; x++)
994 dst = dst2;
995 dst2 += LCD_HEIGHT/8;
996 data = 0;
997 y = 0;
999 if (ny > 8)
1001 /* First partial row */
1002 data = *src++ << shift;
1003 *dst = (*dst & mask) | data;
1004 data >>= 8;
1005 dst++;
1007 /* Intermediate rows */
1008 for (y = 8; y < ny-8; y += 8)
1010 data |= *src++ << shift;
1011 *dst = (*dst & mask2) | data;
1012 data >>= 8;
1013 dst++;
1017 /* Last partial row */
1018 if (y + shift < ny)
1019 data |= *src++ << shift;
1020 *dst = (*dst & mask3) | (data & mask4);
1025 * Draw a rectangle with point a (upper left) at (x, y)
1026 * and size (nx, ny)
1028 void lcd_drawrect (int x, int y, int nx, int ny)
1030 int i;
1032 if (x > LCD_WIDTH)
1033 return;
1034 if (y > LCD_HEIGHT)
1035 return;
1037 if (x + nx > LCD_WIDTH)
1038 nx = LCD_WIDTH - x;
1039 if (y + ny > LCD_HEIGHT)
1040 ny = LCD_HEIGHT - y;
1042 /* vertical lines */
1043 for (i = 0; i < ny; i++) {
1044 DRAW_PIXEL(x, (y + i));
1045 DRAW_PIXEL((x + nx - 1), (y + i));
1048 /* horizontal lines */
1049 for (i = 0; i < nx; i++) {
1050 DRAW_PIXEL((x + i),y);
1051 DRAW_PIXEL((x + i),(y + ny - 1));
1056 * Clear a rectangular area at (x, y), size (nx, ny)
1058 void lcd_clearrect (int x, int y, int nx, int ny)
1060 int i;
1061 for (i = 0; i < nx; i++)
1062 lcd_bitmap (zeros, x+i, y, 1, ny, true);
1066 * Fill a rectangular area at (x, y), size (nx, ny)
1068 void lcd_fillrect (int x, int y, int nx, int ny)
1070 int i;
1071 for (i = 0; i < nx; i++)
1072 lcd_bitmap (ones, x+i, y, 1, ny, true);
1075 /* Invert a rectangular area at (x, y), size (nx, ny) */
1076 void lcd_invertrect (int x, int y, int nx, int ny)
1078 int i, j;
1080 if (x > LCD_WIDTH)
1081 return;
1082 if (y > LCD_HEIGHT)
1083 return;
1085 if (x + nx > LCD_WIDTH)
1086 nx = LCD_WIDTH - x;
1087 if (y + ny > LCD_HEIGHT)
1088 ny = LCD_HEIGHT - y;
1090 for (i = 0; i < nx; i++)
1091 for (j = 0; j < ny; j++)
1092 INVERT_PIXEL((x + i), (y + j));
1095 void lcd_drawline( int x1, int y1, int x2, int y2 )
1097 int numpixels;
1098 int i;
1099 int deltax, deltay;
1100 int d, dinc1, dinc2;
1101 int x, xinc1, xinc2;
1102 int y, yinc1, yinc2;
1104 deltax = abs(x2 - x1);
1105 deltay = abs(y2 - y1);
1107 if(deltax >= deltay)
1109 numpixels = deltax;
1110 d = 2 * deltay - deltax;
1111 dinc1 = deltay * 2;
1112 dinc2 = (deltay - deltax) * 2;
1113 xinc1 = 1;
1114 xinc2 = 1;
1115 yinc1 = 0;
1116 yinc2 = 1;
1118 else
1120 numpixels = deltay;
1121 d = 2 * deltax - deltay;
1122 dinc1 = deltax * 2;
1123 dinc2 = (deltax - deltay) * 2;
1124 xinc1 = 0;
1125 xinc2 = 1;
1126 yinc1 = 1;
1127 yinc2 = 1;
1129 numpixels++; /* include endpoints */
1131 if(x1 > x2)
1133 xinc1 = -xinc1;
1134 xinc2 = -xinc2;
1137 if(y1 > y2)
1139 yinc1 = -yinc1;
1140 yinc2 = -yinc2;
1143 x = x1;
1144 y = y1;
1146 for(i=0; i<numpixels; i++)
1148 DRAW_PIXEL(x,y);
1150 if(d < 0)
1152 d += dinc1;
1153 x += xinc1;
1154 y += yinc1;
1156 else
1158 d += dinc2;
1159 x += xinc2;
1160 y += yinc2;
1165 void lcd_clearline( int x1, int y1, int x2, int y2 )
1167 int numpixels;
1168 int i;
1169 int deltax, deltay;
1170 int d, dinc1, dinc2;
1171 int x, xinc1, xinc2;
1172 int y, yinc1, yinc2;
1174 deltax = abs(x2 - x1);
1175 deltay = abs(y2 - y1);
1177 if(deltax >= deltay)
1179 numpixels = deltax;
1180 d = 2 * deltay - deltax;
1181 dinc1 = deltay * 2;
1182 dinc2 = (deltay - deltax) * 2;
1183 xinc1 = 1;
1184 xinc2 = 1;
1185 yinc1 = 0;
1186 yinc2 = 1;
1188 else
1190 numpixels = deltay;
1191 d = 2 * deltax - deltay;
1192 dinc1 = deltax * 2;
1193 dinc2 = (deltax - deltay) * 2;
1194 xinc1 = 0;
1195 xinc2 = 1;
1196 yinc1 = 1;
1197 yinc2 = 1;
1199 numpixels++; /* include endpoints */
1201 if(x1 > x2)
1203 xinc1 = -xinc1;
1204 xinc2 = -xinc2;
1207 if(y1 > y2)
1209 yinc1 = -yinc1;
1210 yinc2 = -yinc2;
1213 x = x1;
1214 y = y1;
1216 for(i=0; i<numpixels; i++)
1218 CLEAR_PIXEL(x,y);
1220 if(d < 0)
1222 d += dinc1;
1223 x += xinc1;
1224 y += yinc1;
1226 else
1228 d += dinc2;
1229 x += xinc2;
1230 y += yinc2;
1236 * Set a single pixel
1238 void lcd_drawpixel(int x, int y)
1240 DRAW_PIXEL(x,y);
1244 * Clear a single pixel
1246 void lcd_clearpixel(int x, int y)
1248 CLEAR_PIXEL(x,y);
1252 * Invert a single pixel
1254 void lcd_invertpixel(int x, int y)
1256 INVERT_PIXEL(x,y);
1260 * Return width and height of a given font.
1262 void lcd_getfontsize(unsigned int font, int *width, int *height)
1264 if(font < sizeof(fonts)) {
1265 *width = fonts[font];
1266 *height = fontheight[font];
1270 #else
1271 /* no LCD defined, no code to use */
1272 #endif
1274 void lcd_puts_scroll(int x, int y, unsigned char* string )
1276 struct scrollinfo* s = &scroll;
1277 #ifdef HAVE_LCD_CHARCELLS
1278 s->space = 11 - x;
1279 #else
1281 #if defined(LCD_PROPFONTS) || defined(LOADABLE_FONTS)
1282 unsigned char ch[2];
1283 int w, h;
1284 #endif
1285 int width, height;
1286 lcd_getfontsize(font, &width, &height);
1287 #if defined(LCD_PROPFONTS) || defined(LOADABLE_FONTS)
1288 ch[1] = 0; /* zero terminate */
1289 ch[0] = string[0];
1290 width = 0;
1291 s->space = 0;
1292 while ( ch[0] &&
1293 #ifdef LCD_PROPFONTS
1294 (width + lcd_getstringsize(ch, 0, &w, &h) <
1295 (LCD_WIDTH - x*8))) {
1296 #else
1297 (width + lcd_getstringsize(ch, _font, &w, &h) <
1298 (LCD_WIDTH - x*8))) {
1299 #endif
1300 width += w;
1301 s->space++;
1302 ch[0]=string[s->space];
1304 #else
1305 s->space = (LCD_WIDTH - xmargin - x*width) / width;
1306 #endif
1307 #endif
1309 lcd_puts(x,y,string);
1310 s->textlen = strlen(string);
1313 #if defined(LCD_PROPFONTS)
1314 s->space += 2;
1315 lcd_getstringsize(string,0,&w,&h);
1316 if ( w > LCD_WIDTH - xmargin ) {
1317 #elif defined(LOADABLE_FONTS)
1318 s->space += 2;
1319 lcd_getstringsize(string,_font,&w,&h);
1320 if ( w > LCD_WIDTH - xmargin ) {
1321 #else
1322 if ( s->textlen > s->space ) {
1323 #endif
1324 s->offset=s->space;
1325 s->startx=x;
1326 s->starty=y;
1327 strncpy(s->text,string,sizeof s->text);
1328 s->text[sizeof s->text - 1] = 0;
1329 memset(s->line, 0, sizeof s->line);
1330 strncpy(s->line,string,
1331 s->space > (int)sizeof s->line ?
1332 (int)sizeof s->line : s->space );
1333 s->line[sizeof s->line - 1] = 0;
1334 scroll_count = 1;
1338 void lcd_stop_scroll(void)
1340 if ( scroll_count ) {
1341 struct scrollinfo* s = &scroll;
1342 scroll_count = 0;
1344 #ifdef LCD_PROPFONTS
1346 lcd_clearrect(xmargin + s->startx*fonts[font],
1347 ymargin + s->starty*fontheight[font],
1348 LCD_WIDTH - xmargin,
1349 fontheight[font]);
1351 #elif defined(LOADABLE_FONTS)
1353 int w,h;
1354 lcd_getstringsize( s->text, _font, &w, &h);
1355 lcd_clearrect(xmargin + s->startx*w/s->textlen,
1356 ymargin + s->starty*h,
1357 LCD_WIDTH - xmargin,
1361 #endif
1364 /* restore scrolled row */
1365 lcd_puts(s->startx,s->starty,s->text);
1366 lcd_update();
1370 void lcd_scroll_pause(void)
1372 scroll_count = 0;
1375 void lcd_scroll_resume(void)
1377 scroll_count = 1;
1380 void lcd_scroll_speed(int speed)
1382 scroll_speed = speed;
1385 static void scroll_thread(void)
1387 struct scrollinfo* s = &scroll;
1389 while ( 1 ) {
1390 if ( !scroll_count ) {
1391 yield();
1392 continue;
1394 /* wait 0.5s before starting scroll */
1395 if ( scroll_count < scroll_speed/2 )
1396 scroll_count++;
1397 else {
1398 int i;
1399 for ( i=0; i<s->space-1; i++ )
1400 s->line[i] = s->line[i+1];
1402 if ( s->offset < s->textlen ) {
1403 s->line[(int)s->space - 1] = s->text[(int)s->offset];
1404 s->offset++;
1406 else {
1407 s->line[s->space - 1] = ' ';
1408 if ( s->offset < s->textlen + scroll_spacing - 1 )
1409 s->offset++;
1410 else
1411 s->offset = 0;
1414 #ifdef LCD_PROPFONTS
1415 lcd_clearrect(xmargin + s->startx*fonts[font],
1416 ymargin + s->starty*fontheight[font],
1417 LCD_WIDTH - xmargin,
1418 fontheight[font]);
1419 #elif defined(LOADABLE_FONTS)
1421 int w,h;
1422 lcd_getstringsize( s->text, _font, &w, &h);
1423 lcd_clearrect(xmargin + s->startx*w/s->textlen,
1424 ymargin + s->starty*h,
1425 LCD_WIDTH - xmargin,
1428 #endif
1429 lcd_puts(s->startx,s->starty,s->line);
1430 lcd_update();
1432 sleep(HZ/scroll_speed);
1437 /* -----------------------------------------------------------------
1438 * local variables:
1439 * eval: (load-file "../rockbox-mode.el")
1440 * end: