diff options
| author | reinelt <reinelt@3ae390bd-cb1e-0410-b409-cd5a39f66f1f> | 2000-04-12 08:05:45 +0000 | 
|---|---|---|
| committer | reinelt <reinelt@3ae390bd-cb1e-0410-b409-cd5a39f66f1f> | 2000-04-12 08:05:45 +0000 | 
| commit | 73ffb61bfcbbba0abaeb26912a7408c4e0d143ab (patch) | |
| tree | 00296cc199b3242eb56466e7f19022506839b8f1 | |
| parent | 66d30deaa9b4b9bb575560b69e811265eebbffec (diff) | |
| download | lcd4linux-73ffb61bfcbbba0abaeb26912a7408c4e0d143ab.tar.gz | |
[lcd4linux @ 2000-04-12 08:05:45 by reinelt]
first version of the HD44780 driver
git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@43 3ae390bd-cb1e-0410-b409-cd5a39f66f1f
| -rw-r--r-- | HD44780.c | 496 | ||||
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | Makefile.in | 13 | ||||
| -rw-r--r-- | MatrixOrbital.c | 17 | ||||
| -rw-r--r-- | display.c | 8 | ||||
| -rw-r--r-- | lcd4linux.conf.sample | 24 | 
6 files changed, 535 insertions, 24 deletions
diff --git a/HD44780.c b/HD44780.c new file mode 100644 index 0000000..cdea5bf --- /dev/null +++ b/HD44780.c @@ -0,0 +1,496 @@ +/* $Id: HD44780.c,v 1.1 2000/04/12 08:05:45 reinelt Exp $ + * + * driver for display modules based on the HD44780 chip + * + * Copyright 1999, 2000 by Michael Reinelt (reinelt@eunet.at) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * $Log: HD44780.c,v $ + * Revision 1.1  2000/04/12 08:05:45  reinelt + * + * first version of the HD44780 driver + * + */ + +/*  + * + * exported fuctions: + * + * struct LCD HD44780[] + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <asm/io.h> + +#include "cfg.h" +#include "display.h" + +#define XRES 5 +#define YRES 8 +#define CHARS 8 +#define BARS ( BAR_L | BAR_R | BAR_U | BAR_D | BAR_H2 ) + +static LCD Lcd; + +typedef struct { +  int len1; +  int len2; +  int type; +  int segment; +} BAR; + +typedef struct { +  int len1; +  int len2; +  int type; +  int used; +  int ascii; +} SEGMENT; + +static unsigned short Port=0; + +static char Txt[4][40]; +static BAR  Bar[4][40]; + +static int nSegment=2; +static SEGMENT Segment[128] = {{ len1:0,   len2:0,   type:255, used:0, ascii:32 }, +			       { len1:255, len2:255, type:255, used:0, ascii:255 }}; + + +static void HD_delay (unsigned long usec) +{ +  usleep(usec); +} + +static void HD_command (unsigned char cmd) +{ +  outb (cmd, Port);    // put data on DB1..DB8 +  outb (0x02, Port+2); // set Enable = bit 0 invertet +  HD_delay(1); +  outb (0x03, Port+2); // clear Enable +} + +static void HD_write (char *string, int len) +{ +  while (len--) { +    outb (*string++, Port); // put data on DB1..DB8 +    outb (0x00, Port+2); // set Enable = bit 0 invertet +    HD_delay(1); +    outb (0x01, Port+2); // clear Enable +    HD_delay(40); +  } +} + +static int HD_open (void) +{ +  if (ioperm(Port, 3, 1)!=0) { +    fprintf (stderr, "HD44780: ioperm() failed: %s\n", strerror(errno)); +    return -1; +  } + +  HD_command (0x30);  // 8 Bit mode +  HD_delay (4100);      // wait 4.1 ms +  HD_command (0x30);  // 8 Bit mode +  HD_delay (100);       // wait 100 us +  HD_command (0x30);  // 8 Bit mode +  HD_delay (4100);      // wait 4.1 ms +  HD_command (0x38);  // 8 Bit mode, 1/16 duty cycle, 5x8 font +  HD_delay (40);        // wait 40 us +  HD_command (0x08);  // Display off, cursor off, blink off +  HD_delay (40);        // wait 40 us +  HD_command (0x0c);  // Display on, cursor off, blink off +  HD_delay (1640);      // wait 1.64 ms +  HD_command (0x06);  // curser moves to right, no shift +  HD_delay (40);        // wait 40 us + +  return 0; +} + +static void HD_process_bars (void) +{ +  int row, col; +  int i, j; +   +  for (i=2; i<nSegment && Segment[i].used; i++); +  for (j=i+1; j<nSegment; j++) { +    if (Segment[j].used) +      Segment[i++]=Segment[j]; +  } +  nSegment=i; +   +  for (row=0; row<Lcd.rows; row++) { +    for (col=0; col<Lcd.cols; col++) { +      if (Bar[row][col].type==0) continue; +      for (i=0; i<nSegment; i++) { +	if (Segment[i].type & Bar[row][col].type && +	    Segment[i].len1== Bar[row][col].len1 && +	    Segment[i].len2== Bar[row][col].len2) break; +      } +      if (i==nSegment) { +	nSegment++; +	Segment[i].len1=Bar[row][col].len1; +	Segment[i].len2=Bar[row][col].len2; +	Segment[i].type=Bar[row][col].type; +	Segment[i].used=0; +	Segment[i].ascii=-1; +      } +      Bar[row][col].segment=i; +    } +  } +} + +static int HD_segment_diff (int i, int j) +{ +  int RES; +  int i1, i2, j1, j2; +   +  if (i==j) return 65535; +  if (!(Segment[i].type & Segment[j].type)) return 65535; +  if (Segment[i].len1==0 && Segment[j].len1!=0) return 65535; +  if (Segment[i].len2==0 && Segment[j].len2!=0) return 65535; +  RES=Segment[i].type & BAR_H ? XRES:YRES; +  if (Segment[i].len1>=RES && Segment[j].len1<RES) return 65535; +  if (Segment[i].len2>=RES && Segment[j].len2<RES) return 65535; +  if (Segment[i].len1==Segment[i].len2 && Segment[j].len1!=Segment[j].len2) return 65535; + +  i1=Segment[i].len1; if (i1>RES) i1=RES; +  i2=Segment[i].len2; if (i2>RES) i2=RES; +  j1=Segment[j].len1; if (j1>RES) i1=RES; +  j2=Segment[j].len2; if (j2>RES) i2=RES; +   +  return (i1-i2)*(i1-i2)+(j1-j2)*(j1-j2); +} + +static void HD_compact_bars (void) +{ +  int i, j, r, c, min; +  int pack_i, pack_j; +  int pass1=1; +  int error[nSegment][nSegment]; +   +  if (nSegment>CHARS+2) { + +    for (i=2; i<nSegment; i++) { +      for (j=0; j<nSegment; j++) { +	error[i][j]=HD_segment_diff(i,j); +      } +    } +     +    while (nSegment>CHARS+2) { +      min=65535; +      pack_i=-1; +      pack_j=-1; +      for (i=2; i<nSegment; i++) { +	if (pass1 && Segment[i].used) continue; +	for (j=0; j<nSegment; j++) { +	  if (error[i][j]<min) { +	    min=error[i][j]; +	    pack_i=i; +	    pack_j=j; +	  } +	} +      } +      if (pack_i==-1) { +	if (pass1) { +	  pass1=0; +	  continue; +	} else { +	  fprintf (stderr, "HD44780: unable to compact bar characters\n"); +	  nSegment=CHARS; +	  break; +	} +      }  +       +      nSegment--; +      Segment[pack_i]=Segment[nSegment]; +       +      for (i=0; i<nSegment; i++) { +	error[pack_i][i]=error[nSegment][i]; +	error[i][pack_i]=error[i][nSegment]; +      } +       +      for (r=0; r<Lcd.rows; r++) { +	for (c=0; c<Lcd.cols; c++) { +	  if (Bar[r][c].segment==pack_i) +	    Bar[r][c].segment=pack_j; +	  if (Bar[r][c].segment==nSegment) +	    Bar[r][c].segment=pack_i; +	} +      } +    } +  } +} + +static void HD_define_chars (void) +{ +  int c, i, j; +  char buffer[8]; + +  for (i=2; i<nSegment; i++) { +    if (Segment[i].used) continue; +    if (Segment[i].ascii!=-1) continue; +    for (c=0; c<CHARS; c++) { +      for (j=2; j<nSegment; j++) { +	if (Segment[j].ascii==c) break; +      } +      if (j==nSegment) break; +    } +    Segment[i].ascii=c; +    switch (Segment[i].type) { +    case BAR_L: +      for (j=0; j<4; j++) { +	char Pixel[] = { 0, 1, 3, 7, 15, 31 }; +	buffer[j]=Pixel[Segment[i].len1]; +	buffer[j+4]=Pixel[Segment[i].len2]; +      } +      break; +    case BAR_R: +      for (j=0; j<4; j++) { +	char Pixel[] = { 0, 16, 24, 28, 30, 31 }; +	buffer[j]=Pixel[Segment[i].len1]; +	buffer[j+4]=Pixel[Segment[i].len2]; +      } +      break; +    case BAR_U: +      for (j=0; j<Segment[i].len1; j++) { +	buffer[7-j]=31; +      } +      for (; j<YRES; j++) { +	buffer[7-j]=0; +      } +      break; +    case BAR_D: +      for (j=0; j<Segment[i].len1; j++) { +	buffer[j]=31; +      } +      for (; j<YRES; j++) { +	buffer[j]=0; +      } +      break; +    } +    HD_command (0x40|8*c); +    HD_write (buffer, 8); +  } +} + +int HD_clear (void) +{ +  int row, col; + +  for (row=0; row<Lcd.rows; row++) { +    for (col=0; col<Lcd.cols; col++) { +      Txt[row][col]='\t'; +      Bar[row][col].len1=-1; +      Bar[row][col].len2=-1; +      Bar[row][col].type=0; +      Bar[row][col].segment=-1; +    } +  } +  HD_command (0x01); // clear display +  HD_delay (1640); +  return 0; +} + +static void HD_quit (int signal); //forward declaration + +int HD_init (LCD *Self) +{ +  int rows=-1, cols=-1; +  char *s, *e; +   +  s=cfg_get ("Port"); +  if (s==NULL || *s=='\0') { +    fprintf (stderr, "HD44780: no 'Port' entry in %s\n", cfg_file()); +    return -1; +  } +  if ((Port=strtol(s, &e, 0))==0 || *e!='\0') { +    fprintf (stderr, "HD44780: bad port '%s' in %s\n", s, cfg_file()); +    return -1; +  }     + +  s=cfg_get("Size"); +  if (s==NULL || *s=='\0') { +    fprintf (stderr, "HD44780: no 'Size' entry in %s\n", cfg_file()); +    return -1; +  } +   +  if (sscanf(s,"%dx%d",&cols,&rows)!=2 || rows<1 || cols<1) { +    fprintf(stderr,"HD44780: bad size '%s'\n",s); +    return -1; +  } +   +  Self->rows=rows; +  Self->cols=cols; +  Lcd=*Self; +   +  if (HD_open()!=0) +    return -1; +   +  HD_clear(); + +  signal(SIGINT,  HD_quit); +  signal(SIGQUIT, HD_quit); +  signal(SIGTERM, HD_quit); + +  return 0; +} + +void HD_goto (int row, int col) +{ +  int pos; +  pos=(row%2)*64+col; +  if (row>2) pos+=20; +  HD_command (0x80|pos); +  HD_delay(40); +} + +int HD_put (int row, int col, char *text) +{ +  char *p=&Txt[row][col]; +  char *t=text; +   +  while (*t && col++<=Lcd.cols) { +    *p++=*t++; +  } +  return 0; +} + +int HD_bar (int type, int row, int col, int max, int len1, int len2) +{ +  int rev=0; +   +  if (len1<1) len1=1; +  else if (len1>max) len1=max; +   +  if (len2<1) len2=1; +  else if (len2>max) len2=max; +   +  switch (type) { +  case BAR_L: +    len1=max-len1; +    len2=max-len2; +    rev=1; +     +  case BAR_R: +    while (max>0 && col<=Lcd.cols) { +      Bar[row][col].type=type; +      Bar[row][col].segment=-1; +      if (len1>=XRES) { +	Bar[row][col].len1=rev?0:XRES; +	len1-=XRES; +      } else { +	Bar[row][col].len1=rev?XRES-len1:len1; +	len1=0; +      } +      if (len2>=XRES) { +	Bar[row][col].len2=rev?0:XRES; +	len2-=XRES; +      } else { +	Bar[row][col].len2=rev?XRES-len2:len2; +	len2=0; +      } +      max-=XRES; +      col++; +    } +    break; + +  case BAR_U: +    len1=max-len1; +    len2=max-len2; +    rev=1; +     +  case BAR_D: +    while (max>0 && row<=Lcd.rows) { +      Bar[row][col].type=type; +      Bar[row][col].segment=-1; +      if (len1>=YRES) { +	Bar[row][col].len1=rev?0:YRES; +	len1-=YRES; +      } else { +	Bar[row][col].len1=rev?YRES-len1:len1; +	len1=0; +      } +      if (len2>=YRES) { +	Bar[row][col].len2=rev?0:YRES; +	len2-=YRES; +      } else { +	Bar[row][col].len2=rev?YRES-len2:len2; +	len2=0; +      } +      max-=YRES; +      row++; +    } +    break; + +  } +  return 0; +} + +int HD_flush (void) +{ +  char buffer[256]; +  char *p; +  int s, row, col; +   +  HD_process_bars(); +  HD_compact_bars(); +  HD_define_chars(); +   +  for (s=0; s<nSegment; s++) { +    Segment[s].used=0; +  } + +  for (row=0; row<Lcd.rows; row++) { +    for (col=0; col<Lcd.cols; col++) { +      s=Bar[row][col].segment; +      if (s!=-1) { +	Segment[s].used=1; +	Txt[row][col]=Segment[s].ascii; +      } +    } +    for (col=0; col<Lcd.cols; col++) { +      if (Txt[row][col]=='\t') continue; +      HD_goto (row, col); +      for (p=buffer; col<Lcd.cols; col++, p++) { +	if (Txt[row][col]=='\t') break; +	*p=Txt[row][col]; +      } +      HD_write (buffer, p-buffer); +    } +  } +  return 0; +} + +int lcd_hello (void); // prototype from lcd4linux.c + +static void HD_quit (int signal) +{ +  HD_clear(); +  lcd_hello(); +  // Fixme: ioperm rückgängig machen? +  exit (0); +} + +LCD HD44780[] = { +  { "HD44780", 0, 0, XRES, YRES, BARS, HD_init, HD_clear, HD_put, HD_bar, HD_flush }, +  { NULL } +}; diff --git a/Makefile.am b/Makefile.am index 62d720e..d753ee0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,5 +25,6 @@ pixmap.c pixmap.h \  fontmap.c fontmap.h \  Skeleton.c \  MatrixOrbital.c \ +HD44780.c \  Raster.c \  XWindow.c diff --git a/Makefile.in b/Makefile.in index 722390e..de72cb1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -73,7 +73,7 @@ AM_CFLAGS = $(X_CFLAGS) -Wall  lcd4linux_LDFLAGS = $(X_LIBS)  @WITH_X_TRUE@lcd4linux_LDADD = -lX11 -lcd4linux_SOURCES =  lcd4linux.c cfg.c cfg.h lock.c lock.h parser.c parser.h processor.c processor.h system.c system.h isdn.c isdn.h filter.c filter.h display.c display.h pixmap.c pixmap.h fontmap.c fontmap.h Skeleton.c MatrixOrbital.c Raster.c XWindow.c +lcd4linux_SOURCES =  lcd4linux.c cfg.c cfg.h lock.c lock.h parser.c parser.h processor.c processor.h system.c system.h isdn.c isdn.h filter.c filter.h display.c display.h pixmap.c pixmap.h fontmap.c fontmap.h Skeleton.c MatrixOrbital.c HD44780.c Raster.c XWindow.c  ACLOCAL_M4 = $(top_srcdir)/aclocal.m4  mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs @@ -91,7 +91,7 @@ X_EXTRA_LIBS = @X_EXTRA_LIBS@  X_PRE_LIBS = @X_PRE_LIBS@  lcd4linux_OBJECTS =  lcd4linux.o cfg.o lock.o parser.o processor.o \  system.o isdn.o filter.o display.o pixmap.o fontmap.o Skeleton.o \ -MatrixOrbital.o Raster.o XWindow.o +MatrixOrbital.o HD44780.o Raster.o XWindow.o  @WITH_X_TRUE@lcd4linux_DEPENDENCIES =   CFLAGS = @CFLAGS@  COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) @@ -105,10 +105,11 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)  TAR = tar  GZIP_ENV = --best -DEP_FILES =  .deps/MatrixOrbital.P .deps/Raster.P .deps/Skeleton.P \ -.deps/XWindow.P .deps/cfg.P .deps/display.P .deps/filter.P \ -.deps/fontmap.P .deps/isdn.P .deps/lcd4linux.P .deps/lock.P \ -.deps/parser.P .deps/pixmap.P .deps/processor.P .deps/system.P +DEP_FILES =  .deps/HD44780.P .deps/MatrixOrbital.P .deps/Raster.P \ +.deps/Skeleton.P .deps/XWindow.P .deps/cfg.P .deps/display.P \ +.deps/filter.P .deps/fontmap.P .deps/isdn.P .deps/lcd4linux.P \ +.deps/lock.P .deps/parser.P .deps/pixmap.P .deps/processor.P \ +.deps/system.P  SOURCES = $(lcd4linux_SOURCES)  OBJECTS = $(lcd4linux_OBJECTS) diff --git a/MatrixOrbital.c b/MatrixOrbital.c index ebd224d..e178f79 100644 --- a/MatrixOrbital.c +++ b/MatrixOrbital.c @@ -1,4 +1,4 @@ -/* $Id: MatrixOrbital.c,v 1.14 2000/04/10 04:40:53 reinelt Exp $ +/* $Id: MatrixOrbital.c,v 1.15 2000/04/12 08:05:45 reinelt Exp $   *   * driver for Matrix Orbital serial display modules   * @@ -20,6 +20,10 @@   *   *   * $Log: MatrixOrbital.c,v $ + * Revision 1.15  2000/04/12 08:05:45  reinelt + * + * first version of the HD44780 driver + *   * Revision 1.14  2000/04/10 04:40:53  reinelt   *   * minor changes and cleanups @@ -95,7 +99,6 @@  #include "lock.h"  #include "display.h" -#define SPEED 19200  #define XRES 5  #define YRES 8  #define CHARS 8 @@ -367,7 +370,7 @@ int MO_clear (void)    return 0;  } -static void MO_quit (int signal); //forward decvlaration +static void MO_quit (int signal); //forward declaration  int MO_init (LCD *Self)  { @@ -411,10 +414,6 @@ int MO_init (LCD *Self)    Device=MO_open();    if (Device==-1) return -1; -  signal(SIGINT,  MO_quit); -  signal(SIGQUIT, MO_quit); -  signal(SIGTERM, MO_quit); -    MO_clear();    MO_contrast(); @@ -425,6 +424,10 @@ int MO_init (LCD *Self)    MO_write ("\376R", 2);  // auto scroll off    MO_write ("\376V", 2);  // GPO off +  signal(SIGINT,  MO_quit); +  signal(SIGQUIT, MO_quit); +  signal(SIGTERM, MO_quit); +    return 0;  } @@ -1,4 +1,4 @@ -/* $Id: display.c,v 1.14 2000/04/03 17:31:52 reinelt Exp $ +/* $Id: display.c,v 1.15 2000/04/12 08:05:45 reinelt Exp $   *   * framework for device drivers   * @@ -20,6 +20,10 @@   *   *   * $Log: display.c,v $ + * Revision 1.15  2000/04/12 08:05:45  reinelt + * + * first version of the HD44780 driver + *   * Revision 1.14  2000/04/03 17:31:52  reinelt   *   * suppress welcome message if display is smaller than 20x2 @@ -119,12 +123,14 @@  extern LCD Skeleton[];  extern LCD MatrixOrbital[]; +extern LCD HD44780[];  extern LCD Raster[];  extern LCD XWindow[];  FAMILY Driver[] = {    { "Skeleton",        Skeleton },    { "Matrix Orbital",  MatrixOrbital }, +  { "Parallel port",   HD44780 },    { "Raster",          Raster },  #ifndef X_DISPLAY_MISSING    { "X Window System", XWindow }, diff --git a/lcd4linux.conf.sample b/lcd4linux.conf.sample index 2f37c77..f3ed752 100644 --- a/lcd4linux.conf.sample +++ b/lcd4linux.conf.sample @@ -3,6 +3,11 @@  #Speed 19200  #Contrast 160 +Display HD44780 +Port 0x378 +Size 16x2 + +  #Display PPM  #size 20x4  #font 5x8 @@ -13,16 +18,15 @@  #halfground \#70c000  #background \#80d000 -Display X11 -size 20x5 -font 5x8 -pixel 1+0 -gap -1x-1 -border 1 -foreground \#102000 -halfground \#90c000 -background \#a0d000 - +#Display X11 +#size 20x5 +#font 5x8 +#pixel 1+0 +#gap -1x-1 +#border 1 +#foreground \#102000 +#halfground \#90c000 +#background \#a0d000  #Row1 "*** %o %v ***"  #Row2 "%p CPU  %r MB RAM"  | 
