////////////////////////////////////////////////////////////////////////// // This is a driver for 122x32 pixel graphic displays based on the // // SED1520 Controller connected to the parallel port. Check // // www.adams-online.de/lcd for where to buy // // and how to build the hardware. This Controller has no built in // // character generator. Therefore all fonts and pixels are generated // // by this driver. // // // // This driver is based on drv_base.c and hd44780.c. // // The HD44780 font in sed1520fm.c was shamelessly stolen from // // Michael Reinelt / lcd4linux and is (C) 2000 by him. // // The rest of fontmap.c and this driver is // // // // Moved the delay timing code by Charles Steinkuehler to timing.h. // // Guillaume Filion , December 2001 // // // // (C) 2001 Robin Adams ( robin@adams-online.de ) // // // // This driver is released under the GPL. See file COPYING in this // // package for further details. // ////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include "port.h" #include "timing.h" #define uPause timing_uPause #include "sed1520fm.h" #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef LPTPORT #define LPTPORT 0x378 #endif #define A0 0x08 #define CS2 0x04 #define CS1 0x02 #define WR 0x01 #define IODELAY 500 #include "shared/str.h" #include "lcd.h" #include "sed1520.h" #include "report.h" unsigned int sed1520_lptport = LPTPORT; char *framebuf = NULL; int width = LCD_DEFAULT_WIDTH; int height = LCD_DEFAULT_HEIGHT; int cellwidth = LCD_DEFAULT_CELLWIDTH; int cellheight = LCD_DEFAULT_CELLHEIGHT; // Vars for the server core MODULE_EXPORT char *api_version = API_VERSION; MODULE_EXPORT int stay_in_foreground = 0; MODULE_EXPORT int supports_multiple = 0; MODULE_EXPORT char *symbol_prefix = "sed1520_"; ///////////////////////////////////////////////////////////////// // writes command value to one or both sed1520 selected by chip // void writecommand (int value, int chip) { port_out ( sed1520_lptport,value); port_out ( sed1520_lptport + 2,WR + CS1 - (chip & CS1) + (chip & CS2)); port_out ( sed1520_lptport + 2,CS1 - (chip & CS1) + (chip & CS2)); uPause (IODELAY); port_out ( sed1520_lptport + 2,WR + CS1 - (chip & CS1) + (chip & CS2)); uPause (IODELAY); } ///////////////////////////////////////////////////////////////// // writes data value to one or both sed 1520 selected by chip // void writedata (int value, int chip) { port_out ( sed1520_lptport,value); port_out ( sed1520_lptport + 2,A0 + WR + CS1 - (chip & CS1) + (chip & CS2)); port_out ( sed1520_lptport + 2,A0 + CS1 - (chip & CS1) + (chip & CS2)); uPause (IODELAY); port_out ( sed1520_lptport + 2,A0 + WR + CS1 - (chip & CS1) + (chip & CS2)); uPause (IODELAY); } ///////////////////////////////////////////////////////////////// // selects a page (=row) on both sed1520s // void selectpage (int page) { writecommand (0xB8 + (page & 3), CS1 + CS2); } ///////////////////////////////////////////////////////////////// // selects a column on the sed1520s specified by chip // void selectcolumn (int column, int chip) { writecommand ((column & 0x7F), chip); } ///////////////////////////////////////////////////////////////// // draws char z from fontmap to the framebuffer at position // x,y. These are zero-based textmode positions. // The Fontmap is stored in rows while the framebuffer is stored // in columns, so we need a little conversion. // void drawchar2fb (int x, int y, unsigned char z) { int i, j, k; if (x < 0 || x > 19 || y < 0 || y > 3) return; for (i = 6; i > 0; i--) { k = 0; for (j = 0; j < 7; j++) { k = k + (((fontmap[(int) z][j] * 2) & (1 << i)) / (1 << i)) * (1 << j); } framebuf[(y * 122) + (x * 6) + (6 - i)] = k; } } ///////////////////////////////////////////////////////////////// // This initialises the stuff. We support supplying port as // a command line argument. // MODULE_EXPORT int sed1520_init (Driver *drvthis) { /* Read config file */ /* What port to use */ sed1520_lptport = drvthis->config_get_int(drvthis->name, "Port", 0, LPTPORT); /* End of config file parsing */ if (timing_init() == -1) { report(RPT_ERR, "timing_init: failed (%s)\n", strerror(errno)); return -1; } // Allocate our framebuffer framebuf = malloc (122 * 4); if (!framebuf) { // sed1520_close (); return -1; } // clear screen memset (framebuf, 0, 122 * 4); // Initialize the Port and the sed1520s if(port_access(sed1520_lptport)) return -1; if(port_access(sed1520_lptport+2)) return -1; port_out (sed1520_lptport,0); port_out (sed1520_lptport +2,WR + CS2); writecommand (0xE2, CS1 + CS2); writecommand (0xAF, CS1 + CS2); writecommand (0xC0, CS1 + CS2); selectpage (3); cellwidth = 6; cellheight = 8; return 0; } ///////////////////////////////////////////////////////////////// // Frees the frambuffer and exits the driver. // MODULE_EXPORT void sed1520_close (Driver *drvthis) { if (framebuf != NULL) free (framebuf); framebuf = NULL; } ///////////////////////////////////////////////////////////////// // Returns the display width // MODULE_EXPORT int sed1520_width (Driver *drvthis) { return width; } ///////////////////////////////////////////////////////////////// // Returns the display height // MODULE_EXPORT int sed1520_height (Driver *drvthis) { return height; } ///////////////////////////////////////////////////////////////// // Returns the display width // MODULE_EXPORT int sed1520_cellwidth (Driver *drvthis) { return cellwidth; } ///////////////////////////////////////////////////////////////// // Returns the display height // MODULE_EXPORT int sed1520_cellheight (Driver *drvthis) { return cellheight; } ///////////////////////////////////////////////////////////////// // Clears the LCD screen // MODULE_EXPORT void sed1520_clear (Driver *drvthis) { memset (framebuf, 0, 488); } ///////////////////////////////////////////////////////////////// // // Flushes all output to the lcd... // MODULE_EXPORT void sed1520_flush (Driver *drvthis) { int i, j; for (i = 0; i < 4; i++) { selectpage (i); selectcolumn (0, CS2) ; for (j = 0; j < 61; j++) writedata (framebuf[j + (i * 122)], CS2); selectcolumn (0, CS1) ; for (j = 61; j < 122; j++) writedata (framebuf[j + (i * 122)], CS1); } } ///////////////////////////////////////////////////////////////// // Prints a string on the lc display, at position (x,y). The // upper-left is (1,1), and the lower right should be (20,4). // MODULE_EXPORT void sed1520_string (Driver *drvthis, int x, int y, char string[]) { int i; x--; // Convert 1-based coords to 0-based... y--; for (i = 0; string[i]; i++) { drawchar2fb (x + i, y, string[i]); } } ///////////////////////////////////////////////////////////////// // Writes char c at position x,y into the framebuffer. // x and y are 1-based textmode coordinates. // MODULE_EXPORT void sed1520_chr (Driver *drvthis, int x, int y, char c) { y--; x--; drawchar2fb (x, y, c); } ///////////////////////////////////////////////////////////////// // This function draws a number num into the last 3 rows of the // framebuffer at 1-based position x. It should draw a 4-row font, // but methinks this would look a little stretched. When // num=10 a colon is drawn. // FIXME: make big numbers use less memory // MODULE_EXPORT void sed1520_num (Driver *drvthis, int x, int num) { int z, c, i, s; x--; if (x < 0 || x > 19 || num < 0 || num > 10) return; if (num != 10 && (x < 0 || x > 17)) return; if (num == 10 && (x < 0 || x > 19)) return; if (num == 10) { // Doppelpunkt for (z = 0; z < 3; z++) { // Zeilen a 8 Punkte for (c = 0; c < 6; c++) { // 6 Spalten s = 0; for (i = 0; i < 8; i++) { // 8 bits aus zeilen s >>= 1; if (*(fontbigdp[(z * 8) + i] + c) == '.') s += 128; } framebuf[(z * 122) + 122 + (x * 6) + c] = s; } } } else { for (z = 0; z < 3; z++) { // Zeilen a 8 Punkte for (c = 0; c < 18; c++) { // 18 Spalten s = 0; for (i = 0; i < 8; i++) { // 8 bits aus zeilen s >>= 1; if (*(fontbignum[num][z * 8 + i] + c) == '.') s += 128; } framebuf[(z * 122) + 122 + (x * 6) + c] = s; } } } } ///////////////////////////////////////////////////////////////// // Changes the font of character n to a pattern given by *dat. // HD44780 Controllers only posses 8 programmable chars. But // we store the fontmap completely in RAM, so every character // can be altered. !Important: Characters have to be redraw // by drawchar2fb() to show their new shape. Because we use // a non-standard 6x8 font a *dat not calculated from // widthth and sed1520->height will fail. // MODULE_EXPORT void sed1520_set_char (Driver *drvthis, int n, char *dat) { int row, col, i; if (n < 0 || n > 255) return; if (!dat) return; for (row = 0; row < 8; row++) { i = 0; for (col = 0; col < 6; col++) { i <<= 1; i |= (dat[(row * 6) + col] > 0); } fontmap[n][row] = i; } } ///////////////////////////////////////////////////////////////// // Draws a vertical from the bottom up to the last 3 rows of the // framebuffer at 1-based position x. len is given in pixels. // MODULE_EXPORT void sed1520_old_vbar (Driver *drvthis, int x, int len) { int i, j, k; x--; for (j = 0; j < 3; j++) { i = 0; k = 0; for (i = 0; i < 8; i++) { if (len > i) k += 1 << (7 - i); } framebuf[((3 - j) * 122) + (x * 6)] = 0; framebuf[((3 - j) * 122) + (x * 6) + 1] = 0; framebuf[((3 - j) * 122) + (x * 6) + 2] = k; framebuf[((3 - j) * 122) + (x * 6) + 3] = k; framebuf[((3 - j) * 122) + (x * 6) + 4] = k; framebuf[((3 - j) * 122) + (x * 6) + 5] = 0; len -= 8; } } ///////////////////////////////////////////////////////////////// // Draws a horizontal bar from left to right at 1-based position // x,y into the framebuffer. len is given in pixels. // MODULE_EXPORT void sed1520_old_hbar (Driver *drvthis, int x, int y, int len) { int i; x--; y--; if (y < 0 || y > 3 || x < 0 || len < 0 || (x + (len / 6)) > 19) return; for (i = 0; i < len; i++) framebuf[(y * 122) + (x * 6) + i] = 0x3C; } ///////////////////////////////////////////////////////////////// // Reprogrammes character dest to contain an icon given by // which. Calls set_char() to do this. // MODULE_EXPORT int sed1520_icon (Driver *drvthis, int x, int y, int icon) { static char heart_open[] = { 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }; static char heart_filled[] = { 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }; switch( icon ) { case ICON_BLOCK_FILLED: sed1520_chr( drvthis, x, y, 255 ); break; case ICON_HEART_FILLED: sed1520_set_char( drvthis, 0, heart_filled ); sed1520_chr( drvthis, x, y, 0 ); break; case ICON_HEART_OPEN: sed1520_set_char( drvthis, 0, heart_open ); sed1520_chr( drvthis, x, y, 0 ); break; default: return -1; } return 0; }