Base: LCDproc 0.5.2
[lcdproc-de200c.git] / server / drivers / sed1520.c
blobcc9317343bde3902957a846ce625c82ce794fe3a
1 //////////////////////////////////////////////////////////////////////////
2 // This is a driver for 122x32 pixel graphic displays based on the //
3 // SED1520 Controller connected to the parallel port. Check //
4 // http://www.usblcd.de/lcdproc/ for where to buy //
5 // and how to build the hardware. This Controller has no built in //
6 // character generator. Therefore all fonts and pixels are generated //
7 // by this driver. //
8 // //
9 // This driver is based on drv_base.c and hd44780.c. //
10 // The HD44780 font in sed1520fm.c was shamelessly stolen from //
11 // Michael Reinelt / lcd4linux and is (C) 2000 by him. //
12 // The rest of fontmap.c and this driver is //
13 // //
14 // Moved the delay timing code by Charles Steinkuehler to timing.h. //
15 // Guillaume Filion <gfk@logidac.com>, December 2001 //
16 // //
17 // (C) 2001 Robin Adams ( robin@adams-online.de ) //
18 // //
19 // This driver is released under the GPL. See file COPYING in this //
20 // package for further details. //
21 //////////////////////////////////////////////////////////////////////////
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <termios.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <sys/errno.h>
30 #include <time.h>
31 #include "port.h"
32 #include "timing.h"
33 #define uPause timing_uPause
35 #include "sed1520fm.h"
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
42 #ifndef DEFAULT_PORT
43 # define DEFAULT_PORT 0x378
44 #endif
46 #define CELLWIDTH 6
47 #define CELLHEIGHT 8
49 #define PIXELWIDTH 122
50 #define PIXELHEIGHT 32
52 #define WIDTH ((int) (PIXELWIDTH / CELLWIDTH)) /* 20 */
53 #define HEIGHT ((int) (PIXELHEIGHT / CELLHEIGHT)) /* 4 */
55 #define A0 0x08
56 #define CS2 0x04
57 #define CS1 0x02
58 #define WR 0x01
59 #define IODELAY 500
61 #include "shared/str.h"
62 #include "lcd.h"
63 #include "sed1520.h"
64 #include "report.h"
67 typedef struct driver_private_data {
68 unsigned int port;
70 unsigned char *framebuf;
71 } PrivateData;
74 // Vars for the server core
75 MODULE_EXPORT char *api_version = API_VERSION;
76 MODULE_EXPORT int stay_in_foreground = 0;
77 MODULE_EXPORT int supports_multiple = 0;
78 MODULE_EXPORT char *symbol_prefix = "sed1520_";
80 /////////////////////////////////////////////////////////////////
81 // writes command value to one or both sed1520 selected by chip
83 void
84 writecommand (unsigned int port, int value, int chip)
86 port_out(port, value);
87 port_out(port + 2, WR + CS1 - (chip & CS1) + (chip & CS2));
88 port_out(port + 2, CS1 - (chip & CS1) + (chip & CS2));
89 uPause(IODELAY);
90 port_out(port + 2, WR + CS1 - (chip & CS1) + (chip & CS2));
91 uPause(IODELAY);
94 /////////////////////////////////////////////////////////////////
95 // writes data value to one or both sed 1520 selected by chip
97 void
98 writedata (unsigned int port, int value, int chip)
100 port_out(port, value);
101 port_out(port + 2, A0 + WR + CS1 - (chip & CS1) + (chip & CS2));
102 port_out(port + 2, A0 + CS1 - (chip & CS1) + (chip & CS2));
103 uPause(IODELAY);
104 port_out(port + 2, A0 + WR + CS1 - (chip & CS1) + (chip & CS2));
105 uPause(IODELAY);
108 /////////////////////////////////////////////////////////////////
109 // selects a page (=row) on both sed1520s
111 void
112 selectpage (unsigned int port, int page)
114 writecommand(port, 0xB8 + (page & 0x03), CS1 + CS2);
117 /////////////////////////////////////////////////////////////////
118 // selects a column on the sed1520s specified by chip
120 void
121 selectcolumn (unsigned int port, int column, int chip)
123 writecommand(port, (column & 0x7F), chip);
126 /////////////////////////////////////////////////////////////////
127 // draws char z from fontmap to the framebuffer at position
128 // x,y. These are zero-based textmode positions.
129 // The Fontmap is stored in rows while the framebuffer is stored
130 // in columns, so we need a little conversion.
132 void
133 drawchar2fb (unsigned char *framebuf, int x, int y, unsigned char z)
135 int i, j;
137 if ((x < 0) || (x >= WIDTH) || (y < 0) || (y >= HEIGHT))
138 return;
140 for (i = CELLWIDTH; i > 0; i--) {
141 int k = 0;
143 for (j = 0; j < CELLHEIGHT; j++)
144 k |= ((fontmap[(int) z][j] >> (i-1)) & 0x01) << j;
146 framebuf[(y * PIXELWIDTH) + (x * CELLWIDTH) + (CELLWIDTH - i)] = k;
150 /////////////////////////////////////////////////////////////////
151 // This initialises the stuff. We support supplying port as
152 // a command line argument.
154 MODULE_EXPORT int
155 sed1520_init (Driver *drvthis)
157 PrivateData *p;
159 /* Allocate and store private data */
160 p = (PrivateData *) calloc(1, sizeof(PrivateData));
161 if (p == NULL)
162 return -1;
163 if (drvthis->store_private_ptr(drvthis, p))
164 return -1;
167 /* Read config file */
169 /* What port to use */
170 p->port = drvthis->config_get_int(drvthis->name, "Port", 0, DEFAULT_PORT);
172 /* End of config file parsing */
174 if (timing_init() == -1) {
175 report(RPT_ERR, "%s: timing_init() failed (%s)", drvthis->name, strerror(errno));
176 return -1;
179 // Allocate our framebuffer
180 p->framebuf = (unsigned char *) calloc(PIXELWIDTH * HEIGHT, sizeof(unsigned char));
181 if (p->framebuf == NULL) {
182 report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name);
183 // sed1520_close ();
184 return -1;
187 // clear screen
188 memset(p->framebuf, '\0', PIXELWIDTH * HEIGHT);
190 // Initialize the Port and the sed1520s
191 if (port_access(p->port) || port_access(p->port+2)) {
192 report(RPT_ERR, "%s: unable to access port 0x%03X", drvthis->name, p->port);
193 return -1;
196 port_out(p->port,0);
197 port_out(p->port +2, WR + CS2);
198 writecommand(p->port, 0xE2, CS1 + CS2);
199 writecommand(p->port, 0xAF, CS1 + CS2);
200 writecommand(p->port, 0xC0, CS1 + CS2);
201 selectpage(p->port, 3);
203 report(RPT_DEBUG, "%s: init() done", drvthis->name);
205 return 1;
208 /////////////////////////////////////////////////////////////////
209 // Frees the frambuffer and exits the driver.
211 MODULE_EXPORT void
212 sed1520_close (Driver *drvthis)
214 PrivateData *p = drvthis->private_data;
216 if (p != NULL) {
217 if (p->framebuf != NULL)
218 free(p->framebuf);
220 free(p);
222 drvthis->store_private_ptr(drvthis, NULL);
225 /////////////////////////////////////////////////////////////////
226 // Returns the display width
228 MODULE_EXPORT int
229 sed1520_width (Driver *drvthis)
231 //PrivateData *p = drvthis->private_data;
232 return WIDTH;
235 /////////////////////////////////////////////////////////////////
236 // Returns the display height
238 MODULE_EXPORT int
239 sed1520_height (Driver *drvthis)
241 //PrivateData *p = drvthis->private_data;
242 return HEIGHT;
245 /////////////////////////////////////////////////////////////////
246 // Returns the display width
248 MODULE_EXPORT int
249 sed1520_cellwidth (Driver *drvthis)
251 //PrivateData *p = drvthis->private_data;
252 return CELLWIDTH;
255 /////////////////////////////////////////////////////////////////
256 // Returns the display height
258 MODULE_EXPORT int
259 sed1520_cellheight (Driver *drvthis)
261 //PrivateData *p = drvthis->private_data;
262 return CELLHEIGHT;
265 /////////////////////////////////////////////////////////////////
266 // Clears the LCD screen
268 MODULE_EXPORT void
269 sed1520_clear (Driver *drvthis)
271 PrivateData *p = drvthis->private_data;
273 memset(p->framebuf, '\0', PIXELWIDTH * HEIGHT);
276 /////////////////////////////////////////////////////////////////
278 // Flushes all output to the lcd...
280 MODULE_EXPORT void
281 sed1520_flush (Driver *drvthis)
283 PrivateData *p = drvthis->private_data;
284 int i, j;
286 for (i = 0; i < HEIGHT; i++) {
287 selectpage(p->port, i);
289 selectcolumn(p->port, 0, CS2) ;
290 for (j = 0; j < PIXELWIDTH/2; j++)
291 writedata(p->port, p->framebuf[j + (i * PIXELWIDTH)], CS2);
293 selectcolumn(p->port, 0, CS1) ;
294 for (j = PIXELWIDTH/2; j < PIXELWIDTH; j++)
295 writedata(p->port, p->framebuf[j + (i * PIXELWIDTH)], CS1);
299 /////////////////////////////////////////////////////////////////
300 // Prints a string on the lc display, at position (x,y). The
301 // upper-left is (1,1), and the lower right should be (20,4).
303 MODULE_EXPORT void
304 sed1520_string (Driver *drvthis, int x, int y, const char string[])
306 PrivateData *p = drvthis->private_data;
307 int i;
309 x--; // Convert 1-based coords to 0-based
310 y--;
312 for (i = 0; string[i] != '\0'; i++)
313 drawchar2fb(p->framebuf, x + i, y, string[i]);
316 /////////////////////////////////////////////////////////////////
317 // Writes char c at position x,y into the framebuffer.
318 // x and y are 1-based textmode coordinates.
320 MODULE_EXPORT void
321 sed1520_chr (Driver *drvthis, int x, int y, char c)
323 PrivateData *p = drvthis->private_data;
325 y--;
326 x--;
327 drawchar2fb(p->framebuf, x, y, c);
330 /////////////////////////////////////////////////////////////////
331 // This function draws a number num into the last 3 rows of the
332 // framebuffer at 1-based position x. It should draw a 4-row font,
333 // but methinks this would look a little stretched. When
334 // num=10 a colon is drawn.
335 // FIXME: make big numbers use less memory
337 MODULE_EXPORT void
338 sed1520_num (Driver *drvthis, int x, int num)
340 PrivateData *p = drvthis->private_data;
341 int z, c, i, s;
342 x--;
344 // return on illegal char or illegal position
345 if ((x >= WIDTH) || (num < 0) || (num > 10))
346 return;
348 if (num == 10) { // colon
349 for (z = 0; z < 3; z++) { // Zeilen a 8 Punkte
350 for (c = 0; c < 6; c++) { // 6 columns
351 s = 0;
352 for (i = 0; i < 8; i++) { // 8 bits aus zeilen
353 s >>= 1;
354 if (*(fontbigdp[(z * 8) + i] + c) == '.')
355 s |= 0x80;
357 if ((x * CELLWIDTH + c >= 0) && (x * CELLWIDTH + c < PIXELWIDTH))
358 p->framebuf[((z + 1) * PIXELWIDTH) + (x * CELLWIDTH) + c] = s;
362 else { // digits 0 - 9
363 for (z = 0; z < 3; z++) { // Zeilen a 8 Punkte
364 for (c = 0; c < 18; c++) { // 18 columns
365 s = 0;
366 for (i = 0; i < 8; i++) { // 8 bits aus zeilen
367 s >>= 1;
368 if (*(fontbignum[num][z * 8 + i] + c) == '.')
369 s |= 0x80;
371 if ((x * CELLWIDTH + c >= 0) && (x * CELLWIDTH + c < PIXELWIDTH))
372 p->framebuf[((z + 1) * PIXELWIDTH) + (x * CELLWIDTH) + c] = s;
379 /////////////////////////////////////////////////////////////////
380 // Changes the font of character n to a pattern given by *dat.
381 // HD44780 Controllers only posses 8 programmable chars. But
382 // we store the fontmap completely in RAM, so every character
383 // can be altered. !Important: Characters have to be redrawn
384 // by drawchar2fb() to show their new shape. Because we use
385 // a non-standard 6x8 font a *dat not calculated from
386 // width and height will fail.
388 MODULE_EXPORT void
389 sed1520_set_char (Driver *drvthis, int n, char *dat)
391 //PrivateData *p = drvthis->private_data;
392 int row, col;
394 if (n < 0 || n > 255)
395 return;
396 if (!dat)
397 return;
399 for (row = 0; row < CELLHEIGHT; row++) {
400 int i = 0;
402 for (col = 0; col < CELLWIDTH; col++)
403 i = (i << 1) | (dat[(row * CELLWIDTH) + col] > 0);
405 fontmap[n][row] = i;
410 /////////////////////////////////////////////////////////////////
411 // Draws a vertical from the bottom up to the last 3 rows of the
412 // framebuffer at 1-based position x. len is given in pixels.
414 MODULE_EXPORT void
415 sed1520_old_vbar (Driver *drvthis, int x, int len)
417 PrivateData *p = drvthis->private_data;
418 int i, j, k;
420 x--;
422 for (j = 0; j < 3; j++) {
423 k = 0;
424 for (i = 0; i < CELLHEIGHT; i++) {
425 if (len > i)
426 k |= (1 << (CELLHEIGHT-1 - i));
429 p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 0] = 0;
430 p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 1] = 0;
431 p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 2] = k;
432 p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 3] = k;
433 p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 4] = k;
434 p->framebuf[((3 - j) * PIXELWIDTH) + (x * CELLWIDTH) + 5] = 0;
435 len -= CELLHEIGHT;
440 /////////////////////////////////////////////////////////////////
441 // Draws a horizontal bar from left to right at 1-based position
442 // x,y into the framebuffer. len is given in pixels.
444 MODULE_EXPORT void
445 sed1520_old_hbar (Driver *drvthis, int x, int y, int len)
447 PrivateData *p = drvthis->private_data;
448 int i;
450 x--;
451 y--;
453 if ((y < 0) || (y >= HEIGHT) || (x < 0) || (len < 0) || ((x + (len / CELLWIDTH)) >= WIDTH))
454 return;
456 for (i = 0; i < len; i++)
457 p->framebuf[(y * PIXELWIDTH) + (x * CELLWIDTH) + i] = 0x3C; // set low 6 bits
460 /////////////////////////////////////////////////////////////////
461 // Reprogrammes character dest to contain an icon given by
462 // which. Calls set_char() to do this.
464 MODULE_EXPORT int
465 sed1520_icon (Driver *drvthis, int x, int y, int icon)
467 //PrivateData *p = drvthis->private_data;
468 static char heart_open[] = {
469 1, 1, 1, 1, 1,
470 1, 0, 1, 0, 1,
471 0, 0, 0, 0, 0,
472 0, 0, 0, 0, 0,
473 0, 0, 0, 0, 0,
474 1, 0, 0, 0, 1,
475 1, 1, 0, 1, 1,
476 1, 1, 1, 1, 1 };
478 static char heart_filled[] = {
479 1, 1, 1, 1, 1,
480 1, 0, 1, 0, 1,
481 0, 1, 0, 1, 0,
482 0, 1, 1, 1, 0,
483 0, 1, 1, 1, 0,
484 1, 0, 1, 0, 1,
485 1, 1, 0, 1, 1,
486 1, 1, 1, 1, 1 };
488 switch (icon) {
489 case ICON_BLOCK_FILLED:
490 sed1520_chr(drvthis, x, y, 255);
491 break;
492 case ICON_HEART_FILLED:
493 sed1520_set_char(drvthis, 0, heart_filled);
494 sed1520_chr(drvthis, x, y, 0);
495 break;
496 case ICON_HEART_OPEN:
497 sed1520_set_char(drvthis, 0, heart_open);
498 sed1520_chr(drvthis, x, y, 0);
499 break;
500 default:
501 return -1;
503 return 0;