| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2002 by Daniel Stenberg <daniel@haxx.se> |
| * |
| * All files in this archive are subject to the GNU General Public License. |
| * See the file COPYING in the source tree root for full license agreement. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| /* |
| * This file is meant for generic LCD defines and global variables etc. |
| */ |
| |
| #include "lcd.h" |
| #ifdef LCD_DEBUG |
| #include <stdio.h> |
| |
| #define PRINT(x) printf x |
| #else |
| #define PRINT(x) |
| #endif |
| |
| |
| #define DISP_X LCD_WIDTH /* Display width in pixels */ |
| #define DISP_Y LCD_HEIGHT /* Display height in pixels */ |
| |
| #define CHAR_X 6 /* Character width in pixels */ |
| #define CHAR_Y 8 /* Character height in pixels */ |
| #define COL_MASK 0xff /* Character column pixels changed */ |
| |
| /* |
| * ASCII character generation table |
| * |
| * This contains only the printable characters (0x20-0x7f). |
| * Each row in this table is a 5x8 pixel character pattern. |
| * Each byte is a column of pixels, with the top pixel in the LSB. |
| */ |
| #define ASCII_MIN 0x20 /* First char in table */ |
| #define ASCII_MAX 0x7f /* Last char in table */ |
| |
| static const unsigned char lcd_font_data[ASCII_MAX-ASCII_MIN+1][CHAR_X-1] = |
| { |
| 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x2f */ |
| 0x00, 0x00, 0x4f, 0x00, 0x00, |
| 0x00, 0x07, 0x00, 0x07, 0x00, |
| 0x14, 0x7f, 0x14, 0x7f, 0x14, |
| 0x24, 0x2a, 0x7f, 0x2a, 0x12, |
| 0x23, 0x13, 0x08, 0x64, 0x62, |
| 0x36, 0x49, 0x55, 0x22, 0x50, |
| 0x00, 0x05, 0x03, 0x00, 0x00, |
| 0x00, 0x1c, 0x22, 0x41, 0x00, |
| 0x00, 0x41, 0x22, 0x1c, 0x00, |
| 0x14, 0x08, 0x3e, 0x08, 0x14, |
| 0x08, 0x08, 0x3e, 0x08, 0x08, |
| 0x00, 0xa0, 0x60, 0x00, 0x00, |
| 0x08, 0x08, 0x08, 0x08, 0x08, |
| 0x00, 0x60, 0x60, 0x00, 0x00, |
| 0x20, 0x10, 0x08, 0x04, 0x02, |
| |
| 0x3e, 0x51, 0x49, 0x45, 0x3e, /* 0x30-0x3f */ |
| 0x00, 0x42, 0x7f, 0x40, 0x00, |
| 0x42, 0x61, 0x51, 0x49, 0x46, |
| 0x21, 0x41, 0x45, 0x4b, 0x31, |
| 0x18, 0x14, 0x12, 0x7f, 0x10, |
| 0x27, 0x45, 0x45, 0x45, 0x39, |
| 0x3c, 0x4a, 0x49, 0x49, 0x30, |
| 0x01, 0x71, 0x09, 0x05, 0x03, |
| 0x36, 0x49, 0x49, 0x49, 0x36, |
| 0x06, 0x49, 0x49, 0x29, 0x1e, |
| 0x00, 0x6c, 0x6c, 0x00, 0x00, |
| 0x00, 0xac, 0x6c, 0x00, 0x00, |
| 0x08, 0x14, 0x22, 0x41, 0x00, |
| 0x14, 0x14, 0x14, 0x14, 0x14, |
| 0x00, 0x41, 0x22, 0x14, 0x08, |
| 0x02, 0x01, 0x51, 0x09, 0x06, |
| |
| 0x32, 0x49, 0x79, 0x41, 0x3e, /* 0x40-0x4f */ |
| 0x7e, 0x11, 0x11, 0x11, 0x7e, |
| 0x7f, 0x49, 0x49, 0x49, 0x36, |
| 0x3e, 0x41, 0x41, 0x41, 0x22, |
| 0x7f, 0x41, 0x41, 0x22, 0x1c, |
| 0x7f, 0x49, 0x49, 0x49, 0x41, |
| 0x7f, 0x09, 0x09, 0x09, 0x01, |
| 0x3e, 0x41, 0x49, 0x49, 0x7a, |
| 0x7f, 0x08, 0x08, 0x08, 0x7f, |
| 0x00, 0x41, 0x7f, 0x41, 0x00, |
| 0x20, 0x40, 0x41, 0x3f, 0x01, |
| 0x7f, 0x08, 0x14, 0x22, 0x41, |
| 0x7f, 0x40, 0x40, 0x40, 0x40, |
| 0x7f, 0x02, 0x0c, 0x02, 0x7f, |
| 0x7f, 0x04, 0x08, 0x10, 0x7f, |
| 0x3e, 0x41, 0x41, 0x41, 0x3e, |
| |
| 0x7f, 0x09, 0x09, 0x09, 0x06, /* 0x50-0x5f */ |
| 0x3e, 0x41, 0x51, 0x21, 0x5e, |
| 0x7f, 0x09, 0x19, 0x29, 0x46, |
| 0x46, 0x49, 0x49, 0x49, 0x31, |
| 0x01, 0x01, 0x7f, 0x01, 0x01, |
| 0x3f, 0x40, 0x40, 0x40, 0x3f, |
| 0x1f, 0x20, 0x40, 0x20, 0x1f, |
| 0x3f, 0x40, 0x38, 0x40, 0x3f, |
| 0x63, 0x14, 0x08, 0x14, 0x63, |
| 0x07, 0x08, 0x70, 0x08, 0x07, |
| 0x71, 0x51, 0x49, 0x45, 0x43, |
| 0x00, 0x7f, 0x41, 0x41, 0x00, |
| 0x02, 0x04, 0x08, 0x10, 0x20, |
| 0x00, 0x41, 0x41, 0x7f, 0x00, |
| 0x04, 0x02, 0x01, 0x02, 0x04, |
| 0x40, 0x40, 0x40, 0x40, 0x40, |
| |
| 0x00, 0x01, 0x02, 0x04, 0x00, /* 0x60-0x6f */ |
| 0x20, 0x54, 0x54, 0x54, 0x78, |
| 0x7f, 0x48, 0x44, 0x44, 0x38, |
| 0x38, 0x44, 0x44, 0x44, 0x20, |
| 0x38, 0x44, 0x44, 0x48, 0x7f, |
| 0x38, 0x54, 0x54, 0x54, 0x18, |
| 0x08, 0x7e, 0x09, 0x01, 0x02, |
| 0x18, 0xa4, 0xa4, 0xa4, 0x7c, |
| 0x7f, 0x08, 0x04, 0x04, 0x78, |
| 0x00, 0x44, 0x7d, 0x40, 0x00, |
| 0x40, 0x80, 0x84, 0x7d, 0x00, |
| 0x7f, 0x10, 0x28, 0x44, 0x00, |
| 0x00, 0x41, 0x7f, 0x40, 0x00, |
| 0x7c, 0x04, 0x18, 0x04, 0x78, |
| 0x7c, 0x08, 0x04, 0x04, 0x78, |
| 0x38, 0x44, 0x44, 0x44, 0x38, |
| |
| 0xfc, 0x24, 0x24, 0x24, 0x18, /* 0x70-0x7f */ |
| 0x18, 0x24, 0x24, 0x24, 0xfc, |
| 0x7c, 0x08, 0x04, 0x04, 0x08, |
| 0x48, 0x54, 0x54, 0x54, 0x20, |
| 0x04, 0x3f, 0x44, 0x40, 0x20, |
| 0x3c, 0x40, 0x40, 0x20, 0x7c, |
| 0x1c, 0x20, 0x40, 0x20, 0x1c, |
| 0x3c, 0x40, 0x30, 0x40, 0x3c, |
| 0x44, 0x28, 0x10, 0x28, 0x44, |
| 0x1c, 0xa0, 0xa0, 0xa0, 0x7c, |
| 0x44, 0x64, 0x54, 0x4c, 0x44, |
| 0x00, 0x08, 0x36, 0x41, 0x00, |
| 0x00, 0x00, 0x7f, 0x00, 0x00, |
| 0x00, 0x41, 0x36, 0x08, 0x00, |
| 0x04, 0x02, 0x04, 0x08, 0x04, |
| 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, |
| }; |
| |
| /* |
| * Memory copy of display bitmap |
| * |
| * This has the same format as the Recorder hardware: |
| * Bits within a byte are arranged veritcally, LSB at top. |
| * Byte 0 is top left, byte 1 is 2nd left, byte DISP_X starts 2nd row. |
| */ |
| unsigned char display[LCD_HEIGHT/8][LCD_WIDTH]; |
| |
| static int lcd_y; /* Current pixel row */ |
| static int lcd_x; /* Current pixel column */ |
| |
| /* |
| * Set current x,y position |
| */ |
| void lcd_position(int x, int y) |
| { |
| if (x >= 0 && x < DISP_X && y >= 0 && y < DISP_Y) { |
| lcd_x = x; |
| lcd_y = y; |
| PRINT(("lcd_position: set to %d, %d\n", x, y)); |
| } |
| else |
| PRINT(("lcd_position: not set\n")); |
| |
| |
| } |
| |
| /* |
| * Clear the display |
| */ |
| void lcd_clear(void) |
| { |
| lcd_x = 0; |
| lcd_y = 0; |
| memset (display, 0, sizeof display); |
| } |
| |
| /* |
| * Display a character at current position. |
| * This writes a 5x8 character within a 6x8 cell. |
| * The cell does not have to be aligned to a display byte. |
| * The top left of the cell is displayed at the current position. |
| * invert is TRUE to display in reverse video. |
| */ |
| void lcd_char (int ch, char invert) |
| { |
| unsigned char yrow = lcd_y/8; |
| unsigned char (*dp)[LCD_WIDTH] = &display[yrow][lcd_x]; |
| unsigned char shift, mask, col; |
| |
| PRINT(("lcd_char: output %c (%02x) at %d, %d (yrow %d)\n", |
| ch, ch, lcd_x, lcd_y, yrow)); |
| |
| /* Limit to char generation table */ |
| if (ch < ASCII_MIN || ch > ASCII_MAX) |
| ch = ASCII_MAX; |
| |
| /* Calculate shift and masks for cell bit position */ |
| shift = (lcd_y & 0x7); |
| mask = ~(COL_MASK << shift); |
| if (invert) |
| invert = ~mask; |
| |
| /* Write each char column */ |
| for (col = 0; col < CHAR_X-1; col++) { |
| unsigned long data = (lcd_font_data[ch-ASCII_MIN][col] << shift) ^ invert; |
| |
| PRINT(("OR[0]: %02x on x %d y %d \n", data&0xff, col+lcd_x, yrow)); |
| |
| dp[0][col] = (dp[0][col] & mask) | data; |
| if (lcd_y < DISP_Y-8) { |
| PRINT(("OR[1]: %02x on x %d y %d\n", (data>>8), col+lcd_x, yrow+1)); |
| dp[1][col] = (dp[1][col] & (mask >> 8)) | (data >> 8); |
| } |
| } |
| |
| /* Column after char */ |
| dp[0][CHAR_X-1] = (dp[0][CHAR_X-1] & mask) | invert; |
| if (lcd_y < DISP_Y-8) |
| dp[1][CHAR_X-1] = (dp[1][CHAR_X-1] & (mask >> 8)) | (invert >> 8); |
| } |
| |
| /* |
| * Output a string at current position |
| */ |
| void lcd_string(const char *text, char invert) |
| { |
| int ch; |
| |
| PRINT(("lcd_string: output %s at %d, %d\n", text, lcd_x, lcd_y)); |
| |
| while ((ch = *text++) != '\0') { |
| if (lcd_y > DISP_Y-CHAR_Y) { |
| /* Scroll (8 pixels) */ |
| memcpy (display[0], display[1], DISP_X*(DISP_Y/8-1)); |
| lcd_y -= 8; |
| } |
| |
| if (ch == '\n') |
| lcd_x = DISP_X; |
| else { |
| lcd_char (ch, invert); |
| lcd_x += CHAR_X; |
| |
| if (lcd_x > DISP_X-CHAR_X) { |
| /* Wrap to next line */ |
| lcd_x = 0; |
| lcd_y += CHAR_Y; |
| } |
| } |
| } |
| PRINT(("lcd_string: position after write: %d, %d\n", lcd_x, lcd_y)); |
| } |