From 6ef45399b8ad8918826ae91db22a03c9c9a901cb Mon Sep 17 00:00:00 2001 From: marschap Date: Sun, 4 Feb 2007 20:51:33 +0000 Subject: [PATCH] text based serial Point of Sale displays (Eric Pooch) --- docs/lcdproc-user/drivers/serialPOS.docbook | 182 ++++ server/drivers/serialPOS.c | 967 ++++++++++++++++++++ server/drivers/serialPOS.h | 39 + 3 files changed, 1188 insertions(+) create mode 100644 docs/lcdproc-user/drivers/serialPOS.docbook create mode 100644 server/drivers/serialPOS.c create mode 100644 server/drivers/serialPOS.h diff --git a/docs/lcdproc-user/drivers/serialPOS.docbook b/docs/lcdproc-user/drivers/serialPOS.docbook new file mode 100644 index 0000000..63bf031 --- /dev/null +++ b/docs/lcdproc-user/drivers/serialPOS.docbook @@ -0,0 +1,182 @@ + +The serialPOS Driver + + +This section talks about using LCDproc with a point of sale ("POS") character-display. + + + + +The serialPOS-driver is currently working with the AEDEX emulation protocol, +but can be extended to work with various other protocols. + + + +The driver should operate most character POS displays with a serial (rs232) input. +Because these displays use a standardized protocol, if the protocol is +supported by your display, it should work as expected. + Feedback is welcome. + + +serialPOS: Emulation Protocol Status + + + + Protocol + Display tested + Currently Supported + Remark + + + + + AEDEX + Emax + Yes + + + + IEE + + No + + + + Epson + + No + + + + Emax + + No + + + + IBM + + No + + + + Logic Controls + + No + + + + Ultimate + + No + + + + +
+() feature not tested. +
+ + +Connecting The Display + + +Connecting the display should consist of simply plugging it into your computer's +rs232 port. Because these displays typically support full rs232, no additional +wiring is needed. If you do not have this port (many newer computers do not), you +can use a USB to serial adapter with the appropriate driver. + + +If your display supports a "pass-through" function, but you do not have +another rs232 device connected to the pass-through port, you may experience hangs +if an improperly formatted command sneaks through. +This is because the display is waiting for the pass-through +device to accept the data and a blocking state is created within the device. +You can either connect another rs232 device, or rewire the display to send the pass- +through commands back to your computer. + + + + + +Configuration in LCDd.conf + + +[serialPOS] + + + + + + Device= + DEVICE + + + Device to use in serial mode. Usual values are /dev/ttyS0 or /dev/cu.usbserial + [default: /dev/lcd]. + + + + + + Size= + + WIDTH + x + HEIGHT + + + + Specifies the size of the VFD in characters. + [default: 16x2] + + + + + + Type= + + + IEE + AEDEX + Epson + Emax + IBM + LogicControls + Ultimate + + + + + Set the communication protocol to use with the POS display. + If not given [default AEDEX]. + Currently, only AEDEX is supported. + + + + + + Speed= + + + 1200 + 2400 + 9600 + 19200 + 115200 + + + + + Set the the baud rate communication with the POS display. + If not given [default 9600]. + + + + + + + + +
+ diff --git a/server/drivers/serialPOS.c b/server/drivers/serialPOS.c new file mode 100644 index 0000000..803ee1f --- /dev/null +++ b/server/drivers/serialPOS.c @@ -0,0 +1,967 @@ +/* This is the LCDproc driver for Point Of Sale ("POS") devices using + various protocols. While it currently only supports AEDEX, + it can be extended to provide support for many POS emulation types. + + Copyright (C) 2006 Eric Pooch + + This driver is based on MtxOrb.c driver and is subject to its copyrights. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + + +List of driver entry point: + +init Implemented. +close Implemented. +width Implemented. +height Implemented. +clear Implemented by space filling no custom char info. +flush Implemented. +string Implemented. +chr Implemented. +vbar Implemented. +hbar Implemented. +num Implemented. +heartbeat Implemented. +icon NOT IMPLEMENTED: not part of POS protocol +cursor NOT IMPLEMENTED: not part of AEDEX protocol +set_char NOT IMPLEMENTED: not part of AEDEX protocol +get_free_chars Implemented. +cellwidth Implemented. +cellheight Implemented. +get_contrast NOT IMPLEMENTED: not part of AEDEX protocol +set_contrast NOT IMPLEMENTED: not part of AEDEX protocol +get_brightness NOT IMPLEMENTED: not part of AEDEX protocol +set_brightness NOT IMPLEMENTED: not part of AEDEX protocol +backlight NOT IMPLEMENTED: not part of AEDEX protocol +output Not implemented. +get_key Not implemented, no keys. +get_info Implemented. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "lcd.h" +#include "lcd_lib.h" +#include "serialPOS.h" +#include "adv_bignum.h" + +#include "report.h" + + +/* + * The serialPOS driver does not use a lot of hardware features. + * We try to replace them with more flexible software alternatives. + * That's why vbar/hbar/bignum are using locally-defined functions; + * it permits simultaneous use of those features and custom chars. + * + * For the same reason, we don't use the hardware clear but rather + * empty the internal frame buffer. The frame buffer holds all + * the requested changes until the server asks us to flush the + * changes to the display. This also permits us to do an + * incremental update and reduce the number of characters to be + * sent to the display across the serial link. + * + * In order to display graphic widgets, we define and use our own + * custom characters. To avoid multiple definitions of the same + * custom characters, we use a caching mechanism that remembers + * what is currently defined. In order to avoid always redefining + * the same custom character at the beginning of the table, we + * rotate the beginning of the table. This is supposed to reduce + * the number of character redefinitions and make the caching more + * effective. The overall goal is to reduce the number of + * characters sent to the display. + */ + + +typedef enum { + POS_IEE = 0, + POS_AEDEX, + POS_Epson, + POS_Emax, + POS_IBM, + POS_LogicControls, + POS_Ultimate +} POS_EmulationType; + + +#define AEDEXPrefix "!#" + +typedef enum { + AEDEXLine1Display = 1, /* upper line display */ + AEDEXLine2Display, /* bottom line display */ + AEDEXLine3Display, /* not sure what this code really is */ + AEDEXContinuousScroll, /* upper line message scroll continuously */ + AEDEXDisplayTime, /* "hh':'mm" h,m='0'-'9' display time */ + AEDEXSingleScroll, /* upper line message scroll one pass */ + AEDEXAllScroll, /* not sure what this code really is */ + AEDEXChangeCode, /* change attention code */ + AEDEXAllLineDisplay /* two line display */ +} AEDEXCommands; + + +typedef enum { + standard, /* only char 0 is used for heartbeat */ + vbar, /* vertical bars */ + hbar, /* horizontal bars */ + custom, /* custom settings */ + bignum, /* big numbers */ + bigchar /* big characters */ +} CGmode; + + + + +typedef struct { + int fd; /* The LCD file descriptor */ + + /* dimensions */ + int width, height; + int cellwidth, cellheight; + + /* framebuffer and buffer for old LCD contents */ + unsigned char *framebuf; + unsigned char *backingstore; + + /* defineable characters */ + CGmode ccmode; + + /* feature enable */ + int *hardwrap; + int *hardscroll; + + POS_EmulationType emulation_mode; /* The emulation type */ + int output_state; /* static data from serialPOS_output */ + + char info[255]; /* static data from serialPOS_get_info */ +} 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 = 1; +MODULE_EXPORT char *symbol_prefix = "serialPOS_"; + +static void serialPOS_hardware_clear(Driver *drvthis); +static void serialPOS_linewrap(Driver *drvthis, int on); +static void serialPOS_autoscroll(Driver *drvthis, int on); +static void serialPOS_cursorblink(Driver *drvthis, int on); +static void serialPOS_cursor_goto(Driver *drvthis, int x, int y); + + +/* Parse one key from the configfile */ +static char +serialPOS_parse_keypad_setting (Driver *drvthis, char *keyname, char default_value) +{ + char return_val = 0; + const char *s; + char buf[255]; + + s = drvthis->config_get_string(drvthis->name, keyname, 0, NULL); + if (s != NULL) { + strncpy(buf, s, sizeof(buf)); + buf[sizeof(buf)-1] = '\0'; + return_val = buf[0]; + } else { + return_val = default_value; + } + return return_val; +} + + +/** + * Initialize the driver. + * \param drvthis Pointer to driver structure. + * \return Information of success (0) or failure (non-0). + */ +MODULE_EXPORT int +serialPOS_init (Driver *drvthis) +{ + struct termios portset; + + char device[256] = DEFAULT_DEVICE; + int speed = DEFAULT_SPEED; + char size[256] = DEFAULT_SIZE; + char buf[256] = ""; + int tmp, w, h; + + PrivateData *p; + + /* Alocate and store private data */ + p = (PrivateData *) malloc(sizeof(PrivateData)); + if (p == NULL) + return -1; + if (drvthis->store_private_ptr(drvthis, p)) + return -1; + + /* Initialise the PrivateData structure */ + p->fd = -1; + + p->width = LCD_DEFAULT_WIDTH; + p->height = LCD_DEFAULT_HEIGHT; + p->cellwidth = LCD_DEFAULT_CELLWIDTH; + p->cellheight = LCD_DEFAULT_CELLHEIGHT; + + p->framebuf = NULL; + p->backingstore = NULL; + + p->output_state = -1; /* static data from serialPOS_output */ + + p->hardwrap = 0; + p->hardscroll = 0; + + p->emulation_mode = POS_AEDEX; + + debug(RPT_INFO, "serialPOS: init(%p)", drvthis); + + /* READ CONFIG FILE */ + + /* Get serial device to use */ + strncpy(device, drvthis->config_get_string(drvthis->name, "Device", 0, DEFAULT_DEVICE), sizeof(device)); + device[sizeof(device)-1] = '\0'; + report(RPT_INFO, "%s: using Device %s", drvthis->name, device); + + /* Get emulation type */ + strncpy(buf, drvthis->config_get_string(drvthis->name, "Type", 0, DEFAULT_TYPE), sizeof(buf)); + buf[sizeof(buf)-1] = '\0'; + if (strncasecmp(buf, "IEE", 3) == 0) { + p->emulation_mode = POS_IEE; + } else if (strncasecmp(buf, "AED", 3) == 0) { + p->emulation_mode = POS_AEDEX; + } else if (strncasecmp(buf, "Eps", 3) == 0) { + p->emulation_mode = POS_Epson; + } else if (strncasecmp(buf, "Ema", 3) == 0) { + p->emulation_mode = POS_Emax; + } else if (strncasecmp(buf, "Log", 3) == 0) { + p->emulation_mode = POS_LogicControls; + } else if (strncasecmp(buf, "IBM", 3) == 0) { + p->emulation_mode = POS_IBM; + } else if (strncasecmp(buf, "Ult", 3) == 0) { + p->emulation_mode = POS_Ultimate; + } else { + report(RPT_ERR, "%s: unknown display Type %s; must be one of IEE, AEDEX, Epson, Emax, Logic Controls or Ultimate", + drvthis->name, buf); + return -1; + } + + /* Get display size */ + strncpy(size, drvthis->config_get_string(drvthis->name, "Size", 0, DEFAULT_SIZE), sizeof(size)); + size[sizeof(size)-1] = '\0'; + if ((sscanf(size, "%dx%d", &w, &h) != 2) + || (w <= 0) || (w > LCD_MAX_WIDTH) + || (h <= 0) || (h > LCD_MAX_HEIGHT)) { + report(RPT_WARNING, "%s: cannot read Size: %s; using default %s", + drvthis->name, size, DEFAULT_SIZE); + sscanf(DEFAULT_SIZE , "%dx%d", &w, &h); + } + p->width = w; + p->height = h; + + /* Get speed */ + tmp = drvthis->config_get_int(drvthis->name, "Speed", 0, DEFAULT_SPEED); + switch (tmp) { + case 1200: + speed = B1200; + break; + case 2400: + speed = B2400; + break; + case 4800: + speed = B4800; + break; + case 9600: + speed = B9600; + break; + default: + speed = B9600; + report(RPT_WARNING, "%s: Speed must be 1200, 2400, 4800 or 9600; using default %d", + drvthis->name, tmp); + } + + /* Set up io port correctly, and open it... */ + p->fd = open(device, O_RDWR | O_NOCTTY); + if (p->fd == -1) { + report(RPT_ERR, "%s: open(%s) failed (%s)", drvthis->name, device, strerror(errno)); + if (errno == EACCES) + report(RPT_ERR, "%s: %s device could not be opened...", drvthis->name, device); + return -1; + } + report(RPT_INFO, "%s: opened display on %s", drvthis->name, device); + + tcgetattr(p->fd, &portset); + + // THIS ALL COMMENTED OUT BECAUSE WE NEED TO SET TIMEOUTS + /* We use RAW mode */ +#ifdef HAVE_CFMAKERAW_NOT + /* 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; + portset.c_cc[VMIN] = 1; + portset.c_cc[VTIME] = 3; +#endif + + /* Set port speed */ + cfsetospeed(&portset, speed); + cfsetispeed(&portset, B0); + + /* Do it... */ + tcsetattr(p->fd, TCSANOW, &portset); + + /* Make sure the frame buffer is there... */ + p->framebuf = (unsigned char *) calloc(p->width * p->height, 1); + if (p->framebuf == NULL) { + report(RPT_ERR, "%s: unable to create framebuffer", drvthis->name); + return -1; + } + memset(p->framebuf, ' ', p->width * p->height); + + /* make sure the framebuffer backing store is there... */ + p->backingstore = (unsigned char *) malloc(p->width * p->height); + if (p->backingstore == NULL) { + report(RPT_ERR, "%s: unable to create framebuffer backing store", drvthis->name); + return -1; + } + memset(p->backingstore, ' ', p->width * p->height); + + /* set initial LCD configuration */ + serialPOS_hardware_clear(drvthis); + serialPOS_linewrap(drvthis, DEFAULT_LINEWRAP); + serialPOS_autoscroll(drvthis, DEFAULT_AUTOSCROLL); + + report(RPT_DEBUG, "%s: init() done", drvthis->name); + + return 1; +} + + +/** + * Close the driver (do necessary clean-up). + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +serialPOS_close (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + if (p != NULL) { + if (p->fd >= 0) + close(p->fd); + + if (p->framebuf) + free(p->framebuf); + p->framebuf = NULL; + + if (p->backingstore) + free(p->backingstore); + p->backingstore = NULL; + + free(p); + } + drvthis->store_private_ptr(drvthis, NULL); + debug(RPT_DEBUG, "serialPOS: closed"); +} + + +/** + * Return the display width in characters. + * \param drvthis Pointer to driver structure. + * \return Number of characters the display is wide. + */ +MODULE_EXPORT int +serialPOS_width (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + return p->width; +} + + +/** + * Return the display height in characters. + * \param drvthis Pointer to driver structure. + * \return Number of characters the display is high. + */ +MODULE_EXPORT int +serialPOS_height (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + return p->height; +} + + +/** + * Return the width of a character in pixels. + * \param drvthis Pointer to driver structure. + * \return Number of pixel columns a character cell is wide. + */ +MODULE_EXPORT int +MtxcOrb_cellwidth (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + return p->cellwidth; +} + + +/** + * Return the height of a character in pixels. + * \param drvthis Pointer to driver structure. + * \return Number of pixel lines a character cell is high. + */ +MODULE_EXPORT int +MtxcOrb_cellheight (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + return p->cellheight; +} + + +/** + * Print a string on the screen at position (x,y). + * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height). + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param string String that gets written. + */ +MODULE_EXPORT void +serialPOS_string (Driver *drvthis, int x, int y, char string[]) +{ + PrivateData *p = drvthis->private_data; + int i; + + /* Convert 1-based coords to 0-based... */ + x--; + y--; + + if ((y < 0) || (y >= p->height)) + return; + + for (i = 0; (string[i] != '\0') && (x < p->width); i++, x++) { + /* Check for buffer overflows... */ + if (x >= 0) + p->framebuf[(y * p->width) + x] = string[i]; + } + + report(RPT_DEBUG, "serialPOS: printed string at (%d,%d)", x, y); +} + + +/** + * Clear the framebuffer. + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +serialPOS_clear (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + /* replace all chars in framebuf with spaces */ + memset(p->framebuf, ' ', (p->width * p->height)); + + report(RPT_DEBUG, "serialPOS: cleared framebuffer"); +} + + +/** + * Flush data on screen to the LCD. + * \param drvthis Pointer to driver structure. + */ +MODULE_EXPORT void +serialPOS_flush (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + + int modified = 0; + int i; + + for (i = 0; i < p->height; i++) { + // set pointers to start of the line in frame buffer & backing store + unsigned char *sp = p->framebuf + (i * p->width); + unsigned char *sq = p->backingstore + (i * p->width); + + unsigned int length = p->width+5; + + char out[length]; + + debug(RPT_DEBUG, "Framebuf: '%.*s'", p->width, sp); + debug(RPT_DEBUG, "Backingstore: '%.*s'", p->width, sq); + + /* Strategy: + * - not more than one update command per line + * - skip lines that are identical + */ + + // skip over identical lines + if ( memcmp(sp, sq, p->width) == 0) { + /* The lines are the same. */ + continue; + } + + /* there are differences, ... */ + report(RPT_DEBUG, "%s: l=%d string='%.*s'", __FUNCTION__, i, p->width, sp); + + if (p->emulation_mode == POS_AEDEX) { + int command = i+1; + if ( i == 0 && p->hardscroll == 1 ) + command = AEDEXContinuousScroll; + + snprintf(out, length, "%s%d%.*s%c", AEDEXPrefix, command, p->width, sp, 13); + debug(RPT_DEBUG, "%s%d%.*s%c", AEDEXPrefix, command, p->width, sp, 13); + } + + write(p->fd, out, sizeof(out)); + + modified++; + + } + + if (modified) + memcpy(p->backingstore, p->framebuf, p->width * p->height); + + + report(RPT_DEBUG, "serialPOS: frame buffer flushed"); +} + + +/** + * Print a character on the screen at position (x,y). + * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height). + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param c Character that gets written. + */ +MODULE_EXPORT void +serialPOS_chr (Driver *drvthis, int x, int y, char c) +{ + PrivateData *p = drvthis->private_data; + + /* Convert 1-based coords to 0-based... */ + x--; + y--; + + /* The # character might interfere with the AEDEX command set */ + if (p->emulation_mode == POS_AEDEX && c == '#') + c = '%'; + + if ((x >= 0) && (y >= 0) && (x < p->width) && (y < p->height)) + p->framebuf[(y * p->width) + x] = c; + + report(RPT_DEBUG, "writing character %02X to position (%d,%d)", c, x, y); +} + + +/** + * Set output port(s). + * Displays with keypad have 6 outputs whereas the others only have one. + * \param drvthis Pointer to driver structure. + * \param state Integer with bits representing port states. + */ +#ifdef NOTUSED +MODULE_EXPORT void +serialPOS_output (Driver *drvthis, int state) +{ + /* I don't get what this does. Many POS displays have a pass-through function. */ + PrivateData *p = drvthis->private_data; + +} +#endif + + +/** + * Clear the LCD using its hardware command + * \param drvthis Pointer to driver structure. + */ +static void +serialPOS_hardware_clear (Driver *drvthis) +{ + /* There is no hardware clear in the POS command sets, + but most have an easy software clear. */ + /*PrivateData *p = drvthis->private_data; + + char out[6]; + + if (p->emulation_mode == POS_AEDEX) { + snprintf(out, 6, "%s%c %d", AEDEXPrefix, AEDEXAllLineDisplay, 13); + } + + write(p->fd, out, 5);*/ + debug(RPT_DEBUG, "serialPOS: cleared LCD"); +} + + +/** + * Turn the POS's built-in linewrapping feature on or off. + * \param drvthis Pointer to driver structure. + * \param on New state. + */ +static void +serialPOS_linewrap (Driver *drvthis, int on) +{ + PrivateData *p = drvthis->private_data; + + p->hardwrap = on; + + debug(RPT_DEBUG, "serialPOS: linewrap turned %s", (on) ? "on" : "off"); +} + + +/** + * Turn the POS's built-in automatic scrolling feature on or off. + * \param drvthis Pointer to driver structure. + * \param on New state. + */ +static void +serialPOS_autoscroll (Driver *drvthis, int on) +{ + PrivateData *p = drvthis->private_data; + + p->hardscroll = on; + + debug(RPT_DEBUG, "serialPOS: autoscroll turned %s", (on) ? "on" : "off"); +} + + +/** + * Turn POS's hardware cursor blinking on or off. + * \param drvthis Pointer to driver structure. + * \param on New state. + * + */ +static void +serialPOS_cursorblink (Driver *drvthis, int on) +{ + //PrivateData *p = drvthis->private_data; + + debug(RPT_DEBUG, "serialPOS: cursorblink turned %s", (on) ? "on" : "off"); +} + + +/** + * Move cursor to position (x,y). + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + */ +static void +serialPOS_cursor_goto(Driver *drvthis, int x, int y) +{ + //PrivateData *p = drvthis->private_data; +} + + +/** + * Provide general information about the LCD/VFD display. + * \param drvthis Pointer to driver structure. + * \return Constant string with information. + */ +MODULE_EXPORT const char * +serialPOS_get_info (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + strcpy(p->info, "Driver for Point of Sale Displays."); + return p->info; +} + + +/** + * Draw a vertical bar bottom-up. + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column) of the starting point. + * \param y Vertical character position (row) of the starting point. + * \param len Number of characters that the bar is high at 100% + * \param promille Current height level of the bar in promille. + * \param options Options (currently unused). + */ +MODULE_EXPORT void +serialPOS_vbar (Driver * drvthis, int x, int y, int len, int promille, int options) +{ + PrivateData *p = drvthis->private_data; + // map + char ascii_map[] = { ' ', ' ', '-', '-', '=', '=', '%', '%' }; + char *map = ascii_map; + int pixels = ((long) 2 * len * p->cellheight) * promille / 2000; + int pos; + + + if ((x <= 0) || (y <= 0) || (x > p->width)) + return; + + /* x and y are the start position of the bar. + * The bar by default grows in the 'up' direction + * (other direction not yet implemented). + * len is the number of characters that the bar is long at 100% + * promille is the number of promilles (0..1000) that the bar should be filled. + */ + + for (pos = 0; pos < len; pos++) { + + if (y - pos <= 0) + return; + + if (pixels >= p->cellheight) { + /* write a "full" block to the screen... */ + serialPOS_chr(drvthis, x, y-pos, '%'); + } + else if (pixels > 0) { + // write a partial block... + serialPOS_chr(drvthis, x, y-pos, map[len-1]); + break; + } + else { + ; // write nothing (not even a space) + } + + pixels -= p->cellheight; + } +} + + +/** + * Draw a horizontal bar to the right. + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column) of the starting point. + * \param y Vertical character position (row) of the starting point. + * \param len Number of characters that the bar is long at 100% + * \param promille Current length level of the bar in promille. + * \param options Options (currently unused). + */ +MODULE_EXPORT void +serialPOS_hbar (Driver * drvthis, int x, int y, int len, int promille, int options) +{ + PrivateData *p = drvthis->private_data; + int pixels = ((long) 2 * len * p->cellwidth) * promille / 2000; + int pos; + + if ((x <= 0) || (y <= 0) || (y > p->height)) + return; + + /* x and y are the start position of the bar. + * The bar by default grows in the 'right' direction + * (other direction not yet implemented). + * len is the number of characters that the bar is long at 100% + * promille is the number of promilles (0..1000) that the bar should be filled. + */ + + for (pos = 0; pos < len; pos++) { + + if (x + pos > p->width) + return; + + if (pixels >= p->cellwidth * 2/3) { + /* write a "full" block to the screen... */ + serialPOS_chr(drvthis, x+pos, y, '='); + } + else if (pixels > p->cellwidth * 1/3) { + /* write a partial block... */ + serialPOS_chr(drvthis, x+pos, y, '-'); + break; + } + else { + ; // write nothing (not even a space) + } + + pixels -= p->cellwidth; + } +} + + +/** + * Write a big number to the screen. + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param num Character to write (0 - 10 with 10 representing ':') + */ +MODULE_EXPORT void +serialPOS_num (Driver *drvthis, int x, int num) +{ + PrivateData *p = drvthis->private_data; + int do_init = 0; + + if ((num < 0) || (num > 10)) + return; + + if (p->ccmode != bignum) { + if (p->ccmode != standard) { + /* Not supported (yet) */ + report(RPT_WARNING, "%s: num: cannot combine two modes using user-defined characters", + drvthis->name); + return; + } + + p->ccmode = bignum; + + do_init = 1; + } + + // Lib_adv_bignum does everything needed to show the bignumbers. + //lib_adv_bignum(drvthis, x, num, 0, do_init); +} + +#ifdef NOTUSED +/** + * Get number of custom characters available. + * \param drvthis Pointer to driver structure. + * \return Number of custom characters (always NUM_CCs). + */ +MODULE_EXPORT int +serialPOS_get_free_chars (Driver *drvthis) +{ + //PrivateData *p = drvthis->private_data; + + return NUM_CCs; +} + + +/** + * Define a custom character and write it to the LCD. + * \param drvthis Pointer to driver structure. + * \param n Custom character to define [0 - (NUM_CCs-1)]. + * \param dat Array of 8(=cellheight) bytes, each representing a pixel row + * starting from the top to bottom. + * The bits in each byte represent the pixels where the LSB + * (least significant bit) is the rightmost pixel in each pixel row. + */ +MODULE_EXPORT void +serialPOS_set_char (Driver *drvthis, int n, unsigned char *dat) +{ + PrivateData *p = drvthis->private_data; + unsigned char mask = (1 << p->cellwidth) - 1; + int row; + + if ((n < 0) || (n >= NUM_CCs)) + return; + if (!dat) + return; + + out[2] = n; /* Custom char to define. xxx */ + + for (row = 0; row < p->cellheight; row++) { + out[row+3] = dat[row] & mask; + } + write(p->fd, out, 11); +} + + +/** + * Place an icon on the screen. + * \param drvthis Pointer to driver structure. + * \param x Horizontal character position (column). + * \param y Vertical character position (row). + * \param icon synbolic value representing the icon. + * \return Information whether the icon is handled here or needs to be handled by the server core. + */ +MODULE_EXPORT int +serialPOS_icon (Driver *drvthis, int x, int y, int icon) +{ + //PrivateData *p = drvthis->private_data; + + return 0; +} + + +/** + * Set cursor position and state. + * \param drvthis Pointer to driver structure. + * \param x Horizontal cursor position (column). + * \param y Vertical cursor position (row). + * \param state New cursor state. + */ +MODULE_EXPORT void +serialPOS_cursor (Driver *drvthis, int x, int y, int state) +{ + //hPrivateData *p = (PrivateData *) drvthis->private_data; + + /* set cursor state */ + //serialPOS_cursor_goto(drvthis, x, y); +} + +/** + * Get key from the LCD/VFD. + * \param drvthis Pointer to driver structure. + * \return String representation of the key. + * + */ +MODULE_EXPORT const char * +serialPOS_get_key (Driver *drvthis) +{ + PrivateData *p = drvthis->private_data; + char key = 0; + struct pollfd fds[1]; + + /* don't query the keyboard if there are no mapped keys; see \todo above */ + if ((p->keys == 0) && (!p->keypad_test_mode)) + return NULL; + + /* poll for data or return */ + fds[0].fd = p->fd; + fds[0].events = POLLIN; + fds[0].revents = 0; + poll(fds,1,0); + if (fds[0].revents == 0) + return NULL; + + (void) read(p->fd, &key, 1); + report(RPT_DEBUG, "%s: get_key: key 0x%02X", drvthis->name, key); + + if (key == '\0') + return NULL; + + if (!p->keypad_test_mode) { + /* we assume standard key mapping here */ + if ((key >= 'A') && (key <= 'A' + MAX_KEY_MAP)) { + return p->keymap[key-'A']; + } + else { + report(RPT_INFO, "%s: Untreated key 0x%02X", drvthis->name, key); + return NULL; + } + } + else { + fprintf(stdout, "serialPOS: Received character %c\n", key); + fprintf(stdout, "serialPOS: Press another key of your device.\n"); + } + return NULL; +} + +#endif + +/* EOF */ diff --git a/server/drivers/serialPOS.h b/server/drivers/serialPOS.h new file mode 100644 index 0000000..74a16a2 --- /dev/null +++ b/server/drivers/serialPOS.h @@ -0,0 +1,39 @@ +#ifndef SERPOS_H +#define SERPOS_H + +#include "lcd.h" + +#define DEFAULT_DEVICE "/dev/Stty" +#define DEFAULT_SPEED 9800 +#define DEFAULT_LINEWRAP 0 +#define DEFAULT_AUTOSCROLL 0 +#define DEFAULT_CURSORBLINK 0 +#define DEFAULT_SIZE "16x2" +#define DEFAULT_TYPE "AEDEX" + + +MODULE_EXPORT int serialPOS_init (Driver *drvthis); +MODULE_EXPORT void serialPOS_close (Driver *drvthis); +MODULE_EXPORT int serialPOS_width (Driver *drvthis); +MODULE_EXPORT int serialPOS_height (Driver *drvthis); +MODULE_EXPORT int serialPOS_cellwidth (Driver *drvthis); +MODULE_EXPORT int serialPOS_cellheight (Driver *drvthis); +MODULE_EXPORT void serialPOS_clear (Driver *drvthis); +MODULE_EXPORT void serialPOS_flush (Driver *drvthis); +MODULE_EXPORT void serialPOS_string (Driver *drvthis, int x, int y, char string[]); +MODULE_EXPORT void serialPOS_chr (Driver *drvthis, int x, int y, char c); +MODULE_EXPORT const char * serialPOS_get_key (Driver *drvthis); + +MODULE_EXPORT void serialPOS_vbar (Driver * drvthis, int x, int y, int len, int promille, int options); +MODULE_EXPORT void serialPOS_hbar (Driver * drvthis, int x, int y, int len, int promille, int options); +MODULE_EXPORT int serialPOS_icon (Driver *drvthis, int x, int y, int icon); +MODULE_EXPORT void serialPOS_num (Driver *drvthis, int x, int num); +MODULE_EXPORT void serialPOS_cursor (Driver *drvthis, int x, int y, int state); + +//MODULE_EXPORT int serialPOS_get_free_chars (Driver *drvthis); +//MODULE_EXPORT void serialPOS_set_char (Driver *drvthis, int n, unsigned char *dat); + +MODULE_EXPORT void serialPOS_output (Driver *drvthis, int state); +MODULE_EXPORT const char * serialPOS_get_info (Driver *drvthis); + +#endif /* serialPOS_H */