diff --git a/ChangeLog b/ChangeLog index 05711df..3d03ec1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,11 @@ Key: + Something added * Something changed / fixed -v.0.5dev (ongoing development) +v0.5dev (ongoing development) + - Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead! + + new driver: glcd unified graphic display driver (M. Dolze) + +v0.5.5 + sed1330 driver: Add support for HG25504 (L. Lagendijk) * Build system: Fix xosd detection * Reset ccmode on screen clear for NoritakeVFD, tyan driver @@ -36,7 +40,6 @@ v.0.5dev (ongoing development) + Build system: --enable-extra-charmaps option adds language specific charmaps * imonlcd: Fix spinning of disc icon (E. Pooch) * SureElec: Change port initialization (SF 3212891) - - Remove deprecated CFontz633 driver. Use CFontzPacket with Model=633 instead! v0.5.4 * Update driver includes and LDFLAGS (fixed glk and bayrad binding error) diff --git a/LCDd.conf b/LCDd.conf index a5a34a9..ca68cf3 100644 --- a/LCDd.conf +++ b/LCDd.conf @@ -358,6 +358,28 @@ size=20x5 +## glcd generic graphical display driver +[glcd] +# Select what type of connection. See documentation for types. +ConnectionType=t6963 + +# Width and height of the display in pixel. The supported sizes may depend on +# the ConnectionType. [default: 128x64; legal: 1x1 - 640x480] +#Size=128x64 + +# t6963: Parallel port to use [default: 0x378; legal: 0x200 - 0x400] +#Port=0x378 + +# t6963: Use LPT port in bi-directional mode. This should work on most LPT port +# and is required for proper timing! [default: yes; legal: yes, no] +#bidirectional=yes + +# t6963: Insert additional delays into reads / writes. [default: no; +# legal: yes, no] +#delayBus=no + + + ## glcdlib meta driver for graphical LCDs ## [glcdlib] diff --git a/acinclude.m4 b/acinclude.m4 index fa0ad41..06caa6c 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -9,7 +9,7 @@ AC_ARG_ENABLE(drivers, [ which is a comma-separated list of drivers.] [ Possible drivers are:] [ bayrad,CFontz,CFontzPacket,curses,CwLnx,] - [ ea65,EyeboxOne,g15,glcdlib,glk,hd44780,i2500vfd,] + [ ea65,EyeboxOne,g15,glcd,glcdlib,glk,hd44780,i2500vfd,] [ icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,] [ joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,mdm166a,] [ ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,] @@ -22,7 +22,7 @@ AC_ARG_ENABLE(drivers, drivers="$enableval", drivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,glk,lb216,lcdm001,MtxOrb,pyramid,text]) -allDrivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,mdm166a,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,picolcd,pyramid,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,svga,t6963,text,tyan,ula200,xosd] +allDrivers=[bayrad,CFontz,CFontzPacket,curses,CwLnx,ea65,EyeboxOne,g15,glcd,glcdlib,glk,hd44780,i2500vfd,icp_a106,imon,imonlcd,IOWarrior,irman,irtrans,joy,lb216,lcdm001,lcterm,lirc,lis,MD8800,mdm166a,ms6931,mtc_s16209x,MtxOrb,mx5000,NoritakeVFD,picolcd,pyramid,sed1330,sed1520,serialPOS,serialVFD,shuttleVFD,sli,stv5730,SureElec,svga,t6963,text,tyan,ula200,xosd] if test "$debug" = yes; then allDrivers=["${allDrivers},debug"] fi @@ -165,6 +165,14 @@ dnl else AC_MSG_WARN([The g15driver needs libg15render.h]) ]) ;; + glcd) + GLCD_DRIVERS="" + if test "$ac_cv_port_have_lpt" = yes ; then + GLCD_DRIVERS="$GLCD_DRIVERS glcd-t6963.o t6963_low.o" + fi + DRIVERS="$DRIVERS glcd${SO}" + actdrivers=["$actdrivers glcd"] + ;; glcdlib) AC_CHECK_HEADERS([glcdproclib/glcdprocdriver.h],[ AC_CHECK_LIB(glcdprocdriver, main,[ @@ -493,6 +501,7 @@ AC_SUBST(LIBLIRC_CLIENT) AC_SUBST(LIBSVGA) AC_SUBST(DRIVERS) AC_SUBST(HD44780_DRIVERS) +AC_SUBST(GLCD_DRIVERS) AC_SUBST(LIBG15) AC_SUBST(LIBGLCD) AC_SUBST(LIBFTDI) diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am index 3930826..0b9562e 100644 --- a/server/drivers/Makefile.am +++ b/server/drivers/Makefile.am @@ -1,3 +1,4 @@ + ## Process this file with automake to produce Makefile.in ## We use bin_ to generate the shared libraries, because automake only @@ -21,7 +22,7 @@ AM_LDFLAGS = @LDSHARED@ ## Keep the lists sorted! pkglib_PROGRAMS = @DRIVERS@ -EXTRA_PROGRAMS = bayrad CFontz CFontzPacket curses debug CwLnx ea65 EyeboxOne g15 glcdlib glk hd44780 icp_a106 imon imonlcd IOWarrior irman joy lb216 lcdm001 lcterm lirc lis MD8800 mdm166a ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD picolcd pyramid sed1330 sed1520 serialPOS serialVFD shuttleVFD stv5730 SureElec svga t6963 text tyan sli ula200 xosd i2500vfd irtrans +EXTRA_PROGRAMS = bayrad CFontz CFontzPacket curses debug CwLnx ea65 EyeboxOne g15 glcd glcdlib glk hd44780 icp_a106 imon imonlcd IOWarrior irman joy lb216 lcdm001 lcterm lirc lis MD8800 mdm166a ms6931 mtc_s16209x MtxOrb mx5000 NoritakeVFD picolcd pyramid sed1330 sed1520 serialPOS serialVFD shuttleVFD stv5730 SureElec svga t6963 text tyan sli ula200 xosd i2500vfd irtrans noinst_LIBRARIES = libLCD.a libbignum.a g15_CFLAGS = @LIBUSB_CFLAGS@ $(AM_CFLAGS) @@ -41,6 +42,8 @@ CFontzPacket_LDADD = libLCD.a libbignum.a curses_LDADD = @LIBCURSES@ CwLnx_LDADD = libLCD.a libbignum.a g15_LDADD = @LIBG15@ +glcd_LDADD = libLCD.a @GLCD_DRIVERS@ +glcd_DEPENDENCIES = @GLCD_DRIVERS@ glcdlib_LDADD = @LIBGLCD@ glk_LDADD = libbignum.a hd44780_LDADD = libLCD.a @HD44780_DRIVERS@ @LIBUSB_LIBS@ @LIBFTDI_LIBS@ libbignum.a @@ -84,6 +87,8 @@ debug_SOURCES = lcd.h report.h debug.c debug.h ea65_SOURCES = lcd.h ea65.h ea65.c report.h EyeboxOne_SOURCES = lcd.h lcd_lib.h EyeboxOne.c EyeboxOne.h report.h g15_SOURCES = lcd.h lcd_lib.h g15.h g15-num.c g15.c report.h +glcd_SOURCES = lcd.h report.h glcd_drv.c glcd_drv.h glcd-low.h glcd-drivers.h +EXTRA_glcd_SOURCES = glcd-t6963.c glcd-t6963.h t6963_low.c t6963_low.h glcdlib_SOURCES = lcd.h lcd_lib.h glcdlib.h glcdlib.c report.h glk_SOURCES = lcd.h glk.c glk.h glkproto.c glkproto.h report.h hd44780_SOURCES = lcd.h lcd_lib.h hd44780.h hd44780.c hd44780-drivers.h hd44780-low.h hd44780-charmap.h report.h adv_bignum.h diff --git a/server/drivers/glcd-drivers.h b/server/drivers/glcd-drivers.h new file mode 100644 index 0000000..522bfa7 --- /dev/null +++ b/server/drivers/glcd-drivers.h @@ -0,0 +1,45 @@ +/** \file server/drivers/glcd-drivers.h + * Connection type registry for glcd driver. + * + * File file contains includes and pointers to the connection type's init() + * function. + */ + +#ifndef GLCD_DRIVERS_H +#define GLCD_DRIVERS_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Include connection type header below */ +#ifdef HAVE_PCSTYLE_LPT_CONTROL +# include "glcd-t6963.h" +#endif + +/* symbolic names for connection types */ +#define GLCD_CT_UNKNOWN 0 +#define GLCD_CT_T6963 1 + +/** Structure linking symbolic names to initialization routines */ +typedef struct ConnectionMapping { + char *name; + int connectiontype; + int (*init_fn)(Driver *drvthis); +} ConnectionMapping; + + +/** connectionType mapping table: + * - string to identify connection in config file + * - connection type identifier + * - initialization function + */ +static const ConnectionMapping connectionMapping[] = { +#ifdef HAVE_PCSTYLE_LPT_CONTROL + {"t6963", GLCD_CT_T6963, glcd_t6963_init}, +#endif + /* default, end of structure element (do not delete) */ + {NULL, GLCD_CT_UNKNOWN, NULL} +}; + +#endif diff --git a/server/drivers/glcd-low.h b/server/drivers/glcd-low.h new file mode 100644 index 0000000..8dceecc --- /dev/null +++ b/server/drivers/glcd-low.h @@ -0,0 +1,54 @@ +/** \file server/drivers/glcd-low.h + * Interface to low level code to access graphical displays. + * + * \note This file should not include hardware dependent header files (libusb, + * libftdi, libhid, etc.) Those shall be included by the sub drivers. + */ + +#ifndef GLCD_LOW_H +#define GLCD_LOW_H + +#define GLCD_DEFAULT_SIZE "128x64" +#define GLCD_DEFAULT_CELLWIDTH 6 +#define GLCD_DEFAULT_CELLHEIGHT 8 +#define GLCD_MAX_WIDTH 640 +#define GLCD_MAX_HEIGHT 480 + +#define BYTES_PER_LINE (p->px_width / 8) + +/** private data for the \c glcd driver */ +typedef struct glcd_private_data { + unsigned char *framebuf; /**< frame buffer */ + int px_width; /**< display width in dots */ + int px_height; /**< display height in dots */ + int cellwidth; /**< character cell width */ + int cellheight; /**< character cell height */ + int width; /**< display width in characters */ + int height; /**< display height in characters */ + struct hwDependentFns *glcd_functions; /**< pointers to low-level functions */ + void *ct_data; /**< Connection type specific data */ +} PrivateData; + +/** Structure holding pointers to display specific functions */ +typedef struct hwDependentFns { + /* report and debug helper. Set by global glcd init */ + void (*drv_report)(const int level, const char *format,... /* args */ ); + void (*drv_debug)(const int level, const char *format,... /* args */ ); + + /* Transfer the framebuffer to the display */ + void (*blit)(PrivateData *p); + + /* Switch the backlight on or off */ + /* void (*set_backlight)(PrivateData *p, char state); */ + + /* Set the contrast (value from 0-1000) */ + /* void (*set_contrast)(PrivateData *p, unsigned int value); */ + + /* Output "data" to output latch if there is one */ + /* void (*output)(PrivateData *p, int data); */ + + /* Close the interface on shutdown */ + void (*close)(PrivateData *p); +} GLCD_functions; + +#endif diff --git a/server/drivers/glcd-t6963.c b/server/drivers/glcd-t6963.c new file mode 100644 index 0000000..fe28128 --- /dev/null +++ b/server/drivers/glcd-t6963.c @@ -0,0 +1,214 @@ +/** \file server/drivers/glcd-t6963.c + * Connection type to drive displays based on the Toshiba T6963 controller + * connected to the parallel port. The display is driven in graphic mode. See + * \c t6963_low.c for details of the parallel port connection. + * + * \note The display must be wired to use 8x8 font. Check with your datasheet. + */ + +/*- + * Copyright (c) 2011 Markus Dolze, based on the t6963 driver by + * 2001 Manuel Stahl + * + * + * This file is released under the GNU General Public License. Refer to the + * COPYING file distributed with this package. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "lcd.h" +#include "report.h" +#include "glcd-low.h" +#include "glcd-t6963.h" +#include "t6963_low.h" + +#define DEFAULT_PORT 0x378 + +static void t6963_graphic_clear(PrivateData *p); + +typedef struct glcd_t6963_data { + unsigned char *backingstore; /**< backing buffer */ + T6963_port *port_config; /**< parallel port configuration */ +} CT_t6963_data; + +/** + * API: Initialize the connection type driver. + * \param drvthis Pointer to driver structure. + * \retval 0 Success. + * \retval <0 Error. + */ +int +glcd_t6963_init(Driver *drvthis) +{ + PrivateData *p = (PrivateData *)drvthis->private_data; + T6963_port *port_config; + CT_t6963_data *ct_data; + + report(RPT_INFO, "GLCD/T6963: intializing"); + + /* Check the size before doing anything else! */ + if ((p->px_width > T6963_MAX_WIDTH) || (p->px_height > T6963_MAX_HEIGHT)) { + report(RPT_ERR, "GLCD/T6963: Size %dx%d not supported by connection type", + p->px_width, p->px_height); + return -1; + } + + /* Set up connection type low-level functions */ + p->glcd_functions->blit = glcd_t6963_blit; + p->glcd_functions->close = glcd_t6963_close; + + /* Allocate memory structures */ + ct_data = (CT_t6963_data *) calloc(1, sizeof(CT_t6963_data)); + if (ct_data == NULL) { + report(RPT_ERR, "GLCD/T6963: error allocation connection data"); + return -1; + } + p->ct_data = ct_data; + + port_config = (T6963_port *) calloc(1, sizeof(T6963_port)); + if (port_config == NULL) { + report(RPT_ERR, "GLCD/T6963: error allocating port config"); + return -1; + } + ct_data->port_config = port_config; + + ct_data->backingstore = malloc(BYTES_PER_LINE * p->px_height); + if (ct_data->backingstore == NULL) { + report(RPT_ERR, "GLCD/T6963: unable to allocate backing store"); + return -1; + } + memset(ct_data->backingstore, 0x00, BYTES_PER_LINE * p->px_height); + + /* Get port from config */ + port_config->port = drvthis->config_get_int(drvthis->name, "Port", 0, DEFAULT_PORT); + if ((port_config->port < 0x200) || (port_config->port > 0x400)) { + port_config->port = DEFAULT_PORT; + report(RPT_WARNING, "GLCD/T6963: Port value must be between 0x200 and 0x400. Using default 0x%03X", + DEFAULT_PORT); + } + + /* Use bi-directional mode of LPT port? Default: yes */ + port_config->bidirectLPT = drvthis->config_get_bool(drvthis->name, "bidirectional", 0, 1); + /* Additional delay necessary? Default: no */ + port_config->delayBus = drvthis->config_get_bool(drvthis->name, "delayBus", 0, 0); + + /* Now initialize port */ + if (t6963_low_init(port_config) == -1) { + report(RPT_ERR, "GLCD/T6963: Error initializing port 0x%03X: %s", + port_config->port, strerror(errno)); + return -1; + } + + debug(RPT_INFO, "GLCD/T6963: Sending init to display..."); + /* Set graphic address (and text address even though not needed) */ + t6963_low_command_word(port_config, SET_GRAPHIC_HOME_ADDRESS, GRAPHIC_BASE); + t6963_low_command_word(port_config, SET_GRAPHIC_AREA, BYTES_PER_LINE); + t6963_low_command_word(port_config, SET_TEXT_HOME_ADDRESS, TEXT_BASE); + t6963_low_command_word(port_config, SET_TEXT_AREA, BYTES_PER_LINE); + + /* Use OR-mode for text and graphics */ + t6963_low_command(port_config, SET_MODE | OR_MODE); + t6963_graphic_clear(p); + + /* Turn on display, text off, graphics on, cursor off */ + t6963_low_command(port_config, SET_DISPLAY_MODE | GRAPHIC_ON); + + debug(RPT_DEBUG, "GLCD/T6963: init() done"); + + return 0; +} + + +/** + * API: Write the framebuffer to the display + * \param p Pointer to glcd driver's private date structure. + */ +void +glcd_t6963_blit(PrivateData *p) +{ + CT_t6963_data *ct_data = (CT_t6963_data *) p->ct_data; + int x, y; + + for (y = 0; y < p->px_height; y++) { + /* set pointers to start of the line */ + unsigned char *sp = p->framebuf + (y * BYTES_PER_LINE); + unsigned char *sq = ct_data->backingstore + (y * BYTES_PER_LINE); + + /* set pointers to end of the line */ + unsigned char *ep = sp + (BYTES_PER_LINE - 1); + unsigned char *eq = sq + (BYTES_PER_LINE - 1); + + /* find begin and end of differences */ + x = 0; + while ((sp <= ep) && (*sp == *sq)) { + sp++, sq++, x++; + } + while ((ep >= sp) && (*ep == *eq)) { + ep--, eq--; + } + + /* there are differences, ... */ + if (sp <= ep) { + t6963_low_command_word(ct_data->port_config, SET_ADDRESS_POINTER, + GRAPHIC_BASE + (y * BYTES_PER_LINE) + x); + t6963_low_command(ct_data->port_config, AUTO_WRITE); + while (sp <= ep) { + t6963_low_auto_write(ct_data->port_config, *sp); + /* Update backing store and advance */ + *sq++ = *sp++; + } + t6963_low_command(ct_data->port_config, AUTO_RESET); + } + } +} + + +/** + * API: Release low-level resources. + * \param p Pointer to glcd driver's private date structure. + */ +void +glcd_t6963_close(PrivateData *p) +{ + if (p->ct_data != NULL) { + CT_t6963_data *ct_data = (CT_t6963_data *) p->ct_data; + + if (ct_data->port_config != NULL) { + t6963_low_close(ct_data->port_config); + free(ct_data->port_config); + } + + if (ct_data->backingstore != NULL) + free(ct_data->backingstore); + + free(p->ct_data); + } +} + + +/** + * Clears graphic memory. + * \param p Pointer to glcd driver's private date structure. + */ +static void +t6963_graphic_clear(PrivateData *p) +{ + CT_t6963_data *ct_data = (CT_t6963_data *) p->ct_data; + int num = BYTES_PER_LINE * p->px_height; + int i; + + p->glcd_functions->drv_debug(RPT_DEBUG, "GLCD/T6963: Clearing graphic: %d bytes", num); + + t6963_low_command_word(ct_data->port_config, SET_ADDRESS_POINTER, GRAPHIC_BASE); + t6963_low_command(ct_data->port_config, AUTO_WRITE); + for (i = 0; i < num; i++) + t6963_low_auto_write(ct_data->port_config, 0); + t6963_low_command(ct_data->port_config, AUTO_RESET); +} diff --git a/server/drivers/glcd-t6963.h b/server/drivers/glcd-t6963.h new file mode 100644 index 0000000..70c6513 --- /dev/null +++ b/server/drivers/glcd-t6963.h @@ -0,0 +1,8 @@ +#ifndef GLCD_T6963_H +#define GLCD_T6963_H + +int glcd_t6963_init(Driver *drvthis); +void glcd_t6963_blit(PrivateData *p); +void glcd_t6963_close(PrivateData *p); + +#endif diff --git a/server/drivers/glcd_drv.c b/server/drivers/glcd_drv.c new file mode 100644 index 0000000..a101606 --- /dev/null +++ b/server/drivers/glcd_drv.c @@ -0,0 +1,492 @@ +/** \file server/drivers/glcd_drv.c + * Unified driver for graphical displays. + * + * The \c glcd driver consists of a base driver module and sub-drivers. The + * base driver implements the driver API and connects to sub-drivers called + * ConnectionTypes (CT-drivers). This is very similar to the hd44780 driver. + * + * The base driver renders text received by the driver API into an internal + * framebuffer and passes that on to CT-drivers on calls to \c glcd_flush(). + * The CT-driver is responsible to convert the framebuffer into a memory layout + * understood by the display and to transmit the data to the display. + * + * The framebuffer is of linear type, storing a black and white image of the + * screen. Each byte contains 8 pixels (1bpp). + * + * The base driver does not implement incremental updates. Instead the + * CT-driver is responsible for this. + * + * Additionally the CT-driver must create a data structure holding any + * required data (configuration data, runtime information) and store a pointer + * to it in the base driver's PrivateData->ct_data field. + * + * The base driver consists of the following files: + * \li glcd_drv.c This file + * \li glcd-drivers.h CT-driver registry. Add a pointer to your CT-driver's + * init() function here. + * \li glcd-low.h Base driver's PrivateData and ConnectionType API. + * \li glcd_font5x8.h LCDproc's default fixed 5x8 font. + */ + +/*- + * Copyright (C) 2011, Markus Dolze + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "lcd.h" +#include "lcd_lib.h" +#include "glcd_drv.h" +#include "glcd-low.h" +#include "glcd-drivers.h" +#include "report.h" +#include "glcd_font5x8.h" + +/* 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 = "glcd_"; + +static void glcd_render_char(Driver *drvthis, int x, int y, unsigned char c); +static inline void glcd_draw_pixel(PrivateData *p, int x, int y, int color); + +/** + * Initialize the driver. (Required) + * \param drvthis Pointer to driver structure. + * \retval 0 Success. + * \retval <0 Error. + */ +MODULE_EXPORT int +glcd_init(Driver *drvthis) +{ + PrivateData *p; + int i; + int (*init_fn) (Driver *drvthis)= NULL; + const char *s; + char size[200]; + int w, h; + + report(RPT_DEBUG, "%s()", __FUNCTION__); + + /* Allocate and store private data */ + p = (PrivateData *)calloc(1, sizeof(PrivateData)); + if (p == NULL) + return -1; + if (drvthis->store_private_ptr(drvthis, p)) + return -1; + + /* Get and search for the connection type */ + s = drvthis->config_get_string(drvthis->name, "ConnectionType", 0, "t6963"); + for (i = 0; (connectionMapping[i].name != NULL) && + (strcasecmp(s, connectionMapping[i].name) != 0); i++); + if (connectionMapping[i].name == NULL) { + report(RPT_ERR, "%s: unknown ConnectionType: %s", drvthis->name, s); + return -1; + } + else { + /* save connection type's init function */ + init_fn = connectionMapping[i].init_fn; + report(RPT_INFO, "%s: using ConnectionType: %s", drvthis->name, connectionMapping[i].name); + } + + /* + * Set up low-level functions. These should be overwritten by the + * connection type's init function. + */ + if ((p->glcd_functions = (GLCD_functions *) calloc(1, sizeof(GLCD_functions))) == NULL) { + report(RPT_ERR, "%s: error mallocing", drvthis->name); + return -1; + } + p->glcd_functions->drv_report = report; + p->glcd_functions->drv_debug = debug; + p->glcd_functions->blit = NULL; + p->glcd_functions->close = NULL; + + /* Read display size in pixels */ + strncpy(size, drvthis->config_get_string(drvthis->name, "Size", 0, GLCD_DEFAULT_SIZE), sizeof(size)); + size[sizeof(size) - 1] = '\0'; + if ((sscanf(size, "%dx%d", &w, &h) != 2) + || (w <= 0) || (w > GLCD_MAX_WIDTH) + || (h <= 0) || (h > GLCD_MAX_HEIGHT)) { + report(RPT_WARNING, "%s: cannot read Size: %s, Using default %s", + drvthis->name, size, GLCD_DEFAULT_SIZE); + sscanf(GLCD_DEFAULT_SIZE, "%dx%d", &w, &h); + } + p->px_width = w; + p->px_height = h; + + /* Do local (=connection type specific) display init */ + if (init_fn(drvthis) != 0) + return -1; + + /* consistency check: fail if image transfer function was not defined */ + if (p->glcd_functions->blit == NULL) { + report(RPT_ERR, "%s: incomplete functions for connection type", + drvthis->name); + return -1; + } + + /* + * Calculate these values AFTER driver initialization, as the driver + * may update them. + */ + if ((p->px_width > GLCD_MAX_WIDTH) || (p->px_height > GLCD_MAX_HEIGHT)) { + report(RPT_ERR, "%s: Size %dx%d set by ConnectionType is not supported", + drvthis->name, p->px_width, p->px_height); + return -1; + } + p->cellwidth = GLCD_DEFAULT_CELLWIDTH; + p->cellheight = GLCD_DEFAULT_CELLHEIGHT; + p->width = p->px_width / p->cellwidth; + p->height = p->px_height / p->cellheight; + + /* Allocate framebuffer */ + p->framebuf = malloc(BYTES_PER_LINE * p->px_height); + if (p->framebuf == NULL) { + report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name); + return -1; + } + memset(p->framebuf, 0x00, BYTES_PER_LINE * p->px_height); + + glcd_clear(drvthis); + + return 0; +} + + +/** + * Close the driver (do necessary clean-up). (Required) + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +glcd_close(Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + debug(RPT_DEBUG, "%s()", __FUNCTION__); + + if (p != NULL) { + if (p->glcd_functions->close != NULL) + p->glcd_functions->close(p); + if (p->framebuf != NULL) + free(p->framebuf); + p->framebuf = NULL; + + free(p); + } + drvthis->store_private_ptr(drvthis, NULL); +} + + +/** + * Return the display width in characters. (Required for output) + * \param drvthis Pointer to driver structure. + * \return Number of characters the display is wide. + */ +MODULE_EXPORT int +glcd_width(Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + debug(RPT_DEBUG, "%s()", __FUNCTION__); + + return p->width; +} + + +/** + * Return the display height in characters. (Required for output) + * \param drvthis Pointer to driver structure. + * \return Number of characters the display is high. + */ +MODULE_EXPORT int +glcd_height(Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + debug(RPT_DEBUG, "%s()", __FUNCTION__); + + return p->height; +} + + +/** + * Return the width of a character in pixels. (Optional) + * \param drvthis Pointer to driver structure. + * \return Number of pixel columns a character cell is wide. + */ +MODULE_EXPORT int +glcd_cellwidth(Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + debug(RPT_DEBUG, "%s()", __FUNCTION__); + + return p->cellwidth; +} + + +/** + * Return the height of a character in pixels. (Optional) + * \param drvthis Pointer to driver structure. + * \return Number of pixel lines a character cell is high. + */ +MODULE_EXPORT int +glcd_cellheight(Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + debug(RPT_DEBUG, "%s()", __FUNCTION__); + + return p->cellheight; +} + + +/** + * Clear the screen. (Required for output) + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +glcd_clear(Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + debug(RPT_DEBUG, "%s()", __FUNCTION__); + + memset(p->framebuf, 0x00, BYTES_PER_LINE * p->px_height); + +} + + +/** + * Flush data on screen to the display. (Optional) + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +glcd_flush(Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + debug(RPT_DEBUG, "%s()", __FUNCTION__); + + p->glcd_functions->blit(p); + +} + + +/** + * Print a string on the screen at position (x,y). (Required for output) + * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height). + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param string String that gets written. + * + * \see glcd_flush + */ +MODULE_EXPORT void +glcd_string(Driver *drvthis, int x, int y, const char string[]) +{ + PrivateData *p = drvthis->private_data; + int i; + + debug(RPT_DEBUG, "%s(%i,%i,%.40s)", __FUNCTION__, x, y, string); + + y--; /* Convert 1-based coords to 0-based... */ + x--; + + if ((y < 0) || (y >= p->height)) + return; + + for (i = 0; (string[i] != '\0') && (x < p->width); i++, x++) + glcd_render_char(drvthis, x, y, string[i]); +} + + +/** + * Print a character on the screen at position (x,y). (Required for output) + * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height). + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param c Character that gets written. + * + * \note Keep in mind that character 0x00 may be a valid character on your + * display and it is used by the bignum library. Avoid using string handling + * functions here! + * + * \see glcd_flush + */ +MODULE_EXPORT void +glcd_chr(Driver *drvthis, int x, int y, char c) +{ + debug(RPT_DEBUG, "%s(%i,%i,%c)", __FUNCTION__, x, y, c); + + x--; + y--; + glcd_render_char(drvthis, x, y, c); +} + + +/** + * Place an icon on the screen. (Optional) + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param icon synbolic value representing the icon. + * \retval 0 Icon has been successfully defined/written. + * \retval <0 Server core shall define/write the icon. + */ +MODULE_EXPORT int +glcd_icon(Driver *drvthis, int x, int y, int icon) +{ + debug(RPT_DEBUG, "%s(%i,%i,%i)", __FUNCTION__, x, y, icon); + + return (glcd_icon5x8(drvthis, x, y, icon)); +} + + +/** + * API: Draws a vertical bar, from the bottom of the screen up. + */ +MODULE_EXPORT void +glcd_vbar(Driver *drvthis, int x, int y, int len, int promille, int options) +{ + debug(RPT_DEBUG, "%s(%i,%i,%i,%i,%i)", __FUNCTION__, x, y, len, promille, options); + lib_vbar_static(drvthis, x, y, len, promille, options, GLCD_FONT_HEIGHT, 0x90); +} + + +/** + * API: Draws a horizontal bar to the right. + * + * \note For hBars the actual width of the font (5) has to be used instead + * of the cell width (6)! + */ +MODULE_EXPORT void +glcd_hbar(Driver *drvthis, int x, int y, int len, int promille, int options) +{ + int pixels = ((long) 2 * len * GLCD_FONT_WIDTH) * promille / 2000; + int pos; + + debug(RPT_DEBUG, "%s(%i,%i,%i,%i,%i)", __FUNCTION__, x, y, len, promille, options); + + for (pos = 0; pos < len; pos++) { + if (pixels >= GLCD_FONT_WIDTH ) + glcd_chr(drvthis, x + pos, y, 0x9e); + else if (pixels >= 1) + glcd_chr(drvthis, x + pos, y, 0x99 + pixels); + else + ; /* do nothing */ + pixels -= GLCD_FONT_WIDTH; + } +} + + +/** + * Provide some information about this driver. (Optional) + * \param drvthis Pointer to driver structure. + * \return Constant string with information. + */ +MODULE_EXPORT const char * +glcd_get_info(Driver *drvthis) +{ + static char *info_string = "Unified driver for graphical displays"; + + debug(RPT_DEBUG, "%s()", __FUNCTION__); + + return info_string; +} + + +/** + * Draw one pixel into the framebuffer using 1bpp (black and white). This + * function actually decides about the format of the framebuffer. Using this + * implementation (0,0) is top left and bytes contain pixels from left to right. + * + * \param p Pointer to driver's private data. + * \param x X-position + * \param y Y-position + * \param color Pixel color: 1 = set (black), 0 = not set (blank) + */ +static inline void +glcd_draw_pixel(PrivateData *p, int x, int y, int color) +{ + unsigned int pos; /* Byte within the framebuffer */ + unsigned char bit; /* Bit within the framebuffer byte */ + + pos = y * BYTES_PER_LINE + (x / 8); + bit = 0x80 >> (x % 8); + + if (color == 1) + p->framebuf[pos] |= bit; + else + p->framebuf[pos] &= ~bit; +} + + +/** + * Draws char c from font definition to the framebuffer at position + * x,y. These are zero-based textmode positions. + * + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param z Character that gets written. + */ +static void +glcd_render_char(Driver *drvthis, int x, int y, unsigned char c) +{ + PrivateData *p = drvthis->private_data; + int font_x, font_y; /* Position in the font definition array */ + int px, py; /* Pixel position on the display */ + + if (x < 0 || x >= p->width || y < 0 || y >= p->height) + return; + + /* + * Algorithm: For each row in the font definition check if bit (dot) + * at each column is set. If yes, plot a dot into the framebuffer. If + * the bit is not set then clear the dot. Currently it is wrong to + * assume the framebuffer is clear (e.g. the heartbeat does not clear + * it's contents in advance). + */ + /* FIXME: What happens if font is larger than cell size? */ + py = y * p->cellheight; + for (font_y = 0; (font_y < GLCD_FONT_HEIGHT) && (py < p->px_height); font_y++) { + px = x * p->cellwidth; + /* + * Note: Initializing font_x with font's width leaves one + * empty column to the left. + */ + for (font_x = GLCD_FONT_WIDTH; (font_x > -1) && (px < p->px_width); font_x--) { + if (glcd_iso8859_1[c][font_y] & (1 << font_x)) + glcd_draw_pixel(p, px, py, 1); + else + glcd_draw_pixel(p, px, py, 0); + px++; + } + py++; + } +} diff --git a/server/drivers/glcd_drv.h b/server/drivers/glcd_drv.h new file mode 100644 index 0000000..64061ce --- /dev/null +++ b/server/drivers/glcd_drv.h @@ -0,0 +1,21 @@ +#ifndef GLCD_DRV_H +#define GLCD_DRV_H + +MODULE_EXPORT int glcd_init(Driver *drvthis); +MODULE_EXPORT void glcd_close(Driver *drvthis); +MODULE_EXPORT int glcd_width(Driver *drvthis); +MODULE_EXPORT int glcd_height(Driver *drvthis); +MODULE_EXPORT int glcd_cellwidth(Driver *drvthis); +MODULE_EXPORT int glcd_cellheight(Driver *drvthis); +MODULE_EXPORT void glcd_clear(Driver *drvthis); +MODULE_EXPORT void glcd_flush(Driver *drvthis); +MODULE_EXPORT void glcd_string(Driver *drvthis, int x, int y, const char string[]); +MODULE_EXPORT void glcd_chr(Driver *drvthis, int x, int y, char c); + +MODULE_EXPORT void glcd_vbar(Driver *drvthis, int x, int y, int len, int promille, int options); +MODULE_EXPORT void glcd_hbar(Driver *drvthis, int x, int y, int len, int promille, int options); +MODULE_EXPORT int glcd_icon(Driver *drvthis, int x, int y, int icon); + +MODULE_EXPORT const char *glcd_get_info(Driver *drvthis); + +#endif