/* This is the LCDproc driver for the vfd on the Aopen EA65, based on
the Crystal Fontz driver.
Copyright (C) 2004 ????
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 */
/*Initial modification of CFontz driver by Kent Williams (c) 2005*/
/*some additions and updates by Karsten Festag (c) 2007*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "lcd.h"
#include "ea65.h"
#include "report.h"
#include "lcd_lib.h"
typedef struct driver_private_data {
int fd;
int brightness;
int offbrightness;
int width;
int height;
unsigned char *framebuf;
} PrivateData;
// Vars for the server core
MODULE_EXPORT char *api_version = API_VERSION;
MODULE_EXPORT int stay_in_foreground = 1;
MODULE_EXPORT int supports_multiple = 0;
MODULE_EXPORT int does_input = 0;
MODULE_EXPORT int does_output = 1;
MODULE_EXPORT char *symbol_prefix = "EA65_";
/////////////////////////////////////////////////////////////////
// Opens com port and sets baud correctly...
//
MODULE_EXPORT int
EA65_init (Driver *drvthis)
{
debug(RPT_INFO, "EA65: init(%p)", drvthis);
/* device is fixed */
char device[] = "/dev/ttyS1";
/*speed is fixed at 9600*/
int speed = B9600;
/* Allocate and store private data */
PrivateData *p;
p = (PrivateData *) malloc(sizeof(PrivateData));
if (p == NULL)
return -1;
if (drvthis->store_private_ptr(drvthis, p))
return -1;
//// initialize private data
// Width and Height are fixed
p->width = 9;
p->height = 1;
// Make sure the frame buffer is there...
p->framebuf = (unsigned char *) malloc (p->width * p->height);
memset (p->framebuf, ' ', p->width * p->height);
//// Read config file
// Which backlight brightness
p->brightness = drvthis->config_get_int ( drvthis->name , "Brightness" , 0 , DEFAULT_BRIGHTNESS);
if (0 <= p->brightness && p->brightness <= 1000) {
if (p->brightness < 300) {
p->brightness = 0x00; // command char that turns button LEDs off
} else if (p->brightness >= 700 ) {
p->brightness = 0x01; // command char that turns button LEDs on full
} else {
p->brightness = 0x02; // command char that turns button LEDs on half
}
} else {
report (RPT_WARNING, "EA65_init: Brightness must be between 0 and 1000. Using default value.\n");
p->brightness = DEFAULT_BRIGHTNESS;
}
// Which backlight-off "brightness"
p->offbrightness = drvthis->config_get_int ( drvthis->name , "OffBrightness" , 0 , DEFAULT_OFFBRIGHTNESS);
if (0 <= p->offbrightness && p->offbrightness <= 1000) {
if (p->offbrightness < 300) {
p->offbrightness = 0x00; // command char that turns button LEDs off
} else if (p->offbrightness >= 700) {
p->offbrightness = 0x01; // command char that turns button LEDs on full
} else {
p->offbrightness = 0x02; // command char that turns button LEDs on half
}
} else {
report (RPT_WARNING, "EA65_init: OffBrightness must be between 0 and 1000. Using default value.\n");
p->offbrightness = DEFAULT_OFFBRIGHTNESS;
}
// Set up io port correctly, and open it...
debug( RPT_DEBUG, "EA65: Opening serial device: %s", device);
struct termios portset;
p->fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY);
if (p->fd == -1) {
report (RPT_ERR, "EA65_init: failed (%s)\n", strerror (errno));
return -1;
}
tcgetattr (p->fd, &portset);
#ifdef HAVE_CFMAKERAW
// The easy way
cfmakeraw( &portset );
#else
// The hard way
portset.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON );
portset.c_oflag &= ~OPOST;
portset.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
portset.c_cflag &= ~( CSIZE | PARENB | CRTSCTS );
portset.c_cflag |= CS8 | CREAD | CLOCAL ;
#endif
// Set port speed
cfsetospeed (&portset, speed);
cfsetispeed (&portset, B0);
// Do it...
tcsetattr (p->fd, TCSANOW, &portset);
report (RPT_DEBUG, "EA65_init: done\n");
return 0;
}
/////////////////////////////////////////////////////////////////
// Clean-up
//
MODULE_EXPORT void
EA65_close (Driver *drvthis)
{
PrivateData *p = (PrivateData *) drvthis->private_data;
close (p->fd);
if(p->framebuf) free (p->framebuf);
p->framebuf = NULL;
}
/////////////////////////////////////////////////////////////////
// Returns the display width
//
MODULE_EXPORT int
EA65_width (Driver *drvthis)
{
PrivateData *p = (PrivateData *) drvthis->private_data;
return p->width;
}
/////////////////////////////////////////////////////////////////
// Returns the display height
//
MODULE_EXPORT int
EA65_height (Driver *drvthis)
{
PrivateData *p = (PrivateData *) drvthis->private_data;
return p->height;
}
//////////////////////////////////////////////////////////////////
// Flushes all output to the lcd...
//
MODULE_EXPORT void
EA65_flush (Driver *drvthis)
{
char out[6];
int i;
PrivateData *p = (PrivateData *) drvthis->private_data;
// Need to check for and deal with unsupported chars or the display gets a little upset
for (i=0; i < p->width * p->height; i++) {
if ( (p->framebuf[i] >= 224 && p->framebuf[i] <= 253) || // is a lowercase accented letter
(p->framebuf[i] >= 97 && p->framebuf[i] <= 122) ) { // is a lowercase letter
p->framebuf[i] -= 32; // -> convert to upper case
}
if (p->framebuf[i] >= 48 && p->framebuf[i] <= 57) { } // is a number -> do nothing
else if (p->framebuf[i] >= 65 && p->framebuf[i] <= 90) { } // is a uppercase letter -> do nothing
else if (p->framebuf[i] == 42 || p->framebuf[i] == 43 ||
p->framebuf[i] == 45 || p->framebuf[i] == 47 ) { } // is +,-,/,* -> do nothing
// Now lets replace some accented characters with remotely similar looking ones
else if (p->framebuf[i] == 223) p->framebuf[i] = 83; // use an "S" instead of "ß"
else if (p->framebuf[i] >= 192 && p->framebuf[i] <= 197) // use an "A"
p->framebuf[i] = 65;
else if (p->framebuf[i] >= 200 && p->framebuf[i] <= 203) // use an "E"
p->framebuf[i] = 69;
else if (p->framebuf[i] >= 204 && p->framebuf[i] <= 207) // use an "I"
p->framebuf[i] = 73;
else if (p->framebuf[i] >= 210 && p->framebuf[i] <= 214) // use an "O"
p->framebuf[i] = 79;
else if (p->framebuf[i] >= 217 && p->framebuf[i] <= 220) // use an "U"
p->framebuf[i] = 85;
else p->framebuf[i] = 32; // other characters replaced by a space
}
snprintf(out, sizeof(out), "%c%c%c%c%c", 0xa0, 0x00, 0x80, 0x8a, 0x8a);
write(p->fd, out, 5);
write(p->fd, p->framebuf, p->width * p->height);
}
/////////////////////////////////////////////////////////////////
// Prints a character on the lcd display, at position (x,y). The
// upper-left is (1,1), and the lower right should be (9,1).
//
MODULE_EXPORT void
EA65_chr (Driver *drvthis, int x, int y, char c)
{
PrivateData *p = (PrivateData *) drvthis->private_data;
y--;
x--;
//if (c < 32 && c >= 0)
// c += 128;
// For V2 of the firmware to get the block to display right
//if (newfirmware && c==-1) {
// c=214;
//}
p->framebuf[(y * p->width) + x] = c;
}
/////////////////////////////////////////////////////////////////
// Sets the backlight on or off
//
MODULE_EXPORT void
EA65_backlight (Driver *drvthis, int on)
{
PrivateData *p = (PrivateData *) drvthis->private_data;
char out[6];
if (on) {
snprintf (out, sizeof(out), "%c%c%c%c%c", 0xa0, 0x00, 0x50, 0x81, p->brightness);
} else {
snprintf (out, sizeof(out), "%c%c%c%c%c", 0xa0, 0x00, 0x50, 0x81, p->offbrightness);
}
write (p->fd, out, 5);
}
/////////////////////////////////////////////////////////////////
// Clears the LCD screen
//
MODULE_EXPORT void
EA65_clear (Driver *drvthis)
{
PrivateData *p = (PrivateData *) drvthis->private_data;
memset (p->framebuf, ' ', p->width * p->height);
}
/////////////////////////////////////////////////////////////////
// Prints a string on the lcd display, at position (x,y). The
// upper-left is (1,1), and the lower right should be (9,1).
//
MODULE_EXPORT void
EA65_string (Driver *drvthis, int x, int y, const char string[])
{
PrivateData *p = (PrivateData *) drvthis->private_data;
int i;
x -= 1; // Convert 1-based coords to 0-based...
y -= 1;
for (i = 0; string[i]; i++) {
// Check for buffer overflows...
if ((y * p->width) + x + i > (p->width * p->height))
break;
p->framebuf[(y * p->width) + x + i] = string[i];
}
}
/////////////////////////////////////////////////////////////////
//// Turns the recording LED on or off as desired.
////
MODULE_EXPORT void
EA65_output (Driver *drvthis, int on)
{
PrivateData *p = (PrivateData *) drvthis->private_data;
char out[6];
if (on) {
snprintf (out, sizeof(out), "%c%c%c%c%c", 0xa0,0x00,0x32,0x81,0x01);
} else {
snprintf (out, sizeof(out), "%c%c%c%c%c", 0xa0,0x00,0x32,0x81,0x00);
}
write (p->fd, out, 5);
}
syntax highlighted by Code2HTML, v. 0.9.1