////////////////////////////////////////////////////////////////////////// // This is a driver for 122x32 pixel graphic displays based on the // // SED1520 Controller connected to the parallel port. Check // // http://www.usblcd.de/lcdproc/ 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 DEFAULT_PORT # define DEFAULT_PORT 0x378 #endif #define CELLWIDTH 6 #define CELLHEIGHT 8 #define PIXELWIDTH 122 #define PIXELHEIGHT 32 #define WIDTH ((int) (PIXELWIDTH / CELLWIDTH)) /* 20 */ #define HEIGHT ((int) (PIXELHEIGHT / CELLHEIGHT)) /* 4 */ #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" typedef struct driver_private_data { unsigned int port; unsigned char *framebuf; } PrivateData; // 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 (unsigned int port, int value, int chip) { port_out(port, value); port_out(port + 2, WR + CS1 - (chip & CS1) + (chip & CS2)); port_out(port + 2, CS1 - (chip & CS1) + (chip & CS2)); uPause(IODELAY); port_out(port + 2, WR + CS1 - (chip & CS1) + (chip & CS2)); uPause(IODELAY); } ///////////////////////////////////////////////////////////////// // writes data value to one or both sed 1520 selected by chip // void writedata (unsigned int port, int value, int chip) { port_out(port, value); port_out(port + 2, A0 + WR + CS1 - (chip & CS1) + (chip & CS2)); port_out(port + 2, A0 + CS1 - (chip & CS1) + (chip & CS2)); uPause(IODELAY); port_out(port + 2, A0 + WR + CS1 - (chip & CS1) + (chip & CS2)); uPause(IODELAY); } ///////////////////////////////////////////////////////////////// // selects a page (=row) on both sed1520s // void selectpage (unsigned int port, int page) { writecommand(port, 0xB8 + (page & 0x03), CS1 + CS2); } ///////////////////////////////////////////////////////////////// // selects a column on the sed1520s specified by chip // void selectcolumn (unsigned int port, int column, int chip) { writecommand(port, (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 (unsigned char *framebuf, int x, int y, unsigned char z) { int i, j; if ((x < 0) || (x >= WIDTH) || (y < 0) || (y >= HEIGHT)) return; for (i = CELLWIDTH; i > 0; i--) { int k = 0; for (j = 0; j < CELLHEIGHT; j++) k |= ((fontmap[(int) z][j] >> (i-1)) & 0x01) << j; framebuf[(y * PIXELWIDTH) + (x * CELLWIDTH) + (CELLWIDTH - i)] = k; } } ///////////////////////////////////////////////////////////////// // This initialises the stuff. We support supplying port as // a command line argument. // MODULE_EXPORT int sed1520_init (Driver *drvthis) { PrivateData *p; /* Allocate and store private data */ p = (PrivateData *) calloc(1, sizeof(PrivateData)); if (p == NULL) return -1; if (drvthis->store_private_ptr(drvthis, p)) return -1; /* Read config file */ /* What port to use */ p->port = drvthis->config_get_int(drvthis->name, "Port", 0, DEFAULT_PORT); /* End of config file parsing */ if (timing_init() == -1) { report(RPT_ERR, "%s: timing_init() failed (%s)", drvthis->name, strerror(errno)); return -1; } // Allocate our framebuffer p->framebuf = (unsigned char *) calloc(PIXELWIDTH * HEIGHT, sizeof(unsigned char)); if (p->framebuf == NULL) { report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name); // sed1520_close (); return -1; } // clear screen memset(p->framebuf, '\0', PIXELWIDTH * HEIGHT); // Initialize the Port and the sed1520s if (port_access(p->port) || port_access(p->port+2)) { report(RPT_ERR, "%s: unable to access port 0x%03X", drvthis->name, p->port); return -1; } port_out(p->port,0); port_out(p->port +2, WR + CS2); writecommand(p->port, 0xE2, CS1 + CS2); writecommand(p->port, 0xAF, CS1 + CS2); writecommand(p->port, 0xC0, CS1 + CS2); selectpage(p->port, 3); report(RPT_DEBUG, "%s: init() done", drvthis->name); return 1; } ///////////////////////////////////////////////////////////////// // Frees the frambuffer and exits the driver. // MODULE_EXPORT void sed1520_close (Driver *drvthis) { PrivateData *p = drvthis->private_data; if (p != NULL) { if (p->framebuf != NULL) free(p->framebuf); free(p); } drvthis->store_private_ptr(drvthis, NULL); } ///////////////////////////////////////////////////////////////// // Returns the display width // MODULE_EXPORT int sed1520_width (Driver *drvthis) { //PrivateData *p = drvthis->private_data; return WIDTH; } ///////////////////////////////////////////////////////////////// // Returns the display height // MODULE_EXPORT int sed1520_height (Driver *drvthis) { //PrivateData *p = drvthis->private_data; return HEIGHT; } ///////////////////////////////////////////////////////////////// // Returns the display width // MODULE_EXPORT int sed1520_cellwidth (Driver *drvthis) { //PrivateData *p = drvthis->private_data; return CELLWIDTH; } ///////////////////////////////////////////////////////////////// // Returns the display height // MODULE_EXPORT int sed1520_cellheight (Driver *drvthis) { //PrivateData *p = drvthis->private_data; return CELLHEIGHT; } ///////////////////////////////////////////////////////////////// // Clears the LCD screen // MODULE_EXPORT void sed1520_clear (Driver *drvthis) { PrivateData *p = drvthis->private_data; memset(p->framebuf, '\0', PIXELWIDTH * HEIGHT); } ///////////////////////////////////////////////////////////////// // // Flushes all output to the lcd... // MODULE_EXPORT void sed1520_flush (Driver *drvthis) { PrivateData *p = drvthis->private_data; int i, j; for (i = 0; i < HEIGHT; i++) { selectpage(p->port, i); selectcolumn(p->port, 0, CS2) ; for (j = 0; j < PIXELWIDTH/2; j++) writedata(p->port, p->framebuf[j + (i * PIXELWIDTH)], CS2); selectcolumn(p->port, 0, CS1) ; for (j = PIXELWIDTH/2; j < PIXELWIDTH; j++) writedata(p->port, p->framebuf[j + (i * PIXELWIDTH)], 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, const char string[]) { PrivateData *p = drvthis->private_data; int i; x--; // Convert 1-based coords to 0-based y--; for (i = 0; string[i] != '\0'; i++) drawchar2fb(p->framebuf, 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) { PrivateData *p = drvthis->private_data; y--; x--; drawchar2fb(p->framebuf, 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) { PrivateData *p = drvthis->private_data; int z, c, i, s; x--; // return on illegal char or illegal position if ((x >= WIDTH) || (num < 0) || (num > 10)) return; if (num == 10) { // colon for (z = 0; z < 3; z++) { // Zeilen a 8 Punkte for (c = 0; c < 6; c++) { // 6 columns s = 0; for (i = 0; i < 8; i++) { // 8 bits aus zeilen s >>= 1; if (*(fontbigdp[(z * 8) + i] + c) == '.') s |= 0x80; } if ((x * CELLWIDTH + c >= 0) && (x * CELLWIDTH + c < PIXELWIDTH)) p->framebuf[((z + 1) * PIXELWIDTH) + (x * CELLWIDTH) + c] = s; } } } else { // digits 0 - 9 for (z = 0; z < 3; z++) { // Zeilen a 8 Punkte for (c = 0; c < 18; c++) { // 18 columns s = 0; for (i = 0; i < 8; i++) { // 8 bits aus zeilen s >>= 1; if (*(fontbignum[num][z * 8 + i] + c) == '.') s |= 0x80; } if ((x * CELLWIDTH + c >= 0) && (x * CELLWIDTH + c < PIXELWIDTH)) p->framebuf[((z + 1) * PIXELWIDTH) + (x * CELLWIDTH) + 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 redrawn // by drawchar2fb() to show their new shape. Because we use // a non-standard 6x8 font a *dat not calculated from // width and height will fail. // MODULE_EXPORT void sed1520_set_char (Driver *drvthis, int n, char *dat) { //PrivateData *p = drvthis->private_data; int row, col; if (n < 0 || n > 255) return; if (!dat) return; for (row = 0; row < CELLHEIGHT; row++) { int i = 0; for (col = 0; col < CELLWIDTH; col++) i = (i << 1) | (dat[(row * CELLWIDTH) + 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) { PrivateData *p = drvthis->private_data; int i, j, k; x--; for (j = 0; j < 3; j++) { k = 0; for (i = 0; i < CELLHEIGHT; i++) { if (len > i) k |= (1 << (CELLHEIGHT-1 - i)); } p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 0] = 0; p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 1] = 0; p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 2] = k; p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 3] = k; p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 4] = k; p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 5] = 0; len -= CELLHEIGHT; } } ///////////////////////////////////////////////////////////////// // 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) { PrivateData *p = drvthis->private_data; int i; x--; y--; if ((y < 0) || (y >= HEIGHT) || (x < 0) || (len < 0) || ((x + (len / CELLWIDTH)) >= WIDTH)) return; for (i = 0; i < len; i++) p->framebuf[(y * PIXELWIDTH) + (x * CELLWIDTH) + i] = 0x3C; // set low 6 bits } ///////////////////////////////////////////////////////////////// // 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) { //PrivateData *p = drvthis->private_data; 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; }