Step 2: Add glcd unified graphic display driver. See glcd_drv.c for details.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
+11
-2
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 <mythos@xmythos.de>
|
||||
*
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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++;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user