Base: LCDproc 0.5.2
[lcdproc-de200c.git] / server / drivers / serialPOS.c
blob88ba207c337b582ff62f2f8ddebad613535b0b3b
1 /* This is the LCDproc driver for Point Of Sale ("POS") devices using
2 various protocols. While it currently only supports AEDEX,
3 it can be extended to provide support for many POS emulation types.
5 Copyright (C) 2006 Eric Pooch
7 This driver is based on MtxOrb.c driver and is subject to its copyrights.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
24 List of driver entry point:
26 init Implemented.
27 close Implemented.
28 width Implemented.
29 height Implemented.
30 clear Implemented by space filling no custom char info.
31 flush Implemented.
32 string Implemented.
33 chr Implemented.
34 vbar Implemented.
35 hbar Implemented.
36 num Implemented.
37 heartbeat Implemented.
38 icon NOT IMPLEMENTED: not part of POS protocol
39 cursor NOT IMPLEMENTED: not part of AEDEX protocol
40 set_char NOT IMPLEMENTED: not part of AEDEX protocol
41 get_free_chars Implemented.
42 cellwidth Implemented.
43 cellheight Implemented.
44 get_contrast NOT IMPLEMENTED: not part of AEDEX protocol
45 set_contrast NOT IMPLEMENTED: not part of AEDEX protocol
46 get_brightness NOT IMPLEMENTED: not part of AEDEX protocol
47 set_brightness NOT IMPLEMENTED: not part of AEDEX protocol
48 backlight NOT IMPLEMENTED: not part of AEDEX protocol
49 output Not implemented.
50 get_key Not implemented, no keys.
51 get_info Implemented.
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <unistd.h>
57 #include <sys/types.h>
58 #include <sys/time.h>
59 #include <termios.h>
60 #include <fcntl.h>
61 #include <string.h>
62 #include <errno.h>
63 #include <syslog.h>
64 #include <ctype.h>
65 #include <sys/poll.h>
67 #ifdef HAVE_CONFIG_H
68 # include "config.h"
69 #endif
71 #include "lcd.h"
72 #include "lcd_lib.h"
73 #include "serialPOS.h"
74 #include "adv_bignum.h"
76 #include "report.h"
80 * The serialPOS driver does not use a lot of hardware features.
81 * We try to replace them with more flexible software alternatives.
82 * That's why vbar/hbar/bignum are using locally-defined functions;
83 * it permits simultaneous use of those features and custom chars.
85 * For the same reason, we don't use the hardware clear but rather
86 * empty the internal frame buffer. The frame buffer holds all
87 * the requested changes until the server asks us to flush the
88 * changes to the display. This also permits us to do an
89 * incremental update and reduce the number of characters to be
90 * sent to the display across the serial link.
92 * In order to display graphic widgets, we define and use our own
93 * custom characters. To avoid multiple definitions of the same
94 * custom characters, we use a caching mechanism that remembers
95 * what is currently defined. In order to avoid always redefining
96 * the same custom character at the beginning of the table, we
97 * rotate the beginning of the table. This is supposed to reduce
98 * the number of character redefinitions and make the caching more
99 * effective. The overall goal is to reduce the number of
100 * characters sent to the display.
104 typedef enum {
105 POS_IEE = 0,
106 POS_AEDEX,
107 POS_Epson,
108 POS_Emax,
109 POS_IBM,
110 POS_LogicControls,
111 POS_Ultimate
112 } POS_EmulationType;
115 #define AEDEXPrefix "!#"
117 typedef enum {
118 AEDEXLine1Display = 1, /* upper line display */
119 AEDEXLine2Display, /* bottom line display */
120 AEDEXLine3Display, /* not sure what this code really is */
121 AEDEXContinuousScroll, /* upper line message scroll continuously */
122 AEDEXDisplayTime, /* "hh':'mm" h,m='0'-'9' display time */
123 AEDEXSingleScroll, /* upper line message scroll one pass */
124 AEDEXAllScroll, /* not sure what this code really is */
125 AEDEXChangeCode, /* change attention code */
126 AEDEXAllLineDisplay /* two line display */
127 } AEDEXCommands;
130 typedef enum {
131 standard, /* only char 0 is used for heartbeat */
132 vbar, /* vertical bars */
133 hbar, /* horizontal bars */
134 custom, /* custom settings */
135 bignum, /* big numbers */
136 bigchar /* big characters */
137 } CGmode;
142 typedef struct {
143 int fd; /* The LCD file descriptor */
145 /* dimensions */
146 int width, height;
147 int cellwidth, cellheight;
149 /* framebuffer and buffer for old LCD contents */
150 unsigned char *framebuf;
151 unsigned char *backingstore;
153 /* defineable characters */
154 CGmode ccmode;
156 /* feature enable */
157 int hardwrap;
158 int hardscroll;
160 POS_EmulationType emulation_mode; /* The emulation type */
161 int output_state; /* static data from serialPOS_output */
163 char info[255]; /* static data from serialPOS_get_info */
164 } PrivateData;
167 /* Vars for the server core */
168 MODULE_EXPORT char *api_version = API_VERSION;
169 MODULE_EXPORT int stay_in_foreground = 0;
170 MODULE_EXPORT int supports_multiple = 1;
171 MODULE_EXPORT char *symbol_prefix = "serialPOS_";
173 static void serialPOS_hardware_clear(Driver *drvthis);
174 static void serialPOS_linewrap(Driver *drvthis, int on);
175 static void serialPOS_autoscroll(Driver *drvthis, int on);
176 static void serialPOS_cursorblink(Driver *drvthis, int on);
177 static void serialPOS_cursor_goto(Driver *drvthis, int x, int y);
180 /* Parse one key from the configfile */
181 static char
182 serialPOS_parse_keypad_setting (Driver *drvthis, char *keyname, char default_value)
184 char return_val = 0;
185 const char *s;
186 char buf[255];
188 s = drvthis->config_get_string(drvthis->name, keyname, 0, NULL);
189 if (s != NULL) {
190 strncpy(buf, s, sizeof(buf));
191 buf[sizeof(buf)-1] = '\0';
192 return_val = buf[0];
193 } else {
194 return_val = default_value;
196 return return_val;
201 * Initialize the driver.
202 * \param drvthis Pointer to driver structure.
203 * \retval 0 Success.
204 * \retval <0 Error.
206 MODULE_EXPORT int
207 serialPOS_init (Driver *drvthis)
209 struct termios portset;
211 char device[256] = DEFAULT_DEVICE;
212 int speed = DEFAULT_SPEED;
213 char size[256] = DEFAULT_SIZE;
214 char buf[256] = "";
215 int tmp, w, h;
217 PrivateData *p;
219 /* Alocate and store private data */
220 p = (PrivateData *) malloc(sizeof(PrivateData));
221 if (p == NULL)
222 return -1;
223 if (drvthis->store_private_ptr(drvthis, p))
224 return -1;
226 /* Initialise the PrivateData structure */
227 p->fd = -1;
229 p->width = LCD_DEFAULT_WIDTH;
230 p->height = LCD_DEFAULT_HEIGHT;
231 p->cellwidth = LCD_DEFAULT_CELLWIDTH;
232 p->cellheight = LCD_DEFAULT_CELLHEIGHT;
234 p->framebuf = NULL;
235 p->backingstore = NULL;
237 p->output_state = -1; /* static data from serialPOS_output */
239 p->hardwrap = 0;
240 p->hardscroll = 0;
242 p->emulation_mode = POS_AEDEX;
244 debug(RPT_INFO, "serialPOS: init(%p)", drvthis);
246 /* READ CONFIG FILE */
248 /* Get serial device to use */
249 strncpy(device, drvthis->config_get_string(drvthis->name, "Device", 0, DEFAULT_DEVICE), sizeof(device));
250 device[sizeof(device)-1] = '\0';
251 report(RPT_INFO, "%s: using Device %s", drvthis->name, device);
253 /* Get emulation type */
254 strncpy(buf, drvthis->config_get_string(drvthis->name, "Type", 0, DEFAULT_TYPE), sizeof(buf));
255 buf[sizeof(buf)-1] = '\0';
256 if (strncasecmp(buf, "IEE", 3) == 0) {
257 p->emulation_mode = POS_IEE;
258 } else if (strncasecmp(buf, "AED", 3) == 0) {
259 p->emulation_mode = POS_AEDEX;
260 } else if (strncasecmp(buf, "Eps", 3) == 0) {
261 p->emulation_mode = POS_Epson;
262 } else if (strncasecmp(buf, "Ema", 3) == 0) {
263 p->emulation_mode = POS_Emax;
264 } else if (strncasecmp(buf, "Log", 3) == 0) {
265 p->emulation_mode = POS_LogicControls;
266 } else if (strncasecmp(buf, "IBM", 3) == 0) {
267 p->emulation_mode = POS_IBM;
268 } else if (strncasecmp(buf, "Ult", 3) == 0) {
269 p->emulation_mode = POS_Ultimate;
270 } else {
271 report(RPT_ERR, "%s: unknown display Type %s; must be one of IEE, AEDEX, Epson, Emax, Logic Controls or Ultimate",
272 drvthis->name, buf);
273 return -1;
276 /* Get display size */
277 strncpy(size, drvthis->config_get_string(drvthis->name, "Size", 0, DEFAULT_SIZE), sizeof(size));
278 size[sizeof(size)-1] = '\0';
279 if ((sscanf(size, "%dx%d", &w, &h) != 2)
280 || (w <= 0) || (w > LCD_MAX_WIDTH)
281 || (h <= 0) || (h > LCD_MAX_HEIGHT)) {
282 report(RPT_WARNING, "%s: cannot read Size: %s; using default %s",
283 drvthis->name, size, DEFAULT_SIZE);
284 sscanf(DEFAULT_SIZE , "%dx%d", &w, &h);
286 p->width = w;
287 p->height = h;
289 /* Get speed */
290 tmp = drvthis->config_get_int(drvthis->name, "Speed", 0, DEFAULT_SPEED);
291 switch (tmp) {
292 case 1200:
293 speed = B1200;
294 break;
295 case 2400:
296 speed = B2400;
297 break;
298 case 4800:
299 speed = B4800;
300 break;
301 case 9600:
302 speed = B9600;
303 break;
304 default:
305 speed = B9600;
306 report(RPT_WARNING, "%s: Speed must be 1200, 2400, 4800 or 9600; using default %d",
307 drvthis->name, tmp);
310 /* Set up io port correctly, and open it... */
311 p->fd = open(device, O_RDWR | O_NOCTTY);
312 if (p->fd == -1) {
313 report(RPT_ERR, "%s: open(%s) failed (%s)", drvthis->name, device, strerror(errno));
314 if (errno == EACCES)
315 report(RPT_ERR, "%s: %s device could not be opened...", drvthis->name, device);
316 return -1;
318 report(RPT_INFO, "%s: opened display on %s", drvthis->name, device);
320 tcgetattr(p->fd, &portset);
322 // THIS ALL COMMENTED OUT BECAUSE WE NEED TO SET TIMEOUTS
323 /* We use RAW mode */
324 #ifdef HAVE_CFMAKERAW_NOT
325 /* The easy way */
326 cfmakeraw(&portset);
327 #else
328 /* The hard way */
329 portset.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP
330 | INLCR | IGNCR | ICRNL | IXON );
331 portset.c_oflag &= ~OPOST;
332 portset.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
333 portset.c_cflag &= ~( CSIZE | PARENB | CRTSCTS );
334 portset.c_cflag |= CS8 | CREAD | CLOCAL;
335 portset.c_cc[VMIN] = 1;
336 portset.c_cc[VTIME] = 3;
337 #endif
339 /* Set port speed */
340 cfsetospeed(&portset, speed);
341 cfsetispeed(&portset, B0);
343 /* Do it... */
344 tcsetattr(p->fd, TCSANOW, &portset);
346 /* Make sure the frame buffer is there... */
347 p->framebuf = (unsigned char *) calloc(p->width * p->height, 1);
348 if (p->framebuf == NULL) {
349 report(RPT_ERR, "%s: unable to create framebuffer", drvthis->name);
350 return -1;
352 memset(p->framebuf, ' ', p->width * p->height);
354 /* make sure the framebuffer backing store is there... */
355 p->backingstore = (unsigned char *) malloc(p->width * p->height);
356 if (p->backingstore == NULL) {
357 report(RPT_ERR, "%s: unable to create framebuffer backing store", drvthis->name);
358 return -1;
360 memset(p->backingstore, ' ', p->width * p->height);
362 /* set initial LCD configuration */
363 serialPOS_hardware_clear(drvthis);
364 serialPOS_linewrap(drvthis, DEFAULT_LINEWRAP);
365 serialPOS_autoscroll(drvthis, DEFAULT_AUTOSCROLL);
367 report(RPT_DEBUG, "%s: init() done", drvthis->name);
369 return 1;
374 * Close the driver (do necessary clean-up).
375 * \param drvthis Pointer to driver structure.
377 MODULE_EXPORT void
378 serialPOS_close (Driver *drvthis)
380 PrivateData *p = drvthis->private_data;
382 if (p != NULL) {
383 if (p->fd >= 0)
384 close(p->fd);
386 if (p->framebuf)
387 free(p->framebuf);
388 p->framebuf = NULL;
390 if (p->backingstore)
391 free(p->backingstore);
392 p->backingstore = NULL;
394 free(p);
396 drvthis->store_private_ptr(drvthis, NULL);
397 debug(RPT_DEBUG, "serialPOS: closed");
402 * Return the display width in characters.
403 * \param drvthis Pointer to driver structure.
404 * \return Number of characters the display is wide.
406 MODULE_EXPORT int
407 serialPOS_width (Driver *drvthis)
409 PrivateData *p = drvthis->private_data;
411 return p->width;
416 * Return the display height in characters.
417 * \param drvthis Pointer to driver structure.
418 * \return Number of characters the display is high.
420 MODULE_EXPORT int
421 serialPOS_height (Driver *drvthis)
423 PrivateData *p = drvthis->private_data;
425 return p->height;
430 * Return the width of a character in pixels.
431 * \param drvthis Pointer to driver structure.
432 * \return Number of pixel columns a character cell is wide.
434 MODULE_EXPORT int
435 MtxcOrb_cellwidth (Driver *drvthis)
437 PrivateData *p = drvthis->private_data;
439 return p->cellwidth;
444 * Return the height of a character in pixels.
445 * \param drvthis Pointer to driver structure.
446 * \return Number of pixel lines a character cell is high.
448 MODULE_EXPORT int
449 MtxcOrb_cellheight (Driver *drvthis)
451 PrivateData *p = drvthis->private_data;
453 return p->cellheight;
458 * Print a string on the screen at position (x,y).
459 * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height).
460 * \param drvthis Pointer to driver structure.
461 * \param x Horizontal character position (column).
462 * \param y Vertical character position (row).
463 * \param string String that gets written.
465 MODULE_EXPORT void
466 serialPOS_string (Driver *drvthis, int x, int y, const char string[])
468 PrivateData *p = drvthis->private_data;
469 int i;
471 /* Convert 1-based coords to 0-based... */
472 x--;
473 y--;
475 if ((y < 0) || (y >= p->height))
476 return;
478 for (i = 0; (string[i] != '\0') && (x < p->width); i++, x++) {
479 /* Check for buffer overflows... */
480 if (x >= 0)
481 p->framebuf[(y * p->width) + x] = string[i];
484 report(RPT_DEBUG, "serialPOS: printed string at (%d,%d)", x, y);
489 * Clear the framebuffer.
490 * \param drvthis Pointer to driver structure.
492 MODULE_EXPORT void
493 serialPOS_clear (Driver *drvthis)
495 PrivateData *p = drvthis->private_data;
497 /* replace all chars in framebuf with spaces */
498 memset(p->framebuf, ' ', (p->width * p->height));
500 report(RPT_DEBUG, "serialPOS: cleared framebuffer");
505 * Flush data on screen to the LCD.
506 * \param drvthis Pointer to driver structure.
508 MODULE_EXPORT void
509 serialPOS_flush (Driver *drvthis)
511 PrivateData *p = drvthis->private_data;
513 int modified = 0;
514 int i;
516 for (i = 0; i < p->height; i++) {
517 // set pointers to start of the line in frame buffer & backing store
518 unsigned char *sp = p->framebuf + (i * p->width);
519 unsigned char *sq = p->backingstore + (i * p->width);
521 unsigned int length = p->width+5;
523 char out[length];
525 debug(RPT_DEBUG, "Framebuf: '%.*s'", p->width, sp);
526 debug(RPT_DEBUG, "Backingstore: '%.*s'", p->width, sq);
528 /* Strategy:
529 * - not more than one update command per line
530 * - skip lines that are identical
533 // skip over identical lines
534 if ( memcmp(sp, sq, p->width) == 0) {
535 /* The lines are the same. */
536 continue;
539 /* there are differences, ... */
540 report(RPT_DEBUG, "%s: l=%d string='%.*s'", __FUNCTION__, i, p->width, sp);
542 if (p->emulation_mode == POS_AEDEX) {
543 int command = i+1;
544 if ( i == 0 && p->hardscroll == 1 )
545 command = AEDEXContinuousScroll;
547 snprintf(out, length, "%s%d%.*s%c", AEDEXPrefix, command, p->width, sp, 13);
548 debug(RPT_DEBUG, "%s%d%.*s%c", AEDEXPrefix, command, p->width, sp, 13);
551 write(p->fd, out, sizeof(out));
553 modified++;
557 if (modified)
558 memcpy(p->backingstore, p->framebuf, p->width * p->height);
561 report(RPT_DEBUG, "serialPOS: frame buffer flushed");
566 * Print a character on the screen at position (x,y).
567 * The upper-left corner is (1,1), the lower-right corner is (p->width, p->height).
568 * \param drvthis Pointer to driver structure.
569 * \param x Horizontal character position (column).
570 * \param y Vertical character position (row).
571 * \param c Character that gets written.
573 MODULE_EXPORT void
574 serialPOS_chr (Driver *drvthis, int x, int y, char c)
576 PrivateData *p = drvthis->private_data;
578 /* Convert 1-based coords to 0-based... */
579 x--;
580 y--;
582 /* The # character might interfere with the AEDEX command set */
583 if (p->emulation_mode == POS_AEDEX && c == '#')
584 c = '%';
586 if ((x >= 0) && (y >= 0) && (x < p->width) && (y < p->height))
587 p->framebuf[(y * p->width) + x] = c;
589 report(RPT_DEBUG, "writing character %02X to position (%d,%d)", c, x, y);
594 * Set output port(s).
595 * Displays with keypad have 6 outputs whereas the others only have one.
596 * \param drvthis Pointer to driver structure.
597 * \param state Integer with bits representing port states.
599 #ifdef NOTUSED
600 MODULE_EXPORT void
601 serialPOS_output (Driver *drvthis, int state)
603 /* I don't get what this does. Many POS displays have a pass-through function. */
604 PrivateData *p = drvthis->private_data;
607 #endif
611 * Clear the LCD using its hardware command
612 * \param drvthis Pointer to driver structure.
614 static void
615 serialPOS_hardware_clear (Driver *drvthis)
617 /* There is no hardware clear in the POS command sets,
618 but most have an easy software clear. */
619 /*PrivateData *p = drvthis->private_data;
621 char out[6];
623 if (p->emulation_mode == POS_AEDEX) {
624 snprintf(out, 6, "%s%c %d", AEDEXPrefix, AEDEXAllLineDisplay, 13);
627 write(p->fd, out, 5);*/
628 debug(RPT_DEBUG, "serialPOS: cleared LCD");
633 * Turn the POS's built-in linewrapping feature on or off.
634 * \param drvthis Pointer to driver structure.
635 * \param on New state.
637 static void
638 serialPOS_linewrap (Driver *drvthis, int on)
640 PrivateData *p = drvthis->private_data;
642 p->hardwrap = on;
644 debug(RPT_DEBUG, "serialPOS: linewrap turned %s", (on) ? "on" : "off");
649 * Turn the POS's built-in automatic scrolling feature on or off.
650 * \param drvthis Pointer to driver structure.
651 * \param on New state.
653 static void
654 serialPOS_autoscroll (Driver *drvthis, int on)
656 PrivateData *p = drvthis->private_data;
658 p->hardscroll = on;
660 debug(RPT_DEBUG, "serialPOS: autoscroll turned %s", (on) ? "on" : "off");
665 * Turn POS's hardware cursor blinking on or off.
666 * \param drvthis Pointer to driver structure.
667 * \param on New state.
670 static void
671 serialPOS_cursorblink (Driver *drvthis, int on)
673 //PrivateData *p = drvthis->private_data;
675 debug(RPT_DEBUG, "serialPOS: cursorblink turned %s", (on) ? "on" : "off");
680 * Move cursor to position (x,y).
681 * \param drvthis Pointer to driver structure.
682 * \param x Horizontal character position (column).
683 * \param y Vertical character position (row).
685 static void
686 serialPOS_cursor_goto(Driver *drvthis, int x, int y)
688 //PrivateData *p = drvthis->private_data;
693 * Provide general information about the LCD/VFD display.
694 * \param drvthis Pointer to driver structure.
695 * \return Constant string with information.
697 MODULE_EXPORT const char *
698 serialPOS_get_info (Driver *drvthis)
700 PrivateData *p = drvthis->private_data;
701 strcpy(p->info, "Driver for Point of Sale Displays.");
702 return p->info;
707 * Draw a vertical bar bottom-up.
708 * \param drvthis Pointer to driver structure.
709 * \param x Horizontal character position (column) of the starting point.
710 * \param y Vertical character position (row) of the starting point.
711 * \param len Number of characters that the bar is high at 100%
712 * \param promille Current height level of the bar in promille.
713 * \param options Options (currently unused).
715 MODULE_EXPORT void
716 serialPOS_vbar (Driver *drvthis, int x, int y, int len, int promille, int options)
718 PrivateData *p = drvthis->private_data;
719 // map
720 char ascii_map[] = { ' ', ' ', '-', '-', '=', '=', '%', '%' };
721 char *map = ascii_map;
722 int pixels = ((long) 2 * len * p->cellheight) * promille / 2000;
723 int pos;
726 if ((x <= 0) || (y <= 0) || (x > p->width))
727 return;
729 /* x and y are the start position of the bar.
730 * The bar by default grows in the 'up' direction
731 * (other direction not yet implemented).
732 * len is the number of characters that the bar is long at 100%
733 * promille is the number of promilles (0..1000) that the bar should be filled.
736 for (pos = 0; pos < len; pos++) {
738 if (y - pos <= 0)
739 return;
741 if (pixels >= p->cellheight) {
742 /* write a "full" block to the screen... */
743 serialPOS_chr(drvthis, x, y-pos, '%');
745 else if (pixels > 0) {
746 // write a partial block...
747 serialPOS_chr(drvthis, x, y-pos, map[len-1]);
748 break;
750 else {
751 ; // write nothing (not even a space)
754 pixels -= p->cellheight;
760 * Draw a horizontal bar to the right.
761 * \param drvthis Pointer to driver structure.
762 * \param x Horizontal character position (column) of the starting point.
763 * \param y Vertical character position (row) of the starting point.
764 * \param len Number of characters that the bar is long at 100%
765 * \param promille Current length level of the bar in promille.
766 * \param options Options (currently unused).
768 MODULE_EXPORT void
769 serialPOS_hbar (Driver *drvthis, int x, int y, int len, int promille, int options)
771 PrivateData *p = drvthis->private_data;
772 int pixels = ((long) 2 * len * p->cellwidth) * promille / 2000;
773 int pos;
775 if ((x <= 0) || (y <= 0) || (y > p->height))
776 return;
778 /* x and y are the start position of the bar.
779 * The bar by default grows in the 'right' direction
780 * (other direction not yet implemented).
781 * len is the number of characters that the bar is long at 100%
782 * promille is the number of promilles (0..1000) that the bar should be filled.
785 for (pos = 0; pos < len; pos++) {
787 if (x + pos > p->width)
788 return;
790 if (pixels >= p->cellwidth * 2/3) {
791 /* write a "full" block to the screen... */
792 serialPOS_chr(drvthis, x+pos, y, '=');
794 else if (pixels > p->cellwidth * 1/3) {
795 /* write a partial block... */
796 serialPOS_chr(drvthis, x+pos, y, '-');
797 break;
799 else {
800 ; // write nothing (not even a space)
803 pixels -= p->cellwidth;
809 * Write a big number to the screen.
810 * \param drvthis Pointer to driver structure.
811 * \param x Horizontal character position (column).
812 * \param num Character to write (0 - 10 with 10 representing ':')
814 MODULE_EXPORT void
815 serialPOS_num (Driver *drvthis, int x, int num)
817 PrivateData *p = drvthis->private_data;
818 int do_init = 0;
820 if ((num < 0) || (num > 10))
821 return;
823 if (p->ccmode != bignum) {
824 if (p->ccmode != standard) {
825 /* Not supported (yet) */
826 report(RPT_WARNING, "%s: num: cannot combine two modes using user-defined characters",
827 drvthis->name);
828 return;
831 p->ccmode = bignum;
833 do_init = 1;
836 // Lib_adv_bignum does everything needed to show the bignumbers.
837 //lib_adv_bignum(drvthis, x, num, 0, do_init);
840 #ifdef NOTUSED
842 * Get total number of custom characters available.
843 * \param drvthis Pointer to driver structure.
844 * \return Number of custom characters (always NUM_CCs).
846 MODULE_EXPORT int
847 serialPOS_get_free_chars (Driver *drvthis)
849 //PrivateData *p = drvthis->private_data;
851 return NUM_CCs;
856 * Define a custom character and write it to the LCD.
857 * \param drvthis Pointer to driver structure.
858 * \param n Custom character to define [0 - (NUM_CCs-1)].
859 * \param dat Array of 8(=cellheight) bytes, each representing a pixel row
860 * starting from the top to bottom.
861 * The bits in each byte represent the pixels where the LSB
862 * (least significant bit) is the rightmost pixel in each pixel row.
864 MODULE_EXPORT void
865 serialPOS_set_char (Driver *drvthis, int n, unsigned char *dat)
867 PrivateData *p = drvthis->private_data;
868 unsigned char mask = (1 << p->cellwidth) - 1;
869 int row;
871 if ((n < 0) || (n >= NUM_CCs))
872 return;
873 if (!dat)
874 return;
876 out[2] = n; /* Custom char to define. xxx */
878 for (row = 0; row < p->cellheight; row++) {
879 out[row+3] = dat[row] & mask;
881 write(p->fd, out, 11);
886 * Place an icon on the screen.
887 * \param drvthis Pointer to driver structure.
888 * \param x Horizontal character position (column).
889 * \param y Vertical character position (row).
890 * \param icon synbolic value representing the icon.
891 * \return Information whether the icon is handled here or needs to be handled by the server core.
893 MODULE_EXPORT int
894 serialPOS_icon (Driver *drvthis, int x, int y, int icon)
896 //PrivateData *p = drvthis->private_data;
898 return 0;
903 * Set cursor position and state.
904 * \param drvthis Pointer to driver structure.
905 * \param x Horizontal cursor position (column).
906 * \param y Vertical cursor position (row).
907 * \param state New cursor state.
909 MODULE_EXPORT void
910 serialPOS_cursor (Driver *drvthis, int x, int y, int state)
912 //hPrivateData *p = (PrivateData *) drvthis->private_data;
914 /* set cursor state */
915 //serialPOS_cursor_goto(drvthis, x, y);
919 * Get key from the LCD/VFD.
920 * \param drvthis Pointer to driver structure.
921 * \return String representation of the key.
924 MODULE_EXPORT const char *
925 serialPOS_get_key (Driver *drvthis)
927 PrivateData *p = drvthis->private_data;
928 char key = 0;
929 struct pollfd fds[1];
931 /* don't query the keyboard if there are no mapped keys; see \todo above */
932 if ((p->keys == 0) && (!p->keypad_test_mode))
933 return NULL;
935 /* poll for data or return */
936 fds[0].fd = p->fd;
937 fds[0].events = POLLIN;
938 fds[0].revents = 0;
939 poll(fds,1,0);
940 if (fds[0].revents == 0)
941 return NULL;
943 (void) read(p->fd, &key, 1);
944 report(RPT_DEBUG, "%s: get_key: key 0x%02X", drvthis->name, key);
946 if (key == '\0')
947 return NULL;
949 if (!p->keypad_test_mode) {
950 /* we assume standard key mapping here */
951 if ((key >= 'A') && (key <= 'A' + MAX_KEY_MAP)) {
952 return p->keymap[key-'A'];
954 else {
955 report(RPT_INFO, "%s: Untreated key 0x%02X", drvthis->name, key);
956 return NULL;
959 else {
960 fprintf(stdout, "serialPOS: Received character %c\n", key);
961 fprintf(stdout, "serialPOS: Press another key of your device.\n");
963 return NULL;
966 #endif
968 /* EOF */