/* $Id: drv_generic_serial.c,v 1.17 2005/05/08 04:32:44 reinelt Exp $ * * generic driver helper for serial and usbserial displays * * 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. * * * $Log: drv_generic_serial.c,v $ * Revision 1.17 2005/05/08 04:32:44 reinelt * CodingStyle added and applied * * Revision 1.16 2005/01/18 06:30:23 reinelt * added (C) to all copyright statements * * Revision 1.15 2004/06/26 12:04:59 reinelt * * uh-oh... the last CVS log message messed up things a lot... * * Revision 1.14 2004/06/26 09:27:21 reinelt * * added '-W' to CFLAGS * changed all C++ comments to C ones * cleaned up a lot of signed/unsigned mistakes * * Revision 1.13 2004/06/26 06:12:15 reinelt * * support for Beckmann+Egle Compact Terminals * some mostly cosmetic changes in the MatrixOrbital and USBLCD driver * added debugging to the generic serial driver * fixed a bug in the generic text driver where icons could be drawn outside * the display bounds * * Revision 1.12 2004/06/20 10:09:55 reinelt * * 'const'ified the whole source * * Revision 1.11 2004/06/01 06:45:30 reinelt * * some Fixme's processed * documented some code * * Revision 1.10 2004/05/31 21:05:13 reinelt * * fixed lots of bugs in the Cwlinux driver * do not emit EAGAIN error on the first retry * made plugin_i2c_sensors a bit less 'chatty' * moved init and exit functions to the bottom of plugin_pop3 * * Revision 1.9 2004/05/28 13:51:42 reinelt * * ported driver for Beckmann+Egle Mini-Terminals * added 'flags' parameter to serial_init() * * Revision 1.8 2004/03/03 04:44:16 reinelt * changes (cosmetics?) to the big patch from Martin * hash patch un-applied * * Revision 1.7 2004/03/03 03:47:04 reinelt * big patch from Martin Hejl: * - use qprintf() where appropriate * - save CPU cycles on gettimeofday() * - add quit() functions to free allocated memory * - fixed lots of memory leaks * * Revision 1.6 2004/02/14 11:56:17 reinelt * M50530 driver ported * changed lots of 'char' to 'unsigned char' * * Revision 1.5 2004/02/04 19:10:51 reinelt * Crystalfontz driver nearly finished * * Revision 1.4 2004/02/01 08:05:12 reinelt * Crystalfontz 633 extensions (CRC checking and stuff) * Models table for HD44780 * Noritake VFD BVrightness patch from Bill Paxton * * Revision 1.3 2004/01/29 04:40:02 reinelt * every .c file includes "config.h" now * * Revision 1.2 2004/01/25 05:30:09 reinelt * plugin_netdev for parsing /proc/net/dev added * * Revision 1.1 2004/01/20 14:26:09 reinelt * moved drv_generic to drv_generic_serial * * Revision 1.2 2004/01/20 05:36:59 reinelt * moved text-display-specific stuff to drv_generic_text * moved all the bar stuff from drv_generic_bar to generic_text * * Revision 1.1 2004/01/20 04:51:39 reinelt * moved generic stuff from drv_MatrixOrbital to drv_generic * implemented new-stylish bars which are nearly finished * */ /* * * exported fuctions: * * int drv_generic_serial_open (char *section, char *driver, unsigned int flags) * opens the serial port * * int drv_generic_serial_poll (char *string, int len) * reads from the serial or USB port * without retry * * int drv_generic_serial_read (char *string, int len); * reads from the serial or USB port * with retry * * void drv_generic_serial_write (char *string, int len); * writes to the serial or USB port * * int drv_generic_serial_close (void); * closes the serial port * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "qprintf.h" #include "cfg.h" #include "drv_generic_serial.h" static char *Section; static char *Driver; static char *Port; static speed_t Speed; static int Device = -1; #define LOCK "/var/lock/LCK..%s" /****************************************/ /*** generic serial/USB communication ***/ /****************************************/ static pid_t drv_generic_serial_lock_port(const char *Port) { char lockfile[256]; char tempfile[256]; char buffer[16]; char *port, *p; int fd, len, pid; if (strncmp(Port, "/dev/", 5) == 0) { port = strdup(Port + 5); } else { port = strdup(Port); } while ((p = strchr(port, '/')) != NULL) { *p = '_'; } qprintf(lockfile, sizeof(lockfile), LOCK, port); qprintf(tempfile, sizeof(tempfile), LOCK, "TMP.XXXXXX"); free(port); if ((fd = mkstemp(tempfile)) == -1) { error("mkstemp(%s) failed: %s", tempfile, strerror(errno)); return -1; } if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { error("fchmod(%s) failed: %s", tempfile, strerror(errno)); close(fd); unlink(tempfile); return -1; } snprintf(buffer, sizeof(buffer), "%10d\n", (int) getpid()); len = strlen(buffer); if (write(fd, buffer, len) != len) { error("write(%s) failed: %s", tempfile, strerror(errno)); close(fd); unlink(tempfile); return -1; } close(fd); while (link(tempfile, lockfile) == -1) { if (errno != EEXIST) { error("link(%s, %s) failed: %s", tempfile, lockfile, strerror(errno)); unlink(tempfile); return -1; } if ((fd = open(lockfile, O_RDONLY)) == -1) { if (errno == ENOENT) continue; /* lockfile disappared */ error("open(%s) failed: %s", lockfile, strerror(errno)); unlink(tempfile); return -1; } len = read(fd, buffer, sizeof(buffer) - 1); if (len < 0) { error("read(%s) failed: %s", lockfile, strerror(errno)); unlink(tempfile); return -1; } buffer[len] = '\0'; if (sscanf(buffer, "%d", &pid) != 1 || pid == 0) { error("scan(%s) failed.", lockfile); unlink(tempfile); return -1; } if (pid == getpid()) { error("%s already locked by us. uh-oh...", lockfile); unlink(tempfile); return 0; } if ((kill(pid, 0) == -1) && errno == ESRCH) { error("removing stale lockfile %s", lockfile); if (unlink(lockfile) == -1 && errno != ENOENT) { error("unlink(%s) failed: %s", lockfile, strerror(errno)); unlink(tempfile); return pid; } continue; } unlink(tempfile); return pid; } unlink(tempfile); return 0; } static pid_t drv_generic_serial_unlock_port(const char *Port) { char lockfile[256]; char *port, *p; if (strncmp(Port, "/dev/", 5) == 0) { port = strdup(Port + 5); } else { port = strdup(Port); } while ((p = strchr(port, '/')) != NULL) { *p = '_'; } qprintf(lockfile, sizeof(lockfile), LOCK, port); unlink(lockfile); free(port); return 0; } int drv_generic_serial_open(const char *section, const char *driver, const unsigned int flags) { int i, fd; pid_t pid; struct termios portset; Section = (char *) section; Driver = (char *) driver; Port = cfg_get(section, "Port", NULL); if (Port == NULL || *Port == '\0') { error("%s: no '%s.Port' entry from %s", Driver, section, cfg_source()); return -1; } if (cfg_number(section, "Speed", 19200, 1200, 115200, &i) < 0) return -1; switch (i) { case 1200: Speed = B1200; break; case 2400: Speed = B2400; break; case 4800: Speed = B4800; break; case 9600: Speed = B9600; break; case 19200: Speed = B19200; break; case 38400: Speed = B38400; break; case 57600: Speed = B57600; break; case 115200: Speed = B115200; break; default: error("%s: unsupported speed '%d' from %s", Driver, i, cfg_source()); return -1; } info("%s: using port '%s' at %d baud", Driver, Port, i); if ((pid = drv_generic_serial_lock_port(Port)) != 0) { if (pid == -1) error("%s: port %s could not be locked", Driver, Port); else error("%s: port %s is locked by process %d", Driver, Port, pid); return -1; } fd = open(Port, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { error("%s: open(%s) failed: %s", Driver, Port, strerror(errno)); drv_generic_serial_unlock_port(Port); return -1; } if (tcgetattr(fd, &portset) == -1) { error("%s: tcgetattr(%s) failed: %s", Driver, Port, strerror(errno)); drv_generic_serial_unlock_port(Port); return -1; } cfmakeraw(&portset); portset.c_cflag |= flags; cfsetispeed(&portset, Speed); cfsetospeed(&portset, Speed); if (tcsetattr(fd, TCSANOW, &portset) == -1) { error("%s: tcsetattr(%s) failed: %s", Driver, Port, strerror(errno)); drv_generic_serial_unlock_port(Port); return -1; } Device = fd; return Device; } int drv_generic_serial_poll(char *string, const int len) { int ret; if (Device == -1) return -1; ret = read(Device, string, len); if (ret < 0 && errno != EAGAIN) { error("%s: read(%s) failed: %s", Driver, Port, strerror(errno)); } return ret; } int drv_generic_serial_read(char *string, const int len) { int count, run, ret; count = len < 0 ? -len : len; for (run = 0; run < 10; run++) { ret = drv_generic_serial_poll(string, count); if (ret >= 0 || errno != EAGAIN) break; info("%s: read(%s): EAGAIN", Driver, Port); usleep(1000); } if (ret > 0 && ret != count && len > 0) { error("%s: partial read(%s): len=%d ret=%d", Driver, Port, len, ret); } return ret; } void drv_generic_serial_write(const char *string, const int len) { int run, ret; #if 0 int i; for (i = 0; i < len; i++) { int c = string[i]; debug("serial_write: %03d %03o 0x%02x %c", c, c, c, iscntrl(c) ? '*' : c); } #endif if (Device == -1) return; for (run = 0; run < 10; run++) { ret = write(Device, string, len); if (ret >= 0 || errno != EAGAIN) break; if (run > 0) info("%s: write(%s): EAGAIN #%d", Driver, Port, run); usleep(1000); } if (ret < 0) { error("%s: write(%s) failed: %s", Driver, Port, strerror(errno)); } else if (ret != len) { error("%s: partial write(%s): len=%d ret=%d", Driver, Port, len, ret); } return; } int drv_generic_serial_close(void) { info("%s: closing port %s", Driver, Port); close(Device); drv_generic_serial_unlock_port(Port); free(Port); return 0; } #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
ToDo-List / Wishlist for lcd4linux

// 2000-04-04 Michael Reinelt <reinelt@eunet.at>
// implement some sort of 'graphs', similar to bars, but with a time axis
// can be filled (made up of bars) or not (needs raster graphics)
// done 2001-03-16 -lt.

// 2000-04-04 Michael Reinelt <reinelt@eunet.at>
// write a driver for PNG. This should be the first step towards a WWW-driver.
// Done 2001-03-01 -lt.

2000-04-15 Thomas Skyt Jessen <thskyt@foni.net>
show partition information (used, free, ...)

2000-04-25 Michael Mueller <m.mueller@netsystec.de>
show process information            

// 2000-12-03 Ghassan Matar <gmatar@hexapods.com>
// show other sensors than temperature
// we have to use libsensors instead of parsing the proc files directly
// Refused 2003-08-01 -mr

// 2000-12-03 Ghassan Matar <gmatar@hexapods.com>
// show contents of any text file
// the file should only contain one line, with a fixed format
// there are two possibilities: text and numbers
// numbers can be used for bars, too
// Done 2000-03-08, look at %x -lt

// 2000-12-03 Ghassan Matar <gmatar@hexapods.com>
// accept data from external sources (fifo?)
// Done 2000-03-08, look at %x -lt

// 2001-02-11 Carsten Nau <info@cnau.de>
// connect a LED to a spare pin of the parallel port and show if ISDN
// is online
// Done with GPO's -mr

// 2001-01-27 Axel Ehnert <axel@ehnert.net>
// - display numer of emails in a mailbox
// - display seti@home values
// done.

// 2001-03-05 Leo T�tsch <lt@toetsch.at>
// rename some tokens: %o->%os, %v->%ov, %r->%or, %p->%op,
// will be done with the big config-rework
// done with the "Next Generation Layout"

// 2001-03-05 Leo T�tsch <lt@toetsch.at>
// replace T_EXTENDED with a Flag similar to 'bar'
// rejected, T_EXTENDED does a good job  -mr

// 2001-03-07 Michael Reinelt <reinelt@eunet.at>
// use ppdev instead of ugly outb()
// done 2001-03-14 -mr

// 2001-03-09 Michael Reinelt <reinelt@eunet.at>
// replace udelay() assembly loop with rdtsc (read time stamp counter)
// at least try to....
// done 2001-03-14 -mr

// 2001-03-09 Leo T�tsch <lt@toetsch.at>
// read configuration file earlier (before forking) so that specific drivers
// (especially 'Text') would not fork.
// There's a reason for forking that early, but I forgot...
// done somewhere in mid 2003 MR

// 2001-03-12 Michael Reinelt <reinelt@eunet.at>
// remove USE_OLD_UDELAY after wide testing of new udelay code
// done with the "Next Generation Layout"

// 2001-03-12 Michael Reinelt <reinelt@eunet.at>
// create a NEWS file with changes/enhancements of every release
// done 2001-03-13 -mr

2001-03-14 Leopold Toetsch <lt@toetsch.at>
improve unseen for mbox (check Status:)

// 2001-03-14 Michael Reinelt <reinelt@eunet.at>
// add a new Token 'nc' for 'network collisions'
// done with the "Next Generation Layout"

2001-03-14 Michael Reinelt <reinelt@eunet.at>
add translation tables ('german umlauts' don't 
follow any scheme on most displays)

// 2001-03-15 Leopold Toetsch <lt@toetsch.at>
// Text display has troubles with '\r'
// done 2001-03-16, replace \r,\n with '_'  -lt

// 2001-03-24 Carsten Nau <info@cnau.de>
// change network clients to support different devices
// at the moment the sum of all eth* devices is calculated
// %n* should be extended tokens
// done with the "Next Generation Layout"

// 2001-03-24 Brian Cleven <lcleven@home.com>
// support 40x4 displays with two HD44780 chips on it
// we need another 'Enable' line for this
// this way one could connect two displays to one parallel port, too
// done with 0.9.11 MR

// 2001-05-25 Jens Garthe <outline@xslan.de>
// detect wether curses.h and libncurses is installed, and
// don't include the 'Text'-driver if not.
// _should_ work now 2001-05-31 -lt

// 2001-09-11 Michael Reinelt <reinelt@eunet.at>
// use new extended tokens to split up several data sources
// (CPU, Net, Disk, ISDN, ...)
// e.g. '%nw'  is 'network transmit' for _all_ devices
//     '%n0w' is 'network transmit' for eth0
//     '%n1w' for eth1
// done with the "Next Generation Layout"

// 2001-09-11 Michael Reinelt <reinelt@eunet.at>
// remove bar code from drivers and create a common bar library
// done somewhere in 2003 -mr

// 2001-09-12 Carsten Nau <info@cnau.de>
// make the output for emails shorter (at the moment up to 9999 emails)
// done with the "Next Generation Layout" 

2001-09-13 Michael Reinelt <reinelt@eunet.at>
combine mail.c and mail2.c
if there's an error getting mail info, display "?" instead of "0"

2001-09-14 Michael Reinelt <reinelt@eunet.at>
do not disable mail check in first error
instead use a number of retries
errors can occur in case of short disconnects, but normal operation 
should resume 

2002-02-15 Udo Altmann (udo.altmann@web.de)
support for inversed/blinking text
don't know if displays support this feature...

// 2003-09-08 Michael Reinelt (reinelt@eunet.at>
// at least one of my HD44780 displays use an inverted "P" instead of 
// a full block. Therefore a bar my look strange. Make the ASCII code
// of the full block configurable...
// done with the "Next Generation Layout"
// see the "asc255bug" attribute

// 2003-09-14 Markus <markus@norad.de>
// change %t tokens from Byte/sec to kB/sec, ith one decimal places. 
// Either make it configurabel, or add new tokens.
// done with the "Next Generation Layout"

// 2003-10-29 Matt Thrailkill <xwred1@modestolan.com>
// > To go off on another tangent... have you at all considered some sort of
// > marquee support?  I toyed with the row scrolling support which was
// > recently added, and it is nifty.  But marquees would be handy for doing
// > something like horizontally scrolling, say, the title of the currently
// > playing mp3.  I've toyed with trying to dive in and add it, but I'm a
// > pretty lazy guy and haven't done it.  What do you think?
// done with the "Next Generation Layout"

2003-12-31 Stefan ???  <nef17@gmx.net>
add support for software-controlled backlight for HD44780
http://www.jalcds.de/images/4x20backlight.gif

2004-01-25 Michael Reinelt <reinelt@eunet.at>
add attribute "blinking" to text widgets

2004-01-25 Xavier VELLO <xavier66@free.fr>
add "inverse" attribute to text widget
possible with Cwlinux and all graphics displays

2004-01-25 Xavier VELLO <xavier66@free.fr>
add an "image" widget

2004-01-25 Xavier VELLO <xavier66@free.fr>
icons should not only be updated regularly, but shown only when 
a certain expression returns 1
n535'>535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725