aboutsummaryrefslogtreecommitdiffstats
path: root/drv_SimpleLCD.c
diff options
context:
space:
mode:
Diffstat (limited to 'drv_SimpleLCD.c')
-rw-r--r--drv_SimpleLCD.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/drv_SimpleLCD.c b/drv_SimpleLCD.c
new file mode 100644
index 0000000..f308d87
--- /dev/null
+++ b/drv_SimpleLCD.c
@@ -0,0 +1,350 @@
+/* $Id: drv_SimpleLCD.c 771 2007-02-25 12:27:26Z michael $
+ * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_SimpleLCD.c $
+ *
+ * driver for a simple serial terminal.
+ *
+ * Copyright (C) 2005 Julien Aube <ob@obconseil.net>
+ * Copyright (C) 2005 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.
+ *
+ */
+
+/*
+ * This driver simply send out caracters on the serial port, without any
+ * formatting instructions for a particular LCD device.
+ * This is useful for custom boards of for very simple LCD.
+ *
+ * I use it for tests on a custom-made board based on a AVR microcontroler
+ * and also for driver a Point-of-Sale text-only display.
+ * I assume the following :
+ * - CR (0x0d) Return to the begining of the line without erasing,
+ * - LF (0x0a) Initiate a new line (but without sending the cursor to
+ * the begining of the line)
+ * - BS (0x08) Move the cursor to the previous caracter (but does no erase it).
+ * - It's not possible to return to the first line. Thus a back buffer is used
+ * in this driver.
+ *
+ * ******** UPDATE *********
+ * I have added a "VT-100 Compatible mode" that allows the driver to support
+ * control-sequence code. This greatly reduce flickering and eliminate the need
+ * for the back-buffer. But it is optional since all displays cannot support them.
+ * Here are the codes:
+ * Delete the display (but does not move the cursor) :
+ * "ESC [ 2 J" (0x1b 0x5b 0x32 0x4a)
+ * Position the cursor :
+ * "ESC [ YY ; XX H" ( 0x1b 0x5b YY 0x3b XX 0x48 ) where YY is the ascii for the line
+ * number, and XX is the ascii for the column number ( first line/column is '1', not zero)
+ * Delete to the end of line from current cursor position :
+ * "ESC [ 0 K" ( 0x1b 0x5b 0x30 0x4b )
+ * Set Country Code :
+ * "ESC R NN" (0x1b 0x52 NN) where NN is the country code *in byte, NOT ascii*.
+ * The default is 0 (USA), see below for specific countries.
+ * the list of accessible characters page are available on this page :
+ * http://www.wincor-nixdorf.com/internet/com/Services/Support/TechnicalSupport/POSSystems
+ * /Manuals/BAxx/index.html
+ * Get the display identification : (Doesn't work reliably, timing issues here)
+ * "ESC [ 0 c" ( 0x1b 0x5b 0x30 0x63). Return a string which look like this :
+ * ESC [ ? M ; NN ; OO ; PP ; QQ c) where M is type of display (2 for VFD),
+ * NN is the rom version, 00 is the current caracter set, PP is the number of lines and
+ * QQ the number of colomns.
+ *
+ *
+ * A "bar" capability is now provided if the config file has a "BarCharValue" parameter in it.
+ *
+ * The code come mostly taken from the LCDTerm driver in LCD4Linux, from
+ * Michaels Reinelt, many thanks to him.
+ *
+ * This driver is released under the GPL.
+ */
+
+/*
+ *
+ * exported fuctions:
+ *
+ * struct DRIVER drv_SimpleLCD
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "debug.h"
+#include "cfg.h"
+#include "qprintf.h"
+#include "plugin.h"
+#include "widget.h"
+#include "widget_text.h"
+#include "widget_icon.h"
+#include "widget_bar.h"
+#include "drv.h"
+#include "drv_generic_text.h"
+#include "drv_generic_serial.h"
+
+
+static char Name[] = "SimpleLCD";
+static char *backbuffer = 0;
+static int backbuffer_size = 0;
+static int vt100_mode = 0;
+static unsigned char bar_char = 0;
+
+/****************************************/
+/*** hardware dependant functions ***/
+/****************************************/
+
+/** No clear function on SimpleLCD : Just send CR-LF * number of lines **/
+static void drv_SL_simple_clear(void)
+{
+ char cmd[2];
+ int i;
+ cmd[0] = '\r';
+ cmd[1] = '\n';
+ for (i = 0; i < DROWS; ++i) {
+ drv_generic_serial_write(cmd, 2);
+ }
+ memset(backbuffer, ' ', backbuffer_size);
+}
+
+/** vt-100 mode : send the ESC-code **/
+static void drv_SL_vt100_clear(void)
+{
+ char cmd[4];
+ cmd[0] = 0x1b;
+ cmd[1] = '[';
+ cmd[2] = '2';
+ cmd[3] = 'J';
+ drv_generic_serial_write(cmd, 4);
+
+}
+
+static void drv_SL_clear(void)
+{
+ vt100_mode == 1 ? drv_SL_vt100_clear() : drv_SL_simple_clear();
+}
+
+
+/* If full_commit = true, then the whole buffer is to be sent to screen.
+ if full_commit = false, then only the last line is to be sent (faster on slow screens)
+*/
+
+static void drv_SL_commit(int full_commit)
+{
+ int row;
+ char cmd[2] = { '\r', '\n' };
+ if (full_commit) {
+ for (row = 0; row < DROWS; row++) {
+ drv_generic_serial_write(cmd, 2);
+ drv_generic_serial_write(backbuffer + (DCOLS * row), DCOLS);
+ }
+ } else {
+ drv_generic_serial_write(cmd, 1); /* Go to the beginning of the line only */
+ drv_generic_serial_write(backbuffer + (DCOLS * (DROWS - 1)), DCOLS);
+ }
+}
+
+static void drv_SL_simple_write(const int row, const int col, const char *data, int len)
+{
+ memcpy(backbuffer + (row * DCOLS) + col, data, len);
+ if (row == DROWS - 1)
+ drv_SL_commit(0);
+ else
+ drv_SL_commit(1);
+}
+
+static void drv_SL_vt100_write(const int row, const int col, const char *data, int len)
+{
+ char cmd[8];
+ cmd[0] = 0x1b;
+ cmd[1] = '[';
+ cmd[2] = row + '1';
+ cmd[3] = ';';
+ cmd[4] = (col / 10) + '0';
+ cmd[5] = (col % 10) + '1';
+ cmd[6] = 'H';
+ drv_generic_serial_write(cmd, 7);
+ drv_generic_serial_write(data, len);
+}
+
+
+static int drv_SL_start(const char *section, const int quiet)
+{
+ int rows = -1, cols = -1;
+ int value;
+ unsigned int flags = 0;
+ char *s;
+ char *model = 0;
+
+ vt100_mode = 0;
+ model = cfg_get(section, "Model", "generic");
+ if (model != NULL && *model != '\0') {
+ if (strcasecmp("vt100", model) == 0)
+ vt100_mode = 1;
+ }
+
+ cfg_number(section, "BarCharValue", 0, 0, 255, &value);
+ bar_char = value;
+ cfg_number(section, "Options", 0, 0, 0xffff, &value);
+ flags = value;
+ if (drv_generic_serial_open(section, Name, flags) < 0)
+ return -1;
+
+ s = cfg_get(section, "Size", NULL);
+ if (s == NULL || *s == '\0') {
+ error("%s: no '%s.Size' entry from %s", Name, section, cfg_source());
+ return -1;
+ }
+ if (sscanf(s, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) {
+ error("%s: bad %s.Size '%s' from %s", Name, section, s, cfg_source());
+ free(s);
+ return -1;
+ }
+
+ DROWS = rows;
+ DCOLS = cols;
+
+ if (!vt100_mode) {
+ backbuffer_size = DROWS * DCOLS;
+ backbuffer = malloc(backbuffer_size);
+ if (!backbuffer) {
+ return -1;
+ }
+ }
+
+ /* real worker functions */
+ if (vt100_mode) {
+ drv_generic_text_real_write = drv_SL_vt100_write;
+ } else {
+ drv_generic_text_real_write = drv_SL_simple_write;
+ }
+
+ drv_SL_clear(); /* clear */
+
+
+ if (!quiet) {
+ char buffer[40];
+ qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
+ if (drv_generic_text_greet(buffer, NULL)) {
+ sleep(3);
+ drv_SL_clear();
+ }
+ }
+
+ return 0;
+}
+
+
+/****************************************/
+/*** plugins ***/
+/****************************************/
+
+/* none */
+
+
+/****************************************/
+/*** widget callbacks ***/
+/****************************************/
+
+
+/* using drv_generic_text_draw(W) */
+
+
+/****************************************/
+/*** exported functions ***/
+/****************************************/
+
+
+/* list models */
+int drv_SL_list(void)
+{
+ printf("generic vt100");
+ return 0;
+}
+
+
+/* initialize driver & display */
+int drv_SL_init(const char *section, const int quiet)
+{
+ WIDGET_CLASS wc;
+ int ret;
+
+ info("%s: %s", Name, "$Rev: 771 $");
+
+ /* display preferences */
+ XRES = 5; /* pixel width of one char */
+ YRES = 8; /* pixel height of one char */
+ CHARS = 0; /* number of user-defineable characters */
+ CHAR0 = 0; /* ASCII of first user-defineable char */
+
+ GOTO_COST = -1; /* number of bytes a goto command requires */
+
+
+ /* start display */
+ if ((ret = drv_SL_start(section, quiet)) != 0)
+ return ret;
+
+ /* initialize generic text driver */
+ if ((ret = drv_generic_text_init(section, Name)) != 0)
+ return ret;
+
+ /* register text widget */
+ wc = Widget_Text;
+ wc.draw = drv_generic_text_draw;
+ widget_register(&wc);
+
+ /* register plugins */
+ /* none */
+
+ return 0;
+}
+
+
+/* close driver & display */
+int drv_SL_quit(const int quiet)
+{
+
+ info("%s: shutting down.", Name);
+
+ drv_generic_text_quit();
+
+ /* clear display */
+ drv_SL_clear();
+
+ /* say goodbye... */
+ if (!quiet) {
+ drv_generic_text_greet("goodbye!", NULL);
+ }
+
+ drv_generic_serial_close();
+
+ if (backbuffer) {
+ free(backbuffer);
+ backbuffer = 0;
+ backbuffer_size = 0;
+ }
+ return (0);
+}
+
+
+DRIVER drv_SimpleLCD = {
+ .name = Name,
+ .list = drv_SL_list,
+ .init = drv_SL_init,
+ .quit = drv_SL_quit,
+};