/* This is the LCDproc driver for tyan lcd module (tyan Barebone GS series) Author: yhlu@tyan.com Copyright (C) 2004 Tyan Corp 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 of the License, or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 */ /* * Driver status * 02/04/2004: Working driver * * * */ #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "lcd.h" #include "tyan_lcdm.h" #include "report.h" #include "lcd_lib.h" #define TYAN_LCDM_KEY_ENTER 0xf2 #define TYAN_LCDM_KEY_ESCAPE 0xf3 #define TYAN_LCDM_KEY_RIGHT 0xf5 #define TYAN_LCDM_KEY_LEFT 0xf6 #define TYAN_LCDM_KEY_UP 0xf7 #define TYAN_LCDM_KEY_DOWN 0xf8 #define TYAN_LCDM_CMD_BEGIN 0xf1 #define TYAN_LCDM_CMD_END 0xf2 static int custom = 0; typedef enum { hbar = 1, vbar = 2, cust = 3, } custom_type; static int fd; static char *framebuf = NULL; static char *old = NULL; static int width = 0; static int height = 0; static int cellwidth = DEFAULT_CELL_WIDTH; static int cellheight = DEFAULT_CELL_HEIGHT; /* 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 = "tyan_lcdm_"; /* Internal functions */ static void tyan_lcdm_init_vbar (Driver * drvthis); static void tyan_lcdm_init_hbar (Driver * drvthis); static void tyan_lcdm_switch_mode (); static void tyan_lcdm_hardware_clear (Driver * drvthis); static void tyan_lcdm_set_rampos(unsigned char pos); static void tyan_lcdm_write_str(char *str,unsigned char start_addr, int length); #if 0 static void tyan_lcdm_set_cursor(unsigned char start_addr, int pos); #endif static unsigned char tyan_lcdm_read_key(); /* * Opens com port and sets baud correctly... */ MODULE_EXPORT int tyan_lcdm_init (Driver * drvthis, char *args) { struct termios portset; int tmp, w, h; char device[200] = DEFAULT_DEVICE; int speed = DEFAULT_SPEED; char size[200] = DEFAULT_SIZE; debug(RPT_INFO, "tyan_lcdm: init(%p,%s)", drvthis, args ); /* Read config file */ /* Which serial device should be used */ strncpy(device, drvthis->config_get_string ( drvthis->name , "Device" , 0 , DEFAULT_DEVICE),sizeof(device)); device[sizeof(device)-1]=0; debug (RPT_INFO,"tyan_lcdm: Using device: %s", device); /* Which size */ strncpy(size, drvthis->config_get_string ( drvthis->name , "Size" , 0 , DEFAULT_SIZE),sizeof(size)); size[sizeof(size)-1]=0; if( sscanf(size , "%dx%d", &w, &h ) != 2 || (w <= 0) || (w > LCD_MAX_WIDTH) || (h <= 0) || (h > LCD_MAX_HEIGHT)) { report (RPT_WARNING, "tyan_lcdm_init: Cannot read size: %s. Using default value.\n", size); sscanf( DEFAULT_SIZE , "%dx%d", &w, &h ); } else { width = w; height = h; } /* Which speed */ tmp = drvthis->config_get_int ( drvthis->name , "Speed" , 0 , DEFAULT_SPEED); if (tmp == 4800) speed = B4800; else if (tmp == 9600) speed = B9600; else { report (RPT_WARNING, "tyan_lcdm_init: Speed must be 4800 or 9600. Using default value.\n", speed); } /* Set up io port correctly, and open it... */ debug( RPT_DEBUG, "tyan_lcdm: Opening serial device: %s", device); fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { report (RPT_ERR, "tyan_lcdm_init: failed (%s)\n", strerror (errno)); return -1; } tcgetattr (fd, &portset); /* We use RAW mode */ #ifdef HAVE_CFMAKERAW /* The easy way */ cfmakeraw( &portset ); #else /* The hard way */ portset.c_cflag = CS8 | CREAD | CLOCAL; portset.c_iflag = IXON | IXOFF | IGNBRK | IGNCR; portset.c_oflag &= ~ONLCR; portset.c_lflag = 0; portset.c_cc[VMIN] = 1; portset.c_cc[VTIME] = 0; #endif /* Set port speed */ cfsetospeed (&portset, speed); cfsetispeed (&portset, speed); /* Do it... */ tcsetattr (fd, TCSANOW, &portset); /* Make sure the frame buffer is there... */ framebuf = (unsigned char *) malloc (width * height); memset (framebuf, ' ', width * height); /* Set display-specific stuff.. */ tyan_lcdm_switch_mode (); report (RPT_DEBUG, "tyan_lcdm_init: done\n"); return 0; } /* * Clean-up */ MODULE_EXPORT void tyan_lcdm_close (Driver * drvthis) { close (fd); if(framebuf) free (framebuf); framebuf = NULL; if(old) free (old); old = NULL; } /* * Returns the display width */ MODULE_EXPORT int tyan_lcdm_width (Driver *drvthis) { return width; } /* * Returns the display height */ MODULE_EXPORT int tyan_lcdm_height (Driver *drvthis) { return height; } /* * Flushes all output to the lcd... */ MODULE_EXPORT void tyan_lcdm_flush (Driver * drvthis) { int i; char *xp, *xq; /* * We don't use delta update yet. * It is possible but not easy, we can only update a line, full or begining. */ if (old==NULL) { old = (unsigned char *) malloc (width * height); memset (old, ' ', width * height); tyan_lcdm_hardware_clear (drvthis); } xp = framebuf; xq = old; for (i=0; i 0 mean "on" and values <= 0 are "off". * * The input is just an array of characters... */ MODULE_EXPORT void tyan_lcdm_set_char (Driver * drvthis, int n, char *dat) { char out[8]; int row, col; int letter; if (n < 0 || n > 7) return; if (!dat) return; for (row = 0; row < cellheight; row++) { letter = 0; for (col = 0; col < cellwidth; col++) { letter <<= 1; letter |= (dat[(row * cellwidth) + col] > 0); /* I should remove that debug code. */ // if (dat[(row * cellheight) + col] == 0) printf("."); // if (dat[(row * cellheight) + col] == 1) printf("+"); // if (dat[(row * cellheight) + col] == 2) printf("x"); // if (dat[(row * cellheight) + col] == 3) printf("*"); // printf("'%1d'", dat[(row * cellwidth) + col]); // printf("%3d ", letter); } out[row+1]=letter; // printf(": %d\n", letter); } tyan_lcdm_write_str(out,(unsigned char)(0x40+n*8),8); } /* * Places an icon on screen */ MODULE_EXPORT int tyan_lcdm_icon (Driver * drvthis, int x, int y, int icon) { char icons[8][5 * 8] = { /* Empty Heart */ { 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, }, /* Filled Heart */ { 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, }, /* arrow_up */ { 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }, /* arrow_down */ { 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }, /* checkbox_off */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, }, /* checkbox_on */ { 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, }, /* checkbox_gray */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, }, /* Ellipsis */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, }, }; /* Yes we know, this is a VERY BAD implementation :-) */ switch( icon ) { case ICON_BLOCK_FILLED: tyan_lcdm_chr( drvthis, x, y, 255 ); break; case ICON_HEART_FILLED: custom = cust; tyan_lcdm_set_char( drvthis, 0, icons[1] ); tyan_lcdm_chr( drvthis, x, y, 0 ); break; case ICON_HEART_OPEN: custom = cust; tyan_lcdm_set_char( drvthis, 0, icons[0] ); tyan_lcdm_chr( drvthis, x, y, 0 ); break; case ICON_ARROW_UP: custom = cust; tyan_lcdm_set_char( drvthis, 1, icons[2] ); tyan_lcdm_chr( drvthis, x, y, 1 ); break; case ICON_ARROW_DOWN: custom = cust; tyan_lcdm_set_char( drvthis, 2, icons[3] ); tyan_lcdm_chr( drvthis, x, y, 2 ); break; case ICON_ARROW_LEFT: tyan_lcdm_chr( drvthis, x, y, 0x7F ); break; case ICON_ARROW_RIGHT: tyan_lcdm_chr( drvthis, x, y, 0x7E ); break; case ICON_CHECKBOX_OFF: custom = cust; tyan_lcdm_set_char( drvthis, 3, icons[4] ); tyan_lcdm_chr( drvthis, x, y, 3 ); break; case ICON_CHECKBOX_ON: custom = cust; tyan_lcdm_set_char( drvthis, 4, icons[5] ); tyan_lcdm_chr( drvthis, x, y, 4 ); break; case ICON_CHECKBOX_GRAY: custom = cust; tyan_lcdm_set_char( drvthis, 5, icons[6] ); tyan_lcdm_chr( drvthis, x, y, 5 ); break; default: return -1; /* Let the core do other icons */ } return 0; } /* * Clears the LCD screen */ MODULE_EXPORT void tyan_lcdm_clear (Driver * drvthis) { memset (framebuf, ' ', width * height); } /* * Hardware clears the LCD screen */ static void tyan_lcdm_hardware_clear (Driver * drvthis) { char lcdcmd[5]; //set os selection lcdcmd[0]=TYAN_LCDM_CMD_BEGIN; lcdcmd[1]=0x70; lcdcmd[2]=0x00; lcdcmd[3]=0x01; lcdcmd[4]=TYAN_LCDM_CMD_END; write(fd,lcdcmd,5); } /* * Prints a string on the lcd display, at position (x,y). The * upper-left is (1,1), and the lower right should be (16,2). */ MODULE_EXPORT void tyan_lcdm_string (Driver * drvthis, int x, int y, char string[]) { int i; /* Convert 1-based coords to 0-based... */ x -= 1; y -= 1; for (i = 0; string[i]; i++) { /* Check for buffer overflows... */ if ((y * width) + x + i > (width * height)) break; framebuf[(y * width) + x + i] = string[i]; } } static void tyan_lcdm_set_rampos(unsigned char pos) { char cmd_str[5]; cmd_str[0]=TYAN_LCDM_CMD_BEGIN; cmd_str[1]=0x70; cmd_str[2]=0x00; cmd_str[3]=pos; cmd_str[4]=TYAN_LCDM_CMD_END; write( fd,cmd_str,5); } static void tyan_lcdm_write_str(char *str,unsigned char start_addr, int length) { //CGRAM 0x40, 0x48,.... //if Line 1: start_addr = 0x80 //if Line 2: start_addr = 0xc0 // 1<= length <=16 char cmd_str[20]; tyan_lcdm_set_rampos(start_addr); memset(cmd_str,' ', 20); cmd_str[0] = TYAN_LCDM_CMD_BEGIN; cmd_str[1] = 0x70; cmd_str[2] = 0x02; cmd_str[19] = TYAN_LCDM_CMD_END; memcpy(cmd_str+3,str,length); write(fd,cmd_str,20); } #if 0 static void tyan_lcdm_set_cursor(unsigned char start_addr, int pos){ char cmd_str[5]; tyan_lcdm_set_rampos(pos+start_addr); cmd_str[0] = TYAN_LCDM_CMD_BEGIN; cmd_str[1] = 0x70; cmd_str[2] = 0x00; cmd_str[3] = 0x0e; cmd_str[4] = TYAN_LCDM_CMD_END; write(fd,cmd_str,5); } #endif static unsigned char tyan_lcdm_read_key(){ int count=0; char key_str[4]; memset(key_str,0,4); count=read(fd,key_str,4); if( key_str[0] == (char)TYAN_LCDM_CMD_BEGIN && key_str[1]==(char)0x72 && key_str[3]==(char)TYAN_LCDM_CMD_END){ return key_str[2]; } return 0xf4; //error }