diff --git a/server/drivers/CwLnx.c b/server/drivers/CwLnx.c new file mode 100644 index 0000000..1bef580 --- /dev/null +++ b/server/drivers/CwLnx.c @@ -0,0 +1,1555 @@ +/* #define COUNT -1 */ + +/* +List of driver entry point: + +init Work in progress... +close Implemented. +width If this is a variable, then implemented. +height If this is a variable, then implemented. +clear Implemented by space filling no custom char info. +flush Calling draw_frame only. +string Implemented. +chr Implemented. +vbar . +hbar . +num . +heartbeat Implemented for testing only. +icon . +cursor NOT IMPLEMENTED: Is it really used? +set_char . +get_free_chars NOT IMPLEMENTED: Custom char should not be exported. +cellwidth If this is a variable, then implemented. +cellheight If this is a variable, then implemented. +get_contrast Not implemented, no software control. +set_contrast Not implemented, no software control. +get_brightness Implemented, still need flush code. +set_brightness Implemented, still need flush code. +backlight Implemented, still need flush code. +output . +get_key Implemented like in CF633, need cleaning in init. +get_info . + +*/ + +/* This is the LCDproc driver for Cwlinux devices (http://www.cwlinux.com) + + Copyright (C) 2002, Andrew Ip + 2003, David Glaude + + 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 */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "lcd.h" +#include "CwLnx.h" +#include "report.h" +#include "lcd_lib.h" + +#define ValidX(x) if ((x) > p->width) { (x) = p->width; } else (x) = (x) < 1 ? 1 : (x); +#define ValidY(y) if ((y) > p->height) { (y) = p->height; } else (y) = (y) < 1 ? 1 : (y); + +#define MaxKeyMap 6 + +static char *defaultKeyMap[MaxKeyMap] = { "Up", "Down", "Left", "Right", "Enter", "Escape" }; + +typedef enum { + hbar = 1, + vbar = 2, + bign = 4, +} custom_type; + +typedef struct p { + int custom; + int fd; + + int have_keypad; + int keypad_test_mode; + char *KeyMap[MaxKeyMap]; + +/*I*/ int width; +/*I*/ int height; + +/*I*/ int cellwidth; +/*I*/ int cellheight; + +/*I*/ char *backingstore; +/*I*/ char *framebuf; /* Frame buffer */ + +/*I*/ char saved_backlight; /* current state of the backlight */ +/*I*/ char backlight; /* state of the backlight at next flush */ + +/*I*/ int saved_brightness; /* brightness as displayed on the LCD currently */ +/*I*/ int brightness; /* brightness as it will be displayed at next flush */ + +/*I*/ int saved_heartbeat; /* heartbeat as displayed on the LCD currently */ +/*I*/ int heartbeat; /* heartbeat as it will be displayed at next flush */ + +/*I*/ int heartbeat_state; /* toggle to remember when we turn on or off */ + +} PrivateData; + +/* API: Vars for the server core */ +MODULE_EXPORT char *api_version = API_VERSION; +MODULE_EXPORT int stay_in_foreground = 0; /* For testing only */ +MODULE_EXPORT int supports_multiple = 1; +MODULE_EXPORT char *symbol_prefix = "CwLnx_"; + + +static void CwLnx_linewrap(int fd, int on); +static void CwLnx_autoscroll(int fd, int on); +static void CwLnx_hidecursor(int fd); + +void CwLnx_draw_frame(Driver *drvthis, char *dat); + +#define LCD_CMD 254 +#define LCD_CMD_END 253 +#define LCD_INIT_CHINESE_T 56 +#define LCD_INIT_CHINESE_S 55 +#define LCD_LIGHT_ON 66 +#define LCD_LIGHT_OFF 70 +#define LCD_LIGHT_BRIGHTNESS 65 +#define LCD_CLEAR 88 +#define LCD_SET_INSERT 71 +#define LCD_INIT_INSERT 72 +#define LCD_SET_BAUD 57 +#define LCD_ENABLE_WRAP 67 +#define LCD_DISABLE_WRAP 68 +#define LCD_SETCHAR 78 +#define LCD_ENABLE_SCROLL 81 +#define LCD_DISABLE_SCROLL 82 +#define LCD_OFF_CURSOR 72 + +#define LCD_PUT_PIXEL 112 +#define LCD_CLEAR_PIXEL 113 + +#define LCD_LENGTH 20 + +#define DELAY 20 +#define UPDATE_DELAY 0 /* 1 sec */ +#define SETUP_DELAY 1 /* 2 sec */ + +/* Parse one key from the configfile */ +static char CwLnx_parse_keypad_setting (Driver *drvthis, char * keyname, char default_value) +{ + char return_val = 0; + char * s; + char buf [255]; + + s = drvthis->config_get_string ( drvthis->name, keyname, 0, NULL); + if (s != NULL){ + strncpy (buf, s, sizeof(buf)); + buf[sizeof(buf)-1]=0; + return_val = buf[0]; + } else { + return_val=default_value; + } + return return_val; +} + +int Read_LCD(int fd, char *c, int size) +{ + int rc; + rc = read(fd, c, size); +/* usleep(DELAY); */ + return rc; +} + +int Write_LCD(int fd, char *c, int size) +{ + int rc; + rc = write(fd, c, size); +/* Debuging code to be cleaned when very stable */ +/* + if (size==1) { + if (*c>=0) + printf("%3d ", *c); + else + { + if (*c+256==254) + + printf("\n%3d ", *c+256); + else printf("%3d ", *c+256); + } + } +*/ +/* usleep(DELAY); */ + return rc; +} + + + + +/********************************************* + * Real hardware function. + * Will be called by API function. + */ + + +/* Hardware function */ +void Enable_Backlight(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_LIGHT_ON; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + +/* Hardware function */ +void Disable_Backlight(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_LIGHT_OFF; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + +/* Hardware function */ +void Enable_Pixel(int fd, int x, int y) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_PUT_PIXEL; + rc = Write_LCD(fd, &c, 1); + + c = x; + rc = Write_LCD(fd, &c, 1); + c = y; + rc = Write_LCD(fd, &c, 1); + + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + +/* Hardware function */ +void Disable_Pixel(int fd, int x, int y) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_CLEAR_PIXEL; + rc = Write_LCD(fd, &c, 1); + + c = x; + rc = Write_LCD(fd, &c, 1); + c = y; + rc = Write_LCD(fd, &c, 1); + + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + + +/* Hardware function */ +void Backlight_Brightness(int fd, int brightness) +{ + char c; + int rc; + + if (brightness == 1) { + Disable_Backlight(fd); + } else if (brightness == 7) { + Enable_Backlight(fd); + } else { + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_LIGHT_BRIGHTNESS; + rc = Write_LCD(fd, &c, 1); + c = (char) brightness; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); + } +} + +/* Hardware function */ +void Enable_Scroll(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_ENABLE_SCROLL; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + +/* Hardware function */ +void Disable_Scroll(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_DISABLE_SCROLL; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + + +/* Hardware function */ +void Clear_Screen(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_CLEAR; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); + usleep(UPDATE_DELAY); +} + +/* Hardware function */ +void Enable_Wrap(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_ENABLE_WRAP; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + +/* Hardware function */ +void Disable_Wrap(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_DISABLE_WRAP; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + +/* Hardware function */ +void Disable_Cursor(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_OFF_CURSOR; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + + +/* Hardware function */ +void Init_Port(fd) +{ + /* Posix - set baudrate to 0 and back */ + struct termios tty, old; + + tcgetattr(fd, &tty); + tcgetattr(fd, &old); + cfsetospeed(&tty, B0); + cfsetispeed(&tty, B0); + tcsetattr(fd, TCSANOW, &tty); + usleep(SETUP_DELAY); + tcsetattr(fd, TCSANOW, &old); +} + +/* Hardware function */ +void Setup_Port(int fd, speed_t speed) +{ + struct termios portset; + + tcgetattr(fd, &portset); + cfsetospeed(&portset, speed); + cfsetispeed(&portset, speed); + portset.c_iflag = IGNBRK; + portset.c_lflag = 0; + portset.c_oflag = 0; + portset.c_cflag |= CLOCAL | CREAD; + portset.c_cflag &= ~CRTSCTS; + portset.c_cc[VMIN] = 1; + portset.c_cc[VTIME] = 5; + tcsetattr(fd, TCSANOW, &portset); +} + +/* Hardware function */ +void Set_9600(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_SET_BAUD; + rc = Write_LCD(fd, &c, 1); + c = 0x20; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + +/* Hardware function */ +void Set_19200(int fd) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + c = LCD_SET_BAUD; + rc = Write_LCD(fd, &c, 1); + c = 0xf; + rc = Write_LCD(fd, &c, 1); + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + + +/* + * ONLY USED BY flush_box +int Write_Line_LCD(int fd, char *buf) +{ + int i; + char c; + int isEnd = 0; + int rc; + + for (i = 0; i < LCD_LENGTH; i++) { + if (buf[i] == '\0') { + isEnd = 1; + } + if (isEnd) { + c = ' '; + } else { + c = buf[i]; + } + rc = Write_LCD(fd, &c, 1); + } +*/ +/* printf("%s\n", buf); */ +/* + return 0; +} +*/ + + +/***************************************************** + * Here start the API function + */ + +/***************************************************** + * API: Opens com port and sets baud correctly... + */ +int CwLnx_init(Driver * drvthis, char *args) +{ + struct termios portset_save; + + char device[200] = DEFAULT_DEVICE; + int speed = DEFAULT_SPEED; + char size[200] = DEFAULT_SIZE; + + char buf[256] = ""; + int tmp; + int w; + int h; + char *s; + char x; + + PrivateData *p; + + /* Alocate and store private data */ + p = (PrivateData *) malloc( sizeof( PrivateData) ); + if( ! p ) + return -1; + if( drvthis->store_private_ptr( drvthis, p ) ) + return -1; + + /* Initialise the PrivateData structure */ + + p->framebuf = NULL; + +/* height and width are computed from DEFAULT_SIZE */ +/* p->width = DEFAULT_WIDTH; */ +/* p->height = DEFAULT_HEIGHT; */ + p->cellwidth = DEFAULT_CELLWIDTH; + p->cellheight = DEFAULT_CELLHEIGHT; + + p->saved_backlight = -1; + p->backlight = DEFAULT_BACKLIGHT; + + p->saved_brightness = -1; + p->brightness = DEFAULT_BRIGHTNESS; + + p->heartbeat_state = 0; + p->saved_heartbeat = -1; + p->heartbeat = 0; + + debug(RPT_INFO, "CwLnx: 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; + report(RPT_INFO, "CwLnx: 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, "CwLnx: Cannot read size: %s. Using default value.\n", size); + sscanf(DEFAULT_SIZE, "%dx%d", &w, &h); + } + p->width = w; + p->height = h; + + /* Contrast of the LCD can be change by adjusting the trimpot R7 */ + + /* Which speed */ + tmp = drvthis->config_get_int(drvthis->name, "Speed", 0, DEFAULT_SPEED); + + switch (tmp) { + case 9600: + speed = B9600; + break; + case 19200: + speed = B19200; + break; + default: + speed = DEFAULT_SPEED; + + switch (speed) { + case B9600: + strncpy(buf, "9600", sizeof(buf)); + break; + case B19200: + strncpy(buf, "19200", sizeof(buf)); + break; + } + + report(RPT_WARNING, + "CwLnx: Speed must be 9600 or 19200. Using default value of %s baud!", + buf); + strncpy(buf, "", sizeof(buf)); + } + + + /* do we have a keypad? */ + if (drvthis->config_get_bool( drvthis->name , "Keypad" , 0 , 0)) { + report (RPT_INFO, "CwLnx: Config file tell us we have a keypad...\n"); + p->have_keypad = 1; + } + + /* keypad test mode? */ + if (drvthis->config_get_bool( drvthis->name , "keypad_test_mode" , 0 , 0)) { + report (RPT_INFO, "CwLnx: Config tell us to test the keypad mapping...\n"); + p->keypad_test_mode = 1; + stay_in_foreground = 1; + } + + /* read the keypad mapping only if we have a keypad. */ + if (p->have_keypad) + { + + + /* Read keymap */ + for(x=0; xKeyMap[x] = defaultKeyMap[x]; +/* The line above make a warning... the code is comming from hd44780.c */ + +/* printf("%s-%s\n", defaultKeyMap[x], p->KeyMap[x]); */ + + /* Read config value */ + sprintf( buf, "KeyMap_%c", x+'A' ); + s = drvthis->config_get_string( drvthis->name, buf, 0, NULL ); + + /* Was a key specified in the config file ? */ + if( s ) { + p->KeyMap[x] = strdup( s ); +/* Code from hd44780 but why a strcpy adfter a strdup ? */ +/* strcpy( p->KeyMap[x], s ); */ +/* printf("CwLnx: Key '%c' to \"%s\"\n", x+'A', s ); */ + report( RPT_INFO, "CwLnx: Key '%c' to \"%s\"", x+'A', s ); + } + } + + } + + /* End of config file parsing */ + + /* Allocate framebuffer memory */ + if (!p->framebuf) { + p->framebuf = malloc(p->width * p->height); + p->backingstore = calloc(p->width * p->height, 1); + memset(p->backingstore, ' ', p->width * p->height); + } + + if (!p->framebuf) { + report(RPT_ERR, "CwLnx: Error: unable to create framebuffer.\n"); + return -1; + } + + /* Set up io port correctly, and open it... */ + debug(RPT_DEBUG, "CwLnx: Opening serial device: %s", device); + p->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); + if (p->fd == -1) { + report(RPT_ERR, "CwLnx: init() failed (%s)\n", strerror(errno)); + return -1; + } else { + report(RPT_INFO, "CwLnx: Opened display on %s", device); + } + + Init_Port(p->fd); + tcgetattr(p->fd, &portset_save); + speed = B19200; + Setup_Port(p->fd, speed); + Set_9600(p->fd); + close(p->fd); + + p->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); + if (p->fd == -1) { + report(RPT_ERR, "CwLnx: init() failed (%s)\n", strerror(errno)); + return -1; + } else { + report(RPT_INFO, "CwLnx: Opened display on %s", device); + } + Init_Port(p->fd); + speed = B9600; + Setup_Port(p->fd, speed); + CwLnx_hidecursor(p->fd); + CwLnx_linewrap(p->fd, 1); + CwLnx_autoscroll(p->fd, 0); + CwLnx_backlight(drvthis, 1); /* WHY force the backlight to on ? */ + /* What is the default brightness ? */ + + /* Set the functions the driver supports... */ + + /* TODO: WHY this ??? $$$ */ +/* drvthis->daemonize = 1; */ /* make the server daemonize after initialization */ + /* no daemonize in Driver ??? */ + + report(RPT_DEBUG, "CwLnx_init: done\n"); + + Clear_Screen(p->fd); + CwLnx_clear(drvthis); + usleep(SETUP_DELAY); + + return p->fd; +} + +/****************************************************** + * API: Clean-up + */ +MODULE_EXPORT void +CwLnx_close(Driver *drvthis) +{ + PrivateData * p = drvthis->private_data; + + close(p->fd); + + if (p->framebuf) + free(p->framebuf); + + if (p->backingstore) + free(p->backingstore); + + p->framebuf = NULL; + p->backingstore = NULL; + + free(p); + + debug(RPT_DEBUG, "CwLnx: closed"); +} + +/****************************************************** + * API: Returns the displays width + */ +MODULE_EXPORT int +CwLnx_width(Driver *drvthis) +{ + PrivateData * p = drvthis->private_data; + + debug(RPT_DEBUG, "CwLnx: returning width"); + + return p->width; +} + +/****************************************************** + * API: Returns the displays height + */ +MODULE_EXPORT int +CwLnx_height(Driver *drvthis) +{ + PrivateData * p = drvthis->private_data; + + debug(RPT_DEBUG, "CwLnx: returning height"); + + return p->height; +} + + + +/****************************************************** + * API: Clean-up + */ +/* +MODULE_EXPORT void +CwLnx_flushtime_backlight(Driver *drvthis) +{ + PrivateData * p = drvthis->private_data; + + int bright; + + if ( ( (p->saved_backlight)&&(!p->backlight) ) + || ( (p->backlight)&&(!p->saved_backlight) ) ) + { + p->backlight = p->saved_backlight; + if (p->backlight) + { + Enable_Backlight(p->fd); + } + else + { + Disable_Backlight(p->fd); + } + } + + if ( p->brightness != p->saved_brightness ) + { + p->brightness = p->saved_brightness; + Backlight_Brightness(p->fd, p->brightness) + } + + debug(RPT_DEBUG, "CwLnx: updating the backlight and brightness at flush time"); +} +*/ + +/***************************************************** + * This is a test to see how a driver can overwrite build-in heartbeat. + * It make a pixel blink at calling rate independently of flush call. + */ +MODULE_EXPORT void +CwLnx_flushtime_heartbeat( Driver * drvthis ) +{ + PrivateData * p = drvthis->private_data; + + if ( p->heartbeat != p->saved_heartbeat ) { + p->saved_heartbeat=p->heartbeat; + if (p->heartbeat) { + Enable_Pixel(p->fd, 121, 0); + Enable_Pixel(p->fd, 60, 0); + Enable_Pixel(p->fd, 121, 31); + } else { + Disable_Pixel(p->fd, 121, 0); + Disable_Pixel(p->fd, 60, 0); + Disable_Pixel(p->fd, 121, 31); + } + } +} + +/****************************************************** + * API: Send what we have to the hardware + */ +MODULE_EXPORT void +CwLnx_flush(Driver *drvthis) +{ + PrivateData * p = drvthis->private_data; + + CwLnx_draw_frame(drvthis, p->framebuf); + + CwLnx_flushtime_heartbeat(drvthis); +/* CwLnx_flushtime_backlight(drvthis); */ +} + +void Set_Insert(int fd, int row, int col) +{ + char c; + int rc; + + c = LCD_CMD; + rc = Write_LCD(fd, &c, 1); + if (row==0 && col==0) + { + c = LCD_INIT_INSERT; + rc = Write_LCD(fd, &c, 1); + } + else + { + c = LCD_SET_INSERT; + rc = Write_LCD(fd, &c, 1); + c = col; + rc = Write_LCD(fd, &c, 1); + c = row; + rc = Write_LCD(fd, &c, 1); + } + c = LCD_CMD_END; + rc = Write_LCD(fd, &c, 1); +} + +/*********************************************** + * + * _flush_box is not an API entry anymore. + * +void CwLnx_flush_box(int lft, int top, int rgt, int bot) +{ + int y; + + debug(RPT_DEBUG, "CwLnx: flush_box (%i,%i)-(%i,%i)\n", lft, top, rgt, + bot); + for (y = top; y <= bot; y++) { + Set_Insert(fd, top, lft); + Write_Line_LCD(fd, CwLnx->framebuf + (y * p->width) + lft); + } +} +*/ + + +/******************************************************************* + * API: Prints a character on the lcd display, at position (x,y). The + * upper-left is (1,1), and the lower right should be (20,4). + */ +MODULE_EXPORT void +CwLnx_chr(Driver *drvthis, int x, int y, char c) +{ + PrivateData * p = drvthis->private_data; + + int offset; + + ValidX(x); + ValidY(y); + + y--; + x--; + + offset = (y * p->width) + x; + p->framebuf[offset] = c; + + debug(RPT_DEBUG, "CwLnx: writing character %02X to position (%d,%d)", c, x, y); +} + +/* + * The CwLinux hardware does not support contrast setting by software, + * but only by changing the hardware configuration. + * Since the get_contrast and set_contrast are not mandatory in the API, + * it is better not to implement a dummy version. + */ + + + + +/* + * CwLnx support 7 level of brightness + * 1 is the minimum and correspond to backlight OFF + * 7 is the maximum. + * + * When the backlight is turned off, we remember the brightness + * so that when the backlight is turned back on, we have the previous + * brightness. + * + * Backlight and Brightness in this driver will not be set real-time, + * but we will wait for the flush command. The same way we use a framebuffer, + * and we update the LCD only at flush time. + */ + +/********************************************************* + * API: Sets the backlight + * the API only permit setting to off=0 and on<>0 + */ +MODULE_EXPORT void +CwLnx_backlight(Driver * drvthis, int on) +{ + PrivateData * p = drvthis->private_data; + + p->backlight = on; +} + + +/********************************************************* + * API: Get the backlight brightness + */ +MODULE_EXPORT int +CwLnx_get_brightness(Driver * drvthis) +{ + PrivateData * p = drvthis->private_data; + + return p->saved_brightness; +} + + +/********************************************************* + * API: Set the backlight brightness + */ +MODULE_EXPORT void +CwLnx_set_brightness(Driver * drvthis, int promille) +{ + PrivateData * p = drvthis->private_data; + + p->brightness = promille; +} + + +/********************************************************* + * Toggle the built-in linewrapping feature + */ +static void CwLnx_linewrap (int fd, int on) +{ + if (on) + Enable_Wrap(fd); + else + Disable_Wrap(fd); +} + + +/**************************************************************** + * Toggle the built-in automatic scrolling feature + */ +static void CwLnx_autoscroll(int fd, int on) +{ + if (on) + Enable_Scroll(fd); + else + Disable_Scroll(fd); +} + + +/******************************************************************* + * Get rid of the blinking curson + */ +static void CwLnx_hidecursor(int fd) +{ + Disable_Cursor(fd); +} + + +/********************************************************* + * NOTAPI: Inits vertical bars... + * This was part of API in 0.4 and removed in 0.5 + */ +void CwLnx_init_vbar(Driver * drvthis) +{ + PrivateData * p = drvthis->private_data; + + char a[] = { + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + }; + char b[] = { + 1, 1, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, + }; + char c[] = { + 1, 1, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, + }; + char d[] = { + 1, 1, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + }; + char e[] = { + 1, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, + }; + char f[] = { + 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 0, 0, + }; + char g[] = { + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, + }; + + if (p->custom != vbar) { + CwLnx_set_char(drvthis, 1, a); + CwLnx_set_char(drvthis, 2, b); + CwLnx_set_char(drvthis, 3, c); + CwLnx_set_char(drvthis, 4, d); + CwLnx_set_char(drvthis, 5, e); + CwLnx_set_char(drvthis, 6, f); + CwLnx_set_char(drvthis, 7, g); + p->custom = vbar; + } +} + +/********************************************************* + * NOTAPI: Inits horizontal bars... + * This was part of API in 0.4 and removed in 0.5 + */ +void CwLnx_init_hbar(Driver * drvthis) +{ + PrivateData * p = drvthis->private_data; + + char a[] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 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, 0, 0, 0, 0, + }; + char b[] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 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, + }; + char c[] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + char d[] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + char e[] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + char f[] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + }; + + if (p->custom != hbar) { + CwLnx_set_char(drvthis, 1, a); + CwLnx_set_char(drvthis, 2, b); + CwLnx_set_char(drvthis, 3, c); + CwLnx_set_char(drvthis, 4, d); + CwLnx_set_char(drvthis, 5, e); + CwLnx_set_char(drvthis, 6, f); + p->custom = hbar; + } + +} + +/************************************************************* + * API: Draws a vertical bar... + */ +MODULE_EXPORT void +CwLnx_vbar(Driver * drvthis, int x, int y, int len, int promille, int options) +{ + PrivateData * p = drvthis->private_data; + + CwLnx_init_vbar(drvthis); + + lib_vbar_static(drvthis, x, y, len, promille, options, p->cellheight, 0); +} + +/***************************************************************** + * API: Draws a horizontal bar to the right. + */ +MODULE_EXPORT void +CwLnx_hbar(Driver * drvthis, int x, int y, int len, int promille, int options) +{ + PrivateData * p = drvthis->private_data; + + CwLnx_init_hbar(drvthis); + + lib_hbar_static(drvthis, x, y, len, promille, options, p->cellwidth, 0); +} + + +/******************************************************************* + * API: Writes a big number. + */ +/* Currently using the server ascii default */ +/* +MODULE_EXPORT void +CwLnx_num(Driver * drvthis, int x, int num) +{ + return; +} +*/ + +/********************************************************************* + * API: Sets a custom character... + * This should be removed from API since it is hardware dependent. + * + * The API only permit setting to off=0 and on<>0 + * For input, values > 0 mean "on" and values <= 0 are "off". + * + * The input is just an array of characters... + */ +MODULE_EXPORT void +CwLnx_set_char(Driver * drvthis, int n, char *dat) +{ + PrivateData * p = drvthis->private_data; + + int row, col; + int letter; + char c; + int rc; + + if (n < 1 || n > 16) + return; + if (!dat) + return; + + c = LCD_CMD; + rc = Write_LCD(p->fd, &c, 1); + c = LCD_SETCHAR; + rc = Write_LCD(p->fd, &c, 1); + c = (char) n; + rc = Write_LCD(p->fd, &c, 1); + + for (col = 0; col < p->cellwidth; col++) { + letter = 0; + for (row = 0; row < p->cellheight; row++) { + letter <<= 1; + letter |= (dat[(col * p->cellheight) + row] > 0); + } + c=letter; + Write_LCD(p->fd, &c, 1); + } + c = LCD_CMD_END; + rc = Write_LCD(p->fd, &c, 1); +} + +MODULE_EXPORT int +CwLnx_icon(Driver * drvthis, int x, int y, int icon) +{ + char heart_open[] = + { + 1,1,1,0,0,0,1,1, + 1,1,0,0,0,0,0,1, + 1,0,0,0,0,0,1,1, + 1,1,0,0,0,0,0,1, + 1,1,1,0,0,0,1,1, + 1,1,1,1,1,1,1,1 + }; + + char heart_filled[] = + { + 1,1,1,0,0,0,1,1, + 1,1,0,1,1,1,0,1, + 1,0,1,1,1,0,1,1, + 1,1,0,1,1,1,0,1, + 1,1,1,0,0,0,1,1, + 1,1,1,1,1,1,1,1 + }; + + char arrow_up[] = + { + 0,0,0,0,1,1,0,0, + 0,0,0,0,0,1,1,0, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 0,0,0,0,0,1,1,0, + 0,0,0,0,1,1,0,0 + }; + + char arrow_down[] = + { + 0,0,1,1,0,0,0,0, + 0,1,1,0,0,0,0,0, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 0,1,1,0,0,0,0,0, + 0,0,1,1,0,0,0,0 + }; + + char checkbox_off[] = + { + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0 + }; + + char checkbox_on[] = + { + 0,1,1,1,1,1,0,0, + 0,1,0,0,0,1,0,0, + 0,1,0,1,1,1,1,0, + 0,1,0,0,1,0,0,0, + 0,1,1,1,0,1,0,0, + 0,0,0,0,0,0,1,0 + }; + + char checkbox_gray[] = + { + 0,1,1,1,1,1,0,0, + 0,1,0,1,0,1,0,0, + 0,1,1,0,1,1,0,0, + 0,1,0,1,0,1,0,0, + 0,1,1,1,1,1,0,0, + 0,0,0,0,0,0,0,0 + }; + + char block_filled[] = + { + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1 + }; + + char arrow_left[] = + { + 0,0,0,1,1,0,0,0, + 0,0,1,1,1,1,0,0, + 0,1,1,1,1,1,1,0, + 1,1,0,1,1,0,1,1, + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0 + }; + + char arrow_right[] = + { + 0,0,0,1,1,0,0,0, + 0,0,0,1,1,0,0,0, + 1,1,0,1,1,0,1,1, + 0,1,1,1,1,1,1,0, + 0,0,1,1,1,1,0,0, + 0,0,0,1,1,0,0,0 + }; + + +/* Yes we know, this is a VERY BAD implementation */ + switch( icon ) { + case ICON_HEART_FILLED: + CwLnx_set_char( drvthis, 8, heart_filled ); + CwLnx_chr( drvthis, x, y, 8 ); + break; + case ICON_HEART_OPEN: + CwLnx_set_char( drvthis, 8, heart_open ); + CwLnx_chr( drvthis, x, y, 8 ); + break; + case ICON_CHECKBOX_GRAY: + CwLnx_set_char( drvthis, 9, checkbox_gray ); + CwLnx_chr( drvthis, x, y, 9 ); + break; + case ICON_BLOCK_FILLED: + CwLnx_set_char( drvthis, 10, block_filled ); + CwLnx_chr( drvthis, x, y, 10 ); + break; + case ICON_ARROW_UP: + CwLnx_set_char( drvthis, 11, arrow_up ); + CwLnx_chr( drvthis, x, y, 11 ); + break; + case ICON_ARROW_DOWN: + CwLnx_set_char( drvthis, 12, arrow_down ); + CwLnx_chr( drvthis, x, y, 12 ); + break; + case ICON_ARROW_LEFT: + CwLnx_set_char( drvthis, 13, arrow_left ); + CwLnx_chr( drvthis, x, y, 13 ); + break; + case ICON_ARROW_RIGHT: + CwLnx_set_char( drvthis, 14, arrow_right ); + CwLnx_chr( drvthis, x, y, 14 ); + break; + case ICON_CHECKBOX_OFF: + CwLnx_set_char( drvthis, 15, checkbox_off ); + CwLnx_chr( drvthis, x, y, 15 ); + break; + case ICON_CHECKBOX_ON: + CwLnx_set_char( drvthis, 16, checkbox_on ); + CwLnx_chr( drvthis, x, y, 16 ); + break; + default: + return -1; /* Let the core do other icons */ + } + return 0; +} + +/********************************************************** + * ONLY CALLED FROM _flush ... + * + * Blasts a single frame onscreen, to the lcd... + * + * Input is a character array, sized CwLnx->wid*CwLnx->hgt + */ +void CwLnx_draw_frame(Driver *drvthis, char *dat) +{ + PrivateData * p = drvthis->private_data; + + int i, j, mv, rc; + char *q, *r; +/* char c; */ +/* static int count=0; */ + + if (!dat) + return; + + mv = 1; + q = dat; + r = p->backingstore; + +/* printf("\n_draw_frame: %d\n", count); */ + + for (i = 0; i < p->height; i++) + { + for (j = 0; j < p->width; j++) + { + if ( (*q == *r) && !( (0<*q) && (*q<16) ) ) + { + mv = 1; +/* count++; if (count==COUNT) exit(0); */ + } + else + { + /* Draw characters that have changed, as well + * as custom characters. We know not if a custom + * character has changed. + */ + if (mv == 1) + { + Set_Insert(p->fd, i, j); + mv = 0; + } + rc = Write_LCD(p->fd, q, 1); + } + q++; + r++; + } + } + strncpy(p->backingstore, dat, p->width * p->height); + +} + +/********************************************************* + * API: Clears the LCD screen + */ +MODULE_EXPORT void +CwLnx_clear(Driver *drvthis) +{ + PrivateData * p = drvthis->private_data; + + /* WHY: are we the only function to check framebuf for null? */ + if (p->framebuf != NULL) + memset(p->framebuf, ' ', p->width * p->height); + + /* We could remember the custom char are not in use anymore. $$$ */ + + debug(RPT_DEBUG, "CwLnx: cleared framebuffer"); +} + +/***************************************************************** + * API: Prints a string on the lcd display, at position (x,y). + * The upper-left is (1,1), and the lower right should be (20,4). + */ +MODULE_EXPORT void +CwLnx_string(Driver * drvthis, int x, int y, char *string) +{ + PrivateData * p = drvthis->private_data; + + int offset, siz; + + ValidX(x); + ValidY(y); + + x--; + y--; + + offset = (y * p->width) + x; + + siz = (p->width * p->height) - offset; + siz = siz > strlen(string) ? strlen(string) : siz; + + memcpy(p->framebuf + offset, string, siz); + +/* + This is another way to check for buffer overflow + + for (int i = 0; string[i]; i++) { + if ((y * p->width) + x + i > (p->width * p->height)) + break; + CwLnx->framebuf[(y * p->width) + x + i] = string[i]; + } +*/ + + debug(RPT_DEBUG, "CwLnx: printed string at (%d,%d)", x, y); +} + +/********************************************************* + * API: Get a key translated into a string. + */ +MODULE_EXPORT char * +CwLnx_get_key(Driver * drvthis) +{ + PrivateData * p = drvthis->private_data; + + char akey = 0; + char * keystr = NULL; + + read (p->fd, &akey, 1); + + if (akey != 0) + { + if ((akey>='A')&&(akey<='F')) + { + keystr = p->KeyMap[akey-'A']; + } + else + { + report( RPT_INFO, "CwLnx: Untreated key 0x%2x", akey); + } + } + + return keystr; +} + +/***************************************************** + * API: This is a test to see how a driver can overwrite build-in heartbeat. + * It make a pixel blink at calling rate independently of flush call. + */ +/* + * The Pixel is not very visible when located at (121,0). + * Maybe the display of text caracter hide the pixel. + * It might be the flush just after the heartbeat call. + */ + +/*I*/ int saved_heartbeat; +/*I*/ int heartbeat; +/*I*/ int heartbeat_state; + +MODULE_EXPORT void +CwLnx_heartbeat( Driver * drvthis, int type ) +{ + PrivateData * p = drvthis->private_data; + + if (type) { + if (p->heartbeat_state) { + p->heartbeat=1; + p->heartbeat_state = 0; + } else { + p->heartbeat=0; + p->heartbeat_state = 1; + } + } else { + if (p->heartbeat_state) { + p->heartbeat=0; + p->heartbeat_state = 0; + } + } +} + +/* +MODULE_EXPORT void +CwLnx_heartbeat( Driver * drvthis, int type ) +{ + PrivateData * p = drvthis->private_data; + + if (type) { + if (p->heartbeat_state) { + Enable_Pixel(p->fd, 121, 0); + p->heartbeat_state = 0; + } else { + Disable_Pixel(p->fd, 121, 0); + p->heartbeat_state = 1; + } + } else { + if (p->heartbeat_state) { + Disable_Pixel(p->fd, 121, 0); + p->heartbeat_state = 0; + } + } +} +*/ diff --git a/server/drivers/CwLnx.h b/server/drivers/CwLnx.h new file mode 100644 index 0000000..ff4ff79 --- /dev/null +++ b/server/drivers/CwLnx.h @@ -0,0 +1,80 @@ +/* This is the LCDproc driver for Cwlinux devices (http://www.cwlinux.com) + + Copyright (C) 2002, Andrew Ip + 2002, David Glaude + 2003, David Glaude + + 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 */ + +#ifndef CWLNX_H +#define CWLNX_H + +#include "lcd.h" + +// #define DEFAULT_CONTRAST 560 +// #define DEFAULT_BRIGHTNESS 60 +// #define DEFAULT_OFFBRIGHTNESS 0 +// #define DEFAULT_EXITBRIGHTNESS 0 + +#define DEFAULT_CELLWIDTH 6 +#define DEFAULT_CELLHEIGHT 8 +#define DEFAULT_DEVICE "/dev/lcd" +#define DEFAULT_SPEED B19200 +#define DEFAULT_SIZE "20x4" +#define DEFAULT_BACKLIGHT 1 +#define DEFAULT_BRIGHTNESS 200 + +/* These are the keys for a (possibly) broken LK202-25...*/ +/* NOTE: You should configure these settings in the configfile + * These defines are just used to get *some* defaults + */ +#define CWLNX_KEY_UP 'A' +#define CWLNX_KEY_DOWN 'B' +#define CWLNX_KEY_LEFT 'C' +#define CWLNX_KEY_RIGHT 'D' +#define CWLNX_KEY_YES 'E' +#define CWLNX_KEY_NO 'F' + +#define DEFAULT_PAUSE_KEY CWLNX_KEY_UP +#define DEFAULT_BACK_KEY CWLNX_KEY_LEFT +#define DEFAULT_FORWARD_KEY CWLNX_KEY_RIGHT +#define DEFAULT_MAIN_MENU_KEY CWLNX_KEY_DOWN + +MODULE_EXPORT int CwLnx_init(Driver * drvthis, char *device); +MODULE_EXPORT void CwLnx_close(Driver * drvthis); +/* */ MODULE_EXPORT int CwLnx_width (Driver * drvthis); +/* */ MODULE_EXPORT int CwLnx_height (Driver * drvthis); +MODULE_EXPORT void CwLnx_clear (Driver * drvthis); +MODULE_EXPORT void CwLnx_flush(Driver * drvthis); +MODULE_EXPORT void CwLnx_string(Driver * drvthis, int x, int y, char string[]); +MODULE_EXPORT void CwLnx_chr(Driver * drvthis, int x, int y, char c); +MODULE_EXPORT void CwLnx_vbar(Driver * drvthis, int x, int y, int len, int promille, int options); +MODULE_EXPORT void CwLnx_hbar(Driver * drvthis, int x, int y, int len, int promille, int options); + MODULE_EXPORT void CwLnx_num(Driver * drvthis, int x, int num); +MODULE_EXPORT int CwLnx_icon(Driver * drvthis, int x, int y, int icon); +MODULE_EXPORT void CwLnx_set_char(Driver * drvthis, int n, char *dat); +MODULE_EXPORT int CwLnx_get_contrast(Driver * drvthis); +MODULE_EXPORT void CwLnx_set_contrast(Driver * drvthis, int contrast); +MODULE_EXPORT void CwLnx_clear(Driver * drvthis); +MODULE_EXPORT void CwLnx_backlight(Driver * drvthis, int on); + +// MODULE_EXPORT void CwLnx_flush_box(Driver * drvthis, int lft, int top, int rgt, int bot); +// MODULE_EXPORT void CwLnx_init_vbar( Driver * drvthis); +// MODULE_EXPORT void CwLnx_init_hbar( Driver * drvthis); +// MODULE_EXPORT void CwLnx_init_num( Driver * drvthis); +// MODULE_EXPORT void CwLnx_draw_frame(Driver * drvthis, char *dat); + +#endif +