diff options
| -rw-r--r-- | drv.c | 17 | ||||
| -rw-r--r-- | drv_MatrixOrbital.c | 602 | 
2 files changed, 605 insertions, 14 deletions
| @@ -1,4 +1,4 @@ -/* $Id: drv.c,v 1.1 2004/01/09 17:03:07 reinelt Exp $ +/* $Id: drv.c,v 1.2 2004/01/10 10:20:22 reinelt Exp $   *   * new framework for display drivers   * @@ -23,6 +23,9 @@   *   *   * $Log: drv.c,v $ + * Revision 1.2  2004/01/10 10:20:22  reinelt + * new MatrixOrbital changes + *   * Revision 1.1  2004/01/09 17:03:07  reinelt   * initiated transfer to new driver architecture   * new file 'drv.c' will someday replace 'display.c' @@ -144,7 +147,7 @@ DRIVER *Driver[] = {  }; -static DRIVER *Lcd = NULL; +static DRIVER *Drv = NULL;  int drv_list (void) @@ -167,9 +170,9 @@ int drv_init (char *section, char *driver)    int i;    for (i=0; Driver[i]; i++) {      if (strcmp (Driver[i]->name, driver)==0) { -      Lcd=Driver[i]; -      if (Lcd->init==NULL) return 0; -      return Lcd->init(Lcd); +      Drv=Driver[i]; +      if (Drv->init==NULL) return 0; +      return Drv->init(section);      }    }    error ("drv_init(%s) failed: no such driver", driver); @@ -179,6 +182,6 @@ int drv_init (char *section, char *driver)  int drv_quit (void)  { -  if (Lcd->quit==NULL) return 0; -  return Lcd->quit(); +  if (Drv->quit==NULL) return 0; +  return Drv->quit();  } diff --git a/drv_MatrixOrbital.c b/drv_MatrixOrbital.c index 1bb55e7..b537ae7 100644 --- a/drv_MatrixOrbital.c +++ b/drv_MatrixOrbital.c @@ -1,4 +1,4 @@ -/* $Id: drv_MatrixOrbital.c,v 1.1 2004/01/09 17:03:07 reinelt Exp $ +/* $Id: drv_MatrixOrbital.c,v 1.2 2004/01/10 10:20:22 reinelt Exp $   *   * new style driver for Matrix Orbital serial display modules   * @@ -23,6 +23,9 @@   *   *   * $Log: drv_MatrixOrbital.c,v $ + * Revision 1.2  2004/01/10 10:20:22  reinelt + * new MatrixOrbital changes + *   * Revision 1.1  2004/01/09 17:03:07  reinelt   * initiated transfer to new driver architecture   * new file 'drv.c' will someday replace 'display.c' @@ -56,21 +59,606 @@  #include "bar.h"  #include "icon.h" + +static char *Port=NULL; +static speed_t Speed; +static int Device=-1; +static int Model; + +static int ROWS, COLS; +static int XRES, YRES; +static int CHARS, ICONS, GPOS; +static int PROTOCOL; + +static char *FrameBuffer1=NULL; +static char *FrameBuffer2=NULL; +static int GPO[8]; + + +typedef struct { +  int type; +  char *name; +  int rows; +  int cols; +  int gpos; +  int protocol; +} MODEL; + +// Fixme #1: number of gpo's should be verified +// Fixme #2: protocol should be verified + +static MODEL Models[] = { +  { 0x01, "LCD0821",      2,  8, 0, 1 }, +  { 0x03, "LCD2021",      2, 20, 0, 1 }, +  { 0x04, "LCD1641",      4, 16, 0, 1 }, +  { 0x05, "LCD2041",      4, 20, 0, 1 }, +  { 0x06, "LCD4021",      2, 40, 0, 1 }, +  { 0x07, "LCD4041",      4, 40, 0, 1 }, +  { 0x08, "LK202-25",     2, 20, 0, 2 }, +  { 0x09, "LK204-25",     4, 20, 0, 2 }, +  { 0x0a, "LK404-55",     4, 40, 0, 2 }, +  { 0x0b, "VFD2021",      2, 20, 0, 1 }, +  { 0x0c, "VFD2041",      4, 20, 0, 1 }, +  { 0x0d, "VFD4021",      2, 40, 0, 1 }, +  { 0x0e, "VK202-25",     2, 20, 0, 1 }, +  { 0x0f, "VK204-25",     4, 20, 0, 1 }, +  { 0x10, "GLC12232",    -1, -1, 0, 1 }, +  { 0x13, "GLC24064",    -1, -1, 0, 1 }, +  { 0x15, "GLK24064-25", -1, -1, 0, 1 }, +  { 0x22, "GLK12232-25", -1, -1, 0, 1 }, +  { 0x31, "LK404-AT",     4, 40, 0, 2 }, +  { 0x32, "VFD1621",      2, 16, 0, 1 }, +  { 0x33, "LK402-12",     2, 40, 0, 2 }, +  { 0x34, "LK162-12",     2, 16, 0, 2 }, +  { 0x35, "LK204-25PC",   4, 20, 0, 2 }, +  { 0x36, "LK202-24-USB", 2, 20, 0, 2 }, +  { 0x38, "LK204-24-USB", 4, 20, 0, 2 }, +  { 0xff, "Unknown",     -1, -1, 0, 0 } +}; + + +static int drv_MO_open (void) +{ +  int fd; +  pid_t pid; +  struct termios portset; +   +  if ((pid=lock_port(Port))!=0) { +    if (pid==-1) +      error ("MatrixOrbital: port %s could not be locked", Port); +    else +      error ("MatrixOrbital: port %s is locked by process %d", Port, pid); +    return -1; +  } +  fd = open(Port, O_RDWR | O_NOCTTY | O_NDELAY);  +  if (fd==-1) { +    error ("MatrixOrbital: open(%s) failed: %s", Port, strerror(errno)); +    unlock_port(Port); +    return -1; +  } +  if (tcgetattr(fd, &portset)==-1) { +    error ("MatrixOrbital: tcgetattr(%s) failed: %s", Port, strerror(errno)); +    unlock_port(Port); +    return -1; +  } +  cfmakeraw(&portset); +  cfsetospeed(&portset, Speed); +  if (tcsetattr(fd, TCSANOW, &portset)==-1) { +    error ("MatrixOrbital: tcsetattr(%s) failed: %s", Port, strerror(errno)); +    unlock_port(Port); +    return -1; +  } +  return fd; +} + + +static int drv_MO_read (char *string, int len) +{ +  int run, ret; +   +  if (Device==-1) return -1; +  for (run=0; run<10; run++) { +    ret=read (Device, string, len); +    if (ret>=0 || errno!=EAGAIN) break; +    debug ("read(): EAGAIN"); +    usleep(1000); +  } +   +  if (ret<0) { +    error("MatrixOrbital: read(%s, %d) failed: %s", Port, len, strerror(errno)); +  } +   +  return ret; +} + + +static void drv_MO_write (char *string, int len) +{ +  int run, ret; +   +  if (Device==-1) return; +  for (run=0; run<10; run++) { +    ret=write (Device, string, len); +    if (ret>=0 || errno!=EAGAIN) break; +    debug ("write(): EAGAIN"); +    usleep(1000); +  } + +  if (ret<0) { +    error ("MatrixOrbital: write(%s) failed: %s", Port, strerror(errno)); +  } + +  // Fixme +  if (ret!=len) { +    error ("MatrixOrbital: partial write: len=%d ret=%d", len, ret); +  } + +  return; +} + + +static int drv_MO_contrast (void) +{ +  char buffer[4]; +  int  contrast; + +  if (cfg_number(NULL, "Contrast", 160, 0, 255, &contrast)<0) return -1; +  snprintf (buffer, 4, "\376P%c", contrast); +  drv_MO_write (buffer, 3); +  return 0; +} + + +static void drv_MO_define_char (int ascii, char *buffer) +{ +  char cmd[3]="\376N"; + +  cmd[2]=(char)ascii; +  drv_MO_write (cmd, 3); +  drv_MO_write (buffer, 8); +} + + +static int drv_MO_clear (int protocol) +{ +  int gpo; +   +  memset (FrameBuffer1, ' ', ROWS*COLS*sizeof(char)); + +  icon_clear(); +  bar_clear(); +  memset(GPO, 0, sizeof(GPO)); + +  if (protocol) { +    memset (FrameBuffer2, ' ', ROWS*COLS*sizeof(char)); +    switch (protocol) { +    case 1: +      drv_MO_write ("\014",  1);  // Clear Screen +      drv_MO_write ("\376V", 2);  // GPO off +      break; +    case 2: +      drv_MO_write ("\376\130",  2);  // Clear Screen +      for (gpo=1; gpo<=GPOS; gpo++) { +	char cmd1[3]="\376V"; +	char cmd2[4]="\376\300x\377"; +	cmd1[2]=(char)gpo; +	cmd2[2]=(char)gpo; +	drv_MO_write (cmd1, 3);  // GPO off +	drv_MO_write (cmd2, 4);  // PWM full power +      } +      break; +    } +  } +   +  return 0; +} + +static void plugin_contrast (RESULT *result, RESULT *arg1) +{ +  char buffer[4]; +  double contrast; + +  contrast=R2N(arg1); +  if (contrast<0  ) contrast=0; +  if (contrast>255) contrast=255; +  snprintf (buffer, 4, "\376P%c", (int)contrast); +  drv_MO_write (buffer, 3); +   +  SetResult(&result, R_NUMBER, &contrast);  +} + + +static void plugin_backlight (RESULT *result, RESULT *arg1) +{ +  char buffer[4]; +  double backlight; + +  backlight=R2N(arg1); +  if (backlight<-1  ) backlight=-1; +  if (backlight>255) backlight=255; +  if (backlight<0) { +    // backlight off +    snprintf (buffer, 3, "\376F"); +    drv_MO_write (buffer, 2); +  } else { +    // backlight on for n minutes +    snprintf (buffer, 4, "\376B%c", (int)backlight); +    drv_MO_write (buffer, 3); +  } +  SetResult(&result, R_NUMBER, &backlight);  +} + + +static void plugin_gpo (RESULT *result, RESULT *arg1, RESULT *arg2) +{ +  int num; +  double val; +  char cmd[3]="\376"; +  // Fixme +  int protocol=2; +   +  num=R2N(arg1); +  val=R2N(arg2); +   +  if (num<1) num=1; +  if (num>6) num=6; +   +  if (val>=1.0) { +    val=1.0; +  } else { +    val=0.0; +  } +   +  switch (protocol) { +  case 1: +    if (num==0) { +      if (val>=1.0) { +	drv_MO_write ("\376W", 2);  // GPO on +      } else { +	drv_MO_write ("\376V", 2);  // GPO off +      } +    } else { +      error("Fixme"); +      val=-1.0; +    } +    break; +     +  case 2: +    if (val>=1.0) { +      cmd[1]='W';  // GPO on +    } else { +      cmd[1]='V';  // GPO off +    } +    cmd[2]=(char)num; +    drv_MO_write (cmd, 3); +    break; +  } +   +  SetResult(&result, R_NUMBER, &val);  +} + + +static void plugin_pwm (RESULT *result, RESULT *arg1, RESULT *arg2) +{ +  int    num; +  double val; +  char   cmd[4]="\376\300"; +   +  num=R2N(arg1); +  if (num<1) num=1; +  if (num>6) num=6; +  cmd[2]=(char)num; +   +  val=R2N(arg2); +  if (val<  0.0) val=  0.0; +  if (val>255.0) val=255.0; +  cmd[3]=(char)val; + +  drv_MO_write (cmd, 4); + +  SetResult(&result, R_NUMBER, &val);  +} + + +static void plugin_rpm (RESULT *result, RESULT *arg1) +{ +  int    num; +  double val; +  char   cmd[3]="\376\301"; +  char   buffer[7]; +   +  num=R2N(arg1); +  if (num<1) num=1; +  if (num>6) num=6; +  cmd[2]=(char)num; +   +  drv_MO_write (cmd, 3); +  usleep(100000); +  drv_MO_read (buffer, 7); +   +  debug ("rpm: buffer[0]=0x%01x", buffer[0]); +  debug ("rpm: buffer[1]=0x%01x", buffer[1]); +  debug ("rpm: buffer[2]=0x%01x", buffer[2]); +  debug ("rpm: buffer[3]=0x%01x", buffer[3]); +  debug ("rpm: buffer[4]=0x%01x", buffer[4]); +  debug ("rpm: buffer[5]=0x%01x", buffer[5]); +  debug ("rpm: buffer[6]=0x%01x", buffer[6]); + +  SetResult(&result, R_NUMBER, &val);  +} + + +static void drv_MO_goto (int row, int col) +{ +  char cmd[5]="\376Gyx"; +  cmd[2]=(char)col+1; +  cmd[3]=(char)row+1; +  drv_MO_write(cmd,4); +} + + +static int drv_MO_put (int row, int col, char *text) +{ +  char *p=FrameBuffer1+row*COLS+col; +  char *t=text; +   +  while (*t && col++<=COLS) { +    *p++=*t++; +  } +  return 0; +} + + +static int drv_MO_bar (int type, int row, int col, int max, int len1, int len2) +{ +  return bar_draw (type, row, col, max, len1, len2); +} + + +static int drv_MO_icon (int num, int seq, int row, int col) +{ +  return icon_draw (num, seq, row, col); +} + + +static int drv_MO_gpo (int num, int val) +{ +  if (num>=GPOS)  +    return -1; + +  GPO[num]=val; +   +  // Fixme +  GPO[num]=255; + +  return 0; +} + + +static int drv_MO_flush (int protocol) +{ +  int row, col, pos1, pos2; +  int c, equal; +  int gpo; +   +  bar_process(drv_MO_define_char); +   +  for (row=0; row<ROWS; row++) { +    for (col=0; col<COLS; col++) { +      c=bar_peek(row, col); +      if (c==-1) c=icon_peek(row, col); +      if (c!=-1) { +	FrameBuffer1[row*COLS+col]=(char)c; +      } +    } +    for (col=0; col<COLS; col++) { +      if (FrameBuffer1[row*COLS+col]==FrameBuffer2[row*COLS+col]) continue; +      drv_MO_goto (row, col); +      for (pos1=col++, pos2=pos1, equal=0; col<COLS; col++) { +	if (FrameBuffer1[row*COLS+col]==FrameBuffer2[row*COLS+col]) { +	  // If we find just one equal byte, we don't break, because this  +	  // would require a goto, which takes one byte, too. +	  if (++equal>5) break; +	} else { +	  pos2=col; +	  equal=0; +	} +      } +      drv_MO_write (FrameBuffer1+row*COLS+pos1, pos2-pos1+1); +    } +  } +   +  memcpy (FrameBuffer2, FrameBuffer1, ROWS*COLS*sizeof(char)); +   +  switch (protocol) { +  case 1: +    if (GPO[0]) { +      drv_MO_write ("\376W", 2);  // GPO on +    } else { +      drv_MO_write ("\376V", 2);  // GPO off +    } +    break; +  case 2: +    for (gpo=1; gpo<=GPOS; gpo++) { +      char cmd[3]="\376"; +      cmd[1]=GPO[gpo]? 'W':'V'; +      cmd[2]=(char)gpo; +      drv_MO_write (cmd, 3); +    } +    break; +  } +   +  return 0; +} + + +// ***************************** +// exported functions start here +// ***************************** + +  int drv_MO_list (void)  { -  printf ("this and that"); +  int i; +   +  for (i=0; Models[i].type!=0xff; i++) { +    printf ("%s ", Models[i].name); +  }    return 0;  } -int drv_MO_init (struct DRIVER *Self) + +int drv_MO_init (char *section)  { -  debug ("consider me initialized"); +  int i;   +  char *port, buffer[256]; +  char *model; +   +  if (Port) { +    free (Port); +    Port=NULL; +  } + +  model=cfg_get(section, "Model", NULL); +  if (model!=NULL && *model!='\0') { +    for (i=0; Models[i].type!=0xff; i++) { +      if (strcasecmp(Models[i].name, model)==0) break; +    } +    if (Models[i].type==0xff) { +      error ("MatrixOrbital: %s.Model '%s' is unknown from %s", section, model, cfg_source()); +      return -1; +    } +    Model=i; +    info ("MatrixOrbital: using model '%s'", Models[Model].name); +  } else { +    info ("MatrixOrbital: no '%s.Model' entry from %s, auto-dedecting", section, cfg_source()); +    Model=-1; +  } +   +   +  port=cfg_get(section, "Port", NULL); +  if (port==NULL || *port=='\0') { +    error ("MatrixOrbital: no '%s.Port' entry from %s", section, cfg_source()); +    return -1; +  } +  Port=strdup(port); + +  if (cfg_number(section, "Speed", 19200, 1200, 19200, &i)<0) return -1; +  switch (i) { +  case 1200: +    Speed=B1200; +    break; +  case 2400: +    Speed=B2400; +    break; +  case 9600: +    Speed=B9600; +    break; +  case 19200: +    Speed=B19200; +    break; +  default: +    error ("MatrixOrbital: unsupported speed '%d' from %s", i, cfg_source()); +    return -1; +  }     +   +  info ("MatrixOrbital: using port '%s' at %d baud", Port, i); +   +  Device=drv_MO_open(); +  if (Device==-1) return -1; + +  // read module type +  drv_MO_write ("\3767", 2); +  usleep(1000); +  drv_MO_read (buffer, 1); +  for (i=0; Models[i].type!=0xff; i++) { +    if (Models[i].type == (int)*buffer) break; +  } +  info ("MatrixOrbital: Display identifies itself as a '%s' (type 0x%02x)",  +	Models[i].name, Models[i].type); +   +  // auto-dedection +  if (Model==-1) Model=i; +   +  // auto-dedection matches specified model? +  if (Model!=i) { +    error ("MatrixOrbital: %s.Model '%s' from %s does not match dedected Model '%s'",  +	   section, model, cfg_source(), Models[i].name); +    return -1; +  } + +  // read serial number +  drv_MO_write ("\3765", 2); +  usleep(100000); +  drv_MO_read (buffer, 2); +  info ("MatrixOrbital: Display reports Serial Number 0x%x", *(short*)buffer); +   +  // read version number +  drv_MO_write ("\3766", 2); +  usleep(100000); +  drv_MO_read (buffer, 1); +  info ("MatrixOrbital: Display reports Firmware Version 0x%x", *buffer); + + +  // Init the framebuffers +  FrameBuffer1 = (char*)malloc(COLS*ROWS*sizeof(char)); +  FrameBuffer2 = (char*)malloc(COLS*ROWS*sizeof(char)); +  if (FrameBuffer1==NULL || FrameBuffer2==NULL) { +    error ("MatrixOrbital: framebuffer could not be allocated: malloc() failed"); +    return -1; +  } + +  // init Icons +  if (cfg_number(NULL, "Icons", 0, 0, CHARS, &ICONS)<0) return -1; +  if (ICONS>0) { +    debug ("reserving %d of %d user-defined characters for icons", ICONS, CHARS); +    icon_init(ROWS, COLS, XRES, YRES, CHARS, ICONS, drv_MO_define_char); +  } +   +  // init Bars +  bar_init(ROWS, COLS, XRES, YRES, CHARS-ICONS); +  bar_add_segment(  0,  0,255, 32); // ASCII  32 = blank +  bar_add_segment(255,255,255,255); // ASCII 255 = block + + +  drv_MO_clear(PROTOCOL); +  drv_MO_contrast(); + +  drv_MO_write ("\376B", 3);  // backlight on +  drv_MO_write ("\376K", 2);  // cursor off +  drv_MO_write ("\376T", 2);  // blink off +  drv_MO_write ("\376D", 2);  // line wrapping off +  drv_MO_write ("\376R", 2);  // auto scroll off + +  // register as a plugin +  AddFunction ("contrast",  1, plugin_contrast); +  AddFunction ("backlight", 1, plugin_backlight); +  AddFunction ("gpo",       2, plugin_gpo); +  AddFunction ("pwm",       2, plugin_pwm); +  AddFunction ("rpm",       1, plugin_rpm); +    return 0;  } +  int drv_MO_quit (void) { -  debug ("consider me gone"); -  return 0; +  info("MatrixOrbital: shutting down."); +   +  debug ("closing port %s", Port); +  close (Device); +  unlock_port(Port); +   +  if (FrameBuffer1) { +    free(FrameBuffer1); +    FrameBuffer1=NULL; +  } +   +  if (FrameBuffer2) { +    free(FrameBuffer2); +    FrameBuffer2=NULL; +  } +   +  return (0);  } @@ -78,5 +666,5 @@ DRIVER drv_MatrixOrbital = {    name: "MatrixOrbital",    list:  drv_MO_list,    init:  drv_MO_init, -  quit:  drv_MO_quit  +  quit:  drv_MO_quit,   }; | 
