Files
lcdproc/server/drivers/i2500vfd.c
T
mmdolze 3bb27d1611 New common 5x8 font for t6963, sed1520, mdm166a and i2500vfd. It resembles
the original font of the HD44780 with European character set, but includes
only characters from ISO 8859-1 and has been extended with bar graph and icons.

The t6963 driver now has its size to be configured in pixels! The size in
characters is automatically calculated based on the cell size. This makes
internal calculations more easy.
2011-04-03 18:07:15 +00:00

422 lines
12 KiB
C

/** \file server/drivers/i2500vfd.c
* LCDd \c i2500vfd driver for Intra2net's Intranator 2500 VFD displays.
*/
//////////////////////////////////////////////////////////////////////////
// This is a driver for the Intra2net Intranator 2500 VFD display //
// //
// The display features: //
// - B/W and two additional grayscale colors //
// - USB data transfer //
// - Animated boot logo //
// - Hardware double buffering, limit is 27 FPS //
// - Adjustable brightness / brightness of single colors //
// //
// (C) 2003,2007 Intra2net AG //
// //
// The HD44780 font in i2500vfdfm.c was taken from //
// Michael Reinelt / lcd4linux and is (C) 2000 by him. //
// //
// Code here is basend on sed1520.c: //
// (C) 2001,2002 Robin Adams ( robin@adams-online.de ) //
// //
// This driver is released under the GPL. See file COPYING in this //
// package for further details. //
//////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ftdi.h>
#include "lcd.h"
#include "i2500vfd.h"
#include "glcd_font5x8.h"
#include "report.h"
// The display itself stores three pixels in one byte
// We waste a little memory as we store one pixel per byte
// as we want to keep the drawing code simple.
// Take a look at i2500vfd_flush for the conversion
#define INTRA2NET_VFD_XSIZE 140
#define INTRA2NET_VFD_YSIZE 32
#define INTRA2NET_VFD_SCREENSIZE INTRA2NET_VFD_XSIZE*INTRA2NET_VFD_YSIZE
#define INTRA2NET_VFD_PACKEDSIZE 47*32
#define INTRA2NET_VFD_XSHIFT 0
#define WIDTH 23
#define HEIGHT 4
#define CELLWIDTH 6
#define CELLHEIGHT 8
/** private data for the \c i2500vfd driver */
typedef struct i2500vfd_private_data {
struct ftdi_context ftdi;
unsigned char *framebuf;
int changed;
} PrivateData;
// 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 = "i2500vfd_";
/////////////////////////////////////////////////////////////////
// draws char z from fontmap to the framebuffer at position
// x,y. These are zero-based textmode positions.
// The Fontmap is stored in rows while the framebuffer is stored
// in columns, so we need a little conversion.
//
void
drawchar2fb (Driver *drvthis, int x, int y, unsigned char z)
{
PrivateData *p = drvthis->private_data;
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT)
return;
x++;
int font_x, font_y;
for (font_y = 0; font_y < 8; font_y++) {
for (font_x = 5; font_x > -1; font_x--) {
if ((glcd_iso8859_1[z][font_y] & 1<<font_x) == 1<<font_x)
p->framebuf[INTRA2NET_VFD_XSHIFT+x*6-font_x + (y*8+font_y)*140] = 1;
else
p->framebuf[INTRA2NET_VFD_XSHIFT+x*6-font_x + (y*8+font_y)*140] = 0;
}
}
p->changed = 1;
}
/////////////////////////////////////////////////////////////////
// This initialises the stuff.
//
MODULE_EXPORT int
i2500vfd_init (Driver *drvthis)
{
PrivateData *p;
int i;
unsigned char c;
/* 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;
if (ftdi_init (&p->ftdi) < 0) {
report (RPT_ERR, "ftdi_init failed. Out of memory?");
return -1;
}
i = ftdi_usb_open (&p->ftdi, 0x0403, 0xF8A8);
if (i != 0 && i != -5) {
report (RPT_ERR, "Unable to find i2500 VFD display on USB bus. Aborting");
return -1;
}
// Allocate our framebuffer
p->framebuf = (unsigned char *) malloc(INTRA2NET_VFD_SCREENSIZE * 2 + INTRA2NET_VFD_PACKEDSIZE + 1);
if (p->framebuf == NULL) {
report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name);
i2500vfd_close (drvthis);
return -1;
}
// Fade out (set brightness to zero)
c = 4|64;
ftdi_write_data (&p->ftdi, &c, 1);
c = 0|64;
ftdi_write_data (&p->ftdi, &c, 1);
sleep (1);
// Blank display
c = 2|64;
ftdi_write_data (&p->ftdi, &c, 1);
// Bring voltage up again
c = 4|64;
ftdi_write_data (&p->ftdi, &c, 1);
c = 63|64;
ftdi_write_data (&p->ftdi, &c, 1);
// Flip to blank page
c = 64;
ftdi_write_data (&p->ftdi, &c, 1);
sleep (1);
// Clear internal screen
i2500vfd_clear(drvthis);
// Unblank display
c = 3|64;
ftdi_write_data (&p->ftdi, &c, 1);
report(RPT_DEBUG, "%s: init() done", drvthis->name);
return 0;
}
/////////////////////////////////////////////////////////////////
// Frees the frambuffer and exits the driver.
//
MODULE_EXPORT void
i2500vfd_close (Driver *drvthis)
{
PrivateData *p = drvthis->private_data;
if (p) {
ftdi_usb_close (&p->ftdi);
ftdi_deinit(&p->ftdi);
if (p->framebuf)
free(p->framebuf);
free(p);
}
drvthis->store_private_ptr(drvthis, NULL);
}
/////////////////////////////////////////////////////////////////
// Returns the display width
//
MODULE_EXPORT int
i2500vfd_width (Driver *drvthis)
{
return WIDTH;
}
/////////////////////////////////////////////////////////////////
// Returns the display height
//
MODULE_EXPORT int
i2500vfd_height (Driver *drvthis)
{
return HEIGHT;
}
/////////////////////////////////////////////////////////////////
// Returns the display width
//
MODULE_EXPORT int
i2500vfd_cellwidth (Driver *drvthis)
{
return CELLWIDTH;
}
/////////////////////////////////////////////////////////////////
// Returns the display height
//
MODULE_EXPORT int
i2500vfd_cellheight (Driver *drvthis)
{
return CELLHEIGHT;
}
/////////////////////////////////////////////////////////////////
// Clears the LCD screen
//
MODULE_EXPORT void
i2500vfd_clear (Driver *drvthis)
{
PrivateData *p = drvthis->private_data;
memset(p->framebuf, 0, INTRA2NET_VFD_SCREENSIZE);
p->changed = 1;
}
/////////////////////////////////////////////////////////////////
//
// Flushes all output to the VFD...
//
MODULE_EXPORT void
i2500vfd_flush (Driver *drvthis)
{
PrivateData *p = drvthis->private_data;
if (!p->changed)
return;
// Grayscales are currently discarded.
// Could be useful for antialised fonts
int packed_begin = INTRA2NET_VFD_SCREENSIZE*2;
int packed_offset = packed_begin, offset = 0, pixpos = 0, xpos = 0;
memset (p->framebuf+packed_begin, 0, INTRA2NET_VFD_PACKEDSIZE);
while (offset != INTRA2NET_VFD_SCREENSIZE) {
if (p->framebuf[offset] != 0) {
switch(pixpos) {
case 0:
p->framebuf[packed_offset] = 3;
break;
case 1:
p->framebuf[packed_offset] |= 3<<2;
break;
case 2:
p->framebuf[packed_offset] |= 3<<4;
break;
}
}
xpos++;
offset++;
pixpos++;
if (pixpos == 3) {
pixpos = 0;
packed_offset++;
}
// Special: The display is organized in 3-pixel columns, but the last column got only 2 pixels
if (xpos == 140) {
packed_offset++;
pixpos = 0;
xpos = 0;
}
}
// Page flip command
p->framebuf[INTRA2NET_VFD_SCREENSIZE * 2 + INTRA2NET_VFD_PACKEDSIZE] = 64;
// Write data to display
ftdi_write_data (&p->ftdi, p->framebuf+packed_begin, INTRA2NET_VFD_PACKEDSIZE+1);
p->changed = 0;
}
/////////////////////////////////////////////////////////////////
// Prints a string on the lc display, at position (x,y). The
// upper-left is (1,1), and the lower right should be (20,4).
//
MODULE_EXPORT void
i2500vfd_string (Driver *drvthis, int x, int y, const char string[])
{
int i;
x--; // Convert 1-based coords to 0-based
y--;
for (i = 0; string[i]; i++)
drawchar2fb (drvthis, x + i, y, string[i]);
}
/////////////////////////////////////////////////////////////////
// Writes char c at position x,y into the framebuffer.
// x and y are 1-based textmode coordinates.
//
MODULE_EXPORT void
i2500vfd_chr (Driver *drvthis, int x, int y, char c)
{
y--;
x--;
drawchar2fb(drvthis, x, y, c);
}
/////////////////////////////////////////////////////////////////
// Changes the font of character n to a pattern given by *dat.
// HD44780 Controllers only posses 8 programmable chars. But
// we store the fontmap completely in RAM, so every character
// can be altered. !Important: Characters have to be redrawn
// by drawchar2fb() to show their new shape. Because we use
// a non-standard 6x8 font a *dat not calculated from
// width and height will fail.
//
MODULE_EXPORT void
i2500vfd_set_char (Driver *drvthis, int n, char *dat)
{
int row;
unsigned char mask = (1 << CELLWIDTH) - 1;
if (n < 0 || n > 255)
return;
if (!dat)
return;
for (row = 0; row < CELLHEIGHT; row++) {
glcd_iso8859_1[n][row] = dat[row] & mask;
}
}
/////////////////////////////////////////////////////////////////
// Draws a vertical from the bottom up to the last 3 rows of the
// framebuffer at 1-based position x. len is given in pixels.
//
MODULE_EXPORT void
i2500vfd_vbar(Driver *drvthis, int x, int y, int len, int promille, int pattern)
{
PrivateData *p = drvthis->private_data;
unsigned int offset;
int i, j, pixels;
x--;
// don't do y-- as we draw bottom up
if (x < 0 || y < 1 || x >= WIDTH || y > HEIGHT || len > HEIGHT) {
report(RPT_DEBUG, "%s: [vbar ERROR] x: %d, y: %d, len: %d", drvthis->name, x, y, len);
return;
}
offset = INTRA2NET_VFD_XSHIFT + x*CELLWIDTH + y*INTRA2NET_VFD_XSIZE*CELLHEIGHT;
pixels = len*CELLHEIGHT*promille/1000;
// printf("[vbar] x: %d, y: %d, len: %d, offset: %d, pixels: %d\n", x, y, len, offset, pixels);
for (i = 0; i < pixels; i++) {
for (j = 0; j < CELLWIDTH; j++) {
p->framebuf[offset+j] = 1;
}
// go to next y-line
offset -= INTRA2NET_VFD_XSIZE;
}
p->changed = 1;
}
/////////////////////////////////////////////////////////////////
// Draws a horizontal bar from left to right at 1-based position
// x,y into the framebuffer. len is given in characters;
//
MODULE_EXPORT void
i2500vfd_hbar(Driver *drvthis, int x, int y, int len, int promille, int pattern)
{
PrivateData *p = drvthis->private_data;
unsigned int offset;
int i, j, pixels;
x--;
y--;
if (y < 0 || y >= HEIGHT || x < 0 || len < 0 || x + len > WIDTH) {
return;
}
offset = INTRA2NET_VFD_XSHIFT + 2 + x*CELLWIDTH + (y*CELLHEIGHT+1)*INTRA2NET_VFD_XSIZE;
// calculate length of bar
pixels = len*CELLWIDTH*promille/1000;
for (i = 0; i < CELLHEIGHT-1; i++) {
for (j = 0; j < pixels; j++) {
p->framebuf[offset+j] = 1;
}
// go to next y-line
offset += INTRA2NET_VFD_XSIZE;
}
p->changed = 1;
}
/////////////////////////////////////////////////////////////////
// Reprogrammes character dest to contain an icon given by
// which. Calls set_char() to do this.
//
MODULE_EXPORT int
i2500vfd_icon (Driver *drvthis, int x, int y, int icon)
{
return (glcd_icon5x8(drvthis, x, y, icon));
}