Files
archived-lcd4linux/drv_Cwlinux.c
2008-12-31 06:40:59 +00:00

539 lines
12 KiB
C

/* $Id$
* $URL$
*
* new style driver for Cwlinux display modules
*
* Copyright (C) 1999, 2000 Michael Reinelt <michael@reinelt.co.at>
* Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
*
* This file is part of LCD4Linux.
*
* LCD4Linux 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, or (at your option)
* any later version.
*
* LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
*
* exported fuctions:
*
* struct DRIVER drv_Cwlinux
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "debug.h"
#include "cfg.h"
#include "qprintf.h"
#include "timer.h"
#include "plugin.h"
#include "widget.h"
#include "widget_text.h"
#include "widget_icon.h"
#include "widget_bar.h"
#include "widget_keypad.h"
#include "drv.h"
#include "drv_generic_text.h"
#include "drv_generic_gpio.h"
#include "drv_generic_serial.h"
#include "drv_generic_keypad.h"
static char Name[] = "Cwlinux";
static int Model;
static int Protocol;
/* ring buffer for bytes received from the display */
static unsigned char RingBuffer[256];
static unsigned int RingRPos = 0;
static unsigned int RingWPos = 0;
typedef struct {
int type;
char *name;
int rows;
int cols;
int xres; /* pixel width of one char */
int yres; /* pixel height of one char */
int gpos;
int gpis;
int chars; /* number of user definable chars */
int protocol;
} MODEL;
/* Fixme: number of gpo's should be verified */
static MODEL Models[] = {
/* type, name, rows, cols, xres/char, yres/char, gpo's, gpi's, definable chars, protocol */
{0x01, "CW1602", 2, 16, 5, 7, 2, 2, 8, 1},
{0x02, "CW12232", 4, 20, 6, 8, 2, 2, 16, 2},
{0x03, "CW12832", 4, 21, 6, 8, 2, 2, 16, 2},
{0xff, "Unknown", -1, -1, -1, -1, -1, -1, -1, -1}
};
/****************************************/
/*** hardware dependant functions ***/
/****************************************/
static void drv_CW_process_input(void)
{
while (RingRPos != RingWPos) {
drv_generic_keypad_press(RingBuffer[RingRPos++]);
if (RingRPos >= sizeof(RingBuffer))
RingRPos = 0;
}
}
static int drv_CW_poll(void)
{
while (1) {
char buffer[32];
int num, n;
num = drv_generic_serial_poll(buffer, sizeof(buffer));
if (num <= 0)
break; /* no more input */
/* put result into RingBuffer */
for (n = 0; n < num; n++) {
RingBuffer[RingWPos++] = (unsigned char) buffer[n];
if (RingWPos >= sizeof(RingBuffer))
RingWPos = 0;
}
}
if (RingRPos != RingWPos)
return 1;
else
return 0;
}
static void drv_CW_timer(void __attribute__ ((unused)) * notused)
{
while (drv_CW_poll()) {
drv_CW_process_input();
}
}
static void drv_CW_send(const char *string, const int len)
{
drv_generic_serial_write(string, len);
usleep(20);
if (drv_CW_poll())
drv_CW_process_input();
}
static void drv_CW_write(const int row, const int col, const char *data, const int len)
{
char cmd[6] = "\376Gxy\375";
cmd[2] = (char) col;
cmd[3] = (char) row;
drv_CW_send(cmd, 5);
drv_CW_send(data, len);
}
static void drv_CW1602_defchar(const int ascii, const unsigned char *buffer)
{
int i;
char cmd[12] = "\376Nn12345678\375";
cmd[2] = (char) ascii;
for (i = 0; i < 8; i++) {
cmd[3 + i] = buffer[i] & 0x1f;
}
drv_CW_send(cmd, 12);
}
static void drv_CW12232_defchar(const int ascii, const unsigned char *buffer)
{
int i, j;
char cmd[10] = "\376Nn123456\375"; /* 0xfe 'N' [1..16] (6 Bytes Data) 0xfd */
cmd[2] = (char) ascii;
/* The CW12232 uses a vertical bitmap layout, */
/* so we have to 'rotate' the bitmap. */
for (i = 0; i < 6; i++) {
cmd[3 + i] = 0;
for (j = 0; j < 8; j++) {
if (buffer[j] & (1 << (5 - i))) {
cmd[3 + i] |= (1 << j);
}
}
}
drv_CW_send(cmd, 10);
}
static int drv_CW_GPO(const int num, const int val)
{
/* Fixme: GPO's not yet implemented! */
error("%s: GPO's not yet implemented!", Name);
/* Fixme: num*val to avoid compiler warning */
return num * val;
}
static int drv_CW_GPI(const int num)
{
if (num < 0 || num > GPIS) {
return 0;
}
error("%s: GPI's not yet implemented!", Name);
return num;
}
static void drv_CW_clear(void)
{
#if 1
drv_CW_send("\376X\375", 3); /* Clear Display */
usleep(500000);
#else
/* for some mysterious reason, we have to sleep after */
/* the command _and_ after the CMD_END... */
drv_CW_send("\376X", 2); /* Clear Display */
drv_CW_send("\375", 1); /* Command End */
#endif
}
static int drv_CW_brightness(int brightness)
{
static unsigned char Brightness = 0;
char cmd[5] = "\376A_\375";
/* -1 is used to query the current brightness */
if (brightness == -1)
return Brightness;
if (brightness < 0)
brightness = 0;
if (brightness > 8)
brightness = 8;
Brightness = brightness;
switch (Brightness) {
case 0:
/* backlight off */
drv_CW_send("\376F\375", 3);
break;
case 8:
/* backlight on */
drv_CW_send("\376B\375", 3);
break;
default:
/* backlight level */
cmd[2] = (char) Brightness;
drv_CW_send(cmd, 4);
break;
}
return Brightness;
}
static int drv_CW_keypad(const int num)
{
int val = WIDGET_KEY_PRESSED;
switch (num) {
case 65:
val += WIDGET_KEY_UP;
break;
case 66:
val += WIDGET_KEY_DOWN;
break;
case 67:
val += WIDGET_KEY_LEFT;
break;
case 68:
val += WIDGET_KEY_RIGHT;
break;
case 69:
val += WIDGET_KEY_CONFIRM;
break;
case 70:
val += WIDGET_KEY_CANCEL;
break;
default:
error("%s: unknown keypad value %d", Name, num);
}
debug("%s: key %c (0x%x) pressed", Name, num, num);
return val;
}
static int drv_CW_start(const char *section)
{
int i;
char *model;
char buffer[16];
model = cfg_get(section, "Model", NULL);
if (model != NULL && *model != '\0') {
for (i = 0; Models[i].type != 0xff; i++) {
if (strcasecmp(Models[i].name, model) == 0)
break;
}
if (Models[i].type == 0xff) {
error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source());
return -1;
}
Model = i;
info("%s: using model '%s'", Name, Models[Model].name);
} else {
error("%s: no '%s.Model' entry from %s", Name, section, cfg_source());
return -1;
}
/* open serial port */
if (drv_generic_serial_open(section, Name, 0) < 0)
return -1;
/* read firmware version: 0xfe '1' 0xfd */
drv_generic_serial_write("\3761\375", 3);
usleep(100000);
if (drv_generic_serial_read(buffer, 2) != 2) {
info("unable to read firmware version!");
} else {
info("Cwlinux Firmware V%d.%d", (int) buffer[0], (int) buffer[1]);
}
/* read model mumber: 0xfe 0x30 0xfd */
drv_generic_serial_write("\3760\375", 3);
usleep(100000);
if (drv_generic_serial_read(buffer, 2) != 2) {
info("unable to read model number!");
} else {
info("Cwlinux model CW%d%d", (int) buffer[0], (int) buffer[1]);
}
/* initialize global variables */
DROWS = Models[Model].rows;
DCOLS = Models[Model].cols;
XRES = Models[Model].xres;
YRES = Models[Model].yres;
GPOS = Models[Model].gpos;
GPIS = Models[Model].gpis;
CHARS = Models[Model].chars;
Protocol = Models[Model].protocol;
/* regularly process display input */
timer_add(drv_CW_timer, NULL, 250, 0);
drv_CW_clear();
drv_CW_send("\376D\375", 3); /* auto line wrap off */
drv_CW_send("\376R\375", 3); /* auto scroll off */
drv_CW_send("\376K\375", 3); /* underline cursor off */
drv_CW_send("\376B\375", 3); /* backlight on */
/* set brightness */
if (cfg_number(section, "Brightness", 0, 0, 8, &i) > 0) {
drv_CW_brightness(i);
}
return 0;
}
/****************************************/
/*** plugins ***/
/****************************************/
static void plugin_brightness(RESULT * result, const int argc, RESULT * argv[])
{
double brightness;
switch (argc) {
case 0:
brightness = drv_CW_brightness(-1);
SetResult(&result, R_NUMBER, &brightness);
break;
case 1:
brightness = drv_CW_brightness(R2N(argv[0]));
SetResult(&result, R_NUMBER, &brightness);
break;
default:
error("%s.brightness(): wrong number of parameters", Name);
SetResult(&result, R_STRING, "");
}
}
/****************************************/
/*** widget callbacks ***/
/****************************************/
/* using drv_generic_text_draw(W) */
/* using drv_generic_text_icon_draw(W) */
/* using drv_generic_text_bar_draw(W) */
/* using drv_generic_gpio_draw(W) */
/* using drv_generic_keypad_draw(W) */
/****************************************/
/*** exported functions ***/
/****************************************/
/* list models */
int drv_CW_list(void)
{
int i;
for (i = 0; Models[i].type != 0xff; i++) {
printf("%s ", Models[i].name);
}
return 0;
}
/* initialize driver & display */
int drv_CW_init(const char *section, const int quiet)
{
WIDGET_CLASS wc;
int ret;
info("%s: %s", Name, "$Rev$");
/* display preferences */
CHAR0 = 1; /* ASCII of first user-defineable char */
GOTO_COST = 3; /* number of bytes a goto command requires */
INVALIDATE = 1; /* re-defined chars must be re-sent to the display */
/* start display */
if ((ret = drv_CW_start(section)) != 0)
return ret;
/* real worker functions */
drv_generic_text_real_write = drv_CW_write;
drv_generic_gpio_real_set = drv_CW_GPO;
drv_generic_gpio_real_get = drv_CW_GPI;
drv_generic_keypad_real_press = drv_CW_keypad;
switch (Protocol) {
case 1:
drv_generic_text_real_defchar = drv_CW1602_defchar;
break;
case 2:
drv_generic_text_real_defchar = drv_CW12232_defchar;
break;
}
if (!quiet) {
char buffer[40];
qprintf(buffer, sizeof(buffer), "%s %s", Name, Models[Model].name);
if (drv_generic_text_greet(buffer, "www.cwlinux.com")) {
sleep(3);
drv_CW_clear();
}
}
/* initialize generic text driver */
if ((ret = drv_generic_text_init(section, Name)) != 0)
return ret;
/* initialize generic icon driver */
if ((ret = drv_generic_text_icon_init()) != 0)
return ret;
/* initialize generic bar driver */
if ((ret = drv_generic_text_bar_init(0)) != 0)
return ret;
/* add fixed chars to the bar driver */
drv_generic_text_bar_add_segment(0, 0, 255, 32); /* ASCII 32 = blank */
/* initialize generic GPIO driver */
if ((ret = drv_generic_gpio_init(section, Name)) != 0)
return ret;
/* initialize generic key pad driver */
if ((ret = drv_generic_keypad_init(section, Name)) != 0)
return ret;
/* register text widget */
wc = Widget_Text;
wc.draw = drv_generic_text_draw;
widget_register(&wc);
/* register icon widget */
wc = Widget_Icon;
wc.draw = drv_generic_text_icon_draw;
widget_register(&wc);
/* register bar widget */
wc = Widget_Bar;
wc.draw = drv_generic_text_bar_draw;
widget_register(&wc);
/* register plugins */
AddFunction("LCD::brightness", -1, plugin_brightness);
return 0;
}
/* close driver & display */
int drv_CW_quit(const int quiet)
{
info("%s: shutting down.", Name);
drv_generic_text_quit();
drv_generic_gpio_quit();
drv_generic_keypad_quit();
/* clear display */
drv_CW_clear();
/* say goodbye... */
if (!quiet) {
drv_generic_text_greet("goodbye!", NULL);
}
drv_generic_serial_close();
return (0);
}
DRIVER drv_Cwlinux = {
.name = Name,
.list = drv_CW_list,
.init = drv_CW_init,
.quit = drv_CW_quit,
};