From 181cec4348da40331b3e8ab365732c025ec149b2 Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Wed, 27 Apr 2011 19:24:15 +0200 Subject: Import upstream version 0.11.0~svn1143 --- drv_Cwlinux.c | 538 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 538 insertions(+) create mode 100644 drv_Cwlinux.c (limited to 'drv_Cwlinux.c') diff --git a/drv_Cwlinux.c b/drv_Cwlinux.c new file mode 100644 index 0000000..fbf2393 --- /dev/null +++ b/drv_Cwlinux.c @@ -0,0 +1,538 @@ +/* $Id: drv_Cwlinux.c 929 2008-12-31 06:40:59Z michael $ + * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_Cwlinux.c $ + * + * new style driver for Cwlinux display modules + * + * Copyright (C) 1999, 2000 Michael Reinelt + * Copyright (C) 2004 The LCD4Linux Team + * + * 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 +#include +#include +#include + +#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: 929 $"); + + /* 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, +}; -- cgit v1.2.3