commit 2635c3085d0efae33ca91cf89d8d1eceff03dccd Author: William Ferrell Date: Thu Dec 9 23:15:14 1999 +0000 Initial revision diff --git a/BUGS b/BUGS new file mode 100644 index 0000000..a57e4f8 --- /dev/null +++ b/BUGS @@ -0,0 +1,13 @@ +Known Bugs: +-------------- +V0.4-pre1: + - The server tends to crash if the joystick driver is the last one loaded. + Specifically, if the "E" key is pressed... + - The lcdproc client doesn't have a disk screen. + - Menus are not implemented. + - Scrollers are not implemented. + - Dynamic driver adding/removing is not implemented. + - LCDproc needs more documentation! + +But, it's pretty stable considering I rewrote 400k of source since the +last release... diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..e77696a --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 + (at your option) 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..46a5e69 --- /dev/null +++ b/INSTALL @@ -0,0 +1,160 @@ +0. REALLY-QUICK START + +Try this, if you're in a hurry: + edit Makefile.config (use your preferred text editor, of course) + make + su + make install + + +1. GETTING STARTED + +First read the README if you haven't already. + +2. CONNECTING THE DISPLAY TO YOUR SYSTEM + +WARNING! Danger, Will Robinson, Danger! This is pretty easy, but if +by chance you screw up your machine by crossing some wires or by +pouring water on things with the power turned on, don't blame us! +Neither we, Matrix Orbital Corporation, or any manufacturer of LCDs +you're trying to use shall be held responsible for damage incurred +by following these directions. + +These instructions are SPECIFICALLY FOR MATRIX ORBITAL'S DISPLAYS! +Other displays will quite obviously have different requirements! + +2.1. POWER CONNECTION + +Matrix Orbital has instructions online for connecting the power +cable. It's at http://www.matrix-orbital.com/addendum.htm +Go there, if you're online. Or you can just read this: + +The LCD takes either +5V or +12V, depending on which model you +bought. You should have the +5V model unless you requested +otherwise. Either amount can be provided conveniently by a slightly +modified floppy power cable. + + ************* For +5V, use the RED wire. ************** + *********** For +12V, use the YELLOW wire. ************ + +Basically, disconnect the wire you don't need (yellow for +12V, or red +for +5V) and one of the black wires (they're both grounds so it +shouldn't matter which one you use). Then move the two remaining +wires to the opposite ends of the connector. The power wire goes to the +clearly marked +5V pin, and the black one goes to the also clearly +marked GND pin. + +Assuming you modified the cable right (we'll have pictures on the +web site in a few days to show how this connection should be made), +plug the other end of your modified wire into your system's power +cables and turn the system on (you don't need to connect the serial +cable until you know you got the power working). The LCD should light +up and tell you what version of the BIOS it has in it. If it does, +you've got it. If it doesn't, uh-oh. Turn the machine off quickly and +try it again. + +2.2. SERIAL CONNECTION + +The LCD uses a standard DB9 serial connector. However you want to +get from your motherboard or add-in card's serial port to the back of +the LCD is up to you. In one of my machines, I just literally pulled +one of the DB9 connectors off the back of my machine and plugged it +straight into the LCD, so it was just running from the motherboard +right to the LCD. YMMV (your milage may vary). In my new machine, I +needed a longer cable, so I just went out and bought a 6' external +serial cable, rolled it up and put it on top of my power supply, and +everything worked. + +By default (at least mine was shipped this way ;) the LCD is +configured to run at 19,200 baud, 8-N-1. You might want to make sure +yours is set like this; otherwise you'll need to hack our code which +you shouldn't have to do for this to work right. + +3. BUILDING LCDPROC + +As long as you have a working gcc and make, this should work. + + - Edit Makefile.config to configure some options. + - Run "make" + +LCDproc will build in (hopefully) a few seconds. It's not very big. If +you want, you can install it (if you're root) by typing: + +make install + +This will install the binaries and the man page, and will make a link +called /dev/lcd which points to whatever port you specified in the +Makefile. It will also change the permissions on the specified port +to allow all users to write to the port (so users can run LCDproc). +If you _don't_ want to allow this, change the permissions back after +installing LCDproc. :) + +4. RUNNING LCDPROC / MANUAL INSTALL + +First, you'll need to run the LCDd server. If you're in the LCDproc +source directory, and have just built it, run... + + server/LCDd -d joy -d MtxOrb + +This assumes you want to use the Matrix Orbital LCD driver and a +joystick. You can find out what other drivers are available by +running "LCDd -h". Note that you can use more than one driver at the +same time. + +Then, you'll need some clients. LCDproc comes with one: + + clients/lcdproc/lcdproc C M T X & + +This will run the main LCDproc client, with the [C]pu, [M]emory, +[T]ime, and [X]load screens. The ampersand (&) puts it in the background. + +To install manually, you'll want to do something like the following: + + su + cp server/LCDd /usr/local/bin + cp clients/lcdproc/lcdproc /usr/local/bin + cp docs/lcdproc.1.gz /usr/local/man/cat1 + ln -s /dev/ttyS0 /dev/lcd + +Some prereleases or development releases will have broken auto-install +scripts, so manual installs may be necessary for those versions. + + +5. PUTTING LCDPROC IN SYSTEM STARTUP + +It's nice to have LCDproc start when the computer boots, so here's how +to do it: + +In Slackware or RedHat: + Add lines to your /etc/rc.d/rc.local, such as the following: + echo "Starting LCDproc..." + /usr/local/bin/lcdproc C M X & + +In Debian: + - Make a file "/etc/init.d/lcd" which works the same as the + other scripts in that directory. (it should accept "start" + and "stop" as parameters...) + - To start, run "LCDd" with any necessary parameters. It will + put itself in the background as a daemon. + - Also in the "start" section, add "lcdproc" with some + parameters. Be sure to put a "&" on the end, or the system + will get stuck there when you boot. + - And, put in any other clients you want to run all the time. + - For the "stop" section, simply "kill" all the programs you + started in the "start" section. They will shut down and exit. + I recommend killing the server after all the clients, but it + really doesn't matter much. + + - Now, add symlinks from /etc/rc[2-5].d/S50lcd to /etc/init.d/lcd, + and be sure to get /etc/rc[06].d/K50lcd to /etc/init.d/lcd. + This will cause LCDproc to shut down when your system does. + +That's all the OS`s we've actually done this with so far.. + +6. OUR WEB SITE + +Visit http://lcdproc.omnipotent.net/ for the latest updates and news +for LCDproc. If you've got comments, suggestions, bug fixes, or +problems (related to LCDproc, not women ;), send e-mail to either +William W. Ferrell (choadster@earthlink.net) or Scott Scriven +(scriven@cs.colostate.edu). diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..573e031 --- /dev/null +++ b/Makefile @@ -0,0 +1,133 @@ +include Makefile.config + +######################################################################## +# Please edit Makefile.config to configure LCDproc for your system. +######################################################################## + + +######################################################################## +# You shouldn't need to touch anything below here. +######################################################################## + +#GCC = gcc -Wall -Wp,-lang-c-c++-comments -O6 +DIRS = shared clients/lcdproc clients server/drivers server +TARGETS = server clients shared +SOURCES = Makefile \ + shared/Makefile \ + shared/LL.c shared/LL.h \ + shared/config.c shared/config.h \ + shared/sockets.c shared/sockets.h \ + clients/Makefile \ + clients/mode.c clients/mode.h \ + tests/Makefile \ + server/Makefile \ + server/main.c server/main.h \ + server/lcd.c server/lcd.h \ + server/drv_base.c server/drv_base.h \ + server/drivers/MtxOrb.c server/drivers/MtxOrb.h \ + server/drivers/wirz-sli.c server/drivers/wirz-sli.h \ + server/drivers/text.c server/drivers/text.h \ + server/drivers/debug.c server/drivers/debug.h \ + server/drivers/curses_drv.c server/drivers/curses_drv.h \ + server/drivers/hd44780.c server/drivers/hd44780.h server/drivers/port.h +EXTRAS = WHATSNEW INSTALL README COPYING TODO README.IRman \ + docs/menustuff.txt docs/netstuff.txt docs/README.dg \ + docs/README.dg2 docs/hd44780_howto.txt +DOCS = docs/lcdproc.1 +#MISC += $(OS) $(DRIVERS) + + + +################################################################### +# Compilation... +# + +# TODO: Make sure lcdproc is configured first... +#@NOTCONFIGURED=`find . -newer . -name Makefile.config` +#@if [ $(NOTCONFIGURED) ]; do \ +# echo Please configure lcdproc before compiling! ;\ +# echo Edit "Makefile.config" to configure. ;\ +# exit 0 ;\ +#@done; +all: + @echo Compiling LCDproc... + @for i in $(DIRS); do \ + (cd $$i; [ -f Makefile ] && $(MAKE) $@) \ + done; true + + +server: + cd server; $(MAKE) + +clients: + cd clients; $(MAKE) + +shared: + cd shared; $(MAKE) + +tests: + cd tests; $(MAKE) + + +################################################################## +# Installation +# +install: $(TARGETS) $(DOCS) + @echo Installing LCDproc... +# @echo Sorry! Cannot do that yet... +# @echo Please read INSTALL for instructions + @for i in $(DIRS); do \ + (cd $$i; [ -f Makefile ] && $(MAKE) $@) \ + done; true + if [ ! -e /dev/lcd ]; then ln -s $(DEVICE) /dev/lcd ; chmod a+rw $(DEVICE) ; fi + @echo "All done -- enjoy!" + @echo "Be sure to verify that /dev/lcd points to the correct device." + @ls -l /dev/lcd + +# TODO: Have the installer insert lcdproc in system startup scripts? + + +################################################################## +# Other stuff... +# +clean: + @for i in $(DIRS); do \ + (cd $$i; [ -f Makefile ] && $(MAKE) $@) \ + done + rm -f *~ core + +# Distribution file +dist: + @echo Making distributable tarball... + make clean + rm -rf lcdproc-$(VERSION) + rm -rf lcdproc-$(VERSION).tar.gz + mkdir lcdproc-$(VERSION) + tar cBf - . --exclude CVS --exclude lcdproc-$(VERSION) | (cd lcdproc-$(VERSION) && tar xBfv -) + tar cfv lcdproc-$(VERSION).tar lcdproc-$(VERSION) + gzip lcdproc-$(VERSION).tar + rm -rf lcdproc-$(VERSION) + +# This includes source... +#tarball: +# tar cfv lcd.tar . +# gzip lcd.tar + +edit: + emacs . & + +.PHONY : todo +todo : + @echo ---------------=========================================== + @grep -n TODO\\\|FIXME `find . -type f` | grep -v grep + @echo ---------------=========================================== + +#todo: +# @echo ---------------=========================================== +# @grep TODO $(SOURCES) | grep -v SOURCES +# @grep FIXME $(SOURCES) | grep -v SOURCES +# @echo ---------------=========================================== + +#TODO: Keep updating the "Thank You's" section of the README. +#TODO: Don't forget about homework! + diff --git a/Makefile.config b/Makefile.config new file mode 100644 index 0000000..673a58e --- /dev/null +++ b/Makefile.config @@ -0,0 +1,136 @@ +######################################################################## +# Modify these variables to fit your system. +######################################################################## + +##################### Installation base directory +# This should point to /usr/local, for most people, or +# to /usr if you want to integrate LCDproc into your main filesystem. +INSTALL_DIR = /usr/local + +##################### Serial device +# This should be whatever your display is connected to. +# "make install" will create a link from /dev/lcd to DEVICE +# if you don't already have a /dev/lcd +DEVICE = /dev/ttyS0 + +##################### Operating System +# Uncomment the section for your OS. + +### For Linux... +OS=-DLINUX + +### For BSD. We call it xBSD to +# avoid a clash with the BSD in sys/param.h +#OS=-DxBSD + +### For IRIX... +#OS=-DIRIX + +### For Alpha processors... +#CFLAGS += -mieee + +##################### Inet port to use... +# Use whatever you want... +# The default is 13666 +LCDPORT=-DLCDPORT=13666 + +##################### Modescreen Options + +##### Load Screen +# Max: Load Avg at which the backlight will start blinking +MISC += -DLOAD_MAX=1.3 +# Min: Load Avg at which the backlight will turn off (asleep) +MISC += -DLOAD_MIN=0.05 + +##### Filesystems to display stats for... (comment out ones you don't want) +# NFS (Network File System) +MISC += -DSTAT_NFS +# SMBFS (Samba filesystem -- Windows drives) +MISC += -DSTAT_SMBFS + + +##################### Drivers +# Comment out each section you don't want. + +# Matrix-Orbital displays +DRIVERS += -DMTXORB_DRV +DOBJ += MtxOrb.o + +# Wirz SLI +DRIVERS += -DSLI_DRV +DOBJ += wirz-sli.o + +# CrystalFontz displays +DRIVERS += -DCFONTZ_DRV +DOBJ += CFontz.o + +# Curses text-based output +DRIVERS += -DCURSES_DRV +DOBJ += curses_drv.o +LIB += -lncurses + +# Regular text output (ugly) +DRIVERS += -DTEXT_DRV +DOBJ += text.o + +# HD44780 parallel port lcd displays +#DRIVERS += -DHD44780_DRV +#DOBJ += hd44780.o +# Pick one of the following ports to use +#LPTPORT = 0x378 +#LPTPORT = 0x278 +#LPTPORT = 0x3bc + +# Joystick input... handy! +DRIVERS += -DJOY_DRV +DOBJ += joy.o + +# Irman input... handy! +#DRIVERS += -DIRMANIN_DRV +#DOBJ += irmanin.o ../../../libirman-0.4.1b/libirman.a +#IRMAN=1 + + +##################### Debugging Options +# Please uncomment only one of these two, and comment the other: +# Uncomment this to build a debugging executable +#DEBUG = -g -DDEBUG +# If the above is commented, this shouldn't be... +MISC += -Wno-unused + + +######################################################################## +# You shouldn't need to touch anything below here. +######################################################################## + +GCC = gcc -Wall -Wp,-lang-c-c++-comments -O6 $(CFLAGS) +VERSION = 0.4-pre9 +MISC += $(OS) $(DRIVERS) $(DEBUG) $(LCDPORT) -DVERSION=\"$(VERSION)\" + + +################################################################### +# Compilation... +# +#all: +# @echo Compiling LCDproc... +# @for i in $(DIRS); do \ +# (cd $$i; [ -f Makefile ] && $(MAKE) $@) \ +# done; true + +################################################################## +# Other stuff... +# +#clean: +# @for i in $(DIRS); do \ +# (cd $$i; [ -f Makefile ] && $(MAKE) $@) \ +# done +# rm -f *~ core +# +#edit: +# emacs . & + +#.PHONY : todo +#todo : +# @echo ---------------=========================================== +# @grep -n TODO\\\|FIXME `find . -type f` | grep -v grep +# @echo ---------------=========================================== diff --git a/README b/README new file mode 100644 index 0000000..ae3d1f7 --- /dev/null +++ b/README @@ -0,0 +1,64 @@ +Warning: This is a prerelease. It will probably have some rough edges. + + +INTRODUCTION + +LCDproc is a small program that extracts various statistics about your +machine and displays them on an LCD display. It works with several types +and sizes of displays. + +Our site is located at http://lcdproc.omnipotent.net/ ... so check +there first for new versions or updates. We've got a spot on the web +site for user's suggestions, and you can e-mail us as well: + +choadster@earthlink.net (William W. Ferrell) +scriven@cs.colostate.edu (Scott Scriven) + +INSTALLATION + +Refer to the INSTALL file included with this archive for installation +instructions (including how to connect the LCD to your system). + +Also, be sure to EDIT THE Makefile.config before compiling. It +contains many configuration options. (these will be removed as soon +as LCDproc uses a real config file) + +CHANGES + +Woow... a lot. :) + +HELPING OUT + +If you get the urge to help out by writing code, feel free to "make todo" +and find out what needs to be done... (also, of course, new ideas are +good too :) + +To add new drivers, read drv_base.h for instructions. + +SPECIAL THANKS + +We'd like to thank the following people for helping out with this: + Everyone at Matrix Orbital Corporation -- you guys are great! + Gareth Watts -- Patches, mailing list, ideas, www, etc. Thanks! + Everyone on the mailing list. :) + And... Where's that list of contributors?? + +LEGAL STUFF + +LCDproc is Copyright (C) 1999 William Ferrell and Scott Scriven +The included file, "COPYING", contains the full GNU license. + +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 (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + diff --git a/README.IRman b/README.IRman new file mode 100644 index 0000000..355ee3a --- /dev/null +++ b/README.IRman @@ -0,0 +1,65 @@ +Hello, + +I made a IRman input driver for lcdproc-0.4 wich is now include in +"lcdproc-0.4-pre6". This input driver require "libirman-0.4.1b" the +library with function support for IRman. + +I want to help you use this new driver (if anybody other than me use +it... please tell me!!!). + +In order to help you compile your own version of LCDd with support for +IRman, I recorded every step I took in order to compile my own copy +based on two file downloaded directly from the internet. + +The first file is " lcdproc-0.4-pre6.tar.gz " the current version of +lcdproc. You can download this file from +"http://lcdproc.omnipotent.net/download.php3" The second file is +"libirman-0.4.1b.tar.gz" the current version of libirman. You can +download this file from http://www.evation.com/libirman/ DO NOT USE +THE COPY OF LIBIRMAN FROM LCDPROC HOME PAGE... I don't know what is +wrong with that one but I can't decompress it??? + +How to compile lcdproc for use with support for IRman: + +-Untar lcdproc and libirman: + tar -xzvf lcdproc-0.4-pre6.tgz + tar -xzvf libirman$$$ +-Go, configure and compile libirman: + cd libirman-0.4.1b/ + ./configure + make + cd .. +-Go in lcdproc directory: + cd lcdproc-0.4-pre6 +-Here is the modification you need to include IRman driver in lcdproc: + edit Makefile.config + # Irman input... handy! + DRIVERS += -DIRMANIN_DRV + DOBJ += irmanin.o ../../../libirman-0.4.1b/libirman.a + IRMAN=1 +-Compile lcdproc + make +-Make sure you have a network interface up and working: + ifup lo +-Go and install your IRman configuration file: + cd server + cd drivers + cp DOTirmanrc ~/.irmanrc +-Modify if needed (if you use another remote control) the .irmanrc file. +-Run LCDd with two driver, irmanin and an output driver: + ./LCDd -d irmanin "-d /dev/ttyS0" -d curses +-Try to access the menu by pressing the remote control. + +Now if it does not work: +· Try your IRMAN on ttyS0 alone (with other software). +· Try LCDd without the IrmanIN driver. +· ... + +David GLAUDE + +PS: If you really have successfuly made LCDd working without IRman AND +You have successfuly made IRman device working AND you don't succeed +to make it work together ussing my driver... then maybe I can help and +give you some support (as time permit and if it does not eat up too +much bandwidth). + diff --git a/TODO b/TODO new file mode 100644 index 0000000..ca07eef --- /dev/null +++ b/TODO @@ -0,0 +1,86 @@ +Stuff planned for future releases... (in no particular order) + +Feel free to help out with any of this stuff! :) + + +---------------------------------------- +Client driver + +An LCDproc client can connect, request the "client" driver, then get +all screen information sent to it! This allows things such as logging +in remotely and starting up a curses display of LCDproc. It also +gives another method for writing drivers. In a sense, it could even +let you write and link in new drivers without having to recompile and +restart LCDproc... + +Another bonus is that LCDproc will come with a client which can, for +example, start up a "client" driver to send "keypresses" from the +command line. Or, + + lcdtool -key A + +would have the same result as pressing a key on the keypad. + + +---------------------------------------- +Menus / Client menus + +LCDproc will have a "menu" mode, where various options can be +configured. You can rearrange the screenlist, change the contrast, +add/remove drivers, change screen priorities, kick off clients, etc... + +You can also access client menus to configure options in each client. + +---------------------------------------- +Config Files... + +LCDproc will use a config file for its parameters, like other +programs; instead of relying upon long command lines. Keypresses, +drivers, and other things will be configurable here. Also, LCDproc +will have the ability to load/modify/save config files via its menu +interface, so you don't have to edit it by hand. + +Info about particular clients/screens will also be stored in the +LCDproc config file, so you can (for example) save your preferences +about screen priorities, etc... + +Code will be made generic, so that other programs can use it for their +own config files. Clients may want to use this.. + +---------------------------------------- +Scheduling modes + +Instead of the simplistic "round robin" circular screen-scheduling in +the current release, later versions will offer several different +algorithms for screen-ordering. + +One example: High-priority screens will be shown more often than +low-priority screens, simply by showing up more often. + +---------------------------------------- +Shell Commands + +The server will also be able to run arbitrary shell commands from the +config file. This will allow you to, for example, shut down the +machine, get online, or other system tasks. + +---------------------------------------- +Improved display driver API + +The desirable aspects of what a driver should do has changed somewhat +since I first read the LCD manual. The driver spec is based largely +on the functions MtxOrb's LCDs provide easily, but it is not +well-suited to other types of display. + +So, I'll be working on a new driver spec which is more flexible and +more powerful. In addition, I'm looking for ways to better handle +multiple driver devices. + +---------------------------------------- +Anonymous CVS + +I want to *really* open up LCDproc development, by giving everyone +access to the CVS repository. But, alas, I've got to figure out how +to set up a CVS server first... (or convince Gareth to do it.. :) + +---------------------------------------- diff --git a/WHATSNEW b/WHATSNEW new file mode 100644 index 0000000..08752f9 --- /dev/null +++ b/WHATSNEW @@ -0,0 +1,108 @@ +Recent changes: + +Key: + - Something removed + + Something added + * Something changed / fixed + +Coming soon: (?) (my list of stuff to do soon...) + + Client menus + + Configuration file support + * Better syntax for driver parameters + * Dynamically-loaded driver system + +V0.4-pre9: + * small fixes for irix + * Added flag in LCDd to shut off server screen: + "-i off" or "--serverinfo off" + + Wirz SLI driver + + 16x2 support (server only) + + MtxOrb generic output support in driver + * Misc libc5 fixes + + support for arbitrary display sizes; anything 16-80 characters + wide, and 2-25 characters tall. (doesn't work if you try to use + a display size bigger than your LCD.. :) + * curses driver looks slightly better (titles) + * sizes > 20x4 no longer crash + +V0.4-pre8: + * LCDd gives more updated info in the connect string: + cell size, lcd dimensions. + * bargraphs are now the correct length on CFontz displays, in the main + lcdproc client. For other clients, please parse the connect string! + * MtxOrb driver supports simultaneous vbars/hbars now, with a + mechanism to automatically use custom characters for as many + as possible. + + 20x2 support in LCDd! Use "--type 20x2". + (LCDd --type 20x2 -d MtxOrb ) + * LCDd can change backlight brightness instead of shutting it "off" + * HD44780 should work again (LCDd forks earlier now.. oops :) + + 20x2 support in lcdproc client for the following screens: + C G T M X D B S U A + Support will not be added for K and O screens. + + BSD support (?) + * 20x4 screens should display correctly on 40x4 displays + +V0.4-pre7: new driver + + CrystalFontz (CFontz) LCD driver added + * Backlight control improved + + Brightness control added + +V0.4-pre6: + + Backlight control added. Modes so far are "on", "off", and "open". + Client commands are "on", "off", "toggle", "blink", and "flash". + * Main clients' screen titles now include hostname + + New sample client: fortune.pl + * Added changes from David Glaude: + + IRman support + + Big Digit support (MtxOrb driver doesn't display it correctly yet) + + Big cloc[K] screen + * MtxOrb serial speed is configurable with "--speed" + * misc bugfixes + + ... more + +V0.4-pre5: + * Fixed bug which could take server down with a dead client + * Fixed small scroller bug + + Added "frame" widgets.. use "-in " after widget_add + to put something in a frame. + + The disk screen is back! + - Frame rendering isn't finished.. the renderer probably needs a + complete rewrite. Any volunteers? :) + +V0.4-pre4: + + Server menus (fairly small so far) + + Ability to shut down, reboot, change some options, etc (menu only) + * Driver arguments no longer required + * Curses driver doesn't start server in background any more... + * Argument handling fixed... + * Drivers support "--help" for command-line info + +V0.4-pre3: + + Scroller widgets + * Proper errno messages... + * "make install" should work now + * Joystick driver allows key remapping + + Screen "durations" are actually *used* now. (oops) + + Initial support for screen priorities (strict priority queue) + * Misc (but annoying!) bugs fixed, which hadn't yet affected anything + + Drivers support parameters now (MtxOrb, joy, at least) + + +V0.4-pre2: + * Memory leaks fixed + + Memory "top" screen (S) + + Titles now autoscroll + * Fixed small screen-visibility bug (clients weren't always + notified of screen cycles) + + Heartbeat modes implemented. Clients can remove it with + widget_del my_screen heartbeat + or turn it back on with + widget_add my_screen heartbeat " " + Note that the client only has control over this when the heartbeat + is in "open" mode. (currently, it always is) + + +V0.4-pre1: + * Too much to mention... + diff --git a/clients/Makefile b/clients/Makefile new file mode 100644 index 0000000..a3d714d --- /dev/null +++ b/clients/Makefile @@ -0,0 +1,39 @@ +######################################################################## +# You shouldn't need to touch anything below here. +######################################################################## +include ../Makefile.config + +DIRS = lcdproc +TARGETS = lcdproc/lcdproc + +################################################################### +# Compilation... +# +all: $(TARGETS) + for i in $(DIRS); do \ + (cd $$i; [ -f Makefile ] && $(MAKE) $@) \ + done + + +################################################################## +# Installation +# +install: $(TARGETS) + @echo Installing LCD clients... + for i in $(DIRS); do \ + (cd $$i; [ -f Makefile ] && $(MAKE) $@) \ + done; true + + +################################################################## +# Other stuff... +# +clean: + for i in $(DIRS); do \ + (cd $$i; [ -f Makefile ] && $(MAKE) $@) \ + done; true + rm -f *.o *~ core + +edit: + emacs . & + diff --git a/clients/examples/fortune.pl b/clients/examples/fortune.pl new file mode 100755 index 0000000..8c42eb6 --- /dev/null +++ b/clients/examples/fortune.pl @@ -0,0 +1,75 @@ +#!/usr/local/bin/perl -w + +use IO::Socket; +use Fcntl; + + +# Connect to the server... +$remote = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => "localhost", + PeerPort => "13666", + ) + || die "Cannot connect to LCDproc port\n"; + +# Make sure our messages get there right away +$remote->autoflush(1); + +sleep 1; # Give server plenty of time to notice us... + +print $remote "hello\n"; +my $lcdconnect = <$remote>; +#print $lcdconnect; + + +# Turn off blocking mode... +fcntl($remote, F_SETFL, O_NONBLOCK); + + +# Set up some screen widgets... +print $remote "client_set name {fortune.pl}\n"; +print $remote "screen_add fortune\n"; +print $remote "screen_set fortune name {Fortune}\n"; +print $remote "widget_add fortune title title\n"; +print $remote "widget_set fortune title {Fortune}\n"; +print $remote "widget_add fortune text scroller\n"; + + +&update_text(); + +# Forever, we should do stuff... +while(1) +{ + # Handle input... (spew it to the console) + # Also, certain keys scroll the display + while(defined($input = <$remote>)) { + #print $input; + + # Make sure we handle each line... + @lines = split(/\n/, $input); + foreach $line (@lines) + { + if($line =~ /^ignore (\S)/) # Update just after disappearing + { + &update_text(); + } + } + } + + # And wait a little while before we check for input again. + sleep 1; +} + +close ($remote) || die "close: $!"; +exit; + +sub update_text { + # Grab some text. + $text = `fortune`; + @lines = split(/\n/, $text); + $text = join(" / ", @lines); + + # Now, show a fortune... + print $remote "widget_set fortune text 1 2 20 4 v 16 {$text}\n"; + +} diff --git a/clients/examples/iosock.pl b/clients/examples/iosock.pl new file mode 100755 index 0000000..8f663d5 --- /dev/null +++ b/clients/examples/iosock.pl @@ -0,0 +1,85 @@ +#!/usr/local/bin/perl -w + +use IO::Socket; +use Fcntl; + +# Connect to the server... +$remote = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => "localhost", + PeerPort => "13666", + ) + || die "Cannot connect to LCDproc port\n"; + +# Make sure our messages get there right away +$remote->autoflush(1); + +`sleep 1`; # Give server plenty of time to notice us... + +print $remote "hello\n"; +my $lcdconnect = <$remote>; +print $lcdconnect; + + +# Turn off blocking mode... +fcntl($remote, F_SETFL, O_NONBLOCK); + + +# Set up some screen widgets... +print $remote "client_set name {Test Client (Perl)}\n"; +print $remote "screen_add pings\n"; +print $remote "screen_set pings name {Ping Status}\n"; +print $remote "widget_add pings title title\n"; +print $remote "widget_set pings title {Ping Status}\n"; +print $remote "widget_add pings one string\n"; +print $remote "widget_add pings two string\n"; +print $remote "widget_set pings one 1 2 {Checking machines...}\n"; + + +my ($machine, %down, %up, $i, $list); + +while(1) +{ + #print "Main loop...\n"; + # Handle input... (just spew it to the console) + while(defined($line = <$remote>)) { + print $line; + } + + undef %down; + undef %up; + foreach $machine ("ZakaZak", + "webfoot", + "degas", + "cassat", + "miro", + "monet", + "dali", + "escher", + "seurat", + "rodin", + "matisse", + ) + { + `ping -c 1 $machine`; + if($?) { $down{$machine} = 1; } + else { $up{$machine} = 1; } + } + $i = 0; $list = ""; + foreach $machine (keys %up) + { + $i++; + $list .= "$machine, "; + } + print $remote "widget_set pings one 1 2 {Machines Up: $i}\n"; + $i = 0; $list = ""; + foreach $machine (keys %down) + { + $i++; + $list .= "$machine, "; + } + print $remote "widget_set pings two 1 3 {Down ($i): $list}\n"; +} + +close ($remote) || die "close: $!"; +exit; diff --git a/clients/examples/tail.pl b/clients/examples/tail.pl new file mode 100755 index 0000000..c042ef2 --- /dev/null +++ b/clients/examples/tail.pl @@ -0,0 +1,121 @@ +#!/usr/local/bin/perl -w + +use IO::Socket; +use Fcntl; + +if($#ARGV < 0) +{ + print "Usage: tail.pl file\n"; + exit; +} +$filename = shift @ARGV; + + +# Connect to the server... +$remote = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => "localhost", + PeerPort => "13666", + ) + || die "Cannot connect to LCDproc port\n"; + +# Make sure our messages get there right away +$remote->autoflush(1); + +sleep 1; # Give server plenty of time to notice us... + +print $remote "hello\n"; +my $lcdconnect = <$remote>; +print $lcdconnect; + + +# Turn off blocking mode... +fcntl($remote, F_SETFL, O_NONBLOCK); + + +# Set up some screen widgets... +print $remote "client_set name {Tail ($filename)}\n"; +print $remote "screen_add tail\n"; +print $remote "screen_set tail name {Tail $filename}\n"; +print $remote "widget_add tail title title\n"; +print $remote "widget_set tail title {Tail: $filename}\n"; +print $remote "widget_add tail 1 string\n"; +print $remote "widget_add tail 2 string\n"; +print $remote "widget_add tail 3 string\n"; + + +# These define the visible part of the file... +$top = 3; # How far from the end of the file should we start? +$lines = 3; # How many lines to display? +$left = 1; # Left/right scrolling position, +$width = 20; # and number of characters per line to show + +$slow = 1; # Should we pause after the current frame? + +# Forever, we should do stuff... +while(1) +{ + # Handle input... (spew it to the console) + # Also, certain keys scroll the display + while(defined($input = <$remote>)) { + print $input; + + $slow = -10; + # Make sure we handle each line... + @lines = split(/\n/, $input); + foreach $line (@lines) + { + if($line =~ /^key (\S)/) # Keypresses are useful. + { + $key = $1; + if($key eq "G") { $top++; } + if($key eq "H") + { + if($top > $lines) {$top--; } + } + if($key eq "F") { $left++; } + if($key eq "E") + { + if($left > 1) {$left--; } + } + } + } + } + + # Now, show what the file contains, if anything... + if( -f $filename ) + { + # Grab some text. + $right = $left + $width - 1; + $text = `tail -$top $filename | head -$lines | cut -c$left-$right`; + @lines = split(/\n/, $text); + # Now, display that text... + for($i=0; $i<$lines; $i++) + { + $j = $i + 1; + $k = $i + 2; + if($#lines < $i) { $line = " "; } # Avoid blank lines + else { $line = $lines[$i]; } + if(!($line =~ /\S/)) { $line = " ";} + print $remote "widget_set tail $j 1 $k {$line }\n"; + } + } + else # If the file is unreadable, show an error + { + print $remote "widget_set tail one 1 2 {$filename}\n"; + print $remote "widget_set tail two 1 3 {doesn't exist.}\n"; + print $remote "widget_set tail three 1 4 { }\n"; + } + + # And wait a little while before we show stuff again. + if($slow > 0) {sleep 1; $slow++;} + elsif($slow > 4) {sleep 2; $slow++;} + elsif($slow > 64) {sleep 4; } + else {$slow++;} + # The "slow" thing just lets us have a better response time + # while the user is pressing keys... But while the user + # is inactive, it gradually decreases update frequency. +} + +close ($remote) || die "close: $!"; +exit; diff --git a/clients/examples/x11amp.pl b/clients/examples/x11amp.pl new file mode 100755 index 0000000..2ac5113 --- /dev/null +++ b/clients/examples/x11amp.pl @@ -0,0 +1,85 @@ +#!/usr/local/bin/perl -w + +# +# This is just a test! It's simple, cheesy, and doesn't do much +# or even look very nice. +# +# However, it demonstrates one way to handle input from the server. +# (although it seems buggy.. oops! :) +# + +use IO::Socket; +use Fcntl; + +# Connect to the server... +$remote = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => "localhost", + PeerPort => "13666", + ) + || die "Cannot connect to LCDproc port\n"; + +# Make sure our messages get there right away +$remote->autoflush(1); + +sleep 1; # Give server plenty of time to notice us... + +print $remote "hello\n"; +my $lcdconnect = <$remote>; +#print $lcdconnect; + + +# Turn off blocking mode... +fcntl($remote, F_SETFL, O_NONBLOCK); + + +# Set up some screen widgets... +print $remote "client_set name {X11AMP test}\n"; +print $remote "screen_add x11amp\n"; +print $remote "screen_set x11amp name {X11AMP test}\n"; +print $remote "widget_add x11amp title title\n"; +print $remote "widget_set x11amp title {X11AMP test}\n"; +print $remote "widget_add x11amp one string\n"; +print $remote "widget_set x11amp one 1 2 { <-: E ; F :->}\n"; + + +while(1) +{ + # Handle input... + while(defined($line = <$remote>)) { + @items = split(" ", $line); + $command = shift @items; + # Use input to change songs... + if($command eq "key") + { + $key = shift @items; + if($key eq "E") + { + system("x11amp --rew"); + } + if($key eq "F") + { + system("x11amp --fwd"); + } + } + # And ignore everything else + elsif($command eq "connect") + { + } + elsif($command eq "listen") + { + } + elsif($command eq "ignore") + { + } + else { + if($line =~ /\S/) {print "Huh? $line\n";} + } + } + + sleep 1; + +} + +close ($remote) || die "close: $!"; +exit; diff --git a/clients/headlines/lcdheadlines b/clients/headlines/lcdheadlines new file mode 100755 index 0000000..e71c48a --- /dev/null +++ b/clients/headlines/lcdheadlines @@ -0,0 +1,293 @@ +#!/usr/bin/perl -w + +# wmslashdot.pl v1.3, written by Jeff Meininger +# http://rive.boxybutgood.com/WMHeadlines/ - jeffm@boxybutgood.com +# +# Original concept by Pascal Hofstee... +# +# +# Proxy support based on code provided by Dan Gundlach... +# +# +# Proper HTTP/1.1 calls by Kjeld Hoyer Mortensen... +# +# +# wmslashdot is licensed under the GPL version 2. +# wmslashdot is Copyright (C) 1999 by Jeff Meininger +# +# For setup information, please see the following URL... +# http://rive.boxybutgood.com/WMHeadlines/ +# +# For configuration options, type 'wmslashdot.pl --help' +# All options are available from the command line. +# +# NO NEED TO EDIT THIS FILE FOR CONFIGURATION PURPOSES! + +print "Sorry, this doesn't do anything yet..\n"; +exit 0; + +require 5.002; +use strict; +use Socket; +use File::Copy; + +# TODO: my ($upkey, $downkey, $enterkey) = ("E", "F", "G"); + +# TODO: my @sitenames = ("Slashdot", "Freshmeat", ...); +# TODO: my @remotes = ("slashdot.org", "freshmeat.net", ...); +# TODO: my @urls = ("/ultramode.txt", "/whatever.txt", ...); +my $sitename = "Slashdot"; +my $scriptname = "slashdot"; +my $remote = 'slashdot.org'; +my $url = "/ultramode.txt"; + +my @time = localtime(); +my $garble = scalar(localtime); +$garble =~ s/\W//g; +my $randomcrap = rand(900); + +my ($iaddr, $paddr, $proto, $line, $menufile, $tmpfile, $newstring, $proxy); + +my ($twentyfour, $dayfirst, $proxyflag, $loudflag, $forceupdate) = (0)x5; +my ($showdate, $newflag) = (1)x2; + +my ($frontpage, $deathtext, $datestring) = ("")x3; +my $nspath = "netscape"; +$menufile = "$ENV{'HOME'}/.$scriptname" . "menu"; + +my $port = 80; +my $maxlength = 9999; +my $ampmstring = "AM"; +my $kick = "\n\n"; +my $yearstring = "-" . ($time[5] + 1900); + +# get configuration from commandline +my $i; +for ($i = 0; $i < scalar(@ARGV); $i++) { + if ($ARGV[$i] eq "--help") { + print "\nlcd$scriptname.pl usage:\n"; + print "[-proxy host port] - enables use over a proxy\n"; + print "[-n] - prevents netscape from opening a new window for each headline\n"; + print "[-frontpage top|bottom] - adds a persistant item for the $sitename frontpage.\n\tIt can be placed at the top or bottom of the menu.\n"; + print "[-loud] - useful for debugging problems. Otherwise, the script exits quietly\n\tin the case of an error.\n"; + print "[-24] - display time in 24 format instead of 12 AM/PM\n"; + print "[-dayfirst] - display day before month (like 25-12-1999) in date.\n"; + print "[-nodate] - do not display 'last updated' date in menu title.\n"; + print "[-noyear] - do not display the year in the 'last updated' date.\n"; + print "[-proxyfix] - proxy support not working? Try this.\n"; + print "[-maxlength num] - items will not be shown with more than [num] letters.\n"; + print "[-nspath /path/to/netscape/executable] - if your 'netscape' is not in the PATH\n\tused by Window Maker, you may specify the full pathname to the netscape\n\texecutable here.\n"; + print "[-menufile /etc/X11/WindowMaker/menu.$scriptname] - if you want to store the\n\tmenu somewhere other than ~/.$scriptname" . "menu, specify the FULL\n\tpathname with this option. (Keep write permissions in mind...)\n"; + print "[-forceupdate] - force the menu file to be written even if the headlines have\n\tnot changed. For example, a change in preference options will _NOT_\n\tbe visible without using this option.\n"; + print "\n"; + exit(); + } elsif($ARGV[$i] eq "-proxy") { + if ((!defined($ARGV[$i + 2])) || ($ARGV[$i + 1] =~ /^-/) || ($ARGV[$i + 2] =~ /^-/) || ($ARGV[$i + 2] =~ /\D/)) { + print "Please use '-proxy proxy.yourisp.com 3128' or whatever is appropriate.\n"; + exit(); + } else { + $proxyflag = 1; + $proxy = $ARGV[$i + 1]; + $port = $ARGV[$i + 2]; + } + } elsif($ARGV[$i] eq "-n") { + $newflag = 0; + } elsif($ARGV[$i] eq "-frontpage") { + if ((!defined($ARGV[$i + 1])) || (($ARGV[$i + 1] ne "top") && ($ARGV[$i + 1] ne "bottom"))) { + print "Please use '-frontpage top' or '-frontpage bottom' to enable this feature.\n"; + exit(); + } else { + $frontpage = $ARGV[$i + 1]; + } + } elsif($ARGV[$i] eq "-loud") { + $deathtext = "ERROR: Could not connect to remote site"; + } elsif($ARGV[$i] eq "-24") { + $twentyfour = 1; + } elsif($ARGV[$i] eq "-dayfirst") { + $dayfirst = 1; + } elsif($ARGV[$i] eq "-nodate") { + $showdate = 0; + } elsif($ARGV[$i] eq "-noyear") { + $yearstring = ""; + } elsif($ARGV[$i] eq "-proxyfix") { + $kick = "\r\n\r\n"; + } elsif($ARGV[$i] eq "-maxlength") { + if ((!defined($ARGV[$i + 1])) || ($ARGV[$i + 1] =~ /\D/)) { + print "Please use '-maxlength NUM' where NUM is an integer, like 60.\n"; + exit(); + } else { + $maxlength = $ARGV[$i + 1]; + } + } elsif($ARGV[$i] eq "-nspath") { + if (!defined($ARGV[$i + 1]) || ($ARGV[$i + 1] !~ /^\//)) { + print "Please use '-nspath /opt/netscape-4.5/netscape', or whatever is appropriate.\nNote... you must specify the FULL pathname.\n"; + exit(); + } + $nspath = $ARGV[$i + 1]; + } elsif($ARGV[$i] eq "-menufile") { + if (!defined($ARGV[$i + 1]) || ($ARGV[$i + 1] !~ /^\//)) { + print "Please use '-menufile /etc/X11/WindowMaker/menu.$scriptname', or whatever is\nappropriate. Note... you must specify the FULL pathname.\n"; + exit(); + } + $menufile = $ARGV[$i + 1]; + } elsif($ARGV[$i] eq "-forceupdate") { + $forceupdate = 1; + } +} + +if ($newflag == 0) { + $newstring = ""; +} else { + $newstring = ", new-window"; +} + +if ($twentyfour > 0) { + $ampmstring = ""; +} else { + if ($time[2] > 11) { + $ampmstring = "PM"; + } + + if ($time[2] > 12) { + $time[2] = $time[2] - 12; + } +} + +if ($showdate > 0) { + if ($dayfirst > 0) { + $datestring = " [$time[3]-" . ($time[4] + 1) . "$yearstring, " . $time[2] . ":" . sprintf("%02d", $time[1]) . "$ampmstring]"; + } else { + $datestring = " [" . ($time[4] + 1) . "-$time[3]$yearstring, " . $time[2] . ":" . sprintf("%02d", $time[1]) . "$ampmstring]"; + } +} else { + $datestring = ""; +} + +# start the fun +$tmpfile = "/tmp/$scriptname" . "menu$garble$randomcrap"; +open(TMPFILE, ">$tmpfile"); + +print TMPFILE "\"$sitename Headlines$datestring\" MENU\n"; + +if ($frontpage eq "top") { + print TMPFILE "\"$sitename Frontpage\" EXEC $nspath -remote 'openURL(http://$remote/$newstring)' || $nspath 'http://$remote/'\n"; +} + +# network connection portion is pretty much stolen from 'man perlipc' +if ($proxyflag > 0) { + $iaddr = inet_aton($proxy) || wmdie($deathtext); +} else { + $iaddr = inet_aton($remote) || wmdie($deathtext); +} +$paddr = sockaddr_in($port, $iaddr); +$proto = getprotobyname('tcp'); +socket(SOCK, PF_INET, SOCK_STREAM, $proto) || wmdie($deathtext); +connect(SOCK, $paddr) || wmdie($deathtext); + +select(SOCK); $| = 1; select(STDOUT); + +if ($proxyflag > 0) { + print SOCK "GET http://$remote$url HTTP/1.1$kick"; +} else { + print SOCK "GET $url HTTP/1.1\nHost: $remote:80$kick"; +} + + +$i = 0; +my $flag = 0; +while (defined($line = )) { + $i++; + + if ($line =~ /^%%/) { $i = 1; $flag = 1; } + + if ($flag > 0) { + if ($i == 2) { + chop($line); + $line =~ s/"/'/g; # " Balances out quote... + $line =~ s/<.*?>//g; + $line =~ s/&.{1,5}?;//g; + if (length($line) > $maxlength) { + $line = substr($line, 0, $maxlength) . "..."; + } + print TMPFILE "\"$line\" EXEC $nspath -remote 'openURL("; + } elsif ($i == 3) { + chop($line); + print TMPFILE "$line$newstring)' || $nspath '$line'\n"; + } + } +} + +if ($frontpage eq "bottom") { + print TMPFILE "\"$sitename Frontpage\" EXEC $nspath -remote 'openURL(http://$remote/$newstring)' || $nspath 'http://$remote/'\n"; +} + +print TMPFILE "\"$sitename Headlines$datestring\" END\n"; + +close(SOCK) || die "Error closing socket: $!"; +close(TMPFILE); + +# compare tmpfile with current menufile and possibly update it. +if (-e $menufile) { + my ($tmpline, $menuline, $linecount); + + open(MENUFILE, $menufile); + open(TMPFILE, $tmpfile); + + # read in the first 'headline' menu entry from each file. + if ($frontpage eq "top") { + $linecount = 3; + } else { + $linecount = 2; + } + + for ($i = 0; $i < $linecount; $i++) { + if (eof(TMPFILE)) { + if ($forceupdate == 0) { + + close(MENUFILE); + close(TMPFILE); + unlink($tmpfile); + + exit(); + } + } else { + $tmpline = ; + } + + unless (eof(MENUFILE)) { + $menuline = ; + } + } + + if (($forceupdate == 0) && (($tmpline =~ /^"$sitename Headlines/) || ($tmpline =~ /^"$sitename Frontpage/) || ($tmpline eq $menuline))) { + close(MENUFILE); + close(TMPFILE); + unlink($tmpfile); + + exit(); + } +} + +close(MENUFILE); +close(TMPFILE); +copy($tmpfile, $menufile); +unlink($tmpfile); + +exit(); + +sub wmdie { + my $string = shift; + if ($string ne "") { + print "$string\n"; + } + + close(SOCK); + close(TMPFILE); + unlink($tmpfile); + + if ($string eq "") { + exit(0); + } else { + exit(1); + } +} diff --git a/clients/lcdproc/Makefile b/clients/lcdproc/Makefile new file mode 100644 index 0000000..1d812b5 --- /dev/null +++ b/clients/lcdproc/Makefile @@ -0,0 +1,41 @@ +include ../../Makefile.config + +######################################################################## +# You shouldn't need to touch anything below here. +######################################################################## + +TARGET = lcdproc +OBJ = main.o mode.o batt.o chrono.o cpu.o disk.o load.o mem.o +LIB += -L../../shared -lLCDstuff + + +################################################################### +# Compilation... +# + +all: $(TARGET) + +$(TARGET): $(OBJ) Makefile + $(GCC) -s $(MISC) -o $(TARGET) $(OBJ) $(LIB) + +%.o: %.c %.h Makefile + $(GCC) -c $(MISC) $< + + +################################################################## +# Installation +# +install: $(TARGET) + @echo ... lcdproc main client ... + install -m 0755 -o root -g root $(TARGET) /usr/local/bin/ + + +################################################################## +# Other stuff... +# +clean: + rm -f $(OBJ) $(TARGET) *~ core + +edit: + emacs . & + diff --git a/clients/lcdproc/batt.c b/clients/lcdproc/batt.c new file mode 100644 index 0000000..522f2f8 --- /dev/null +++ b/clients/lcdproc/batt.c @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include +#include + +#include "../../shared/sockets.h" + +#include "main.h" +#include "mode.h" +#include "batt.h" + +int batt_fd = 0; + + +static int get_batt_stat(int *acstat, int *battstat, + int *battflag, int *percent); + +static int get_batt_stat(int *acstat, int *battstat, + int *battflag, int *percent) +{ + char str[64]; + + if(!batt_fd) + batt_fd = open("/proc/apm", O_RDONLY); + if(batt_fd <= 0) return -1; + + if(lseek(batt_fd, 0, 0) != 0) return -1; + + if(read(batt_fd, str, sizeof(str)-1) < 0) return -1; + + if(3 > sscanf(str+13, "0x%x 0x%x 0x%x %d", + acstat, battstat, battflag, percent)) + return -1; + + return 0; + +} + + + +int batt_init() +{ + static int first = 1; + + if(first) + { + first = 0; + sock_send_string(sock, "screen_add B\n"); + } + + return 0; +} + +int batt_close() +{ + if(batt_fd) close(batt_fd); + batt_fd = 0; + + return 0; +} + + +//////////////////////////////////////////////////////////////////////// +// Battery Screen shows apm battery status... +// + +//#################### +//## Battery: 100% ### +//AC: Unknown +//Batt: Low (Charging) +//E------------------F + +int battery_screen(int rep, int display) +{ + static int first=1; + + int acstat=0, battstat=0, battflag=0, percent=0; + + + if(first) + { + first = 0; + + sprintf(buffer, "screen_set B name {APM stats: %s}\n", host); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add B title title\n"); + sprintf(tmp, "widget_set B title {LCDPROC %s}\n", version); + sock_send_string(sock, tmp); + sock_send_string(sock, "widget_add B one string\n"); + if(lcd_hgt >= 4) + { + sock_send_string(sock, "widget_add B two string\n"); + sock_send_string(sock, "widget_add B three string\n"); + sock_send_string(sock, "widget_add B gauge hbar\n"); + sock_send_string(sock, + "widget_set B one 1 2 {AC: Unknown}\n"); + sock_send_string(sock, + "widget_set B two 1 3 {Batt: Unknown}\n"); + sock_send_string(sock, + "widget_set B three 1 4 {E F}\n"); + sock_send_string(sock, "widget_set B gauge 2 4 0\n"); + } + } + + // Only run once every 16 frames... + //if(rep&0x0f) return 0; + + get_batt_stat(&acstat, &battstat, &battflag, &percent); + + + if(percent >= 0) sprintf(buffer, "%i%%", percent); + else sprintf(buffer, "??%%"); + sprintf(tmp, "widget_set B title {Batt: %s: %s}\n", buffer, host); + + if(display) sock_send_string(sock, tmp); + + + if(lcd_hgt >= 4) // 4-line version of the screen + { + sprintf(tmp, "widget_set B one 1 2 {"); + switch(acstat) + { + case 0: sprintf(tmp+strlen(tmp), "AC: Off}\n"); + break; + case 1: sprintf(tmp+strlen(tmp), "AC: On}\n"); + break; + case 2: sprintf(tmp+strlen(tmp), "AC: Backup}\n"); + break; + default: sprintf(tmp+strlen(tmp), "AC: Unknown}\n"); + break; + } + + if(display) sock_send_string(sock, tmp); + + + + sprintf(tmp, "widget_set B two 1 3 {"); + if(battflag == 0xff) + { + sprintf(tmp+strlen(tmp), "Battery Stat Unknown"); + } + else + { + sprintf(tmp+strlen(tmp), "Batt:"); + if(battflag & 1) sprintf(tmp+strlen(tmp), " High"); + if(battflag & 2) sprintf(tmp+strlen(tmp), " Low"); + if(battflag & 4) sprintf(tmp+strlen(tmp), " Critical"); + if(battflag & 8 + ||battstat == 3) sprintf(tmp+strlen(tmp), " Charging"); + if(battflag & 128) sprintf(tmp+strlen(tmp), " (NONE)"); + } + sprintf(tmp+strlen(tmp), "}\n"); + if(display) sock_send_string(sock, tmp); + + + if(percent > 0) + { + sprintf(tmp, "widget_set B gauge 2 4 %i\n", + (percent * ((lcd_wid-2)*lcd_cellwid)/100)); + if(display) sock_send_string(sock, tmp); + } + } // end if(lcd_hgt >= 4) + else // two-line version of the screen + { + sprintf(tmp, "widget_set B one 1 2 {"); + if(acstat == 1) + sprintf(tmp+strlen(tmp), "AC, "); + + if(battflag == 0xff) + { + sprintf(tmp+strlen(tmp), "No battery???"); + } + else + { + sprintf(tmp+strlen(tmp), "Batt:"); + if(battflag & 1) sprintf(tmp+strlen(tmp), " High"); + if(battflag & 2) sprintf(tmp+strlen(tmp), " Low"); + if(battflag & 4) sprintf(tmp+strlen(tmp), " Critical"); + if(battflag & 8 + ||battstat == 3) sprintf(tmp+strlen(tmp), " Charging"); + if(battflag & 128) sprintf(tmp+strlen(tmp), " (NONE)"); + } + sprintf(tmp+strlen(tmp), "}\n"); + if(display) sock_send_string(sock, tmp); + + } + + return 0; +} + + diff --git a/clients/lcdproc/batt.h b/clients/lcdproc/batt.h new file mode 100644 index 0000000..b079806 --- /dev/null +++ b/clients/lcdproc/batt.h @@ -0,0 +1,10 @@ +#ifndef BATT_H +#define BATT_H + +int batt_init(); +int batt_close(); + +int battery_screen(int rep, int display); + + +#endif diff --git a/clients/lcdproc/chrono.c b/clients/lcdproc/chrono.c new file mode 100644 index 0000000..08cbbd7 --- /dev/null +++ b/clients/lcdproc/chrono.c @@ -0,0 +1,566 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../../shared/sockets.h" + +#include "main.h" +#include "mode.h" +#include "chrono.h" + +int TwentyFourHour=1; +int uptime_fd = 0; + +static char kver[SYS_NMLN]; +static char sysname[SYS_NMLN]; + +static double get_uptime(double *up, double *idle); + + +static double get_uptime(double *up, double *idle) +{ + double uptime; + + reread(uptime_fd, "get_uptime:"); + sscanf(buffer, "%lf %lf", &uptime, idle); + + *up = uptime; + + return uptime; +} + + +// A couple of tables for later use... +static char *days[] = { + "Sunday, ", + "Monday, ", + "Tuesday, ", + "Wednesday,", + "Thursday, ", + "Friday, ", + "Saturday, ", +}; +static char *shortdays[] = { + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", +}; + +static char *months[] = { + " January", + " February", + " March", + " April", + " May", + " June", + " July", + " August", + "September", + " October", + " November", + " December", +}; +static char *shortmonths[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +}; + + + +int chrono_init() +{ + struct utsname *unamebuf; + + if(!uptime_fd) + { + unamebuf = (struct utsname *) malloc( sizeof(struct utsname) ); + uptime_fd = open("/proc/uptime",O_RDONLY); + +#if 0 + kversion_fd = open("/proc/sys/kernel/osrelease",O_RDONLY); + + reread(kversion_fd, "main:"); + sscanf(buffer, "%s", kver); + + close(kversion_fd); +# endif + + /* Get OS name and version from uname() */ + if( uname( unamebuf ) != 0 ) { + perror( "Error calling uname:" ); + } + strcpy( kver, unamebuf->release ); + strcpy( sysname, unamebuf->sysname ); + + free(unamebuf); + + + + } + + return 0; +} + + +int chrono_close() +{ + if(uptime_fd) + close(uptime_fd); + + uptime_fd = 0; + + return 0; +} + + + +////////////////////////////////////////////////////////////////////// +// Time Screen displays current time and date, uptime, OS ver... +// +//+--------------------+ +//|## Linux 2.0.33 ###@| +//|Up xxx days hh:mm:ss| +//| Wed May 17, 1998 | +//|11:32:57a 100% idle| +//+--------------------+ +// + +int time_screen(int rep, int display) +{ + char hr[8], min[8], sec[8], ampm[8]; + char day[16], month[16]; + static int first = 1; + static int colons = 0; + time_t thetime; + struct tm *rtime; + double uptime, idle; + int i = 0; + char colon; + + + + if(first) + { + first = 0; + + sock_send_string(sock, "screen_add T\n"); + sprintf(buffer, "screen_set T name {Time Screen: %s}\n", host); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add T title title\n"); + sock_send_string(sock, "widget_set T title {Time Screen}\n"); + sock_send_string(sock, "widget_add T one string\n"); + if(lcd_hgt >= 4) + { + sock_send_string(sock, "widget_add T two string\n"); + sock_send_string(sock, "widget_add T three string\n"); + } + else + { + sprintf(buffer, "widget_set T title {TIME: %s}\n", host); + sock_send_string(sock, buffer); + } + } + + + if(colons) + colon = ':'; + else + colon = ' '; + + + time(&thetime); + rtime = localtime(&thetime); + + + if(TwentyFourHour) + { + sprintf(hr, "%02d", rtime->tm_hour); + } + else + { + if (rtime->tm_hour > 12) + { + i = 1; sprintf(hr, "%02d", (rtime->tm_hour - 12)); + } + else if(rtime->tm_hour == 0) + { + i = 0; sprintf(hr, "12"); + } + else + { + i = 0; sprintf(hr, "%02d", rtime->tm_hour); + } + } + if(rtime->tm_hour >= 12) sprintf(ampm, "%s", "P"); + else sprintf(ampm, "%s", "A"); + + sprintf(min, "%02d", rtime->tm_min); + sprintf(sec, "%02d", rtime->tm_sec); + + + strcpy(day, shortdays[rtime->tm_wday]); + strcpy(month, shortmonths[rtime->tm_mon]); + + + + ///////////////////// Write the title bar (os name and version) + + if(lcd_hgt >= 4) + { + sprintf(tmp, "widget_set T title {"); + sprintf(tmp+strlen(tmp), "%s %s: %s}\n", + sysname, kver, host); + if(display) sock_send_string(sock, tmp); + } + + + /////////////////////// Display the time... + if(lcd_hgt >= 4) + { + get_uptime(&uptime, &idle); + idle = (idle * 100) / uptime; + + + if(TwentyFourHour) + sprintf(tmp, "%s%c%s%c%s %2i%% idle", + hr, colon, min, colon, sec, (int)idle); + else + sprintf(tmp, "%s%c%s%c%s%s %2i%% idle", + hr, colon, min, colon, sec, ampm, (int)idle); + // Center the output line... + i = ((lcd_wid - strlen(tmp)) / 2) + 1; + sprintf(buffer, "widget_set T three %i 4 {%s}\n", i, tmp); + if(display) sock_send_string(sock, buffer); + + + + sprintf(tmp, "%s %s %d, %d", day, month, + rtime->tm_mday, (rtime->tm_year + 1900)); + sprintf(buffer, "widget_set T two 3 3 {%s}\n", tmp); + if(display) sock_send_string(sock, buffer); + + + /////////////////////// Display the uptime... + i = (int)uptime / 86400; + sprintf(day, "Up %d day%s,", i, (i != 1 ? "s" : "")); + i = ((int)uptime % 86400) / 60 / 60; + sprintf(hr, "%02i",i); + i = (((int)uptime % 86400) % 3600) / 60; + sprintf(min, "%02i",i); + i = ((int)uptime % 60); + sprintf(sec, "%02i",i); + if (colons) + sprintf(tmp, "%s %s:%s:%s", day, hr, min, sec); + else + sprintf(tmp, "%s %s %s %s", day, hr, min, sec); + //// Center this line automatically... + //i = ((lcd_wid - strlen(tmp)) / 2) + 1; + sprintf(buffer, "widget_set T one 1 2 {%s}\n", tmp); + if(display) sock_send_string(sock, buffer); + + + } + else // 20x2 version of the screen + { + sprintf(tmp, "widget_set T one 1 2 {"); + if(lcd_wid >= 20) + sprintf(tmp+strlen(tmp), "%d-%02d-%02d ", + rtime->tm_year+1900, rtime->tm_mon+1, rtime->tm_mday); + else // 16x2 version... + sprintf(tmp+strlen(tmp), "%02d/%02d ", + rtime->tm_mon+1, rtime->tm_mday); + sprintf(tmp+strlen(tmp), "%s%c%s%c%s", hr, colon, min, colon, sec); + if(! TwentyFourHour) + sprintf(tmp+strlen(tmp), "%s", ampm); + sprintf(tmp+strlen(tmp), "}\n"); + if(display) sock_send_string(sock, tmp); + } + + + + colons = colons ^ 1; + + return 0; +} // End time_screen() + + + +////////////////////////////////////////////////////////////////////// +// Clock Screen displays current time and date... +// +int clock_screen(int rep, int display) +{ + char hr[8], min[8], sec[8], ampm[8]; + char day[16], month[16]; + static int first = 1; + static int colons = 0; + time_t thetime; + struct tm *rtime; + int i=0; + char colon; + + if(lcd_hgt < 4) return 0; + + if(first) + { + first = 0; + + sock_send_string(sock, "screen_add O\n"); + sprintf(buffer, "screen_set O name {Clock Screen: %s}\n", host); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add O title title\n"); + sock_send_string(sock, "widget_add O one string\n"); + if(lcd_hgt >= 4) + { + sock_send_string(sock, "widget_set O title {DATE & TIME}\n"); + sock_send_string(sock, "widget_add O two string\n"); + sock_send_string(sock, "widget_add O three string\n"); + sprintf(buffer, "widget_set O one 3 2 {%s}\n", host); + sock_send_string(sock, buffer); + } + else + { + sprintf(buffer, "widget_set O title {TIME: %s}\n", host); + sock_send_string(sock, buffer); + } + } + + + if(colons) + colon = ':'; + else + colon = ' '; + + time(&thetime); + rtime = localtime(&thetime); + + strcpy(day, days[rtime->tm_wday]); + + if(TwentyFourHour) + { + sprintf(hr, "%02d", rtime->tm_hour); + } + else + { + if (rtime->tm_hour > 12) + { + i = 1; sprintf(hr, "%02d", (rtime->tm_hour - 12)); + } + else + { + i = 0; sprintf(hr, "%02d", rtime->tm_hour); + } + } + if(rtime->tm_hour == 12) i=1; + sprintf(min, "%02d", rtime->tm_min); + sprintf(sec, "%02d", rtime->tm_sec); + if (i == 1) { sprintf(ampm, "%s", "P"); } + else { sprintf(ampm, "%s", "A"); } + strcpy(month, months[rtime->tm_mon]); + + + if(lcd_hgt >= 4) // 4-line version of the screen + { + sprintf(tmp, "widget_set O two 1 3 {"); + if(TwentyFourHour) + sprintf(tmp+strlen(tmp), "%s%c%s%c%s %s", + hr, colon, min, colon, sec, day); + else + sprintf(tmp+strlen(tmp), "%s%c%s%c%s%s %s", + hr, colon, min, colon, sec, ampm, day); + sprintf(tmp+strlen(tmp), "}\n"); + if(display) sock_send_string(sock, tmp); + + + sprintf(tmp, "widget_set O three 2 4 {"); + sprintf(tmp+strlen(tmp), + "%s %d, %d", + month, + rtime->tm_mday, + (rtime->tm_year + 1900)); + sprintf(tmp+strlen(tmp), "}\n"); + if(display) sock_send_string(sock, tmp); + } // end if(lcd_hgt >= 4) + else // 20x2 version of the screen + { + sprintf(tmp, "widget_set O one 1 2 {"); + sprintf(tmp+strlen(tmp), "%d-%02d-%02d ", + rtime->tm_year+1900, rtime->tm_mon+1, rtime->tm_mday); + sprintf(tmp+strlen(tmp), "%s%c%s%c%s", hr, colon, min, colon, sec); + if(! TwentyFourHour) + sprintf(tmp+strlen(tmp), "%s", ampm); + sprintf(tmp+strlen(tmp), "}\n"); + if(display) sock_send_string(sock, tmp); + } + + colons = colons ^ 1; + + return 0; +} // End clock_screen() + + + +//////////////////////////////////////////////////////////////////// +// Uptime Screen shows info about system uptime and OS version +// +int uptime_screen(int rep, int display) +{ + int i; + char date[16], hour[8], min[8], sec[8]; + double uptime, idle; + static int first = 1; + static int colons = 0; + char colon; + + if(first) + { + first = 0; + + sock_send_string(sock, "screen_add U\n"); + sprintf(buffer, "screen_set U name {Uptime Screen: %s}\n", host); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add U title title\n"); + if(lcd_hgt >= 4) + { + sock_send_string(sock, "widget_set U title {SYSTEM UPTIME}\n"); + sock_send_string(sock, "widget_add U one string\n"); + sock_send_string(sock, "widget_add U two string\n"); + sock_send_string(sock, "widget_add U three string\n"); + + sprintf(buffer, "widget_set U one 3 2 {%s}\n", host); + sock_send_string(sock, buffer); + sprintf(tmp, "widget_set U three 5 4 {%s %s}\n", sysname, kver); + sock_send_string(sock, tmp); + } + else + { + sprintf(tmp, "widget_set U title {%s %s: %s}\n", + sysname, kver, host); + sock_send_string(sock, tmp); + sock_send_string(sock, "widget_add U one string\n"); + } + } + + if(colons) + colon = ':'; + else + colon = ' '; + + get_uptime(&uptime, &idle); + i = (int)uptime / 86400; + sprintf(date, "%d day%s,", i, (i != 1 ? "s" : "")); + i = ((int)uptime % 86400) / 60 / 60; + sprintf(hour, "%02i",i); + i = (((int)uptime % 86400) % 3600) / 60; + sprintf(min, "%02i",i); + i = ((int)uptime % 60); + sprintf(sec, "%02i",i); + sprintf(tmp, "%s %s%c%s%c%s", date, hour, colon, min, colon, sec); + i = ((20 - strlen(tmp)) / 2) + 1; + + if(lcd_hgt >= 4) + sprintf(buffer, "widget_set U two %i 3 {%s}\n", i, tmp); + else + sprintf(buffer, "widget_set U one %i 2 {%s}\n", i, tmp); + if(display) sock_send_string(sock, buffer); + + colons = colons ^ 1; + + return 0; +} // End uptime_screen() + + +////////////////////////////////////////////////////////////////////// +// Big Clock Screen displays current time... +// +//Curses display is ugly, but should look nice on Matrix Orbital. +// +//+--------------------+ +//|111555 444222 111333| +//|111555 444222 111333| +//|111555 444222 111333| +//|111555 444222 111333| +//+--------------------+ +// +int big_clock_screen(int rep, int display) +{ + static int first = 1; + static int colons = 0; + time_t thetime; + struct tm *rtime; + int pos[]={1,4,8,11,15,18}; + // int i=0; + + char fulltxt[16], old_fulltxt[16]; + int j=0; + + if(lcd_hgt < 4) return 0; + + if(first) + { + first = 0; + + sock_send_string(sock, "screen_add K\n"); + sock_send_string(sock, "screen_set K name {Big Clock Screen}\n"); + sock_send_string(sock, "widget_del K heartbeat\n"); + sock_send_string(sock, "widget_add K d0 num\n"); + sock_send_string(sock, "widget_add K d1 num\n"); + sock_send_string(sock, "widget_add K d2 num\n"); + sock_send_string(sock, "widget_add K d3 num\n"); + sock_send_string(sock, "widget_add K d4 num\n"); + sock_send_string(sock, "widget_add K d5 num\n"); +// sock_send_string(sock, "widget_add K one string\n"); + sock_send_string(sock, "widget_set K d0 1 0\n"); + sock_send_string(sock, "widget_set K d1 4 0\n"); + sock_send_string(sock, "widget_set K d2 8 0\n"); + sock_send_string(sock, "widget_set K d3 11 0\n"); + sock_send_string(sock, "widget_set K d4 15 0\n"); + sock_send_string(sock, "widget_set K d5 18 0\n"); + old_fulltxt[0]='0'; + old_fulltxt[1]='0'; + old_fulltxt[2]='0'; + old_fulltxt[3]='0'; + old_fulltxt[4]='0'; + old_fulltxt[5]='0'; + old_fulltxt[6]=0; +// sock_send_string(sock, "widget_set K one 1 4 {000000}\n"); + } + + time(&thetime); + rtime = localtime(&thetime); + + sprintf(fulltxt, "%02d%02d%02d", + rtime->tm_hour, rtime->tm_min, rtime->tm_sec); + for(j=0;j<6;j++){ + if (fulltxt[j]!=old_fulltxt[j]){ + sprintf(tmp+strlen(tmp), "widget_set K d%d %d %c\n", + j, pos[j], fulltxt[j]); + old_fulltxt[j]=fulltxt[j]; + } + } + + if(display) + sock_send_string(sock, tmp); + + return 0; +} // End big_clock_screen() + + diff --git a/clients/lcdproc/chrono.h b/clients/lcdproc/chrono.h new file mode 100644 index 0000000..9c83c27 --- /dev/null +++ b/clients/lcdproc/chrono.h @@ -0,0 +1,12 @@ +#ifndef CHRONO_H +#define CHRONO_H + +int chrono_init(); +int chrono_close(); + +int clock_screen(int rep, int display); +int uptime_screen(int rep, int display); +int time_screen(int rep, int display); +int big_clock_screen(int rep, int display); + +#endif diff --git a/clients/lcdproc/cpu.c b/clients/lcdproc/cpu.c new file mode 100644 index 0000000..9dd1c2f --- /dev/null +++ b/clients/lcdproc/cpu.c @@ -0,0 +1,365 @@ +#include +#include +#include +#include +#include + +#include "../../shared/sockets.h" +#include "../../shared/debug.h" + +#include "main.h" +#include "mode.h" +#include "cpu.h" + +struct load { unsigned long total, user, system, nice, idle; }; + +int load_fd = 0; +static void get_load(struct load * result); + + +static void get_load(struct load * result) +{ + static struct load last_load = { 0, 0, 0, 0, 0 }; struct load curr_load; + + reread(load_fd, "get_load:"); + sscanf(buffer, "%*s %lu %lu %lu %lu\n", + &curr_load.user, + &curr_load.nice, + &curr_load.system, + &curr_load.idle); + curr_load.total = curr_load.user + + curr_load.nice + + curr_load.system + + curr_load.idle; + result->total = curr_load.total - last_load.total; + result->user = curr_load.user - last_load.user; + result->nice = curr_load.nice - last_load.nice; + result->system = curr_load.system - last_load.system; + result->idle = curr_load.idle - last_load.idle; + last_load.total = curr_load.total; + last_load.user = curr_load.user; + last_load.nice = curr_load.nice; + last_load.system = curr_load.system; + last_load.idle = curr_load.idle; +} + + + +int cpu_init() +{ + if(!load_fd) + { + load_fd = open("/proc/stat",O_RDONLY); + } + + return 0; +} + +int cpu_close() +{ + if(load_fd) + close(load_fd); + + load_fd = 0; + + return 0; +} + + +////////////////////////////////////////////////////////////////////////// +// CPU screen shows info about percentage of the CPU being used +// +int cpu_screen(int rep, int display) +{ +#undef CPU_BUF_SIZE +#define CPU_BUF_SIZE 4 + int i, j, n; + static int first = 1; + float value; + static float cpu[CPU_BUF_SIZE + 1][5];// last buffer is scratch + struct load load; + + + if(first) + { + first = 0; + + sock_send_string(sock, "screen_add C\n"); + sprintf(buffer, "screen_set C name {CPU Use: %s}\n", host); + sock_send_string(sock, buffer); + if(lcd_hgt >= 4) + { + sock_send_string(sock, "widget_add C title title\n"); + sock_send_string(sock, "widget_set C title {CPU LOAD}\n"); + sock_send_string(sock, "widget_add C one string\n"); + sock_send_string(sock, + "widget_set C one 1 2 {0 1 Sys 0.0%}\n"); + sock_send_string(sock, "widget_add C two string\n"); + sock_send_string(sock, "widget_add C three string\n"); + sock_send_string(sock, + "widget_set C one 1 2 {Usr 0.0% Nice 0.0%}\n"); + sock_send_string(sock, + "widget_set C two 1 3 {Sys 0.0% Idle 0.0%}\n"); + sock_send_string(sock, + "widget_set C three 1 4 {0% 100%}\n"); + sock_send_string(sock, "widget_add C usr string\n"); + sock_send_string(sock, "widget_add C nice string\n"); + sock_send_string(sock, "widget_add C idle string\n"); + sock_send_string(sock, "widget_add C sys string\n"); + sock_send_string(sock, "widget_add C bar hbar\n"); + sock_send_string(sock, "widget_set C bar 3 4 0\n"); + } + else + { + sock_send_string(sock, "widget_add C cpu0 string\n"); + if(lcd_wid >= 20) + sock_send_string(sock, "widget_set C cpu0 1 1 {CPU0[ ]}\n"); + else + sock_send_string(sock, "widget_set C cpu0 1 1 {CPU0[ ]}\n"); + sock_send_string(sock, "widget_add C cpu0% string\n"); + sprintf(buffer, "widget_set C cpu0%% 1 %i { 0.0%%}\n", lcd_wid-4); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add C usni string\n"); + sock_send_string(sock, + "widget_set C usni 1 2 { U S N I}\n"); + sock_send_string(sock, "widget_add C usr hbar\n"); + sock_send_string(sock, "widget_add C sys hbar\n"); + sock_send_string(sock, "widget_add C nice hbar\n"); + sock_send_string(sock, "widget_add C idle hbar\n"); + sock_send_string(sock, "widget_add C total hbar\n"); + sock_send_string(sock, "widget_set C total 6 1 0\n"); + } + + return 0; + } + //else return 0; + + get_load(&load); + + // Shift values over by one + for(i=0; i<(CPU_BUF_SIZE-1); i++) + for(j=0; j<5; j++) + cpu[i][j] = cpu[i+1][j]; + + // Read new data + cpu[CPU_BUF_SIZE-1][0] = ((float)load.user / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][1] = ((float)load.system / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][2] = ((float)load.nice / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][3] = ((float)load.idle / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][4] = (((float)load.user + (float)load.system + + (float)load.nice) / (float)load.total) * 100.0; + + // Only clear on first display... + if(!rep) + { + /* + // Make all the same, if this is the first time... + for(i=0; i= 4) + { + value = cpu[CPU_BUF_SIZE][4]; + n = (int)(value * 70.0); + if (value >= 99.9) { sprintf(tmp, "100%%"); } + else { sprintf(tmp, "%4.1f%%", value); } + sprintf(buffer, "widget_set C title {CPU %s: %s}\n", tmp, host); + if(display) sock_send_string(sock, buffer); + + value = cpu[CPU_BUF_SIZE][0]; + if (value >= 99.9) { sprintf(tmp, " 100%%"); } + else { sprintf(tmp, "%4.1f%%", value); } + sprintf(buffer, "widget_set C usr 5 2 {%s}\n", tmp); + if(display) sock_send_string(sock, buffer); + + value = cpu[CPU_BUF_SIZE][1]; + if (value >= 99.9) { sprintf(tmp, " 100%%"); } + else { sprintf(tmp, "%4.1f%%", value); } + sprintf(buffer, "widget_set C sys 5 3 {%s}\n", tmp); + if(display) sock_send_string(sock, buffer); + + value = cpu[CPU_BUF_SIZE][2]; + if (value >= 99.9) { sprintf(tmp, " 100%%"); } + else { sprintf(tmp, "%4.1f%%", value); } + sprintf(buffer, "widget_set C nice 16 2 {%s}\n", tmp); + if(display) sock_send_string(sock, buffer); + + value = cpu[CPU_BUF_SIZE][3]; + if (value >= 99.9) { sprintf(tmp, " 100%%"); } + else { sprintf(tmp, "%4.1f%%", value); } + sprintf(buffer, "widget_set C idle 16 3 {%s}\n", tmp); + if(display) sock_send_string(sock, buffer); + + value = cpu[CPU_BUF_SIZE][4]; + n = (int)(value * (lcd_cellwid * 14) / 100.0); + sprintf(buffer, "widget_set C bar 3 4 %i\n", n); + if(display) sock_send_string(sock, buffer); + } // end if(lcd_hgt >= 4) + else // 20x2 version + { + value = cpu[CPU_BUF_SIZE][4]; + if (value >= 99.9) { sprintf(tmp, "100%%"); } + else { sprintf(tmp, "%4.1f%%", value); } + sprintf(buffer, "widget_set C cpu0%% %i 1 {%s}\n", lcd_wid-4, tmp); + if(display) sock_send_string(sock, buffer); + + n = (float)(value * lcd_cellwid * (float)(lcd_wid-11)) / 100.0; + sprintf(buffer, "widget_set C total 6 1 %i\n", n); + if(display) sock_send_string(sock, buffer); + + value = cpu[CPU_BUF_SIZE][0]; + n = (float)(value * lcd_cellwid * 4.0) / 100.0; + sprintf(buffer, "widget_set C usr 1 2 %i\n", n); + if(display) sock_send_string(sock, buffer); + + value = cpu[CPU_BUF_SIZE][1]; + n = (float)(value * lcd_cellwid * 3.0) / 100.0; + sprintf(buffer, "widget_set C sys 7 2 %i\n", n); + if(display) sock_send_string(sock, buffer); + + value = cpu[CPU_BUF_SIZE][2]; + n = (float)(value * lcd_cellwid * 3.0) / 100.0; + sprintf(buffer, "widget_set C nice 12 2 %i\n", n); + if(display) sock_send_string(sock, buffer); + + value = cpu[CPU_BUF_SIZE][3]; + n = (float)(value * lcd_cellwid * 3.0) / 100.0; + sprintf(buffer, "widget_set C idle 17 2 %i\n", n); + if(display) sock_send_string(sock, buffer); + + } + + return 0; +} // End cpu_screen() + + + +////////////////////////////////////////////////////////////////////////// +// Cpu Graph Screen shows a quick-moving histogram of CPU use. +// +int cpu_graph_screen(int rep, int display) +{ + int i, j, n=0; + static int first=1; + float value, maxload; +#undef CPU_BUF_SIZE +#define CPU_BUF_SIZE 2 + static float cpu[CPU_BUF_SIZE + 1];// last buffer is scratch + static int cpu_past[LCD_MAX_WIDTH]; + struct load load; + int status=0; + + + if(first) + { + first = 0; + sock_send_string(sock, "screen_add G\n"); + sprintf(buffer, "screen_set G name {CPU Graph: %s}\n", host); + sock_send_string(sock, buffer); + if(lcd_hgt >= 4) + { + sock_send_string(sock, "widget_add G title title\n"); + sprintf(buffer, "widget_set G title {CPU: %s}\n", host); + } + else + { + sock_send_string(sock, "widget_add G title string\n"); + sprintf(buffer, "widget_set G title 1 1 {CPU: %s}\n", host); + } + sock_send_string(sock, buffer); + + for(i=1; i<=lcd_wid; i++) + { + sprintf(tmp, "widget_add G %i vbar\n", i); + sock_send_string(sock, tmp); + sprintf(tmp, "widget_set G %i %i %i 0\n", i, i, lcd_hgt); + sock_send_string(sock, tmp); + } + } + + get_load(&load); + + // Shift values over by one + for(i=0; i<(CPU_BUF_SIZE-1); i++) + cpu[i] = cpu[i+1]; + + // Read new data + cpu[CPU_BUF_SIZE-1] = ((float)load.user + (float)load.system + + (float)load.nice) / (float)load.total; + + + // Only clear on first display... + if(!rep) + { + /* + // Make all the same, if this is the first time... + for(i=0; i maxload) maxload = cpu_past[i]; + } + + value = cpu[CPU_BUF_SIZE]; + if(lcd_hgt > 2) + n = (int)(value * (float)(lcd_cellhgt) * (float)(lcd_hgt-1)); + else + n = (int)(value * (float)(lcd_cellhgt) * (float)(lcd_hgt)); + + cpu_past[lcd_wid-1] = n; + sprintf(tmp, "widget_set G %i %i %i %i\n", + lcd_wid, lcd_wid, lcd_hgt, n); + if(display) sock_send_string(sock, tmp); + + + + if(n > maxload) maxload = n; + + if(cpu_past[lcd_wid-1] > 0 ) status = BACKLIGHT_ON; + if(maxload < 1) status = BACKLIGHT_OFF; + +// return status; + return 0; +} // End cpu_graph_screen() + + diff --git a/clients/lcdproc/cpu.h b/clients/lcdproc/cpu.h new file mode 100644 index 0000000..a0b3681 --- /dev/null +++ b/clients/lcdproc/cpu.h @@ -0,0 +1,12 @@ +#ifndef CPU_H +#define CPU_H + + +int cpu_init(); +int cpu_close(); + + +int cpu_screen(int rep, int display); +int cpu_graph_screen(int rep, int display); + +#endif diff --git a/clients/lcdproc/disk.c b/clients/lcdproc/disk.c new file mode 100644 index 0000000..dc91d41 --- /dev/null +++ b/clients/lcdproc/disk.c @@ -0,0 +1,322 @@ +#include +#include +#include +#include +#include + +#ifdef LINUX +#include +#else +#ifdef xBSD +#include +#include +#else +#include +#endif + +#endif + + +#include "../../shared/sockets.h" + +#include "main.h" +#include "mode.h" +#include "disk.h" + +FILE *mtab_fd; + + +typedef struct mounts +{ + char dev[256], type[64], mpoint[256]; + long bsize, blocks, bfree, files, ffree; +} mounts; + + + +static int get_fs(mounts fs[]) +{ + struct statfs fsinfo; + char line[256]; + int x = 0, y; + + mtab_fd = fopen("/etc/mtab", "r"); + + // Get rid of old, unmounted filesystems... + memset(fs, 0, sizeof(mounts)*256); + + while (x < 256) + { + if(fgets(line, 256, mtab_fd) == NULL) + { + fclose(mtab_fd); + return x; + } + + sscanf(line, "%s %s %s", fs[x].dev, fs[x].mpoint, fs[x].type); + + if(strcmp(fs[x].type, "proc") +#ifndef STAT_NFS + && strcmp(fs[x].type, "nfs") +#endif +#ifndef STAT_SMBFS + && strcmp(fs[x].type, "smbfs") +#endif + ) + { +#if LINUX || BSD + y = statfs(fs[x].mpoint, &fsinfo); +#else + y = statfs(fs[x].mpoint, &fsinfo, sizeof(fsinfo), 0); +#endif + fs[x].blocks = fsinfo.f_blocks; + if(fs[x].blocks > 0) + { + fs[x].bsize = fsinfo.f_bsize; + fs[x].bfree = fsinfo.f_bfree; + fs[x].files = fsinfo.f_files; + fs[x].ffree = fsinfo.f_ffree; + x++; + } + } + } + + fclose(mtab_fd); + return x; +} + +#if 0 +static int get_fs(mounts fs[]) +{ + struct statfs fsinfo; + char line[256]; + int x = 0, y; + + mtab_fd = fopen("/etc/mtab", "r"); + + // Get rid of old, unmounted filesystems... + memset(fs, 0, sizeof(mounts)*256); + + while (x < 256) + { + if(fgets(line, 256, mtab_fd) == NULL) + { + fclose(mtab_fd); + return x; + } + + sscanf(line, "%s %s %s", fs[x].dev, fs[x].mpoint, fs[x].type); + + if( strcmp(fs[x].type, "proc") +#ifndef STAT_NFS + && strcmp(fs[x].type, "nfs") +#endif +#ifndef STAT_SMBFS + && strcmp(fs[x].type, "smbfs") +#endif + ) + { +#ifdef LINUX + y = statfs(fs[x].mpoint, &fsinfo); +#else + y = statfs(fs[x].mpoint, &fsinfo, sizeof(fsinfo), 0); +#endif + fs[x].bsize = fsinfo.f_bsize; + fs[x].blocks = fsinfo.f_blocks; + fs[x].bfree = fsinfo.f_bfree; + fs[x].files = fsinfo.f_files; + fs[x].ffree = fsinfo.f_ffree; + x++; + } + } + + fclose(mtab_fd); + return x; +} +#endif + + +int disk_init() +{ + + return 0; +} + +int disk_close() +{ + + return 0; +} + + +/////////////////////////////////////////////////////////////////////////// +// Gives disk stats. +// +// Stays onscreen until it is done. +// + +// TODO: Disk screen! Requires virtual pages in the server, though... + +int disk_screen(int rep, int display) +{ + static mounts mnt[256]; + static int count=0; + + // Holds info to display (avoid recalculating it) + struct disp + { + char dev[8]; + char cap[8]; + int full; + } table[256]; + int i; + static int num_disks=0; + static int first=1; // First line to display, sort of. + +#define huge long long int + huge size; + + + if(first) + { + first = 0; + + sock_send_string(sock, "screen_add D\n"); + sprintf(buffer, "screen_set D name {Disk Use: %s}\n", host); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add D title title\n"); + sprintf(buffer, "widget_set D title {DISKS: %s}\n", host); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add D f frame\n"); + //sock_send_string(sock, "widget_set D f 1 2 20 4 20 3 v 8\n"); + sprintf(buffer, "widget_set D f 1 2 %i %i %i %i v 12\n", + lcd_wid, lcd_hgt, lcd_wid, lcd_hgt-1); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add D err1 string\n"); + sock_send_string(sock, "widget_add D err2 string\n"); + sock_send_string(sock, "widget_set D err1 5 2 { Reading }\n"); + sock_send_string(sock, "widget_set D err2 5 3 {Filesystems}\n"); + } + + + + // Grab disk stats on first display, and fill "table". + // Get rid of old, unmounted filesystems... + memset(table, 0, sizeof(struct disp)*256); + + count = get_fs(mnt); + first = 0; + + // Fill the display structure... + if(count) + { + sock_send_string(sock, "widget_set D err1 30 5 .\n"); + sock_send_string(sock, "widget_set D err2 30 5 .\n"); + for(i=0; i 6) + { + sprintf(table[i].dev, "%c%s", ELLIPSIS, + (mnt[i].mpoint)+(strlen(mnt[i].mpoint)-5)); + } + else + { + sprintf(table[i].dev, "%s", mnt[i].mpoint); + } + + //table[i].full = (lcd.cellwid * 4) + table[i].full = (huge)(lcd_cellwid * 4) + * (huge)(mnt[i].blocks - mnt[i].bfree) + / (huge)mnt[i].blocks; + + size = (huge)mnt[i].bsize * (huge)mnt[i].blocks; + memset(table[i].cap, 0, 8); + + // Kilobytes + if(size > 0 && size < (huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fk", + (double)(size)/1024.0); + // Megabytes + else if(size >= (huge)1000*(huge)1000 + && size < (huge)1000*(huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fM", + (float)(size/(huge)1024)/1024.0); + // Gigabytes + else if(size >= (huge)1000*(huge)1000*(huge)1000 + && size < (huge)1000*(huge)1000*(huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fG", + (float)(size/((huge)1024*(huge)1024))/1024.0); + // Terabytes + else if(size >= (huge)1000*(huge)1000*(huge)1000*(huge)1000 + && size < (huge)1000*(huge)1000*(huge)1000*(huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fT", + (float)(size/((huge)1024*(huge)1024*(huge)1024))/1024.0); + + // PectaBytes -- Yeah! I want some! + else if(size >= (huge)1000*(huge)1000*(huge)1000*(huge)1000*(huge)1000 + && size < (huge)1000*(huge)1000*(huge)1000*(huge)1000*(huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fP", + (float)(size/((huge)1024*(huge)1024*(huge)1024*(huge)1024))/1024.0); + + } + } + + + + if (!count) + { + sock_send_string(sock, "widget_set D err1 1 2 {Error Retrieving}\n"); + sock_send_string(sock, "widget_set D err2 1 3 {Filesystem Stats}\n"); + return 0; + } + + + // Display stuff... (show for two seconds, then scroll once per + // second, then hold at the end for two seconds) + sprintf(buffer, "widget_set D f 1 2 %i %i %i %i v 12\n", + lcd_wid, lcd_hgt, lcd_wid, count); + sock_send_string(sock, buffer); + //sprintf(tmp, "widget_set D f 1 2 20 4 20 %i v 8\n", count); + //sock_send_string(sock, tmp); + for(i=0; i= num_disks) // Make sure we have enough lines... + { + sprintf(tmp, "widget_add D s%i string -in f\n", i); + sock_send_string(sock, tmp); + sprintf(tmp, "widget_add D h%i hbar -in f\n", i); + sock_send_string(sock, tmp); + + } + sprintf(tmp, "widget_set D s%i 1 %i {%-6s %6s E F}\n", + i, i+1, table[i].dev, table[i].cap); + sock_send_string(sock, tmp); + sprintf(tmp, "widget_set D h%i 16 %i %i\n", + i, i+1, table[i].full); + sock_send_string(sock, tmp); + } + + // Now remove extra widgets... + for(; i < num_disks; i++) + { + sprintf(tmp, "widget_del D s%i\n", i); + sock_send_string(sock, tmp); + sprintf(tmp, "widget_del D h%i\n", i); + sock_send_string(sock, tmp); + } + + + num_disks = count; + + #undef huge + +/* +// ** FILESYSTEMS ***** +// / 543.2M E----F +// /dos/c 2.1G E----F +// /stuff 4.3G E----F +*/ + return 0; +} + diff --git a/clients/lcdproc/disk.h b/clients/lcdproc/disk.h new file mode 100644 index 0000000..097d426 --- /dev/null +++ b/clients/lcdproc/disk.h @@ -0,0 +1,9 @@ +#ifndef DISK_H +#define DISK_H + +int disk_init(); +int disk_close(); + +int disk_screen(int rep, int display); + +#endif diff --git a/clients/lcdproc/load.c b/clients/lcdproc/load.c new file mode 100644 index 0000000..a9ad021 --- /dev/null +++ b/clients/lcdproc/load.c @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include + +#include "../../shared/sockets.h" + +#include "main.h" +#include "mode.h" +#include "load.h" + +int loadavg_fd = 0; + +static double get_loadavg(void); + +static double get_loadavg(void) +{ + double load; + + reread(loadavg_fd, "get_load:"); + sscanf(buffer, "%lf", &load); + return load; +} + + +int load_init() +{ + if(!loadavg_fd) + loadavg_fd = open("/proc/loadavg",O_RDONLY); + + return 0; +} + +int load_close() +{ + if(loadavg_fd) + close(loadavg_fd); + + loadavg_fd = 0; + + return 0; +} + + +/////////////////////////////////////////////////////////////////////////// +// Shows a display very similar to "xload"'s histogram. +// + +int xload_screen(int rep, int display) +{ + static int first = 1; + static float loads[LCD_MAX_WIDTH]; + int n, i; + float loadmax=0, factor, x; + int status = 0; + + + if(first) // Only the first time this is ever called... + { + first = 0; + memset(loads, 0, sizeof(float)*LCD_MAX_WIDTH); + + sock_send_string(sock, "screen_add X\n"); + sprintf(buffer, "screen_set X name {X-Load: %s}\n", host); + sock_send_string(sock, buffer); + // Add the vbars... + for(i=1; i= 4) + { + sock_send_string(sock, "widget_add X title title\n"); + sock_send_string(sock, "widget_set X title {LOAD }\n"); + } + else + { + sock_send_string(sock, "widget_add X title string\n"); + sock_send_string(sock, "widget_set X title 1 1 {LOAD}\n"); + sock_send_string(sock, "widget_del X heartbeat\n"); + } + sock_send_string(sock, "widget_add X zero string\n"); + sock_send_string(sock, "widget_add X top string\n"); + sprintf(tmp, "widget_set X zero %i %i 0\n", lcd_wid, lcd_hgt); + sock_send_string(sock, tmp); + sprintf(tmp, "widget_set X top %i %i 1\n", + lcd_wid, (lcd_hgt==2)?1:2); + sock_send_string(sock, tmp); + } + + + + for(n=0; n<(lcd_wid-2); n++) loads[n] = loads[n+1]; + loads[lcd_wid-2] = get_loadavg(); + + for(n=0; n loadmax) loadmax = loads[n]; + + n = (int)loadmax; + if ((float)n < loadmax) { n++; } + sprintf(tmp, "widget_set X top %i %i %i\n", + lcd_wid, (lcd_hgt==2)?1:2, n); + //if(display) sock_send_string(sock, tmp); + sock_send_string(sock, tmp); + + + if (loadmax < 1.0) factor = (float)(lcd_cellhgt) * ((lcd_hgt==2)?2.0:3.0); + else factor = (float)(lcd_cellhgt) * ((lcd_hgt==2)?2.0:3.0) / (float)n; + + for(n=0; n LOAD_MIN) + { + status = BACKLIGHT_ON; + } + if(loads[lcd_wid-2] > LOAD_MAX) + { + status = BLINK_ON; + } + + // And now the title... + if(lcd_hgt >= 4) + sprintf(tmp, "widget_set X title {LOAD %2.2f: %s}\n", + loads[lcd_wid-2], host); + else + sprintf(tmp, "widget_set X title 1 1 {%s %2.2f}\n", + host, loads[lcd_wid-2]); + //if(display) sock_send_string(sock, tmp); + sock_send_string(sock, tmp); + + + return status; +} // End xload_screen() + + + diff --git a/clients/lcdproc/load.h b/clients/lcdproc/load.h new file mode 100644 index 0000000..61e6fec --- /dev/null +++ b/clients/lcdproc/load.h @@ -0,0 +1,19 @@ +#ifndef LOAD_H +#define LOAD_H + +#ifndef LOAD_MAX +#define LOAD_MAX 1.3 +#endif +#ifndef LOAD_MIN +#define LOAD_MIN 0.5 +#endif + + + +int load_init(); +int load_close(); + +int xload_screen(int rep, int display); + + +#endif diff --git a/clients/lcdproc/main.c b/clients/lcdproc/main.c new file mode 100644 index 0000000..52591dd --- /dev/null +++ b/clients/lcdproc/main.c @@ -0,0 +1,440 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "mode.h" +#include "../../shared/sockets.h" +#include "../../shared/debug.h" + + +// TODO: Commenting... Everything! + + +int Quit = 0; +int sock; + +char *version = VERSION; +char *build_date = __DATE__; + +int lcd_wid; +int lcd_hgt; +int lcd_cellwid; +int lcd_cellhgt; + + +/* + Mode List: + See below... (default_sequence[]) +*/ + +void HelpScreen(); +void exit_program(int val); +void main_loop(mode *sequence); + +#define MAX_SEQUENCE 256 +// 1/8th second is a single time unit... +#define TIME_UNIT 125000 + + +// Contains a list of modes to run +mode default_sequence[] = +{ +// which on off inv timer/visible + { 'C', 1, 2, 0, 0xffff,0,},// [C]PU + { 'M', 4, 16, 0, 0xffff,0,},// [M]emory + { 'X', 64, 128, 1, 0xffff,0,},// [X]-load (load histogram) + { 'T', 4, 64, 0, 0xffff,0,},// [T]ime/Date + { 'A', 999,9999, 0, 0xffff,0,},// [A]bout (credits) + + { 1 , 0, 0, 0, 0,0,},// Modes after this line will not be run by default... + // ... all non-default modes must be in here! + // ... they will not show up otherwise. + { 'O', 4, 64, 0, 0xffff,0,},// [O]ld Timescreen + { 'K', 4, 64, 0, 0xffff,0,},// big cloc[K] + { 'U', 4, 128, 0, 0xffff,0,},// Old [U]ptime Screen + { 'B', 32, 256, 1, 0xffff,0,},// [B]attery Status + { 'G', 1, 2, 0, 0xffff,0,},// Cpu histogram [G]raph + { 'S', 16, 256, 1, 0xffff,0,},// [S]ize of biggest programs + { 'D', 256, 256, 1, 0xffff,0,},// [D]isk stats + { 0, 0, 0, 0,0,},// No more.. all done. +}; + +// TODO: Clean up main()... It is still way too big. + +// TODO: Config file; not just command line + + +int main(int argc, char **argv) +{ + mode sequence[MAX_SEQUENCE]; + char cfgfile[256] = "/etc/lcdproc.cf"; + char server[256] = "localhost"; + int port = LCDPORT; + int i, j, k; + int tmp; + + memset(sequence, 0, sizeof(mode) * MAX_SEQUENCE); + + // Ctrl-C will cause a clean exit... + signal(SIGINT, exit_program); + // and "kill"... + signal(SIGTERM, exit_program); + // and "kill -HUP" (hangup)... + signal(SIGHUP, exit_program); + // and just in case, "kill -KILL" (which cannot be trapped; but oh well) + signal(SIGKILL, exit_program); + + + + // Command line + memcpy(sequence, default_sequence, sizeof(default_sequence)); + for(i=1, j=0; i 0xffff) + fprintf(stderr, "Warning: Port %i outside of standard range\n", + port); + break; + + // otherwise... Get help! + default: HelpScreen(); break; + } + // Parse command line here... read the man page. + else if(strlen(argv[i]) == 1) + { + // Grab the mode letter... + sequence[j].which = argv[i][0]; + + // If we have just a letter with no numbers... + // Set the defaults... + for(tmp=0, k=0; default_sequence[k].which; k++) + { + if(toupper(sequence[j].which) == default_sequence[k].which) + { + memcpy(&sequence[j], &default_sequence[k], sizeof(mode)); + tmp=1; + break; + } + } + if(!tmp) { printf("Invalid Mode: %c\n", argv[i][0]); exit(0); } + + j++; + // Set the last element to 0... + memset(sequence + j, 0, sizeof(mode)); + } // End if(strlen(argv == 1)) + else + { + // A multicharacter parameter by itself + // is assumed to be a config file.. + strcpy(cfgfile, argv[i]); + printf("Ignoring config file: %s\n", cfgfile); + } + } + + + // Connect to the server... + usleep(500000); // wait for the server to start up + sock = sock_connect(server, port); + if (sock <= 0) + { + printf("Error connecting to server %s on port %i.\n", + server, port); + return 0; + } + sock_send_string(sock, "hello\n"); + usleep(500000); // wait for the server to say hi. + + + // We grab the real values below, from the "connect" line. + lcd_wid = 20; + lcd_hgt = 4; + lcd_cellwid = 5; + lcd_cellhgt = 8; + + // Init the status gatherers... + mode_init(sequence); + + // And spew stuff! + main_loop(sequence); + + // Clean up + exit_program(0); + return 0; +} + + +void HelpScreen() +{ + printf("LCDproc, %s\n", version); + printf("Usage: lcdproc [-s server] [-p port] [modelist]\n"); + printf("\tOptions in []'s are optional.\n"); + printf("\tmodelist is \"mode [mode mode ...]\"\n"); + printf("\tMode letters: \t[C]pu [G]raph [T]ime [M]emory [X]load [D]isk [B]attery\n\t\t\tproc_[S]izes [O]ld_time big_cloc[K] [U]ptime [A]bout\n"); + printf("\n"); + printf("\tUse \"man lcdproc\" for more info.\n"); + printf("Example:\n"); + printf("\tlcdproc -s my.lcdproc.server.com C M X -p 13666\n"); + printf("\n"); + exit(0); +} + + +/////////////////////////////////////////////////////////////////// +// Called upon TERM and INTR signals... +// +void exit_program(int val) +{ + Quit = 1; + sock_close(sock); + mode_close(); + exit(0); +} + + +/////////////////////////////////////////////////////////////////// +// Main program loop... +// +void main_loop(mode *sequence) +{ + int i=0, j; + //int status=0; + char buf[8192]; + char *argv[256]; + int argc, newtoken; + int len; + + + // Main loop + // Run whatever screen we want, then wait. Woo-hoo! + while(!Quit) + { + // Check for server input... + len = sock_recv(sock, buf, 8000); + + // Handle server input... + while(len > 0) + { + // Now split the string into tokens... + //for(i=0; i 0) + { + //printf("%s %s\n", argv[0], argv[1]); + if(0 == strcmp(argv[0], "listen")) + { + for(j=0; sequence[j].which; j++) + { + if(sequence[j].which == argv[1][0]) + { + sequence[j].visible = 1; + //debug("Listen %s\n", argv[1]); + } + } + } + else if(0 == strcmp(argv[0], "ignore")) + { + for(j=0; sequence[j].which; j++) + { + if(sequence[j].which == argv[1][0]) + { + sequence[j].visible = 0; + //debug("Ignore %s\n", argv[1]); + } + } + } + else if(0 == strcmp(argv[0], "key")) + { + debug("Key %s\n", argv[1]); + } + else if(0 == strcmp(argv[0], "menu")) + { + } + else if(0 == strcmp(argv[0], "connect")) + { + int a; + for(a=1; a 1; i++) + { + sequence[i].timer++; + if(sequence[i].visible) + { + if(sequence[i].timer >= sequence[i].on_time) + { + sequence[i].timer = 0; + // Now, update the screen... + update_screen(sequence+i, 1); + } + } + else + { + if(sequence[i].show_invisible) + { + if(sequence[i].timer >= sequence[i].off_time) + { + sequence[i].timer = 0; + // Now, update the screen... + update_screen(sequence+i, 1); + } + } + else + { + if(sequence[i].timer >= sequence[i].off_time) + { + sequence[i].timer = 0; + // Now, update the screen... + update_screen(sequence+i, 0); + } + } + } + } + + // Now sleep... + usleep(TIME_UNIT); + +/* Old stuff + timer=0; + for(j=0; hold || (j +#include +#include +#ifdef IRIX +#include +#endif +#include +#include +#include + +#include "../../shared/sockets.h" +#include "../../shared/LL.h" + +#include "main.h" +#include "mode.h" +#include "mem.h" + +struct meminfo { int total, cache, buffers, free, shared; }; + +int meminfo_fd = 0; + +static void get_mem_info(struct meminfo *result); + +static void get_mem_info(struct meminfo *result) +{ +// int i, res; char *bufptr; + + reread(meminfo_fd, "get_meminfo:"); + result[0].total = getentry("MemTotal:", buffer); + result[0].free = getentry("MemFree:", buffer); + result[0].shared = getentry("MemShared:", buffer); + result[0].buffers = getentry("Buffers:", buffer); + result[0].cache = getentry("Cached:", buffer); + result[1].total = getentry("SwapTotal:", buffer); + result[1].free = getentry("SwapFree:", buffer); +} + + +int mem_init() +{ + if(!meminfo_fd) + { + meminfo_fd = open("/proc/meminfo",O_RDONLY); + } + + return 0; +} + +int mem_close() +{ + if(meminfo_fd) + meminfo_fd = open("/proc/meminfo",O_RDONLY); + + meminfo_fd = 0; + + return 0; +} + + +///////////////////////////////////////////////////////////////////////// +// Mem Screen displays info about memory and swap usage... +// +int mem_screen(int rep, int display) +{ + int n; + struct meminfo mem[2]; + static int first = 1; + static int which_title=0; + float value; + + if(first) + { + first = 0; + + sock_send_string(sock, "screen_add M\n"); + sprintf(buffer, "screen_set M name {Memory & Swap: %s}\n", host); + sock_send_string(sock, buffer); + + if(lcd_hgt >= 4) + { + sock_send_string(sock, "widget_add M title title\n"); + sock_send_string(sock, "widget_set M title { MEM -==- SWAP}\n"); + sock_send_string(sock, "widget_add M totl string\n"); + sock_send_string(sock, "widget_add M used string\n"); + sock_send_string(sock, "widget_set M totl 9 2 Totl\n"); + sock_send_string(sock, "widget_set M used 9 3 Free\n"); + sock_send_string(sock, "widget_add M EF string\n"); + sock_send_string(sock, "widget_set M EF 1 4 {E F E F}\n"); + sock_send_string(sock, "widget_add M memused string\n"); + sock_send_string(sock, "widget_add M swapused string\n"); + //sock_send_string(sock, "widget_set M memgauge 2 4 0\n"); + //sock_send_string(sock, "widget_set M swapgauge 13 4 0\n"); + } + else + { + sock_send_string(sock, "widget_add M m string\n"); + sock_send_string(sock, "widget_add M s string\n"); + if(lcd_wid >= 20) + { + sock_send_string(sock, "widget_set M m 1 1 {M [ ]}\n"); + sock_send_string(sock, "widget_set M s 1 2 {S [ ]}\n"); + } + else + { + sock_send_string(sock, "widget_set M m 1 1 {M [ ]}\n"); + sock_send_string(sock, "widget_set M s 1 2 {S [ ]}\n"); + } + sock_send_string(sock, "widget_add M mem% string\n"); + sock_send_string(sock, "widget_add M swap% string\n"); + sock_send_string(sock, "widget_set M mem% 16 1 { 0.0%}\n"); + sock_send_string(sock, "widget_set M swap% 16 2 { 0.0%}\n"); + + //sock_send_string(sock, "widget_set M memgauge 8 1 0\n"); + //sock_send_string(sock, "widget_set M swapgauge 8 2 0\n"); + } + + sock_send_string(sock, "widget_add M memtotl string\n"); + sock_send_string(sock, "widget_add M swaptotl string\n"); + + sock_send_string(sock, "widget_add M memgauge hbar\n"); + sock_send_string(sock, "widget_add M swapgauge hbar\n"); + + //sock_send_string(sock, "\n"); + } + + + get_mem_info(mem); + + + // flip the title back and forth... + if(lcd_hgt >= 4) + { + if(which_title & 4) + { + sprintf(buffer, "widget_set M title {%s}\n", host); + sock_send_string(sock, buffer); + } + else sock_send_string(sock, "widget_set M title { MEM -==- SWAP}\n"); + which_title = (which_title + 1)&7; + + + // Total memory + sprintf(tmp, "widget_set M memtotl 1 2 {%6dk}\n", mem[0].total); + if(display) sock_send_string(sock, tmp); + + // Free memory (plus buffers and cache) + sprintf(tmp, "widget_set M memused 1 3 {%6dk}\n", + mem[0].free + mem[0].buffers + mem[0].cache); + if(display) sock_send_string(sock, tmp); + + // Total swap + sprintf(tmp, "widget_set M swaptotl 14 2 {%6dk}\n", mem[1].total); + if(display) sock_send_string(sock, tmp); + + // Free swap + sprintf(tmp, "widget_set M swapused 14 3 {%6dk}\n", mem[1].free); + if(display) sock_send_string(sock, tmp); + + + // Free memory graph + n = (int)(35.0 - + ((float)mem[0].free + (float)mem[0].buffers + (float)mem[0].cache) + / (float)mem[0].total + * 35.0); + sprintf(tmp, "widget_set M memgauge 2 4 %i\n", n); + if(display) sock_send_string(sock, tmp); + + // Free swap graph + n = (int)(35.0 - + (float)mem[1].free / (float)mem[1].total + * 35.0); + sprintf(tmp, "widget_set M swapgauge 13 4 %i\n", n); + if(display) sock_send_string(sock, tmp); + } + else + { + // Total memory + sprintf(tmp, "widget_set M memtotl 2 1 {%4dM}\n", + (int)(mem[0].total / 1024.0)); + if(display) sock_send_string(sock, tmp); + + // Total swap + sprintf(tmp, "widget_set M swaptotl 2 2 {%4dM}\n", + (int)(mem[1].total / 1024.0)); + if(display) sock_send_string(sock, tmp); + + + // Free memory graph + value = ((float)mem[0].free + (float)mem[0].buffers + (float)mem[0].cache) + / (float)mem[0].total; + value = 1.0 - value; + n = (int)((lcd_cellwid * (float)(lcd_wid-13))*(value)); + sprintf(tmp, "widget_set M memgauge 8 1 %i\n", n); + if(display) sock_send_string(sock, tmp); + + value *= 100.0; + if (value >= 99.9) { sprintf(buffer, "100%%"); } + else { sprintf(buffer, "%4.1f%%", value); } + sprintf(tmp, "widget_set M mem%% %i 1 {%s}\n", lcd_wid-4, buffer); + if(display) sock_send_string(sock, tmp); + + // Free swap graph + value = ((float)mem[1].free / (float)mem[1].total); + value = 1.0 - value; + n = (int)((lcd_cellwid * (float)(lcd_wid-13))*(value)); + sprintf(tmp, "widget_set M swapgauge 8 2 %i\n", n); + if(display) sock_send_string(sock, tmp); + + value *= 100.0; + if (value >= 99.9) { sprintf(buffer, "100%%"); } + else { sprintf(buffer, "%4.1f%%", value); } + sprintf(tmp, "widget_set M swap%% %i 2 {%s}\n", lcd_wid-4, buffer); + if(display) sock_send_string(sock, tmp); + + + } + + + + return 0; +} // End mem_screen() + + + +typedef struct proc_mem_info +{ + char name[16]; // Is this really long enough? + // Size isn't used any more... + // Totl stores the "size" of the program now... + int size, totl; + int number; +} proc_mem_info; + + +static int sort_procs(void *a, void *b) +{ + proc_mem_info *one, *two; + + if(!a) return 0; + if(!b) return 0; + + one = (proc_mem_info *)a; + two = (proc_mem_info *)b; + + return (two->totl > one->totl); +} + + +int mem_top_screen(int rep, int display) +{ + // Much of this code was ripped from "gmemusage" + char buf[128]; + + DIR *proc; + FILE *StatusFile; + struct dirent * procdir; + + char procName[16]; + int + procSize , + procRSS , + procData , + procStk , + procExe ; + const char + *NameLine = "Name:" , + *VmSizeLine = "VmSize:" , + *VmRSSLine = "VmRSS" , + *VmDataLine = "VmData" , + *VmStkLine = "VmStk" , + *VmExeLine = "VmExe" ; + const int + NameLineLen = strlen ( NameLine ) , + VmSizeLineLen = strlen ( VmSizeLine ) , + VmDataLineLen = strlen ( VmDataLine ) , + VmStkLineLen = strlen ( VmStkLine ) , + VmExeLineLen = strlen ( VmExeLine ) , + VmRSSLineLen = strlen ( VmRSSLine ) ; + + + int threshold = 400, unique; + int i; + proc_mem_info *p; + LL * procs; + static int first = 1; + + if(first) + { + first = 0; + + sock_send_string(sock, "screen_add S\n"); + sprintf(buffer, "screen_set S name {Top Memory Use: %s}\n", host); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add S title title\n"); + sprintf(buffer, "widget_set S title {TOP MEM: %s}\n", host); + sock_send_string(sock, buffer); + sock_send_string(sock, "widget_add S f frame\n"); + if(lcd_hgt >= 4) + sock_send_string(sock, "widget_set S f 1 2 20 4 20 5 v 8\n"); + else + sock_send_string(sock, "widget_set S f 1 2 20 2 20 5 v 16\n"); + for(i=1; i<=5; i++) + { + sprintf(buffer, "widget_add S %i string -in f\n", i); + sock_send_string(sock, buffer); + } + sock_send_string(sock, "widget_set S 1 1 1 Checking...\n"); + } + + + procs = LL_new(); + if(!procs) + { + fprintf(stderr, "mem_top_screen: Error allocating list\n"); + return -1; + } + + + if ( ( proc = opendir ( "/proc" ) ) == NULL ) + { + fprintf ( stderr , "mem_top_screen: unable to open /proc" ) ; + perror ( "" ) ; + return -1; + } + + while ( (procdir = readdir ( proc )) ) + { + if ( !index ( "1234567890" , procdir -> d_name [0] ) ) + { + continue ; + } + sprintf ( buf , "/proc/%s/status" , procdir -> d_name ) ; + if ( ( StatusFile = fopen ( buf , "r" ) ) == NULL ) + { + // Not a serious error; process has finished before we could + // examine it: + //fprintf ( stderr , "mem_top_screen: cannot open %s for reading" , + // buf ) ; + //perror ( "" ) ; + continue ; + } + procRSS = procSize = procData = procStk = procExe = 0 ; + while ( fgets ( buf , sizeof ( buf ) , StatusFile ) ) + { + if ( !strncmp ( buf , NameLine , NameLineLen ) ) + { + /* Name: procName */ + sscanf ( buf , "%*s %s" , procName ) ; + } + else if ( !strncmp ( buf , VmSizeLine , VmSizeLineLen ) ) + { + /* VmSize: procSize kB */ + sscanf ( buf , "%*s %d" , &procSize ) ; + } + else if ( !strncmp ( buf , VmRSSLine , VmRSSLineLen ) ) + { + /* VmRSS: procRSS kB */ + sscanf ( buf , "%*s %d" , &procRSS ) ; + } + else if ( !strncmp ( buf , VmDataLine , VmDataLineLen ) ) + { + /* VmData: procData kB */ + sscanf ( buf , "%*s %d" , &procData ) ; + } + else if ( !strncmp ( buf , VmStkLine , VmStkLineLen ) ) + { + /* VmStk: procStk kB */ + sscanf ( buf , "%*s %d" , &procStk ) ; + } + else if ( !strncmp ( buf , VmExeLine , VmExeLineLen ) ) + { + /* VmExe: procExe kB */ + sscanf ( buf , "%*s %d" , &procExe ) ; + } + } + fclose ( StatusFile ) ; + if(procSize > threshold) + { + // Figure out if it's sharing any memory... + unique = 1; + LL_Rewind(procs); + do { + p = LL_Get(procs); + if(p) + { + if(0 == strcmp(p->name, procName)) + { + unique = 0; + p->number ++; + p->totl += procData + procStk + procExe; + } + } + } while(LL_Next(procs) == 0); + + // If this is the first one by this name... + if(unique) + { + p = malloc(sizeof(proc_mem_info)); + if(!p) + { + fprintf(stderr, + "mem_top_screen: Error allocating process entry\n"); + goto end; // Ack! I hate goto's! + } + strcpy(p->name, procName); + p->size = procSize; + p->totl = procData + procStk + procExe; + p->number = 1; + // TODO: Check for errors here? + LL_Push(procs, (void *)p); + } + } + + } + closedir ( proc ) ; + + + // Now, print some info... + LL_Rewind(procs); + LL_Sort(procs, sort_procs); + LL_Rewind(procs); + for(i=1; i<=5; i++) + { + p = LL_Get(procs); + if(p) + { + //printf("Mem hog: %s: %ik\n", p->name, p->size); + if(p->number > 1) + sprintf(buffer, "widget_set S %i 1 %i {%i%6ik %s(%i)}\n", i, i, i, + p->totl, p->name, p->number); + else + sprintf(buffer, "widget_set S %i 1 %i {%i%6ik %s}\n", i, i, i, + p->totl, p->name); + if(display) sock_send_string(sock, buffer); + } + else + { + //printf("Mem hog: none?\n"); + sprintf(buffer, "widget_set S %i 1 %i {}\n", i, i); + if(display) sock_send_string(sock, buffer); + } + + LL_Next(procs); + } + + + + + end: // Ack! I hate using labels! + // Now clean it all up... + LL_Rewind(procs); + do { + p = (proc_mem_info *)LL_Get(procs); + if(p) + { + //printf("Proc: %6ik %s\n", p->size, p->name); + free(p); + } + } while(LL_Next(procs) == 0); + LL_Destroy(procs); + + + return 0; + +} // End mem_top_screen() + diff --git a/clients/lcdproc/mem.h b/clients/lcdproc/mem.h new file mode 100644 index 0000000..3bc1e43 --- /dev/null +++ b/clients/lcdproc/mem.h @@ -0,0 +1,11 @@ +#ifndef MEM_H +#define MEM_H + +int mem_init(); +int mem_close(); + +int mem_screen(int rep, int display); +int mem_top_screen(int rep, int display); + + +#endif diff --git a/clients/lcdproc/mode.c b/clients/lcdproc/mode.c new file mode 100644 index 0000000..dcd4fa3 --- /dev/null +++ b/clients/lcdproc/mode.c @@ -0,0 +1,282 @@ +/* + * This file contains status-gathering code *and* modescreen functions. + * It's long, and messy. + * + */ + +#include +#include +#include +#ifdef IRIX +#include +#endif +#include +#include +#include +#include +#include + +#include "../../shared/sockets.h" + +#include "mode.h" +#include "main.h" + +#include "batt.h" +#include "chrono.h" +#include "cpu.h" +#include "disk.h" +#include "load.h" +#include "mem.h" + + +int ELLIPSIS='-'; + +// TODO: Clean this up... Support multiple display sizes.. + +char buffer[1024]; +char host[16]; + +void reread(int f, char *errmsg); +int getentry(const char *tag, const char *bufptr); + + +int mode_init(mode *sequence) +{ + int i; + struct utsname Uname; + + // Grab the host name + if(0 > uname(&Uname)) + { + perror("Can't get hostname"); + strcpy(host, "host"); + } + else + { + strncpy(host, Uname.nodename, 15); + host[16]=0; + if(index(host,'.')) // truncate at the first dot + *(index(host, '.'))='\0'; + for(i=0; i<16; i++) + if(host[i] == '\n') host[i]=0; + } + + // Init all the modescreens we need + for(i=0; sequence[i].which > 1; i++) + { + switch(sequence[i].which) + { + case 'g': + case 'G': // cpu_graph_screen + cpu_init(); + break; + case 'c': + case 'C': // cpu_screen + cpu_init(); + break; + case 'o': + case 'O': // clock_screen + chrono_init(); + break; + case 'k': + case 'K': // big_clock_screen + chrono_init(); + break; + case 'm': + case 'M': // mem_screen + mem_init(); + break; + case 's': + case 'S': // mem_info_screen + mem_init(); + break; + case 'u': + case 'U': // uptime_screen + chrono_init(); + break; + case 't': + case 'T': // time_screen + chrono_init(); + break; + case 'd': + case 'D': // disk_screen + disk_init(); + break; + case 'x': + case 'X': // xload_screen + load_init(); + break; + case 'b': + case 'B': // battery_screen + batt_init(); + break; + case 'a': + case 'A': // credit_screen + break; + default: break; + } + } + + + + return 0; +} + +void mode_close() +{ + batt_close(); + chrono_close(); + cpu_close(); + disk_close(); + load_close(); + mem_close(); + +} + + +int update_screen(mode *m, int display) +{ + static int status = -1; + int old_status = status; + + if(m) + { + switch(m->which) + { + case 'g': + case 'G': status = cpu_graph_screen(m->timer, display); break; + case 'c': + case 'C': status = cpu_screen(m->timer, display); break; + case 'o': + case 'O': status = clock_screen(m->timer, display); break; + case 'k': + case 'K': status = big_clock_screen(m->timer, display); break; + case 'm': + case 'M': status = mem_screen(m->timer, display); break; + case 's': + case 'S': status = mem_top_screen(m->timer, display); break; + case 'u': + case 'U': status = uptime_screen(m->timer, display); break; + case 't': + case 'T': status = time_screen(m->timer, display); break; + case 'd': + case 'D': status = disk_screen(m->timer, display); break; + case 'x': + case 'X': status = xload_screen(m->timer, display); break; + case 'b': + case 'B': status = battery_screen(m->timer, display); break; + case 'a': + case 'A': status = credit_screen(m->timer, display); break; + default: break; + } + /* Debugging tool... + if(display) + { + printf("Displayed Mode %c\n", m->which); + } + */ + } + + if(status != old_status) + { + if(status == BACKLIGHT_OFF) + { + sock_send_string(sock, "backlight off\n"); + } + if(status == BACKLIGHT_ON) + { + sock_send_string(sock, "backlight on\n"); + } + if(status == BLINK_ON) + { + sock_send_string(sock, "backlight blink\n"); + } + } + return status; + +} + + +void reread(int f, char *errmsg) +{ + if (lseek(f, 0L, 0) == 0 && read(f, buffer, sizeof(buffer) - 1 ) > 0 ) + return; + perror(errmsg); + exit(1); +} + +int getentry(const char *tag, const char *bufptr) +{ + char *tail; + int retval, len = strlen(tag); + + while (bufptr) + { + if (*bufptr == '\n') bufptr++; + if (!strncmp(tag, bufptr, len)) + { + retval = strtol(bufptr + len, &tail, 10); + if (tail == bufptr + len) return -1; + else return retval; + } + bufptr = strchr( bufptr, '\n'); + } + return -1; +} + + +/////////////////////////////////////////////////////////////////////////// +//////////////////////// Let the Modes Begin! ///////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +// Er, these have been moved.. :) + +char tmp[1024]; + + + + +//////////////////////////////////////////////////////////////////////// +// Credit Screen shows who wrote this... +// +int credit_screen(int rep, int display) +{ + static int first = 1; + + if(first) + { + first = 0; + + sock_send_string(sock, "screen_add A\n"); + sock_send_string(sock, + "screen_set A name {Credits for LCDproc}\n"); + sock_send_string(sock, "widget_add A title title\n"); + sprintf(tmp, "widget_set A title {LCDPROC %s}\n", version); + sock_send_string(sock, tmp); + if(lcd_hgt >= 4) + { + sock_send_string(sock, "widget_add A one string\n"); + sock_send_string(sock, "widget_add A two string\n"); + sock_send_string(sock, "widget_add A three string\n"); + sock_send_string(sock, + "widget_set A one 1 2 { for Linux }\n"); + sock_send_string(sock, + "widget_set A two 1 3 { by William Ferrell}\n"); + sock_send_string(sock, + "widget_set A three 1 4 { and Scott Scriven}\n"); + } + else + { + sock_send_string(sock, "widget_add A text scroller\n"); + sock_send_string(sock, + "widget_set A text 1 2 20 2 v 8 { for Linux by William Ferrell and Scott Scriven}\n"); + } + } + + return 0; +} // End credit_screen() + + + + + diff --git a/clients/lcdproc/mode.h b/clients/lcdproc/mode.h new file mode 100644 index 0000000..24fd72c --- /dev/null +++ b/clients/lcdproc/mode.h @@ -0,0 +1,31 @@ +#ifndef MODE_H +#define MODE_H + +#include "main.h" + +//TODO: Net stats screen... +//TODO: "Who" +//TODO: biff / mail checking, etc... + +extern char tmp[]; +extern char buffer[]; +extern char host[]; + +// Character to use for padding title bars, etc... +extern int PAD; +// Character for the "..." symbol. +extern int ELLIPSIS; + +int mode_init(mode *sequence); +void mode_close(); + +int update_screen(mode *m, int display); + +int credit_screen(int rep, int display); + + +// These are for the modescreens' use only.. +void reread(int f, char *errmsg); +int getentry(const char *tag, const char *bufptr); + +#endif diff --git a/docs/README.dg b/docs/README.dg new file mode 100644 index 0000000..7b08f54 --- /dev/null +++ b/docs/README.dg @@ -0,0 +1,68 @@ +William W. Ferrell (choadster@earthlink.net) +Scott Scriven (scriven@cs.colostate.edu). + +Hello, +I am the happy new owner of a matrix-orbital LK-204-25 V. +I also made computer science studies (but currently I only program for fun). +The reason why I wanted this LCD screen was to build a MAME/MPEG3/DVD player. +Currently the IR receaver is missing, but I already started to work on my +project by checking LCDPROC capability and trying to make it work the way I +want. + +I don't know yet if my developpement will be a client of LCDPROC or if I will +make a stand-alone program (more likely reussing some of your code). +Currently, feature in LCDPROC don't cover yet my need yet. +So, my best option is to support you or your team in building the perfect +server in order for me to build only a client. + +So, I downloaded v0.4-pre5 and started to hack. ;-) +I was a little bit confuse with your documentation, sometime talking about +version 0.3.x or about comming feature, but reading the source code (and +the sgml description that I only founded later) was the best. + +I made some "minor" change to a few source file (this is what I remember): + * Cleaning the help screen from LCDd. + * Adding a speed option to MtxOrb driver. + * Updated MtxOrb help screen to indicate those change. + * Added some error checking to parameter sended to MtxOrb driver. + * Added fake support for big number into curses driver. + * Some modification to the debug_driver in order to compile. + * Added bignum widget in order to use that feature from the driver. + * Added big cloc[K] (24H) to lcdproc to test the new widget. (ugly/blinking) + * Added a General Purpose Output function to the MtxOrb driver. + +Here is some kind of todo-list one liner only: + * Implement a debug/error to a syslog server rather than printf(stderr,... + * General Purpose Output support. + * Make "LCDproc Server" and "End Screen" (build-in screen) optionnal. + * Make HeartBeat working with General Purpose Output (led blinking). + * KeyPad support. + * Make KeyPad local feedback using General Purpose Output (led blinking). + * Make the server port number (listen) a param/config option. + * Accept incoming 'telnet' (specific port) as a new i/o device (vt100/ansi). + * MtxOrb driver across an outgoing 'telnet' session (access server). + +My major todo: + * Well, I would like to (one way or another) interconnect IrMan(?) and + LCDProc. I will use LCDProc for the ouput of the name of the song, ... + and maybe for keyboard input. I will also use IrMan or some infrared + library in order to receave remote controle input. Now, I would be nice + to be able to connect to LCDProc and 'register' a new input and/or output + device. + What I am thinking about is to have LCDd be a server with local device + to manage, but also have remote device that could attach themself to + LCDd. I think, by reading your documentation, that you have somethink like + that already in mind. This will allow dynamic addition of new driver without + having to recompile LCDd... + +Change you should make yourself: + * Update the network protocol description with heartbeat function. + * Remove reference/out of date description related to 0.3.x + +I made many change to a lot of different file... (sorry) +I don't have the tool/knowledge available to give you a patch with only my +modification. So, I send you a taz.gz with everything after my change. +I won't have much time to spend on LCDPROC for about two week (and the +week-end in between). This give you time to check my change and incorporate +anything you find interesting. + diff --git a/docs/README.dg2 b/docs/README.dg2 new file mode 100644 index 0000000..e0040ee --- /dev/null +++ b/docs/README.dg2 @@ -0,0 +1,74 @@ +Hello, + +In order to compile LCDd (the lcdproc server) with support for IRman, +you need to put libirman in a neighbor directory. +Currently I use version 0.4.1b and this is hard coded into makefile and +#include string. (could do better). + +Now for libirman to "work" you need a .irmanrc file with description of +you infrared "code" and mapping to command in my driver. +A template of such a file is given in the driver directory. This template +will only work with my JVC remote control, but you already have configured +IRman, you should be able to modify it for yours. + +David GLAUDE + +FINDING THE COMPONENT: + +lcdproc: deamon to display information on a lcd screen. + version: 0.4-pre5 + need libirman and my driver to support input from IrMan. + +libirman: library in use to read input from IrMan on a serial port. + version used: 0.4.1b + currently used untouch and just needed to use my driver for lcdproc. + +-----------Here stop the currently usefull information------------ + +lirc: standardize interface to control IR receaver and emetteur. + version: 0.5.4 + currently not used but might be usefull have support for other IR. + +cdtools: command line program to control the cdrom and play audio cd. + might need some patch to have a better output of cd song information. + +Hello, + +This file describe the personnal developpement I have made and wich sources +you need to bring together in order to integrate everything the same way +I did. + +Basicaly, we are talking about a yet another CD player 'yaCDplayer' but +because the name might already have been in use, it was decided to call it +'lcdcd'. + +This CD player take as input (control) and output (display of the status) the +lcdproc server. It as thus no user interface on it's own. +Lcdproc is a server that allow the control of LCD screen over TCP connection. +Some LCD screen also have support to connect a keypad, it also offer +input user interface for this program. +Because lcdproc is a very flexible input/output server, it also support for +input comming from a joystic, the keyboard (curses output) or even irman. +It also support multiple driver simultaniously and multiple driver like curses +and joystic for those without an LCD screen and an irman. + +Now irman is an infrared receaver with a build in chip to hash the input +signal into a unique key that can be readed throught a serial interface. + +An other important think about lcdcd it is that in order to communicate with +lcdproc we use a TCP/IP connection. Lcdproc need to run in background on the +server where the input/output device are connected. Lcdcd must run on the +client where the cdrom is located. In between, we need to have a TCP/IP +network. Now, if you have a firewall, you will let traffic from the client to +the server on port 13666 wich is the default for lcdproc, be carefull there +is not security build in lcdproc and anybody can connect to it. If you don't +have an IP network and the client and the server are located on a single +computer (with the CDROM, the LCD screen and the IrMan connected) then you +need to enable IP on this computer. This can be done by putting an IP address +on a loopback interface (like 127.0.0.1 on lo, try 'ifup lo' it might work +also on your distribution of Linux). + +Currently, this ... ---to be continued--- + + + diff --git a/docs/hd44780_howto.txt b/docs/hd44780_howto.txt new file mode 100644 index 0000000..308d068 --- /dev/null +++ b/docs/hd44780_howto.txt @@ -0,0 +1,49 @@ +(this text taken from a message by Bill Farrow, more info coming later) + + + +The code in LCDproc for the hd4470 LCD controller chips comes from +"lcdtext" (by Matthias Prinke) or one of the derivatives ("lcdstat4", +"lcdtime"). + +You might like to get those packages down as well and have a play. + +LCDproc-0.4 only supports 4 line displays, but LCDproc-0.3.5 runs 2 line +displays also. A different maintainer is responsible for this version. + +The pinouts are like so : (From lcdtext) + +1.1 Connecting the LCD to a printer port +----------------------------------------- + + LCD printer port +Pin signal Pin signal + +1 GND 18..25 GND +2 +5V --- *) +3 Vadj. --- *) +4 RS 6 D4 +5 RW 7 D5 +6 EN 8 D6 +11 D4 2 D0 +12 D5 3 D1 +13 D6 4 D2 +14 D7 5 D3 + +Getting the supply voltage: + Use a floppy supply connector, get it from the game port, take some +diodes and a capacitor and get it from the port's data lines, get it +from the keyboard connector or whatever you like. Be save to avoid +short circuit. You need only 3mA at 5V! (if you have the same type +lcd) + +Connecting the contrast adjusting pin (Vadj.): + + (variable resistor) + .------. + Vcc ---| 10k |--- GND + `---^--' + /|\ + | + Vadj. + diff --git a/docs/lcdproc.1 b/docs/lcdproc.1 new file mode 100644 index 0000000..5b7ce20 --- /dev/null +++ b/docs/lcdproc.1 @@ -0,0 +1,119 @@ +WARNING! + This man page hasn't been updated since V0.3.4. + + +SYNOPSIS + + lcdproc - displays system status on Matrix-Orbital 20x4 LCD + on a serial port + +USAGE + + lcdproc [-d device] [-c contrast] [modelist] + +DESCRIPTION + + lcdproc uses a 20x4 character LCD manufactured by Matrix-Orbital + to display status information about the system. + + Currently, only Linux is supported (kernels 2.0 and greater), and + /proc filesystem support is required. In addition, only displays + made by Matrix-Orbital are supported at this time (their displays + have built-in controllers and a very good BIOS). + + lcdproc understands these options: + + -l driver + The lcd display driver to use. So far, this can only be: + text Text-mode output. (20x4) + MtxOrb Matrix Orbital displays... (20x4) + curses Curses-based terminal output (20x4) + debug Verbose debugging text output (terminal) + + -d device + The serial port attached to the display. Usually /dev/cua0 + or /dev/cua1. This device is locked by lcdproc. + + -c contrast + Sets the display's contrast setting to the value specified, + ranging from 0 to 255. Note that values below around 30 + yield invisible characters from most viewing angles, and + values above 200 yield solid cells from most viewing + angles. + + modelist + A list specifying what screens to display, and in what order; + in the form: + + mode [mode mode mode ...] + + where mode is one of... + "C" (CPU usage), + "G" (CPU Graph like Xload), + "M" (Memory Usage), + "X" (X-Load), + "T" (Date, time, Uptime, OS version) + "D" (Disk Stats), + "B" (Battery Stats), + "A" (About), + "O" (old date and time screen), (removed soon?) + "U" (System Uptime), (will be removed soon?) + + For example: + + lcdproc -d /dev/cua1 -c 180 C M D X -l MtxOrb + + selects /dev/cua1 (com2) as the serial port for the + MtxOrb driver, sets the display's contrast to 180, + and specifies the following modes: + + - CPU Usage, updated every 1/8th of a second for 4 seconds. + - Memory usage, updated every 1/4th of a second for 4 seconds. + - Uptime, updated every 1/2 second for 4 seconds. + - Date and Time, updated every 1/2 second for 4 seconds. + - X-Load average over time, updated once per mode cycle. + + +CAVEATS + +The command line will change a lot Real Soon Now(tm). Be sure to +check on this when installing new versions. + +The "idle" stat on the time screen (D) reflects how much idle time +your system has had since booting. So, if you leave the machine +running at night without doing anything, you'll have at least 50% +idle. :) + +KNOWN BUGS + + - Only supports 20x4 displays, so far. + - Doesn't lock the com port... yet. + - Doesn't always shut down correctly when killed by init. (?) + (during "shutdown -h now", for example) + +CONTACT INFORMATION + + LCDproc was written by William Ferrell (choadster@earthlink.net) and + Scott Scriven (scriven@cs.colostate.edu). + + Matrix Orbital (http://www.matrix-orbital.com/) designed and + manufactures the LCD displays. + + The newest version of LCDproc should be available from here: + + http://lcdproc.omnipotent.net/ + +LEGAL STUFF + + LCDproc is released as "WorksForMe-Ware". In other words, it is free, + kinda neat, and we don't guarantee that it will do anything in + particular on any machine except the ones it was developed on. + + It is technically released under the GNU GPL license (you should + have received the file, "COPYING", with LCDproc) (also, look on + http://www.fsf.org/ for more information), so you can distribute and + use it for free -- but you must make the source code freely available + to anyone who wants it. + + For any sort of real legal information, read the GNU GPL (GNU General + Public License). It's worth reading. diff --git a/docs/lcdproc.sgml b/docs/lcdproc.sgml new file mode 100644 index 0000000..ad63413 --- /dev/null +++ b/docs/lcdproc.sgml @@ -0,0 +1,674 @@ + + + + + 1999-02-08 + LCDproc User's Guide + Installation and Client Development Guide + + + + + Introduction + LCDproc is a system status monitoring application that drives a + variety of different LCD-based display devices. It provides a powerful + framework for networked statistic gathering, adding new monitors or + LCD-aware applications, and adding new devices. + + The client shipped with LCDproc v0.4 can connect to an LCDproc + server either on the local system or on a remote system as long as it + is reachable. It extracts the same statistics regardless of where it + sends this information. The statistics it gathers include CPU + utilization, memory utilization, disk utilization, network utilization, + system uptime, time, and date, and so on. It displays this information + in assorted ways, and can be tailored to taste. + + + Supported Hardware + As shipped, LCDproc v0.4 supports LCD modules from Matrix + Orbital Corporation, HD447800-controlled LCDs, and can emulate an LCD with + the curses library or plain, raw, ugly text. + + + Matrix Orbital LCD Modules + + LCDproc was born out of original tinkering by William Ferrell with + one of these LCD modules. Their ease of installation and use (as well + as the amazing amount of patience demonstrated by the folks at + Matrix Orbital whilst William figured things out) meant one less thing + to worry about during the early stages of LCDproc's life. + + + These 20x4 alphanumeric modules are connected via standard DB-9 cabling and + connectors. They draw either 5V or 12V, depending on the module purchased, + and are attached with a standard floppy cable connector (with a slightly + modified wire configuration). + + + Once connected, using them is a breeze. They can operate at any number of + different baud rates and serial configurations, but normally they run at + 19,200 baud, 8-N-1, making them quite quick. Sending ASCII to the module + will make it simply display that text at its current cursor position. The + module has a built-in BIOS that recognizes commands (sent by transmitting a + single-byte "marker" signifying that a command is on the way, followed by + the single-byte command character itself along with any parameters, if needed) + allowing the programmer to clear the screen, position the cursor anywhere, + define custom characters (up to 8 at a time), draw bar graphs and large numbers, + change the LCD's contrast, and so on. + + + The BIOS included also implements line-wrapping (i.e. writing past the + twentieth character on the first row will automatically move the cursor + to the first character on the second row), and screen scrolling (i.e. + writing past the twentieth character on the fourth row causes the whole + screen to scroll up one row, clearing the fourth line and positioning the + cursor at the first character on that line). + + + These modules are fast. Using the auto-line-wrap feature and disabling + the auto-scrolling feature, the screen can be updated thirty times per + second if *every* character on the screen is changed. If updating less + than the whole screen, the LCD can update faster than can be seen by + the human eye. This, of course, more than meets LCDproc's needs. + + + + HD44780 Controller-Based LCDs + + These LCDs are controlled by the Hitachi HD44780 LCD controller, and + connect to a system's parallel port. Not much else is known about these + devices at this time. [Update this section]. + + + + LCD Emulation + + LCDproc can emulate an LCD on a curses terminal (or even on a dumb terminal + by writing raw text out, if you're that desperate). The output is confined to + a 20x4 character area, just like on a real LCD, and can be "swallowed" into + window manager panels such as fvwmbuttons. + + + + + LCDproc Documentation + + This document is intended to be full, complete documentation for + LCDproc. While some information presented in this document is present + in assorted files scattered across the LCDproc distribution tarball, + this document is meant to encompass all aspects of dealing with + LCDproc, from installation, all the way to developing custom clients + using LCDproc's client/server API. + + + README and INSTALL files will always be distributed with LCDproc, along + with the requisite copyright and licensing information, but this document + will eventually replace the content of the README and INSTALL files. + + + This documentation was written in SGML and + DocBook. SGML is a + generalized markup language (of which HTML is a subset), and DocBook is a set of + layout tools and markups using SGML that lends itself quite nicely to the publishing + of technical manuals and software documentation like this. + + + In Linux, one can produce DVI, PostScript, HTML, Unix Manual Pages and Info + pages from the same SGML/DocBook source using + SGMLtools. Take a look at this set + of tools if you have any large-scale documentation to write. It might have a bit of + a steep learning curve, but it's certainly worth the effort. + + + + + + Installation + + This chapter covers the installation process for both LCDproc, and the actual LCD + module intended for use with LCDproc. Since our experience has involved almost + exclusively the Matrix Orbital modules, we will spend little time on installation + instructions for other hardware. + + + If you have successfully installed LCDproc-compatible hardware and would care to + document how you did so, please e-mail the author of this book + (choadster@earthlink.net). + + + We will examine the installation process of LCDproc and the hardware it drives in + small steps, as it is vitally important to pay close attention to detail during + hardware installation to avoid damaging equipment, as well as during LCDproc's + installation, since things have become a little more complicated since LCDproc's + split into a client and server model. + + + First, hardware installation is discussed. If you are not using physical LCD + hardware to run LCDproc, you can safely skip the hardware installation sections and + move on to the software installation sections. + + + Hardware Installation + + Regardless of what specific type of hardware you intend to use with LCDproc, + installation is usually straightforward, and requires only a few steps. Regardless, + you must use caution while working inside your computer system or with any hardware + attachments. + + + Warning! + + Installing new hardware inside a computer system can be dangerous to both + system components and the installer. Use caution whenever adding a component + to the inside of your system, altering a power cable, or physically mounting + a device inside a computer system. + + + When installing hardware inside a computer, make sure it's turned off and that + its power is disconnected. This is especially important when making changes to + power cables (as some LCD modules require). + + + + Matrix Orbital LCD/VFD Module Installation + + The LCD and VFD modules from Matrix Orbital are relatively straightforward + to install. With a small, regular (flat-head) screwdriver, a spare floppy drive + power cable, and a bit of luck, installation will take less than an hour. + + + These installation instructions assume that you are installing the module into + a PC or PC-style system (one with AT- or ATX-compliant power cabling) and that + you have some idea of where you intend to permanently mount the module. For + mounting ideas and tips, refer to the section "Mounting" below. + + + Before you start + + Your Matrix Orbital LCD or VFD module should be clearly marked with an + indication of the module's power requirements. It should be either a 5 volt + or 12 volt unit. You should have this information available before proceeding. + + + + Power Cable Modification + + The first step in installing the module is making the necessary modifications + to a floppy drive power cable in order to provide power to the module. The + modifications must be made based on the module's power requirements -- either + 5V or 12V -- depending on which module you purchased. + + + A standard floppy drive power cable has a smaller connection than a "normal" + PC power connector. However, like a "normal" power connector, it has four + wires: one yellow, one red, and two black. The red wire provides +5V power, and + is "hot" or live when the system is powered up. The yellow wire provides +12V + power, and is also hot when the system is powered up. Both black wires are + ground. + [TODO: INCLUDE A FIGURE HERE SHOWING A "STANDARD" FLOPPY CONNECTOR] + + + One of the hot wires and one of the black wires will not be needed for your + module's power connection; they will be completely removed when the power cable + modification is complete. + + + Warning! + + Do NOT make this modification to a power cable attached to a running + system! Electrocution resulting in personal injury and/or damage to the + system can result. + + + + Using a regular screwdriver, press down the small metal locking flap of one + of the two black wires on the small end of the cable, and pull the black wire + from the connector. Using a pair of needle-nose pliers, squeeze the other end + of the same black wire, and pull it out of the large end of the cable. This + black wire can be set aside; it will not be used for the module's power + connection. Either wire can be safely removed; you may safely remove either + wire. + [TODO: INCLUDE A FIGURE HERE SHOWING THIS PROCESS] + + + Next, using the same procedure, remove the unneeded hot wire. If your module + is 5V, you do not need the yellow (+12V) wire. Conversely, if your module is + 12V, you do not need the red (+5V) wire. The removed wire can be set aside; + it will not be used for the module's power connection. + [TODO: INCLUDE A FIGURE HERE] + + + The floppy power connector should now have only two wires attached to it. + Leave the larger end alone from now on; these connections are correct (the + larger end connects to your system's power mains). Move the two remaining wires + to the outside connectors on the small end of the cable. Orientation does not + particularly matter here; the connector will fit on the module's receptacle + in either orientation. + [TODO: A FIGURE HERE] + + + You should now have a properly modified power connector. When physically + attaching this connector to the module, the black (ground) lead should be + connected to the pin labelled GND, while the colored (+5V/+12V) lead should + be connected to the pin labelled +5V/+12V. + + + Test the power connection before connecting the data line or mounting the + module. Connect the module to the power connector, and the connector to your + system's power mains. Turn the system on. + + + Caution + + If the module does not immediately display its initial BIOS screen and light + up its backlight (or light up the screen if a VFD module is being used), + immediately power down the system, disconnect the module + and connector, and double-check the modification before trying again. Do NOT + leave the system on if the module does not immediately respond; module or + system damage could result. + + + + When the LCD powers up and displays its initial BIOS screen, you've gotten the + power connection wired properly and can now properly mount the module and make + its final connections. Matrix Orbital Corporation sells a PC bay insert mount + for the 20x4 and 20x2 modules (LCDproc, however, only supports the 20x4 at + present). The inserts provide an easy means of mounting the LCD modules inside + a PC using one (for the 20x2) or two (for the 20x4) 5 1/4" bays. + + + Note + + Describing how to physically mount the module in a PC case is beyond the + scope of this document; LCDproc's website contains more detailed mounting + information and examples. + + + + + Serial Connection + + The LCD module uses a standard DB9 serial connector. You can attach the module + to your system using a direct cable to the motherboard, or by removing one of + your system's serial ports from the back of the case, then connecting it to a + standard serial cable to the module. + + + While connecting the serial cable to the module, be sure to configure the + module's serial interface settings. Typically, setting the module to its fastest + setting (19,200 baud, 8-N-1) is recommended. At present, the Matrix Orbital + module driver in LCDproc is hardwired to use these settings; using different + ones will require minor changes to the driver's code. + + + + + Other Display Types + + At present, we do not have any detailed information regarding the installation + of other types of LCDs. If you have any information that would be useful to + include here, please contact William Ferrell + (choadster@earthlink.net). + + + + + + LCDproc Distribution Layout + The current LCDproc distribution contains both the LCDproc server + and the LCDproc client. It also contains sparse documentation (this + document will hopefully solve this problem), and a sample Perl client. + [THIS WILL CHANGE -- REWRITE THIS PARAGRAPH] + + + Basic Layout + + LCDproc is distributed in a single archive containing both the client(s) + and the server: + + clients/ + docs/ + old/ + server/ + server/drivers/ + shared/ + tests/ + BUGS + COPYING + INSTALL + Makefile + Makefile.config + README + TODO + WHATSNEW + Contains the LCDproc client and the sample Perl client + Documentation (sparse at the moment) + Contains older source code, unused in compiling v0.4 + Contains the LCDproc server + Contains LCDproc's device drivers + Contains shared code + Contains test code not used in compiling + A list of known bugs in the current version + The GNU General Public License + Installation Instructions + File for the "make" utility, used to compile LCDproc + Contains compile-time user-tunable defaults for LCDproc + Read this file first! Contains basic information regarding LCDproc, + what it does, how it works, and how to start building it. + List of planned changes and improvements. + List of revisions that have been made to LCDproc throughout its + development. [This should be changed to ChangeLog] + + + + + A Stroll Through the Code + + This section attempts to document how LCDproc works. Both the server and + the client are explored at the source code level. This section was written + as an exercise for the author to help him better understand LCDproc's + inner workings, allowing him to better document LCDproc for end users and + developers. Feel free to skip past this entire section unless you really + feel like reading how LCDproc renders screens, manages clients, deals with + input, and handles trouble. + + + The LCDproc Server, LCDd + + LCDd is the central component of LCDproc. It is responsible for several + different activities: + + + Initializing the output device + Initializing the incoming socket + Listening for client connections and accepting them + Storing screens provided by clients + Storing stats provided by clients + Choose the best screen to display on the LCD based on order of + client and screen arrival, and by priority + Provide a rich screen-drawing widget set for clients to use + Render screens to the LCD + Gracefully handle dead sockets and clients + Gracefully remove screens and clients when asked to by clients or + the user + + + + To accomplish all this, LCDd splits into dozens of source files to handle + different bits of the job. We will examine each of these source files one by + one (and, to make things easier, in alphabetical order). Header files (*.h) + will not be included in this discussion. + + + server/client_data.c + + This file appears to contain code that handles the creation and destruction + of linked lists for client data. + + + + server/client_functions.c + + This file actually describes itself as its first comment! It contains + definitions for all the functions that the clients can run. They are to + be called only from server/parse.c. + + + Here the functions that clients call when connected to LCDd are actually + defined and performed. + + + + server/clients.c + + This file contains code allowing LCDd to handle client connections and + data structures. It contains functions to initialize the internal list + of clients, terminate client connections, add new clients to the list, + add, remove, and retrieve messages to clients' message queues, and + locating a client's socket. + + + + server/input.c + + This file contains functions that handle input from keypads, joysticks, + etc. + + + + server/main.c + + Where the action is. + + + This file contains LCDd's main() function and supporting code. It begins + life by configuring signal handlers, then by immediately initializing the + LCD drivers. (Huh?) It then parses the command line, configuring the + LCD driver appropriately, then initializes its internal lists and the + socket. + + Next, it forks into a daemon process (shedding its controlling terminal) + and enters the main loop. The main loop: listens for connections from + new clients and for input from already connected ones, parses all input + from connected clients, checks for input, then updates the screen list + and updates the LCD. + + + Also present are functions to handle graceful exits when various signals + are received, and a help screen. + + + + server/menu.c + + This appears to be code to handle server-generated menu screens on the LCD. + [I don't understand this file in the slightest ... study this harder later] + + + + server/parse.c + + This file contains code that parses input from the clients. + parse_all_client_messages() is called once each time through main()'s loop. + + + + server/render.c + + This file contains code that actually generates the full screen data to + send to the LCD. draw_screen() takes a screen definition and a counter as its + arguments. It builds the screen according to the definition, and using the + counter as a reference. + + + + server/screen.c + + This file stores all the screen definition-handling code. Functions here + provide means to create new screens and destroy existing ones. Screens are + identified by client and by the client's own identifiers for screens. + + + + server/screenlist.c + + This appears to be the screenlist handler that decides which screen to + display based on priorities and screen creation order. + + + + server/serverscreens.c + + This file contains code to allow the server to generate its own screens. + Currently, only the server status screen is provided, showing total number + of connected clients, and the combined total of screens they provide (this + count does not include the server's screens). + + + It is interesting to note that the server creates a special screen + definition for its screens, but uses the same widget set made available + to clients. + + + + server/sock.c + + This file contains all the sockets code used by the server. This contains + the code called upon by main() to initialize the listening socket, as well + as code to deal with sending messages to clients, maintaining connections, + accepting new connections, closing dead connections (or connections + associated with dying/exiting clients), etc. + + + + server/widget.c + + This file houses code that handles the creation and destruction of widget + objects for the server. These functions are called using the arguments + passed by the client, then they store the specified widget into a generic + container that is parsed later by the screen renderer. + + + + server/drivers/* + + These are the individual driver files. Each driver allows LCDproc to display + its output on a different device. A driver is responsible for accepting + LCD-like handling instructions from LCDd, and for returning input from the + device to LCDd. + + + Currently, drivers provided are MtxOrb, hd44780, curses, and joy. The + joystick (joy) driver doesn't provide output, but only input. + + + + + The LCDproc Client + + The client shipped with LCDproc performs all of the statistic gathering + previously performed by LCDproc v0.3.x. Instead of driving the LCD directly, + in this version it now connects to LCDd and sends its screens and data there. + + + In this implementation of the statistic-gathering portions of LCDproc, the + layout departs substantially from the older v0.3.x code. Each screen is + generated by functions stored in separate files -- one file per screen. + This keeps files smaller, and code much simpler to maintain and update. + + + The client appears to use files from the share/ tree as well. + + + clients/lcdproc/batt.c, chrono.c, cpu.c, disk.c, load.c, mem.c + + These files contain the functions implementing all the screens provided by + LCDproc. + + + Each contains several functions, mostly related to actual statistic gathering. + They are also apparently responsible for actually transmitting their screen + definitions to the server and answering the server's requests for statistic + updates. The functions here do *no* checking to determine if they are being + asked for. They *do* check to see if they need to create a new screen + definition or merely update it. It would appear that the client's main() or + other higher-level function is responsible for calling this function when the + server asks for an update. + + + + clients/lcdproc/main.c + + This file contains the LCDproc client's main() function, as well as a few + supporting functions. + + + It first declares and fills a modelist (used only internally by this client) + that determines which screens will run by default (if the user doesn't + specify a custom modelist on the command line). The first thing main() itself + does is configure the signal handlers. + + + Next, it parses the command line for options, yelling at the user if an + invalid or nonsensical argument has been specified. After it has done this, + it tries to open a socket connection to LCDd. If successful, execution + continues. If unsuccessful, the client exits gracefully. + + + Assuming a valid socket connection is established, it sends the "hello" + command to the server, introducing itself and convincing the server that yes, + it really *should* serve this client. Next, it calls the mode_init() function + which appears to set up data structures for the various modes, and then finally + the main_loop() function which executes indefinitely until the client is + killed or is asked to stop. Then the program exits cleanly. + + + main_loop() is defined in this file as well. The main loop listens for any + input from the server, and reacts on what it receives. It appears capable of + dealing with keypresses, listen/ignore signals, and menu activity. After it + has reacted appropriately to inputs, it runs the screen asked for by the + server. + + + The old main() is commented out, but included here for reference. Eventually, + this will be removed from LCDproc's source. For now, however, it serves as a + useful reference. + + + + clients/lcdproc/mode.c + + This file contains functions responsible for initializing mode screens and + calling the appropriate mode screen update function when asked to do so. + main_loop() passes the server's parsed messages to this function to enable it + to select which screen is called for. + + + This file also contains reread() and getentry() functions which are used by + many of the mode screens. + + + + + Shared Files + + Both LCDd and the LCDproc client make extensive use of linked lists and sockets + code. Much of that code is shared, and stored in the shared/ tree. + + + shared/config.c + + This file contains the beginnings of configuration file code. + + + + shared/LL.c + + This file contains all of the functions used in implementing LCDproc's + linked lists. Functions exist here to create new lists, destroy lists, + remove an entry from a list, add an entry to a list, move a pointer to + the beginning or end of a list, move a pointer to the next item in a + list, the previous item of a list, or to retrieve individual items from + a list. + + + + shared/sockets.c + + This file contains all the functions used in implementing LCDproc's socket + handling capabilities. Full bi-directional communication is implemented by + these functions. + + + + shared/str.c + + This file contains only one function, get_args(). It appears to parse + command lines (or command line-like strings) for arguments, and returns them + in a more useful form. + + + + + + diff --git a/docs/menustuff.txt b/docs/menustuff.txt new file mode 100644 index 0000000..bcd79ad --- /dev/null +++ b/docs/menustuff.txt @@ -0,0 +1,126 @@ +Allo... (warning: this was written as I thought it up :) + +Ideas for implementing menus... + +We've got a data structure called "Menu_Item", which has (for starters): + + Title -- Text to display + Child -- Sub-Menu to recurse into, if item is picked + Exec Function -- Function to call if the item is picked + +An item must not have both a child and an exec function. + +The DoMenu(main_menu) handles all input and either calls ExecFunction, +if the picked item has one; or recurses into the Child menu. The +ExecFunction returns a value to specify whether the menus should go +away, back up one level, or stay as-is. Also, a menu title (label) +can be specified by giving neither a Child nor a Function. + +The up/down arrows, blinking, scrolling, etc, are handled by DoMenu(). + +This gives us the functionality of a standard pull-down menu. +However, we need more functionality than that. We need checkboxes, +sliders, and a way to move items up/down. + +So... + +The ExecFunction should take a parameter, telling whether the item was +simply picked, or if it had a +/- pressed on it. This lets us change +a value from the menu. + +We should also add another function to the MenuItem struct: + + Data Function -- returns true, false, or 0-255. + +This lets us find out if a checkbox should be checked, or where a +slider should be. DoMenu() will figure out what widget it's dealing +with (if any), and adjust its display accordingly. + +But we still can't move menu items up/down. + + +... + + +Perhaps... This might work better: + + Title -- Text + Type -- menu, function, checkbox, slider, mover + Data -- Child, ExecFunc, CheckFunc, SlidFunc, ??? + +When an item is picked, DoMenu() decides what to do based on type. +--"Menus" will recurse into the "data", assuming it's a child menu. +--"Function"-type items will have their function called. +--CheckBox-type items will have their function called with a "read" + parameter to get an on/off signal, and called with a "set" signal when + picked. +--Sliders will have the same "read" thing, and the "set" function will + take a plus or minus parameter. +--The Movers will act like a label until picked, and then the +/- keys + will both rearrange the menu, and send the item a signal of some sort + to indicate what happened. It'll act like a label again after the + user presses Enter again. + +The "Data" field will really be a "void *", which is C's "generic" +data type... + +Anyway, this sort of thing would be declared this way: + +======================================================================== + +Menu MainMenu = { + "MENU", NULL, NULL, // Title + "Options", MENU_TYPE, (void *)OptionsMenu, + "Kill LCDproc", FUNC_TYPE, (void *)Shutdown_func, + NULL, NULL, NULL, +}; + +Menu OptionsMenu = { + "OPTIONS", NULL, NULL, // Title + "24-hour Time", CHEK_TYPE, (void *)Time24_func, + "Contrast...", SLID_TYPE, (void *)Contrast_func, + NULL, NULL, NULL, +}; + + +///////////////// Elsewhere, we declare these... + +void Shutdown_func() +{ + // Do something here... + return MENU_KILL; // or MENU_CLOSE, or MENU_OK, or MENU_ERROR +} + +int Time24_func(int input) +{ + if(input == READ) return status; + if(input == SELECT) toggle_status(); // does something. + return (status | MENU_OK); + // The status is "or"-ed with the MENU value to let DoMenu() + // know what to do after selecting the item. (two return + // values in one. :) + + // Also, "MENU_OK" happens to be zero, so it doesn't matter + // unless you want something else (like MENU_CLOSE) +} + +int Contrast_func(int input) +{ + if(input == READ) return status; + if(input == PLUS) increment_status(); // does something. + if(input == MINUS) decrement_status();// does something. + return (status | MENU_OK); +} + + +======================================================================== + +The main reason I like this is that it completely separates the menu +definitions from the code which actually handles it. We have *one* +function which does everything menu-related. + +Also, we'd include a table of some sort to match names to functions, +so that the user can create their own menus with the functionality +already provided. (including user-defined "functions", which will be +rather limited but still useful) + diff --git a/docs/netstuff.txt b/docs/netstuff.txt new file mode 100644 index 0000000..e6f8810 --- /dev/null +++ b/docs/netstuff.txt @@ -0,0 +1,298 @@ +LCDproc client/server protocol +--------------------------------------------- + + +QUICKSTART +---------- + - Open a socket to the LCDproc port (usually 13666). + - say "hello" + - the server will notify you of a good connection, and some info + on the type of display available. + - Identify yourself. "client_set name some_sort_of_name" + - Add a new screen. "screen_add my_screen" + - Put a widget on the screen. + "widget_add my_screen my_widget string" + - Now, update the widget whenever your status info changes... + "widget_set my_screen my_widget 1 1 Booger!" + + - When you're done, just close the socket. + - You probably want to read on for more information, once you've + gotten the LCDproc server to display something. :) + + + +DETAILS +------- + +There are two parts to the spec: + A language for client/server to interact with. + A protocol guiding interactions. + +=================== The protocol ================================== + +The protocol is context-free. So, no commands require responses; and +responses are simply commands. + +The client may send updated info at any time, and the server decides +whether to display it. An ideal communication may flow like this: + client->server server->client + ------------------ ------------------- + (idle) (nothing) + (idle) "I'm listening" + new stats... (nothing; displays updated stats) + new stats... (nothing...) + new stats... (nothing...) + new stats... "Okay, be quiet" + (idle) (nothing; displays new screen) + ... ... + (idle) "Your slider moved up" + Set slider value: 43 (nothing; displays updated slider) + (idle) (nothing) + ... ... +But the client could safely continue to send new stats, knowing that +the server isn't listening and won't display it. Also, the client could +ignore the slider change, and the slider onscreen simply wouldn't move. + + +=================== The syntax ================================== + +The language is ascii-based, so a human can telnet to a port and talk +to the server. This helps with development and debugging. + +With that in mind, a commandline-like syntax seems good: + + function arg1 arg2 arg3 ... + +The syntax dictates that the first word is a function name, and the +rest of the line is passed to that function as an argument. +String-type arguments should always come last. So, for example: + + set_label 23 3 2 Hey, booger. What's up? + +The first argument is a label id number, the 2nd and 3rd are x,y +coordinates onscreen, and the rest of the line is a string. + + +=================== The command set ================================== + +The naming convention dictates that function names are lower-case, +with underscores ("_"'s) between words. + +The naming convention also requires that function-name words go in +descending order. So, "screen_set_priority" would be okay, but +"set_screen_priority" would not. + +Id's are strings. (the "#id" things) + +In general, we're trying to keep the command set small. Especially the +server->client functions, so that clients won't have to handle a lot of +different types of input. + +Now, the function list: + +client->server functions +------------------------- +hello + Client init. You must send this before the server will pay + any attention to you. You'll get some info about the server + in return... (a "connect" string) + + +client_set [name #id] + Set client's name and other info + +client_add_key #id + Tells the server the client can handle keypresses of type #id. + #id is probably just "A", "B", and so on... + All keypresses are disabled by default, so you'll have to tell + the server which ones you want to accept... + +client_del_key #id + Tells the server to never send that keypress. + All keypresses are disabled by default. + + +screen_add #id + Add a new screen + +screen_del #id + Remove a screen + +screen_set #id [priority integer] [name "my_name"] [duration integer] + [wid width] [hgt height] + Initialize a screen, or reset its data. + Priority values are as follows: + 0 You feel like getting kicked off the server, don't you? + 1 The world is about to explode + 16 Emergency priority + 32 Very high priority (important) + 64 High priority (normal) + 128 Normal (recommended) + 192 Low priority (normal) + 224 Very low priority (very unimportant) + 240 Boring as hell + 255 This screen won't show up very much even if there are + no other screens queued... + An example of using priorities is as follows. + + Imagine you're making an mp3 player for LCDproc. When the + song changes, it's nice to display the new name immediately. + So, you could set your screen's priority to 64, wait for + the server to display (or ignore) your screen, then set the + screen back to 128. This would cause the mp3 screen to + show up as soon as the one onscreen was finished, then + return to normal priority afterward. + + Or, let's say your client monitors the health of hospital + patients. If one of the patients has a heart attack, you + could set the screen priority to 16 (emergency), and it + would be displayed immediately. It wouldn't even wait for + the previous screen to finish. ... And it would stay there + most of the time until the user did something about it. + + A priority of 1 would stay onscreen permanently, with + flashing lights and other visual cues if possible. + ... Please *don't* use this priority. :) + + The duration can be either a positive number, or -1. A + positive number indicates how many display frames the screen + should last for. A 0 or -1 means that the server should use + "auto" duration, which is probably a good idea. This will be + whatever the user wants. It defaults to 4 seconds (32 + frames), or will be calculated for things such as scrollers. + +widget_add #screen #id type [-in #id] + Add something onscreen + Widget types can be any of the following: "string", "hbar", + "vbar", "title", "icon", "scroller", "frame", ... more later? + Widgets are drawn in the order you create them. + + You can put a widget inside a frame by adding "-in #id", where + #id is the name of a frame. + +widget_del #screen #id + Kill something onscreen + +widget_set #screen #id data + Set (reset) widget's data + Note that the "string" type should be used for frame buffers. + Strings should not be bigger than the screen. + The widgets take these arguments for data: + + string x y text + + hbar x y length_in_pixels + + vbar x y length_in_pixels + + icon x y binary_data + + title text + + scroller left top right bottom direction speed text + + A scroller is a string which scrolls. + This is useful for things such as the disk + usage screen, which may be very tall. + The speed is how many display frames to delay + between scrolling. Each display frame is + 1/8th of a second, by default. + Direction must be "h" or "v". + Positive speeds indicate frames per movement. + Negative speeds indicate movements per frame. + + frame left top right bottom wid hgt dir speed + + Frames occupy the area (left, top)-(right,bottom) + onscreen, and the inside area is wid x hgt. + The inside may be bigger than the actual size, + so that the frame will scroll. + + +server->client functions +------------------------- +connect args + Verifies connection; gives info about the LCD, etc... + +bye + Notifies the client of a server shutdown. + +huh? [info] + Notifies the client of a request error. + +listen [#screen [#widget [#widgets...]]] + Notifies client that "server is listening for data". + +ignore [#screen [#widget [#widgets...]]] + Tells the client "shut up". + +key #id + Sends a keypress to the client. + + + + +--- Not implemented yet --- +The functions below are planned but not completed. + + +client->server functions +------------------------- +menu_add #id + Add a new menu. + +menu_del #id + Get rid of a menu. + +menu_set [top] [name my_menu_name] + if (top) Gets added to "Client Menus". + else Client must insert it into its own menu heirarchy. + +menu_item_add #menu #id + Add a new, blank menu item. + +menu_item_del #menu #id + Delete a menu item. + +menu_item_set #menu #id type [value] text + (re)Set the menu item's data. + If type is "checkbox" or "slider" or "menu", [value] should + contain appropriate info. (like true, 43, or #menuid) + + +backlight [on] [off] [blink] [flash] [toggle] + Requests that the backlight be toggled... The backlight + command will likely be ignored, but users can enable it if + desired. + + The LCDproc server has [will have] several backlight modes: + On Stays on all the time + Off Stays off all the time + Load? Turns off when the load average is low + Shell? Controlled by a user-supplied shell script + Open Can be controlled by all clients + Vis Controlled by the currently visible client + + +driver_add #id? type args + Start up a new output driver. + Nice if you want to check on your machine remotely with the + curses driver. + +driver_del #id? (or type) + Stop a running output driver. + Good for reclaiming your joystick when you want to play games... + + + + +server->client functions +------------------------- +menu #menu #item #action + Tells the client that a menu item was selected/used/etc... + The action can be "click", "up", or "down". The client should + handle this according to what type of menu item has been + activated, and should probably send the server a new item + definition if the item was a checkbox or slider. + + diff --git a/old/LCDproc_objectmethods.txt b/old/LCDproc_objectmethods.txt new file mode 100644 index 0000000..7dea5eb --- /dev/null +++ b/old/LCDproc_objectmethods.txt @@ -0,0 +1,49 @@ +Object methods and properties and some vars + +Tcomms + Properties + int InboundFD (for select to watch if>0) + IMODE imode {none,polled,fd} (method for reading data) + Tconfig config + Methods + ParseConfig(TConfig config) + Init + poll + writechar + writestr + +Tserial + Private Vars + char port[] + int speed + Properties + + + +Tdriver + Properties + Tconfig config + int backlight_state + int disp_width + int disp_height + Methods + Init + ClearScr + NewCustomChar(struct CustChar defination) + PutCustChar(zoff,yoff,char) + PutChar(xoff,yoff,char) + PlaceString(xoff,yoff,string) + DrawHorizBar(xoff,yoff,chwidth,percentage) + DrawVertBar(xoff,yoff,chheight,percentage) + + + +Tdisplay + Properties + Tdriver driver + Tconfig config + int RefreshInterval (for clock would be 500 for every half second) + Methods + HardInit (called once on prog start) + Init (called on every new cycle) + diff --git a/old/LCDproc_objects.txt b/old/LCDproc_objects.txt new file mode 100644 index 0000000..ba1ee9f --- /dev/null +++ b/old/LCDproc_objects.txt @@ -0,0 +1,92 @@ +LCDproc suggestion object hierarchy + +Tdriver + TVirtualDriver + TMtxOrbDriver + TTextDriver + +Tcomms + TSerial + TParallel + TSCSI + +Tdisplay + Tclock_dsp + Tmail_dsp + Tcpustate_dsp + Tcpugraph_dsp + Tmeminf_dsp + Tuptime_dsp + Txload_dsp + Tcredits_dsp + Theartbeat_dsp + Tstub_dsp + Tusercfg_dsp + +Tremote + Ttcpsockd + TUNIXsockd + +Tchannel + Ttcpsocket + TUNIXsocket + +Tconfig + +Tfeedback + TMtxOrb_keypad + Tserial_buttons + +Tschedular + +--------------------------------------------------- + +Object brief descriptions + +Tdriver (and decendants) provide manipulation of the physical +LCD panel including backlight, typeface loading, etc. +Tdriver will provide default methods for tasks such as + text centering + scrolling + screen clearing + etc + TVirtualDriver could act as a frame buffer / virtual display. + This would allow several display objects to access the (virtual) + display in a single cycle and then the virtual driver can flush + the changes from the last display (delta display) in a single pass. + This provides a portable way to implement display objects + (like the heartbeat which only changes one character at a time) + but overlap a standard full screen display + + + Tcomms (and decendants) transmit and receive all data to and + from the communications interfaces. Tdriver and Tfeedback will + use these objects directly. + + Tdisplay (and decendants) generate the actual display information + by manipulating the Tdriver object which has been given to it. + The Tdriver object should usually be a TVirtualDriver descendant. + + Tremote (and decendants) create, keep track of and ultimately destroy + Tchannel objects. Each Tchannel can potentitally be an external + connection to a remote client. The remote client can generate + either complete screens in a similar style to a Tdisplay object with + Tchannel using a Tstub_dsp to generate the screen based on info + supplied to it or it can feed data into an existing Tdisplay object + (Tchannel will do this by setting Tdisplay properties). + + Tconfig is responsible for parsing the command line and reading/re-reading + the contents of a configuration file. + + Tfeedback (and its descendants) may communicate with a Tcomms object to + retrieve information from a keypad or other input device. + + Tschedular is responsible for the overall co-ordination of everything. + + +Other notes: + I can't decide things like "should scroll stuff be down to Tdriver + or Tdisplay?". + Some sort of Thash would be a useful way of passing data from + sockets to display objects as well + diff --git a/old/cfg.c b/old/cfg.c new file mode 100644 index 0000000..75866f9 --- /dev/null +++ b/old/cfg.c @@ -0,0 +1,443 @@ +/*********************************************** +** +** cfg.c v0.01 +** +** Generic config file handler +** (c) Gareth Watts 1998 +** gareth@omnipotent.net +** +** Alpha code as of 980601 +*/ + +#include +#include +#include +#include +#include + +#include "cfg.h" + + + +/************************** +* PUBLIC METHODS +*/ + +void cfg_free(cfg *self) { + struct cfg_node *ptr, *nextptr; + int i; + + for(i=0;icfg_hash[i]) { + for(ptr=self->cfg_hash[i];ptr;ptr=nextptr) { + nextptr=ptr->next; + free(ptr->optname); + free(ptr->optvalue); + free(ptr); + } + } + } + free(self->filename); + free(self->lasterror); + self->_queuefree(self); + free(self); +} + + +#define CFG_BUZSIZE 4096 +int cfg_openfile(cfg *self,char *fn,int mode) { + char buffer[CFG_BUZSIZE]; + char *keyname,*keyvalue; + int comment; + FILE *fh; + + self->filename=strdup(fn); + fh=fopen(fn,"r"); + if (!fh) { + if (mode==CFG_READONLY) { + self->lasterror=strdup(strerror(errno)); + return(1); + } + return(0); /* read/write but file not found */ + } + + // READ AND PARSE FILE HERE + while(feof(fh)==0) { + fgets(buffer,CFG_BUZSIZE-1,fh); + if (strlen(buffer)) { + if (buffer[strlen(buffer)-1]=='\n') { + buffer[strlen(buffer)-1]='\0'; + } + if (buffer[0]=='#') { + comment=1; + } else { + comment=0; + } + } else { comment=1;} + if (!comment&&self->_splitline(self,buffer,&keyname,&keyvalue)) { + return(1); /* memory error or somesuch */ + } + if (!comment&&keyname&&keyvalue) { + if (!self->_lookup(self,keyname)) { + self->_insert(self,keyname,keyvalue,0); + } + } + + } + return(0); +} + + +char *cfg_getstring(cfg *self,char *keyname) { + return(self->_lookup(self,keyname)); +} + + +int cfg_getint(cfg *self,char *keyname) { + int result=0; + char *keydata; + + keydata=self->_lookup(self,keyname); + if (keydata) + sscanf(keydata,"%d",&result); + return(result); +} + + +/* This is virtually useless due to rounding errors */ +float cfg_getfloat(cfg *self,char *keyname) { + float result=0.0; + char *keydata; + + keydata=self->_lookup(self,keyname); + if (keydata) + sscanf(keydata,"%f",&result); + return(result); +} + + +int cfg_setstring(cfg *self,char *keyname, char *keyvalue) { + return(self->_set(self,keyname,keyvalue)); +} + + +int cfg_setint(cfg *self,char *keyname, int keyvalue) { + char buffer[200]; + + sprintf(buffer,"%d",keyvalue); + return(self->_set(self,keyname,buffer)); +} + +int cfg_setfloat(cfg *self,char *keyname, float keyvalue) { + char buffer[200]; + + sprintf(buffer,"%f",keyvalue); + return(self->_set(self,keyname,buffer)); +} + +int cfg_flush(cfg *self) { + if (self->filemode==CFG_READONLY) { + return(0); + } else { + return(self->_flush(self)); + } +} + + +int cfg_autoflush(cfg *self,int aflush) { + self->aflush=(aflush>0); + return(0); +} + + + +/************************** +* PRIVATE/INTERNAL METHODS +*/ + +int _cfg_init(cfg *self) { + memset(self->cfg_hash,0,sizeof(self->cfg_hash)); + return(0); +} + + +int _cfg_queuepush(cfg *self, struct cfg_node *node) { + struct cfg_queuenode *ptr; + + ptr=(struct cfg_queuenode *)calloc(1,sizeof(struct cfg_queuenode)); + if (!ptr) return(1); + ptr->ref=node; + if (self->cfg_newsttail) { + self->cfg_newsttail->next=ptr; + self->cfg_newsttail=ptr; + } else { + self->cfg_newsthead=self->cfg_newsttail=ptr; + } + return(0); +} + + +struct cfg_queuenode *_cfg_queuenext(cfg *self, struct cfg_queuenode *last) { + if (last) { + return(last->next); + } else { + return(self->cfg_newsthead); + } +} + + +int _cfg_queuefree(cfg *self) { + struct cfg_queuenode *ptr,*next; + + for(ptr=self->cfg_newsthead;ptr;ptr=next) { + next=ptr->next; + free(ptr); + } + self->cfg_newsthead=self->cfg_newsttail=NULL; + return(0); +} + + +int _cfg_getkey(cfg *self,char *str) { + unsigned int total; + int i=1; + int j=0; + + total=(*str)-0x20; + str++; + while(*str) { + total+=i*((*str)-0x20); + str++; + i+=(33+j++)*j; + } + return(total % CFG_HASHSIZE); +} + + +int _cfg_insert(cfg *self,char *keyname, char *keyval,int dirty) { + int key,match=0; + struct cfg_node *ptr,*nextptr;; + + key=self->_getkey(self,keyname); + if (!self->cfg_hash[key]) { + self->cfg_hash[key]=(struct cfg_node *)calloc(1,sizeof(struct cfg_node)); + if (!(self->cfg_hash[key]->optname=strdup(keyname))) { + return(1); + } + if (!(self->cfg_hash[key]->optvalue=strdup(keyval))) { + return(1); + } + if (dirty) self->_queuepush(self,self->cfg_hash[key]); + } else { + for(nextptr=self->cfg_hash[key];(nextptr)&&(!match);nextptr=ptr->next) { + ptr=nextptr; + match=(strcasecmp(ptr->optname,keyname)==0); + } + + if (match) { /* node already exists / overwrite */ + free(ptr->optvalue); + ptr->dirty=dirty; + } else { /* new node */ + ptr->next=(struct cfg_node *)calloc(1,sizeof(struct cfg_node)); + ptr=ptr->next; + if (!(ptr->optname=strdup(keyname))) { + return(1); + } + if (dirty) self->_queuepush(self,ptr); + } + if (!(ptr->optvalue=strdup(keyval))) { + return(1); + } + } + return(0); +} + + +struct cfg_node *_cfg_getnode(cfg *self, char *keyname) { + int key; + struct cfg_node *ptr,*next; + int match=0; + + key=self->_getkey(self,keyname); + if (!self->cfg_hash[key]) + return(NULL); + for(next=self->cfg_hash[key];next&&!match;next=ptr->next) { + ptr=next; + match=(strcasecmp(ptr->optname,keyname)==0); + } + if (match) + return(ptr); + return(NULL); +} + + +char *_cfg_lookup(cfg *self,char *keyname) { + struct cfg_node *ptr; + + ptr=self->_getnode(self,keyname); + if (ptr) + return(ptr->optvalue); + else + return(NULL); +} + + +int _cfg_cleardirty(cfg *self,struct cfg_node *ptr) { + ptr->dirty=0; + return(0); +} + + +int _cfg_set(cfg *self,char *keyname,char *keyvalue) { + int key; + + key=self->_getkey(self,keyname); + if (self->_insert(self,keyname,keyvalue,1)!=0) { + return(1); /* error */ + } + if (self->aflush) { + return(self->flush(self)); + } + return(0); +} + +int _cfg_splitline(cfg *self,char *src, char **f, char **s) { + char *brkpoint; + int offset,slen,fpos; + static char first[4096],second[4096]; + + *f=*s=NULL; + if ((brkpoint=strchr(src,'='))==NULL) { + return(0); + } + offset=brkpoint-src; + slen=strlen(src); + if (offset==slen-1) { + return(0); + } + if (offset>4094) {offset=4094;} + + memset(first,0,4096); + memset(second,0,4096); + strncpy(first,src,offset); + strncpy(second,brkpoint+1,4095); + + fpos=strlen(first)-1; + while((first[fpos]==' ')&&fpos) { + first[fpos]='\0'; + fpos--; + } + *f=first; + for(*s=second;(**s)&&(**s==' ');(*s)++); + return(0); +} + + + +#define CFGF_MAXLINES 50000 +#define CFGF_LINELEN 4096 +int _cfg_realflush(cfg *self) { + char *outbuf[CFGF_MAXLINES]; + char buffer[CFGF_LINELEN]; + int linenum=0; + int comment,i; + char *keyname,*keyvalue; + struct cfg_queuenode *qptr; + struct cfg_node *ptr; + FILE *fh; + char *rd; + + fh=fopen(self->filename,"r"); + if (fh) { + while((feof(fh)==0)&&(linenum_splitline(self,buffer,&keyname,&keyvalue)) { + fclose(fh); + return(1); /* memory error or somesuch */ + } + if ((keyname)&&(ptr=self->_getnode(self,keyname))&&(ptr->dirty)) { + sprintf(buffer,"%s = %s",ptr->optname,ptr->optvalue); + outbuf[linenum]=strdup(buffer); + self->_cleardirty(self,ptr); + } else { + outbuf[linenum]=strdup(buffer); + } + } + linenum++; + } + } + fclose(fh); + } + for(qptr=self->_queuenext(self,NULL);qptr;qptr=self->_queuenext(self,qptr)) { + sprintf(buffer,"%s=%s",qptr->ref->optname,qptr->ref->optvalue); + outbuf[linenum]=strdup(buffer); + linenum++; + } + fh=fopen(self->filename,"w"); + if (!fh) { + self->lasterror=strdup(strerror(errno)); + return(1); + } + for(i=0;i_queuefree(self); + return(0); +} + + + + + + +/***************** +* THE CONSTRUCTOR +*/ + +cfg *cfg_new() { + cfg *ptr; + + ptr=(cfg *)calloc(1,sizeof(cfg)); + if (!ptr) return(NULL); + + ptr->getstring=cfg_getstring; + ptr->getint=cfg_getint; + ptr->getfloat=cfg_getfloat; + ptr->openfile=cfg_openfile; + ptr->setstring=cfg_setstring; + ptr->setint=cfg_setint; + ptr->setfloat=cfg_setfloat; + ptr->flush=cfg_flush; + ptr->autoflush=cfg_autoflush; + ptr->free=cfg_free; + + ptr->_getkey=_cfg_getkey; + ptr->_insert=_cfg_insert; + ptr->_lookup=_cfg_lookup; + ptr->_cleardirty=_cfg_cleardirty; + ptr->_set=_cfg_set; + ptr->_splitline=_cfg_splitline; + ptr->_queuepush=_cfg_queuepush; + ptr->_queuenext=_cfg_queuenext; + ptr->_queuefree=_cfg_queuefree; + ptr->_getnode=_cfg_getnode; + ptr->_flush=_cfg_realflush; + + if (_cfg_init(ptr)) return(NULL); + return(ptr); +} + diff --git a/old/cfg.h b/old/cfg.h new file mode 100644 index 0000000..f166cb5 --- /dev/null +++ b/old/cfg.h @@ -0,0 +1,70 @@ +/*********************************************** +** +** cfg.h v0.01 +** +** Generic config file handler +** (c) Gareth Watts 1998 +*/ + + +#define CFG_READONLY 1 +#define CFG_READWRITE 2 + + +struct cfg_node { + char *optname; + char *optvalue; + int dirty; + struct cfg_node *next; +}; + + +struct cfg_queuenode { + struct cfg_node *ref; + struct cfg_queuenode *next; +}; + + +#define CFG_HASHSIZE 1297 +typedef struct cfg { + + // PUBLIC METHODS + void (*free)(struct cfg *self); + int (*openfile)(struct cfg *self,char *fn,int mode); + int (*autoflush)(struct cfg *self,int flushmode); + char *(*getstring)(struct cfg *self,char *key); + int (*getint)(struct cfg *self,char *key); + float (*getfloat)(struct cfg *self,char *key); + int (*setstring)(struct cfg *self,char *key, char *value); + int (*setint)(struct cfg *self,char *key, int value); + int (*setfloat)(struct cfg *self,char *key, float value); + int (*flush)(struct cfg *self); + + // PUBLIC DATA + char *lasterror; + + + // PRIVATE METHODS + int (*_init)(struct cfg *self); + int (*_getkey)(struct cfg *self,char *str); + int (*_insert)(struct cfg *self,char *keyname,char *keyval,int dirty); + struct cfg_node *(*_getnode)(struct cfg *self,char *keyname); + char *(*_lookup)(struct cfg *self,char *keyname); + int (*_cleardirty)(struct cfg *self,struct cfg_node *ptr); + int (*_splitline)(struct cfg *self,char *src, char **f, char **s); + int (*_set)(struct cfg *self, char *keyname, char *keyvalue); + int (*_queuepush)(struct cfg *self, struct cfg_node *node); + struct cfg_queuenode *(*_queuenext)(struct cfg *self, struct cfg_queuenode *last); + int (*_queuefree)(struct cfg *self); + int (*_flush)(struct cfg *self); + + // PRIVATE DATA + struct cfg_node *cfg_hash[CFG_HASHSIZE]; + struct cfg_queuenode *cfg_newsthead; + struct cfg_queuenode *cfg_newsttail; + char *filename; + int filemode; + int aflush; +} cfg; + +cfg *cfg_new(); diff --git a/old/cfg_test.c b/old/cfg_test.c new file mode 100644 index 0000000..bc94fb0 --- /dev/null +++ b/old/cfg_test.c @@ -0,0 +1,76 @@ +/********************************************* +** cfg.c example +** gareth@omnipotent.net 1/June/1998 +** +** This code will create cfg_testfile.cfg if +** it doesn't already exist and set some +** values within it. Simple really. +*/ + +#include +#include +#include + +#include "cfg.h" + + +#define TESTFILE "cfg_testfile.cfg" + +int main() { + cfg *cfgfile; + + /* First create our object */ + if ((cfgfile=cfg_new())==NULL) { + printf("Error creating config object\n"); + exit(255); + } + + /* Then find a config file to open */ + if (cfgfile->openfile(cfgfile,TESTFILE,CFG_READWRITE)!=0) { + printf("Error reading file: %s\n",cfgfile->lasterror); + cfgfile->free(cfgfile); + } + + /* Save to disk on every update */ + cfgfile->autoflush(cfgfile,1); + + /* print out the current settings - Will return NULL if */ + /* they don't currently exist (eg. new file) */ + printf("'A test string' is set to '%s'\n", + cfgfile->getstring(cfgfile,"A test string")); + printf("'A test integer' is set to %d\n\n", + cfgfile->getint(cfgfile,"A test integer")); + + /* set to some new values */ + cfgfile->setstring(cfgfile,"A test string","Marvin the paranoid android"); + cfgfile->setint(cfgfile,"A test integer",42); + + /* print out the new settings */ + printf("'A test string' is now set to '%s'\n", + cfgfile->getstring(cfgfile,"A test string")); + printf("'A test integer' is now set to %d\n\n", + cfgfile->getint(cfgfile,"A test integer")); + + + /* set the values to something else with autoflush off */ + cfgfile->autoflush(cfgfile,0); + cfgfile->setstring(cfgfile,"A test string","Life, don't talk to me about life"); + cfgfile->setint(cfgfile,"A test integer",417362); + + /* print out the new settings */ + printf("'A test string' is finally set to '%s'\n", + cfgfile->getstring(cfgfile,"A test string")); + printf("'A test integer' is finally set to %d\n\n", + cfgfile->getint(cfgfile,"A test integer")); + + /* flush the last set of data to disk as autoflush is off */ + cfgfile->flush(cfgfile); + + + /* cleanup */ + + cfgfile->free(cfgfile); + + return(0); +} + diff --git a/old/cfg_testfile.cfg b/old/cfg_testfile.cfg new file mode 100644 index 0000000..5a54dc4 --- /dev/null +++ b/old/cfg_testfile.cfg @@ -0,0 +1,15 @@ +########################## +# Test file thingy! # +########################## + +# A string of some sort... +A test string = Life, don't talk to me about life +# An integer... +A test integer = 417362 + +My flag = yes +My other flag = true + +#################### Here's a big-ass comment! ############################################################################################ See, it goes on for a long time! #################################################### + +And stuff = Hell, yeah! diff --git a/old/change.log b/old/change.log new file mode 100644 index 0000000..07a044c --- /dev/null +++ b/old/change.log @@ -0,0 +1,73 @@ +1998-04-26: Scott + all: Implemented logical/physical drivers.. Whew! + main.c, mode.c, lcd.* have changed, and I've added text.* and + MtxOrb.* driver files... + New commandline option "-l driver" selects a driver. + +1998-04-21: Scott + all: Lots of updates... (patches, etc) + Implemented a frame buffer, and custom characters... + Added lots of comments, and cleaned a few things... + Added a few function to lcd.c + +1998-03-22: Scott + main.c: Should exit cleanly now, always... It sometimes wouldn't, if killed + by init at shutdown... (it would get stuck in a usleep for too + long, and then get killed instead of shutting down) + main.c: Changed timing method... Sequences now specify their length in + TIME_UNITs. A time unit is 1/8th of a second. This should make + blinking and other such things easy... + main.c: Removed command line options to specify timings... Why would the + user really need to change that anyway? + main.c: A few mode-feedback things are implemented: blinking, and backlight + on/off stuff... + mode.c: Xload_screen now sends feedback to toggle blinking for a high load, + or turn the backlight off for no load... + +1998-03-13: Scott + Makefile: Installs man page in /usr/local/man/man1... + main.c: Now detects previously running lcdproc. + lock.?: New files for detecting another lcdproc... + Now detects an already-running process, and gets its pid. So far, + it just exits when this happens. + +1998-02-28: Scott + Makefile: Now handles installation with "make install". + main.c: New command line stuff... (in man page) Also, default contrast is + 140 now. Looks better from all angles, at least on my machine. :) + lcd.1: Man page. New.. :) + mode.c: Rearranged memory screen.. Shows Memory and Swap space separately, + with two graphs. + +1998-02-24: Scott + mode.c: Rearranged memory screen. Worked around hbar bios bug. Added swap + info to this screen also, so get_mem_info is back to its former + state. (call it on an array) + mode.c: Fixed xload screen. It was displaying things one space to the left. + main.c: Changed command line style from "mode num_times delay_time" to + "mode total_time delay_time". Is this better or worse? + +1998-02-22: Scott + main.c: Now handles SIGINT (Ctrl-C) and SIGTERM (kill) for a clean exit. + main.c: Default device now works. (device[] was getting overwritten by + argv[0], which would always be "lcd") + mode.c: Fixed CPU load meter. Decreased cpu buffer size back to 4. + mode.c: Made goodbye_screen() do something... + mode.c: Fixed am/pm on clock_screen(). Was previously displaying 12:xx:xxA + during the noon hour, instead of 12:xx:xxP. + +1998-02-18: Scott + mode.c: Fixed crash on memory screen; commented out last two lines of + get_mem_info, which accessed a non-existent variable. + mode.c: Added "rep" parameter to all screen functions. Specifies how many times + that screen has been run. Using 0 will force screen clear/redraw, and + the time-based ones also use this to determine if colons should be drawn. + main.c: Implemented simple command-line parameters. Example: + lcd m 4 .5 /dev/cua1 x 1 2 + uses /dev/cua1 for lcd, displaying memory info 4 times at .5 seconds each, + and the xload screen once for 2 seconds; then loops. + mode.c & lcd.c: created "NOLCD" preprocessor switch. When defined, lcd uses + text output (stdout) instead of the com port. + mode.c: Changed clock string generation to use "%02d" to achieve that + "02:37:06" look. (hint: printf can pad numbers with leading 0's) + main.c: Added minimal command-line help. diff --git a/old/llistd.c b/old/llistd.c new file mode 100644 index 0000000..4c4f2cb --- /dev/null +++ b/old/llistd.c @@ -0,0 +1,429 @@ +#include // for NULL definition +#include "llistd.h" // function prototypes + +/***************************************************************************** +* AUTHOR: Scott Scriven, SSN: 523-21-9640, CLASS: CS151.003, DATE: 96-11-21 +****************************************************************************** +* Doubly Linked Lists! (some of my really old code, commented for this class) +* This code will handle "generic" Doubly-Linked Lists. These lists can be +* any type as long as they satisfy a few requirements: +* Your structure must start with two integer pointers: +* struct mystruct { +* int *next, *prev; +* ... +* }; +* That's all, pretty much. +* +* Most of the functions take integer pointers. This means you will have to +* call them in one of the following ways: +* function((int *)&mystruct); +* function((int *)mystruct); +* function(&mystruct.next); +* +****************************************************************************** +* If I'm not mistaken, this code should work regardless of your machine's +* integer size (16/32/64/etc... bit) +****************************************************************************** +* Note that we have to do NULL checking to make sure we don't try to write +* to protected areas of memory if we reach the beginning/end of a list. +* +* We also do some circular-link checking to avoid infinite loops. +* These loops will work fine: +* a <-> b <-> c <-> a <-> b... +* a <-> b <-> c -> c -> c... +* This loop might make this code puke: +* a <-> b <-> c <-> d -> c d <- e <-> f <-> g +*****************************************************************************/ + + +/***************************************************************************** +* Function: LLMakeFirstNode() +****************************************************************************** +* Description: +* Makes a node stand alone; creates the first node of a list. You must do +* the memory/node allocation manually. It returns the parameter you send it. +****************************************************************************** +* Function Calls: +* None. +*****************************************************************************/ +int * LLMakeFirstNode(int * first) // Make a standalone node... +{ + (int *)first[0] = NULL; + (int *)first[1] = NULL; + return first; +} + + +/***************************************************************************** +* Function: LLFindFirst() +****************************************************************************** +* Description: +* Given a node of a list, it returns the first node of the list (assuming +* that the first node either points to NULL or itself). If list is circular, +* it returns *next* node in the list. +****************************************************************************** +* Function Calls: +* LLFindPrev See below... +*****************************************************************************/ +int * LLFindFirst(int * current) // returns address of First node +{ + int *prev=current; + + // If prev[1] (pointer to previous node) is NULL, we hit the beginning. + // If prev[1] is the same as current, we've got a circular linked list... + while((int *)prev[1] != NULL && (int *)prev[1] != current) + { + prev = LLFindPrev(prev); + } + + return prev; +} + +/***************************************************************************** +* Function: LLFindNext() +****************************************************************************** +* Description: +* Returns the address of the next node in the list, or NULL if we're at the +* end of the list. +****************************************************************************** +* Function Calls: +* None. +*****************************************************************************/ +int * LLFindNext(int * current) // returns address of next node +{ + // Return the address of the next node + if((int *)current[0] != current) + return (int *)current[0]; + else + return NULL; +} + +/***************************************************************************** +* Function: LLFindPrev() +****************************************************************************** +* Description: +* Returns the address of the previous node in the list, or NULL if we're +* at the beginning of the list. +****************************************************************************** +* Function Calls: +* None. +*****************************************************************************/ +int * LLFindPrev(int * current) // returns address of prev node +{ + // Return the address of the previous node + if((int *)current[1] != current) + return (int *)current[1]; + else + return NULL; +} + +/***************************************************************************** +* Function: LLFindLast() +****************************************************************************** +* Description: +* Given any node, returns the address of the last node of that list. This +* works just like LLFindFirst(), but in reverse. +****************************************************************************** +* Function Calls: +* LLFindNext See above... +*****************************************************************************/ +int * LLFindLast(int * current) // returns address of last node +{ + int *next = current; + + // If next[0] (pointer to next node) is NULL, we hit the end. + // If next[0] is the same as current, we've got a circular linked list... + while((int *)next[0] != NULL && (int *)next[0] != current) + { + next = LLFindNext(next); + } + + return next; +} + + +/***************************************************************************** +* Function: LLAddNode() +****************************************************************************** +* Description: +* Inserts a node in the list *after* the "current" node. It updates the +* list neighbors accordingly. +****************************************************************************** +* Function Calls: +* LLFindNext See above... +*****************************************************************************/ +int * LLAddNode(int * current, int * add) // Adds node AFTER current one +{ + int *next; + + if(current == add) return current; // We can't add a node to itself... + + next = LLFindNext(current); // Get the next node address + + (int *)current[0] = add; // Point the current node to the new node + (int *)add[0] = next; // Point the new node to next node + (int *)add[1] = current; // Make new node point back to the current node + + if(next != NULL) + (int *)next[1] = add; // Point next node back to the new node + + return add; // Return the address of the new node +} + +/***************************************************************************** +* Function: LLInsertNode() +****************************************************************************** +* Description: +* Inserts a node in the list *before* the "current" node. It updates the +* list neighbors accordingly. +****************************************************************************** +* Function Calls: +* LLFindPrev See above... +*****************************************************************************/ +int * LLInsertNode(int * current, int * add) // Adds node BEFORE current one +{ + int *prev; + + if(current == add) return current; // We can't add a node to itself... + + prev = LLFindPrev(current); // Get the previous node's address + + if(prev != NULL) + (int *)prev[0] = add; // Previous node points to new node + (int *)add[0] = current; // New node points to current node + (int *)add[1] = prev; // New node points back to previous node + (int *)current[1] = add; // Current node points back to new node + + return add; // Return the address of the new node +} + +/***************************************************************************** +* Function: LLCutNode() +****************************************************************************** +* Description: +* Removes a node from the list, and joins its neighbors. Returns the +* address of the cut node. You must deallocate the node manually, if +* you want to free its memory. +****************************************************************************** +* Function Calls: +* LLFindPrev See Above... +* LLFindNext See Above... +*****************************************************************************/ +int * LLCutNode(int * cut) // Removes a node from the link +{ + int * prev, * next; + + prev = LLFindPrev(cut); // Find surrounding nodes... + next = LLFindNext(cut); + + (int *)cut[0] = NULL; // Make the removed node point nowhere + (int *)cut[1] = NULL; + + if(prev != NULL) // Join the surrounding nodes... + (int *)prev[0] = next; + if(next != NULL) + (int *)next[1] = prev; + + return cut; // Return the address of the node that has been cut... +} + + +/***************************************************************************** +* Function: LLPush() +****************************************************************************** +* Description: +* Inserts a node at the end of the whole list. "Current" can be any node +* in the list, and "add" is the node you want to add. +****************************************************************************** +* Function Calls: +* LLFindLast() See above... +* LLAddNode() See above... +*****************************************************************************/ +int * LLPush(int * current, int * add) // Add node to end of list +{ + int *last; + + last = LLFindLast(current); + + return LLAddNode(last, add); +} + +/***************************************************************************** +* Function: LLPop() +****************************************************************************** +* Description: +* Pops (removes) a node off the end of the list. Returns the address of +* the node we chopped off. "current" can be any node in the list. +****************************************************************************** +* Function Calls: +* LLFindLast See above... +* LLCutNode See above... +*****************************************************************************/ +int * LLPop(int * current) // Remove node from end of list +{ + int *last; + + last = LLFindLast(current); + + return LLCutNode(last); +} + +/***************************************************************************** +* Function: LLShift() +****************************************************************************** +* Description: +* Pops (removes) a node from the beginning of the list. Returns the address +* of the node we cut off. +****************************************************************************** +* Function Calls: +* LLFindFirst See above... +* LLCutNode See above... +*****************************************************************************/ +int * LLShift(int * current) // Remove node from start of list +{ + int *begin; + + begin = LLFindFirst(current); + + return LLCutNode(begin); +} + +/***************************************************************************** +* Function: LLUnshift() +****************************************************************************** +* Description: +* Inserts a node at the beginning of the list. +****************************************************************************** +* Function Calls: +* LLFindFirst See above... +* LLInsertNode See above... +*****************************************************************************/ +int * LLUnshift(int * current, int * add) // Add node to beginning of list +{ + int *begin; + + begin = LLFindFirst(current); + + return LLInsertNode(begin, add); +} + +/***************************************************************************** +* Function: LLSwapNodes() +****************************************************************************** +* Description: +* Switches two nodes' positions in the linked list. It can handle cases +* when the nodes are complete seperate, cases when the nodes are each +* other's neighbors, and cases when the two nodes are the same one. +* No return value. +****************************************************************************** +* Function Calls: +* LLFindNext See Above... +* LLFindPrev See above... +*****************************************************************************/ +void LLSwapNodes(int * one, int * two) // Switch two nodes' positions... +{ + int *firstprev, *firstnext; + int *secondprev, *secondnext; + + if(one == two) return; // if they're the same, do nothing + + firstprev = LLFindPrev(one); // Store the addresses of their neighbors... + firstnext = LLFindNext(one); + secondprev = LLFindPrev(two); + secondnext = LLFindNext(two); + + if(firstprev != NULL) (int *)firstprev[0] = two; // Swap their + if(firstnext != NULL) (int *)firstnext[1] = two; // Neighbors' pointers + if(secondprev != NULL) (int *)secondprev[0] = one; + if(secondnext != NULL) (int *)secondnext[1] = one; + + (int *)one[0] = secondnext; // Swap the two nodes' pointers + (int *)one[1] = secondprev; + (int *)two[0] = firstnext; + (int *)two[1] = firstprev; + + if(firstnext == two) (int *)one[1] = two; // Fix things if they were + if(firstprev == two) (int *)one[0] = two; // next to each other... + if(secondprev == one) (int *)two[0] = one; + if(secondnext == one) (int *)two[1] = one; +} + +/***************************************************************************** +* Function: LLCountNodes() +****************************************************************************** +* Description: +* Traverses the entire list and returns the number of nodes it finds. +****************************************************************************** +* Function Calls: +* LLFindFirst See above... +* LLFindNext See above... +*****************************************************************************/ +int LLCountNodes(int * current) // Returns # of nodes in entire list +{ + int numnodes=1; + int *first, *next; + + first = LLFindFirst(current); // Get the first node... + next = first; + + + // If next[0] (pointer to next node) is NULL, we hit the end. + // If next[0] is the same as current, we've got a circular linked list... + while((int *)next[0] != NULL && (int *)next[0] != first) + { + numnodes++; + next = LLFindNext(next); + } + + return numnodes; +} + + +/***************************************************************************** +* Function: LLSelectSort() +****************************************************************************** +* Description: +* Given any node in a list, sorts the whole list using a selection sort +* algorithm. You must supply a function to compare two nodes. The +* return value is the address of the new first node in the list. +****************************************************************************** +* Function Calls: +* LLCountNodes See above... +* LLFindLast See above... +* LLFindFirst See above... +* LLFindNext See above... +* LLFindPrev See above... +* LLSwapNodes See above... +* compare The user-defined function which compares two nodes. +* If you've ever used qsort, this should be familiar. +*****************************************************************************/ +// Sorts the list and returns a pointer to the first node +int * LLSelectSort(int * current, int compare(void *, void *)) +{ + int i,j; // Junk / loop variables + int numnodes; // number of nodes in list + int *best, *last; // best match and last node in the list + + numnodes = LLCountNodes(current); // get the number of nodes... + last = LLFindLast(current); // Find the last node. + + for(i=numnodes-1; i>1; i--) + { + current = LLFindFirst(current); // get the first node again + best = last; // reset our "best" node + + for(j=0; j 0) // If we found a better match... + { + best = current; // keep track of the "best" match + } + current = LLFindNext(current); // Go to the next node. + } + + LLSwapNodes(last, best); // Switch two nodes... + last = LLFindPrev(best); // And go backwards by one node. + } + + return LLFindFirst(current); // return pointer to the first node. +} diff --git a/old/llistd.h b/old/llistd.h new file mode 100644 index 0000000..6f0a22d --- /dev/null +++ b/old/llistd.h @@ -0,0 +1,63 @@ +#ifndef LLISTD_H +#define LLISTD_H +/***************************************************************************** +* AUTHOR: Scott Scriven, SSN: 523-21-9640, CLASS: CS151.003, DATE: 96-11-21 +****************************************************************************** +* Doubly Linked Lists! +* This code will handle "generic" Doubly-Linked Lists. These lists can be +* any type as long as they satisfy a few requirements: +* Your structure must start with two integer pointers: +* struct mystruct { +* int *next, *prev; +* ... +* }; +* That's all, pretty much. +* +* Most of the functions take integer pointers. This means you will have to +* call them in one of the following ways: +* function((int *)&mystruct); +* function((int *)mystruct); +* function(&mystruct.next); +* +****************************************************************************** +* If I'm not mistaken, this code should work regardless of your machine's +* integer size (16/32/64/etc... bit) +****************************************************************************** +* Note that we have to do NULL checking to make sure we don't try to write +* to protected areas of memory if we reach the beginning/end of a list. +* +* We also do some circular-link checking to avoid infinite loops. +* These loops will work fine: +* a <-> b <-> c <-> a <-> b... +* a <-> b <-> c -> c -> c... +* This loop might make this code puke: +* a <-> b <-> c <-> d -> c d <- e <-> f <-> g +*****************************************************************************/ + + +// See llistd.c for detailed descriptions of these functions. + +int * LLMakeFirstNode(int * first); // Make a standalone node... + +int * LLFindFirst(int * current); // returns address of First node +int * LLFindNext(int * current); // returns address of next node +int * LLFindPrev(int * current); // returns address of prev node +int * LLFindLast(int * current); // returns address of last node + +int * LLAddNode(int * current, int * add); // Adds node AFTER current one +int * LLInsertNode(int * current, int * add); // Adds node BEFORE current one +int * LLCutNode(int * cut); // Removes a node from the link + +int * LLPush(int * current, int * add); // Add node to end of list +int * LLPop(int * current); // Remove node from end of list +int * LLShift(int * current); // Remove node from start of list +int * LLUnshift(int * current, int * add); // Add node to beginning of list + +void LLSwapNodes(int * one, int * two); // Switch two nodes positions... + +int LLCountNodes(int * current); // Returns # of nodes in entire list + +// "Selection Sort"s the list and returns a pointer to the first node +int * LLSelectSort(int * current, int compare(void *, void *)); + +#endif diff --git a/old/main.c b/old/main.c new file mode 100644 index 0000000..b17c1a9 --- /dev/null +++ b/old/main.c @@ -0,0 +1,318 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "lcd.h" +#include "mode.h" +//#include "lock.h" +#include "sockets.h" + + +// TODO: Commenting... Everything! + + +char version[] = "v0.3.4"; +char build_date[] = "1998-06-20"; +int Quit = 0; + +/* + Mode List: + See below... (default_sequence[]) +*/ + +typedef struct mode { + char which; + int num_times; + int delay_time; +} mode; + +void HelpScreen(); +void exit_program(int val); +void main_loop(mode *sequence); + +#define MAX_SEQUENCE 256 +// 1/8th second is a single time unit... +#define TIME_UNIT 125000 + + +// Contains a list of modes to run +mode default_sequence[] = +{ + { 'C', 32, 1, },// [C]PU + { 'M', 8, 4, },// [M]emory + { 'X', 1, 32, },// [X]-load (load histogram) + { 'T', 8, 4, },// [T]ime/Date + { 'D', 32, 1, },// [D]isk stats + { 'A', 1, 16, },// [A]bout (credits) + + { 1 , 0, 0, },// Modes after this line will not be run by default... + // ... all non-default modes must be in here! + // ... they will not show up otherwise. + { 'O', 8, 4, },// [O]ld Timescreen + { 'U', 8, 4, },// Old [U]ptime Screen + { 'B', 32, 1, },// [B]attery Status + { 'G', 32, 1, },// Cpu histogram [G]raph + { 0, 0, 0, },// No more.. all done. +}; + +// TODO: Clean up main()... It is still way too big. + +// TODO: Socket language, client handling... +// TODO: Config file; not just command line + + +int main(int argc, char **argv) +{ + char device[256] = "/dev/lcd"; + char cfgfile[256] = "/etc/lcdproc.cf"; + mode sequence[MAX_SEQUENCE]; + char driver[256] = "MtxOrb"; + int i, j, k; + int already_running = 0; + int contrast = 140; + int tmp; + + memset(sequence, 0, sizeof(mode) * MAX_SEQUENCE); + + // Ctrl-C will cause a clean exit... + signal(SIGINT, exit_program); + // and "kill"... + signal(SIGTERM, exit_program); + // and "kill -HUP" (hangup)... + signal(SIGHUP, exit_program); + // and just in case, "kill -KILL" (which cannot be trapped; but oh well) + signal(SIGKILL, exit_program); + + // Check to see if we are already running... +// already_running = CheckForLock(); + already_running = PingLCDport(); + if(already_running < 0) + { + printf("Error checking for another LCDproc.\n"); + return -1; + } + + + // Communicate with the previously running LCDproc + if(already_running > 0) + { + // "already_running" holds the pid of the LCDproc we want to talk to... + + // Do the command line ("lcd pet status", or "lcd contrast 50") + // And stuff... + // ...Then exit + printf("Detected another LCDproc. (%i) Exiting...\n", already_running); + // Remove me ^^^^ + return 0; + } + + tmp = StartSocketServer(); + if (tmp <= 0) + { + printf("Error starting socket server.\n"); + return 0; + } + + + + // Command line + memcpy(sequence, default_sequence, sizeof(default_sequence)); + for(i=1, j=0; i= 0 + &&ThisMenu.menu[ThisMenu.sel].child) + { + i = do_menu(ThisMenu.menu[ThisMenu.sel].child, &ThisMenu); + if(i == GUI_OK) ret = GUI_OK; + } + + // Or call a function? + else if( // execute was pressed... + &&ThisMenu.sel >= 0 + &&ThisMenu.menu[ThisMenu.sel].func) + { + ret = ThisMenu.menu[ThisMenu.sel].func(); + //ret = GUI_OK; + } + + } while(! ret); + + return ret; +} + + + +////////////////////////////////////////////////////////////////////// +// Initializes a menu... +// +void FillMenuInfo(MenuInfo *m, MenuItem *menu, MenuInfo * parent) +{ + m->menu = menu; + m->parent = parent; + m->sel = 0; + +} + + +void DrawMenu(MenuInfo *m) +{ + int i; + + for(i=0; iitems; i++) + DrawMenuItem(m, i); +} + +void DrawMenuItem(MenuInfo *m, int item) +{ + // Figure out how much to scroll down... + // Write each menu item... + // Put arrows where needed (next to current item, and up/down arrow) + // m->menu[item].text holds the text string... +} + + + diff --git a/old/menu.h b/old/menu.h new file mode 100644 index 0000000..30baafa --- /dev/null +++ b/old/menu.h @@ -0,0 +1,58 @@ +#ifndef MENU_H +#define MENU_H + +////////////////////////////////////////////// +// THIS IS NOT READY YET! +////////////////////////////////////////////// + +/* + + Pull-down menus... + + To use a menu, first define it; then call menu(). + + To define a menu, just declare an array of MenuItems. The last element + must have all NULL fields. + + MenuItem FileMenu[] = + { + "Open", OpenFile_proc, NULL, + "Close", CloseFile_proc, NULL, + "Save", SaveFile_proc, NULL, + "Save As...", NULL, SaveAsMenu, + "Quit", Quit_proc, NULL, + NULL, NULL, NULL, + }; + + The first field is the text for the menu item. + The second field is a function to call when the item is picked. + The function should take no parameters, and return an int. + The return values are: + MENU_OK Normal return value. Menu will close. + MENU_CONT Menu will stay up after function returns. + The third field is the child menu to display when the item is picked. + + Note that either the second or third field must be NULL. If both are + NULL, the item is considered to be just a label. (for example, a title) + It will be non-pickable if both are NULL. + +*/ + + +#define MENU_OK 1 +#define MENU_CONT 2 + +typedef struct MenuItem +{ + char *text; + int (*func)(); + struct MenuItem *child; +} MenuItem; + + + +// This does a pull-down menu... +int menu(MenuItem *menu); + + +#endif diff --git a/old/mode.c b/old/mode.c new file mode 100644 index 0000000..6caa3d0 --- /dev/null +++ b/old/mode.c @@ -0,0 +1,1107 @@ +/* + * This file contains status-gathering code *and* modescreen functions. + * It's long, and messy; but that will change with V0.4. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef LINUX +#include +#else +#include +#endif + +#include "mode.h" +#include "lcd.h" +#include "main.h" + +#ifndef NETDEVICE +#define NETDEVICE "ppp0" +#endif + +#ifndef LOAD_MAX +#define LOAD_MAX 1.3 +#endif +#ifndef LOAD_MIN +#define LOAD_MIN 0.5 +#endif + + +int PAD=255; +int ELLIPSIS=7; +int TwentyFourHour=0; + +// TODO: Clean this up... Support multiple display sizes.. + +struct load { unsigned long total, user, system, nice, idle; }; +struct meminfo { int total, cache, buffers, free, shared; }; +static char buffer[1024]; + +// Nothing else can see these... +static int meminfo_fd, load_fd, loadavg_fd, uptime_fd, batt_fd=0; +static FILE *mtab_fd; + +static char kver[SYS_NMLN]; +static char sysname[SYS_NMLN]; + +static void reread(int f, char *errmsg); +static int getentry(const char *tag, const char *bufptr); +static void get_mem_info(struct meminfo *result); +static double get_loadavg(void); +static double get_uptime(double *up, double *idle); +static void get_load(struct load * result); +static int get_batt_stat(int *acstat, int *battstat, + int *battflag, int *percent); + + +typedef struct mounts +{ + char dev[256], type[64], mpoint[256]; + long bsize, blocks, bfree, files, ffree; +} mounts; + + +int mode_init() +{ + struct utsname *unamebuf = + (struct utsname *) malloc( sizeof(struct utsname) ); + + meminfo_fd = open("/proc/meminfo",O_RDONLY); + loadavg_fd = open("/proc/loadavg",O_RDONLY); + load_fd = open("/proc/stat",O_RDONLY); + uptime_fd = open("/proc/uptime",O_RDONLY); + +#if 0 + kversion_fd = open("/proc/sys/kernel/osrelease",O_RDONLY); + + reread(kversion_fd, "main:"); + sscanf(buffer, "%s", kver); + + close(kversion_fd); +# endif + + /* Get OS name and version from uname() */ + if( uname( unamebuf ) != 0 ) { + perror( "Error calling uname:" ); + } + strcpy( kver, unamebuf->release ); + strcpy( sysname, unamebuf->sysname ); + + return 0; +} + +void mode_close() +{ + close(meminfo_fd); + close(loadavg_fd); + close(load_fd); + close(uptime_fd); + if(batt_fd) close(batt_fd); + +} + + +static void reread(int f, char *errmsg) +{ + if (lseek(f, 0L, 0) == 0 && read(f, buffer, sizeof(buffer) - 1 ) > 0 ) + return; + perror(errmsg); + exit(1); +} + +static int getentry(const char *tag, const char *bufptr) +{ + char *tail; + int retval, len = strlen(tag); + + while (bufptr) + { + if (*bufptr == '\n') bufptr++; + if (!strncmp(tag, bufptr, len)) + { + retval = strtol(bufptr + len, &tail, 10); + if (tail == bufptr + len) return -1; + else return retval; + } + bufptr = strchr( bufptr, '\n'); + } + return -1; +} + +static void get_mem_info(struct meminfo *result) +{ +// int i, res; char *bufptr; + + reread(meminfo_fd, "get_meminfo:"); + result[0].total = getentry("MemTotal:", buffer); + result[0].free = getentry("MemFree:", buffer); + result[0].shared = getentry("MemShared:", buffer); + result[0].buffers = getentry("Buffers:", buffer); + result[0].cache = getentry("Cached:", buffer); + result[1].total = getentry("SwapTotal:", buffer); + result[1].free = getentry("SwapFree:", buffer); +} + +static double get_loadavg(void) +{ + double load; + + reread(loadavg_fd, "get_load:"); + sscanf(buffer, "%lf", &load); + return load; +} + +static double get_uptime(double *up, double *idle) +{ + double uptime; + + reread(uptime_fd, "get_uptime:"); + sscanf(buffer, "%lf %lf", &uptime, idle); + + *up = uptime; + + return uptime; +} + +static int get_fs(mounts fs[]) +{ + struct statfs fsinfo; + char line[256]; + int x = 0, y; + + mtab_fd = fopen("/etc/mtab", "r"); + + // Get rid of old, unmounted filesystems... + memset(fs, 0, sizeof(mounts)*256); + + while (x < 256) + { + if(fgets(line, 256, mtab_fd) == NULL) + { + fclose(mtab_fd); + return x; + } + + sscanf(line, "%s %s %s", fs[x].dev, fs[x].mpoint, fs[x].type); + + if( strcmp(fs[x].type, "proc") +#ifndef STAT_NFS + && strcmp(fs[x].type, "nfs") +#endif +#ifndef STAT_SMBFS + && strcmp(fs[x].type, "smbfs") +#endif + ) + { +#ifdef LINUX + y = statfs(fs[x].mpoint, &fsinfo); +#else + y = statfs(fs[x].mpoint, &fsinfo, sizeof(fsinfo), 0); +#endif + fs[x].bsize = fsinfo.f_bsize; + fs[x].blocks = fsinfo.f_blocks; + fs[x].bfree = fsinfo.f_bfree; + fs[x].files = fsinfo.f_files; + fs[x].ffree = fsinfo.f_ffree; + x++; + } + } + + fclose(mtab_fd); + return x; +} + +static void get_load(struct load * result) +{ + static struct load last_load = { 0, 0, 0, 0, 0 }; struct load curr_load; + + reread(load_fd, "get_load:"); + sscanf(buffer, "%*s %lu %lu %lu %lu\n", &curr_load.user, &curr_load.nice, &curr_load.system, &curr_load.idle); + curr_load.total = curr_load.user + curr_load.nice + curr_load.system + curr_load.idle; + result->total = curr_load.total - last_load.total; + result->user = curr_load.user - last_load.user; + result->nice = curr_load.nice - last_load.nice; + result->system = curr_load.system - last_load.system; + result->idle = curr_load.idle - last_load.idle; + last_load.total = curr_load.total; + last_load.user = curr_load.user; + last_load.nice = curr_load.nice; + last_load.system = curr_load.system; + last_load.idle = curr_load.idle; +} + + +static int get_batt_stat(int *acstat, int *battstat, + int *battflag, int *percent) +{ + char str[64]; + + if(!batt_fd) + batt_fd = open("/proc/apm", O_RDONLY); + if(batt_fd <= 0) return -1; + + if(lseek(batt_fd, 0, 0) != 0) return -1; + + if(read(batt_fd, str, sizeof(str)-1) < 0) return -1; + + if(3 > sscanf(str+13, "0x%x 0x%x 0x%x %d", + acstat, battstat, battflag, percent)) + return -1; + + return 0; + +} + + +/////////////////////////////////////////////////////////////////////////// +//////////////////////// Let the Modes Begin! ///////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +// TODO: Implement more return values for behavior changing... +// TODO: more modes... + +static char tmp[256]; + +// A couple of tables for later use... +static char *days[] = { + "Sunday, ", + "Monday, ", + "Tuesday, ", + "Wednesday,", + "Thursday, ", + "Friday, ", + "Saturday, ", +}; +static char *shortdays[] = { + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", +}; + +static char *months[] = { + " January", + " February", + " March", + " April", + " May", + " June", + " July", + " August", + "September", + " October", + " November", + " December", +}; +static char *shortmonths[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +}; + + +////////////////////////////////////////////////////////////////////////// +// CPU screen shows info about percentage of the CPU being used +// +int cpu_screen(int rep) +{ +#undef CPU_BUF_SIZE +#define CPU_BUF_SIZE 4 + int i, j, n; + float value; + static float cpu[CPU_BUF_SIZE + 1][5];// last buffer is scratch + struct load load; + + + + get_load(&load); + + // Shift values over by one + for(i=0; i<(CPU_BUF_SIZE-1); i++) + for(j=0; j<5; j++) + cpu[i][j] = cpu[i+1][j]; + + // Read new data + cpu[CPU_BUF_SIZE-1][0] = ((float)load.user / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][1] = ((float)load.system / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][2] = ((float)load.nice / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][3] = ((float)load.idle / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][4] = (((float)load.user + (float)load.system + + (float)load.nice) / (float)load.total) * 100.0; + + // Only clear on first display... + if(!rep) + { + lcd.clear(); + lcd.init_hbar(); + + sprintf(tmp, "%c%c CPU LOAD %c%c", PAD, PAD, PAD, PAD); + + lcd.string(1, 1, tmp); + lcd.string(1, 2, "Usr 0.0% Nice 0.0%"); + lcd.string(1, 3, "Sys 0.0% Idle 0.0%"); + lcd.string(1, 4, "0% 100%"); + + // Make all the same, if this is the first time... + for(i=0; i= 99.9) { lcd.string(13, 1, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(13, 1, tmp); } + + value = cpu[CPU_BUF_SIZE][0]; + if (value >= 99.9) { lcd.string(5, 2, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(5, 2, tmp); } + + value = cpu[CPU_BUF_SIZE][1]; + if (value >= 99.9) { lcd.string(5, 3, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(5, 3, tmp); } + + value = cpu[CPU_BUF_SIZE][2]; + if (value >= 99.9) { lcd.string(16, 2, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(16, 2, tmp); } + + value = cpu[CPU_BUF_SIZE][3]; + if (value >= 99.9) { lcd.string(16, 3, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(16, 3, tmp); } + + value = cpu[CPU_BUF_SIZE][4]; + n = (int)(value * 70.0 / 100.0); + lcd.string(1, 4, "0% 100%"); + lcd.hbar(3, 4, n); + + return 0; +} // End cpu_screen() + + + +////////////////////////////////////////////////////////////////////////// +// Cpu Graph Screen shows a quick-moving histogram of CPU use. +// +int cpu_graph_screen(int rep) +{ + int i, j, n; + float value, maxload; +#undef CPU_BUF_SIZE +#define CPU_BUF_SIZE 2 + static float cpu[CPU_BUF_SIZE + 1];// last buffer is scratch + static float cpu_past[LCD_MAX_WIDTH]; + struct load load; + int status=0; + char out[LCD_MAX_WIDTH]; + + + + get_load(&load); + + // Shift values over by one + for(i=0; i<(CPU_BUF_SIZE-1); i++) + cpu[i] = cpu[i+1]; + + // Read new data + cpu[CPU_BUF_SIZE-1] = ((float)load.user + (float)load.system + + (float)load.nice) / (float)load.total; + + + // Only clear on first display... + if(!rep) + { + lcd.init_vbar(); + + // Make all the same, if this is the first time... + for(i=0; i maxload) maxload = cpu_past[i]; + } + + value = cpu[CPU_BUF_SIZE]; + n = (int)(value * 8.0 * (float)(lcd.hgt-1)); + + cpu_past[lcd.wid-1] = n; + lcd.vbar(lcd.wid, cpu_past[lcd.wid-1]); + + sprintf(out, "%c%c CPU GRAPH %c%c%c%c%c%c", PAD,PAD, + PAD,PAD,PAD,PAD,PAD,PAD); + lcd.string(1,1,out); + + + + if(n > maxload) maxload = n; + + if(cpu_past[lcd.wid-1] > 0 ) status = BACKLIGHT_ON; + if(maxload < 1) status = BACKLIGHT_OFF; + +// return status; + return 0; +} // End cpu_graph_screen() + + + +////////////////////////////////////////////////////////////////////// +// Clock Screen displays current time and date... +// +// TODO: 24-hour time on old clock screen, if desired. +int clock_screen(int rep) +{ + char hr[8], min[8], sec[8], ampm[8]; + char day[16], month[16]; + time_t thetime; + struct tm *rtime; + int i; + + + if(!rep) + { + lcd.clear(); + sprintf(tmp, "%c%c DATE & TIME %c%c%c%c%c", PAD, PAD, PAD, PAD, PAD, PAD, PAD); + lcd.string(1, 1, tmp); + } + + time(&thetime); + rtime = localtime(&thetime); + + strcpy(day, days[rtime->tm_wday]); + + if (rtime->tm_hour > 12) { i = 1; sprintf(hr, "%02d", (rtime->tm_hour - 12)); } + else { i = 0; sprintf(hr, "%02d", rtime->tm_hour); } + if(rtime->tm_hour == 12) i=1; + sprintf(min, "%02d", rtime->tm_min); + sprintf(sec, "%02d", rtime->tm_sec); + if (i == 1) { sprintf(ampm, "%s", "P"); } + else { sprintf(ampm, "%s", "A"); } + if (rep & 1) { sprintf(tmp, "%s:%s:%s%s %s", hr, min, sec, ampm, day); } + else { sprintf(tmp, "%s %s %s%s %s", hr, min, sec, ampm, day); } + + strcpy(month, months[rtime->tm_mon]); + + lcd.string(1, 3, tmp); + + sprintf(tmp, "%s %d, %d", month, rtime->tm_mday, (rtime->tm_year + 1900)); + lcd.string(2, 4, tmp); + + return 0; +} // End clock_screen() + + + +////////////////////////////////////////////////////////////////////// +// Time Screen displays current time and date, uptime, OS ver... +// +//+--------------------+ +//|## Linux 2.0.33 ###@| +//|Up xxx days hh:mm:ss| +//| Wed May 17, 1998 | +//|11:32:57a 100% idle| +//+--------------------+ +// + +int time_screen(int rep) +{ + char hr[8], min[8], sec[8], ampm[8]; + char day[16], month[16]; + time_t thetime; + struct tm *rtime; + double uptime, idle; + int i; + + + + if(!rep) + { + lcd.clear(); + } + + + get_uptime(&uptime, &idle); + idle = (idle * 100) / uptime; + + + ///////////////////// Write the title bar (os name and version) + memset(tmp, 0, lcd.wid+1); + sprintf(tmp, "%c%c %s %s ", + PAD, PAD, sysname, kver); + for(i=1; i<(20-strlen(sysname)-strlen(kver)-4); i++) + tmp[lcd.wid-i]=PAD; + + lcd.string(1, 1, tmp); + + /////////////////////// Display the time... + time(&thetime); + rtime = localtime(&thetime); + + if(TwentyFourHour) + { + sprintf(hr, "%02d", rtime->tm_hour); + } + else + { + if (rtime->tm_hour > 12) + { i = 1; sprintf(hr, "%02d", (rtime->tm_hour - 12)); } + else { i = 0; sprintf(hr, "%02d", rtime->tm_hour); } + } + if(rtime->tm_hour == 12) i=1; + if (i == 1) { sprintf(ampm, "%s", "P"); } + else { sprintf(ampm, "%s", "A"); } + + sprintf(min, "%02d", rtime->tm_min); + sprintf(sec, "%02d", rtime->tm_sec); + if (rep & 1) + { + if(TwentyFourHour) + sprintf(tmp, "%s:%s:%s %2i%% idle", hr, min, sec, (int)idle); + else + sprintf(tmp, "%s:%s:%s%s %2i%% idle", hr, min, sec, ampm, (int)idle); + } + else + { + if(TwentyFourHour) + sprintf(tmp, "%s %s %s %2i%% idle", hr, min, sec, (int)idle); + else + sprintf(tmp, "%s %s %s%s %2i%% idle", hr, min, sec, ampm, (int)idle); + } + // Center the output line... + i = ((lcd.wid - strlen(tmp)) / 2) + 1; + lcd.string(i, 4, tmp); + + + + + /////////////////////// Display the uptime... + strcpy(day, shortdays[rtime->tm_wday]); + strcpy(month, shortmonths[rtime->tm_mon]); + + sprintf(tmp, "%s %s %d, %d", day, month, + rtime->tm_mday, (rtime->tm_year + 1900)); + lcd.string(3, 3, tmp); + + + i = (int)uptime / 86400; + sprintf(day, "%d day%s,", i, (i != 1 ? "s" : "")); + i = ((int)uptime % 86400) / 60 / 60; + sprintf(hr, "%02i",i); + i = (((int)uptime % 86400) % 3600) / 60; + sprintf(min, "%02i",i); + i = ((int)uptime % 60); + sprintf(sec, "%02i",i); + if (rep & 1) + sprintf(tmp, "%s %s:%s:%s", day, hr, min, sec); + else + sprintf(tmp, "%s %s %s %s", day, hr, min, sec); + // Center this line automatically... + i = ((lcd.wid - strlen(tmp)) / 2) + 1; + lcd.string(i, 2, tmp); + + return 0; +} // End time_screen() + + +///////////////////////////////////////////////////////////////////////// +// Mem Screen displays info about memory and swap usage... +// +int mem_screen(int rep) +{ + int n; + struct meminfo mem[2]; + + + if(!rep) + { + lcd.clear(); + lcd.init_hbar(); + sprintf(tmp, "%c%c%c MEM %c%c%c%c SWAP %c%c", + PAD,PAD,PAD,PAD,PAD,PAD,PAD,PAD,PAD); + lcd.string(1, 1, tmp); + lcd.string(9, 2, "Totl"); + lcd.string(9, 3, "Free"); + //lcd.string(1, 4, "E F E F"); + } + + + // Total memory + get_mem_info(mem); + sprintf(tmp, "%6dk", mem[0].total); + lcd.string(1, 2, tmp); + + // Free memory (plus buffers and cache) + sprintf(tmp, "%6dk", + mem[0].free + mem[0].buffers + mem[0].cache); + lcd.string(1, 3, tmp); + + // Total swap + sprintf(tmp, "%6dk", mem[1].total); + lcd.string(14, 2, tmp); + + // Free swap + sprintf(tmp, "%6dk", mem[1].free); + lcd.string(14, 3, tmp); + + + // Empty or full? + lcd.string(1, 4, "E F E F"); + + // Free memory graph + n = (int)(35.0 - + ((float)mem[0].free + (float)mem[0].buffers + (float)mem[0].cache) + / (float)mem[0].total + * 35.0); + lcd.hbar(2, 4, n); + + // Free swap graph + n = (int)(35.0 - + (float)mem[1].free / (float)mem[1].total + * 35.0); + lcd.hbar(13, 4, n); + + + return 0; +} // End mem_screen() + + +//////////////////////////////////////////////////////////////////// +// Uptime Screen shows info about system uptime and OS version +// +int uptime_screen(int rep) +{ + int i; + char date[16], hour[8], min[8], sec[8]; + double uptime, idle; + + + if(!rep) + { + lcd.clear(); + sprintf(tmp, "%c%c SYSTEM UPTIME %c%c%c", PAD, PAD, PAD, PAD, PAD); + lcd.string(1, 1, tmp); + + sprintf(tmp, "%s %s", sysname, kver); + lcd.string(5, 4, tmp); + } + + get_uptime(&uptime, &idle); + i = (int)uptime / 86400; + sprintf(date, "%d day%s,", i, (i != 1 ? "s" : "")); + i = ((int)uptime % 86400) / 60 / 60; + sprintf(hour, "%02i",i); + i = (((int)uptime % 86400) % 3600) / 60; + sprintf(min, "%02i",i); + i = ((int)uptime % 60); + sprintf(sec, "%02i",i); + if (rep & 1) + sprintf(tmp, "%s %s:%s:%s", date, hour, min, sec); + else + sprintf(tmp, "%s %s %s %s", date, hour, min, sec); + i = ((20 - strlen(tmp)) / 2) + 1; + lcd.string(i, 3, tmp); + + + return 0; +} // End uptime_screen() + + +/////////////////////////////////////////////////////////////////////////// +// Gives disk stats. +// +// Stays onscreen until it is done. +// +int disk_screen(int rep) +{ + static mounts mnt[256]; + static int count=0; + + struct disp // Holds info to display (avoid recalculating it) + { + char dev[8]; + char cap[8]; + int full; + } table[256]; + int i, y; + static int first=0; // First line to display, sort of. + + #define huge long long int + huge size; + + + // Grab disk stats on first display, and fill "table". + if(!rep) + { + lcd.clear(); + lcd.init_hbar(); + lcd.icon(2,7); + + // Get rid of old, unmounted filesystems... + memset(table, 0, sizeof(struct disp)*256); + + count = get_fs(mnt); + first = 0; + + sprintf(tmp, "%c%c FILESYSTEMS %c%c%c%c", + PAD, PAD, PAD, PAD, PAD, PAD); + lcd.string(1, 1, tmp); + + // Fill the display structure... + if(count) + { + for(i=0; i 6) + { + sprintf(table[i].dev, "%c%s", ELLIPSIS, + (mnt[i].mpoint)+(strlen(mnt[i].mpoint)-5)); + } + else + { + sprintf(table[i].dev, "%s", mnt[i].mpoint); + } + + table[i].full = (lcd.cellwid * 4) + * (huge)(mnt[i].blocks - mnt[i].bfree) + / (huge)mnt[i].blocks; + + size = (huge)mnt[i].bsize * (huge)mnt[i].blocks; + memset(table[i].cap, 0, 8); + + // Kilobytes + if(size > 0 && size < (huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fk", + (double)(size)/1024.0); + // Megabytes + else if(size >= (huge)1000*(huge)1000 + && size < (huge)1000*(huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fM", + (float)(size/(huge)1024)/1024.0); + // Gigabytes + else if(size >= (huge)1000*(huge)1000*(huge)1000 + && size < (huge)1000*(huge)1000*(huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fG", + (float)(size/((huge)1024*(huge)1024))/1024.0); + // Terabytes + else if(size >= (huge)1000*(huge)1000*(huge)1000*(huge)1000 + && size < (huge)1000*(huge)1000*(huge)1000*(huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fT", + (float)(size/((huge)1024*(huge)1024*(huge)1024))/1024.0); + + // PectaBytes -- Yeah! I want some! + else if(size >= (huge)1000*(huge)1000*(huge)1000*(huge)1000*(huge)1000 + && size < (huge)1000*(huge)1000*(huge)1000*(huge)1000*(huge)1000*(huge)1000) + sprintf(table[i].cap, "%3.1fP", + (float)(size/((huge)1024*(huge)1024*(huge)1024*(huge)1024))/1024.0); + + } + } + } // End if(!rep) + + + // Increment this once per second. + if((rep&7) == 0) first++; + + + if (!count) + { + lcd.string(1, 2, "Error Retrieving"); + lcd.string(5, 3, "Filesystem Stats"); + return 0; + } + + // If we are done, tell the system to keep going. + if (first >= count+1) + return CONTINUE; + + + // Display stuff... (show for two seconds, then scroll once per + // second, then hold at the end for two seconds) + for(y=0; y<3; y++) + { + i = first - 2; + if(i>count-3) i=count-3; + if(i<0) i=0; + i += y; + + if(table[i].dev[0] == 0) continue; + sprintf(tmp, "%-6s %6s E F", table[i].dev, table[i].cap); + + lcd.string(1, y+2, tmp); + lcd.hbar(16, y+2, table[i].full); + } + + + #undef huge + +/* +// ** FILESYSTEMS ***** +// / 543.2M E----F +// /dos/c 2.1G E----F +// /stuff 4.3G E----F +*/ + return HOLD_SCREEN; +} + + +/////////////////////////////////////////////////////////////////////////// +// Shows a display very similar to "xload"'s histogram. +// + +int xload_screen(int rep) +{ + static float loads[LCD_MAX_WIDTH]; + static int first_time=1; + int n; + float loadmax=0, factor, x; + int status = 0; + + + if(first_time) // Only the first time this is ever called... + { + memset(loads, 0, sizeof(float)*LCD_MAX_WIDTH); + first_time = 0; + } + + if(!rep) + { + lcd.clear(); + } + + + for(n=0; n<(lcd.wid-2); n++) loads[n] = loads[n+1]; + loads[lcd.wid-2] = get_loadavg(); + + for(n=0; n loadmax) loadmax = loads[n]; + + lcd.string(20, 4, "0"); + n = (int)loadmax; + if ((float)n < loadmax) { n++; } + sprintf(tmp, "%i", n); lcd.string(20, 2, tmp); + + if (loadmax < 1.0) factor = 24.0; + else factor = 24 / (float)n; + + for(n=0; n LOAD_MIN) status = BACKLIGHT_ON; + if(loads[lcd.wid-2] > LOAD_MAX) status = BLINK_ON; + + // This must be drawn *after* the vertical bars... (?) + sprintf(tmp, "%c%c LOAD AVG %2.2f %c%c", PAD, PAD, loads[lcd.wid-2], PAD, PAD); + lcd.string(1, 1, tmp); + + if(!rep) + lcd.init_vbar(); + + + return status; +} // End xload_screen() + + + + + +//////////////////////////////////////////////////////////////////////// +// Battery Screen shows apm battery status... +// + +//#################### +//## Battery: 100% ### +//AC: Unknown +//Batt: Low (Charging) +//E------------------F + +int battery_screen(int rep) +{ + int acstat=0, battstat=0, battflag=0, percent=0; + + + // Only run once every 16 frames... + if(rep&0x0f) return 0; + + get_batt_stat(&acstat, &battstat, &battflag, &percent); + + lcd.clear(); + + + sprintf(tmp, "%c%c Battery: ", PAD, PAD); + + if(percent >= 0) sprintf(tmp+strlen(tmp), "%i%% %c%c%c%c", + percent, PAD, PAD, PAD, PAD); + else sprintf(tmp+strlen(tmp), "??%% %c%c%c", PAD, PAD, PAD); + + lcd.string(1,1,tmp); + + + switch(acstat) + { + case 0: sprintf(tmp, "AC: Off"); + break; + case 1: sprintf(tmp, "AC: On"); + break; + case 2: sprintf(tmp, "AC: Backup"); + break; + default: sprintf(tmp, "AC: Unknown"); + break; + } + + lcd.string(1,2,tmp); + + + if(battflag == 0xff) + { + sprintf(tmp, "Battery Stat Unknown"); + } + else + { + sprintf(tmp, "Batt:"); + if(battflag & 1) sprintf(tmp+strlen(tmp), " High"); + if(battflag & 2) sprintf(tmp+strlen(tmp), " Low"); + if(battflag & 4) sprintf(tmp+strlen(tmp), " Critical"); + if(battflag & 8 + ||battstat == 3) sprintf(tmp+strlen(tmp), " Charging"); + if(battflag & 128) sprintf(tmp+strlen(tmp), " (NONE)"); + } + lcd.string(1,3,tmp); + + lcd.chr(1,4, 'E'); + lcd.chr(lcd.wid,4, 'F'); + + if(percent > 0) + { + lcd.hbar(2,4, (percent * ((lcd.wid-2)*lcd.cellwid)/100)); + } + + + return 0; +} + + + +//////////////////////////////////////////////////////////////////////// +// Credit Screen shows who wrote this... +// +int credit_screen(int rep) +{ + + if(!rep) + { + lcd.clear(); + sprintf(tmp, "%c%c LCDPROC %s %c%c%c%c", + PAD, PAD, version, PAD, PAD, PAD, PAD); + lcd.string(1, 1, tmp); + lcd.string(1, 2, " for Linux "); + lcd.string(1, 3, " by William Ferrell "); + lcd.string(1, 4, " and Scott Scriven "); + } + + return 0; +} // End credit_screen() + + +////////////////////////////////////////////////////////////////////// +// This is mostly for debugging. It should never show up. +// +int dumbass_screen(int rep) +{ + + lcd.string(1,1, "---=== Haha... ==---"); + lcd.string(1,2, " You specified an "); + lcd.string(1,3, " INVALID MODE!!! "); + lcd.string(1,4, "---== Ya LOSER! ==--"); +/* + lcd.string(1,1, "--===GO AWAY!!!===--"); + lcd.string(1,2, " You're a slimy, "); + lcd.string(1,3, " mold-ridden "); + lcd.string(1,4, " pop-tart! "); +*/ + + return BLINK_ON; +} + + +////////////////////////////////////////////////////////////////////////// +// This gets called upon program exit, to say "goodbye" +// +int goodbye_screen(int rep) +{ + + lcd.clear(); +/* + lcd.string(1,1, "---===SHUTDOWN===---"); + lcd.string(1,2, " DANGER, WILL "); + lcd.string(1,3, " ROBINSON! "); + lcd.string(1,4, "---===EJECT!!!===---"); + usleep(250000); +*/ + + lcd.string(1,1, " "); + lcd.string(1,2, " Thanks for using "); + lcd.string(1,3, " LCDproc and Linux! "); + lcd.string(1,4, " "); + + return 0; +} + + diff --git a/old/mode.h b/old/mode.h new file mode 100644 index 0000000..5278aaa --- /dev/null +++ b/old/mode.h @@ -0,0 +1,30 @@ +#ifndef MODE_H +#define MODE_H + + +//TODO: Net stats screen... +//TODO: "Who" +//TODO: biff / mail checking + +// Character to use for padding title bars, etc... +extern int PAD; +// Character for the "..." symbol. +extern int ELLIPSIS; + +int mode_init(); +void mode_close(); + +int cpu_screen(int rep); +int cpu_graph_screen(int rep); +int clock_screen(int rep); +int mem_screen(int rep); +int uptime_screen(int rep); +int time_screen(int rep); +int disk_screen(int rep); +int xload_screen(int rep); +int battery_screen(int rep); +int credit_screen(int rep); +int dumbass_screen(int rep); +int goodbye_screen(int rep); + +#endif diff --git a/old/sockets.c b/old/sockets.c new file mode 100644 index 0000000..e4c5e22 --- /dev/null +++ b/old/sockets.c @@ -0,0 +1,273 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sockets.h" + + +/************************************************** + LCDproc sockets code... + + This is messy, and needs to be finished. +**************************************************/ + +fd_set active_fd_set, read_fd_set; +int sock; + +// Length of longest transmission allowed at once... +#define MAXMSG 8192 + + + +int init_sockaddr (sockaddr_in *name, + const char *hostname, + unsigned short int port) +{ + struct hostent *hostinfo; + + name->sin_family = AF_INET; + name->sin_port = htons (port); + hostinfo = gethostbyname (hostname); + if (hostinfo == NULL) + { + fprintf (stderr,"Unknown host %s.\n", hostname); + return -1; + } + name->sin_addr = *(struct in_addr *) hostinfo->h_addr; + + return 0; + +} + + +#if 0 +// Creates a socket as a file... +int CreateNamedSocket(char *filename) +{ + struct sockaddr_un name; + size_t size; + + sock=socket(PF_FILE, SOCK_STREAM, 0); + if(sock < 0) return -1; + + + name.sun_family = AF_FILE; + strcpy (name.sun_path, filename); + + /* The size of the address is + the offset of the start of the filename, + plus its length, + plus one for the terminating null byte. */ + size = (offsetof (struct sockaddr_un, sun_path) + + strlen (name.sun_path) + 1); + + if (bind (sock, (struct sockaddr *) &name, size) < 0) + return -1; + + return sock; +} +#endif + +// Creates a socket in internet space +int CreateInetSocket(unsigned short int port) +{ + struct sockaddr_in name; + + /* Create the socket. */ + //fprintf(stderr,"Creating Inet Socket\n"); + sock = socket (PF_INET, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + /* Give the socket a name. */ + //fprintf(stderr,"Binding Inet Socket\n"); + name.sin_family = AF_INET; + name.sin_port = htons (port); + name.sin_addr.s_addr = htonl (INADDR_ANY); + if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) + return -1; + + return sock; + +} + +// Checks the LCDproc port for a response... +int PingLCDport() +{ + struct sockaddr_in servername; + int err=0; + char ping[16] = {0xFE, 0x01, 0}; + + + //fprintf(stderr,"Creating socket (client)\n"); + sock = socket(PF_INET, SOCK_STREAM, 0); + if(sock < 0) + { + fprintf(stderr,"Error creating socket (client)\n"); + return sock; + } + //else fprintf(stderr,"Created socket (%i) (client)\n", sock); + + + init_sockaddr(&servername, "localhost", LCDPORT); + + err = connect (sock, + (struct sockaddr *) &servername, + sizeof (servername)); + if(err<0) + { + //fprintf (stderr,"connect failed (client)\n"); + shutdown(sock, 2); + return 0; // Normal exit if server doesn't exist... + } + + err = write (sock, ping, strlen(ping) + 1); + if (err < 0) + { + fprintf (stderr,"socket write error (client)"); + shutdown(sock, 2); + return err; + } + + shutdown(sock, 2); + + return 1; +} + +int ConnectAsClient() +{ + return 0; +} + +int StartSocketServer() +{ + + /* Create the socket and set it up to accept connections. */ + sock = CreateInetSocket (LCDPORT); + if(sock < 0) + { + fprintf(stderr,"Error creating socket (server)\n"); + return -1; + } + + + if (listen (sock, 1) < 0) + { + fprintf (stderr,"Listen error (server)\n"); + return -1; + } + + /* Initialize the set of active sockets. */ + FD_ZERO (&active_fd_set); + FD_SET (sock, &active_fd_set); + + return sock; +} + + +int PollSockets() +{ + int i; + struct sockaddr_in clientname; + size_t size; + struct timeval t; + + + t.tv_sec = 0; + t.tv_usec = 0; + + /* Block until input arrives on one or more active sockets. */ + read_fd_set = active_fd_set; + + if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, &t) < 0) + { + fprintf (stderr,"Select error (server)\n"); + return -1; + } + + /* Service all the sockets with input pending. */ + for (i = 0; i < FD_SETSIZE; ++i) + if (FD_ISSET (i, &read_fd_set)) + { + if (i == sock) + { + /* Connection request on original socket. */ + int new; + size = sizeof (clientname); + new = accept (sock, + (struct sockaddr *) &clientname, + &size); + if (new < 0) + { + fprintf (stderr,"Accept error (server)\n"); + return -1; + } + fprintf (stderr,"Server: connect from host %s, port %hd.\n", + inet_ntoa (clientname.sin_addr), + ntohs (clientname.sin_port)); + FD_SET (new, &active_fd_set); + } + else + { + /* Data arriving on an already-connected socket. */ + if (read_from_client (i) < 0) + { + close (i); + FD_CLR (i, &active_fd_set); + fprintf(stderr,"Closed connection %i\n", i); + } + } + } + return 0; +} + + +int read_from_client (int filedes) +{ + char buffer[MAXMSG]; + int nbytes; + + nbytes = read (filedes, buffer, MAXMSG); + buffer[nbytes] = 0; + buffer[nbytes+1] = 0; + + if (nbytes < 0) // Read error + { + fprintf (stderr,"Read error (server)\n"); + return -1; + } + else if (nbytes == 0) // EOF + return -1; + else // Data Read + { + fprintf (stderr,"Server: got message: `%s'\n", buffer); + return 0; + } +} + +int CloseAllConnections() +{ + int i; + + /* Service all the sockets with input pending. */ + for (i = 0; i < FD_SETSIZE; ++i) + if (FD_ISSET (i, &read_fd_set)) + { + /* Data arriving on an already-connected socket. */ + close (i); + FD_CLR (i, &active_fd_set); + fprintf(stderr,"Closed connection %i\n", i); + } + + return 0; + +} diff --git a/old/sockets.h b/old/sockets.h new file mode 100644 index 0000000..064a12f --- /dev/null +++ b/old/sockets.h @@ -0,0 +1,99 @@ +#define LCDPORT 13666 + +/********************************************************************** + LCDproc socket interface grammar: + + RawText Print whatever you send, at whatever the current position is. + + or... + + 0xFE Command prefix, followed by... + + 0x00 EOT. End of transmission, where applicicable. + 0x01 Ping. Will respond with a "pong". + 'k',x Send "keypad" input, character x (A-Z) + + ?,x,...,EOT Send new mode sequence (x,...)... + ?,x Switch to new mode x immediately + ?,xxxx Pause in current mode for x frames/seconds (0=infinite) + ? Play -- continue mode cycle. + ?,x,y,...,EOT + Send raw text to be displayed. x is style (raw, wrapped), + and y is num frames between lines displayed. + + ?,... Send MtxOrb-like control commands (bargraphs, etc) + + ... more to come later ... +**********************************************************************/ + +/***************************************************************** + LCDproc command line interface: (while running) + + -command + Tells LCDproc to interpret stdin as raw commands to send through + the socket. Input must be formatted as above, in socket interface. + -function f + Runs LCDproc external function f, where f is one of the predefined + functions which can be assigned to keypad keys. (like NEXTMODE, etc) + -key x + Simulates keypad press of key 'x', where 'x' is (A-Z). + -print [time] + Prints stdin on LCD one line at a time, with no line-wrapping (raw), + with [time] frames between updates (lines). + -wrap [time] + Prints stdin as with "-print", but with line wrapping when possible. + -contrast xxx + Sets contrast to xxx (decimal) + -backlight [on/off] + Turns backlight [on/off/auto], or toggles it. + If [off], stays off. + If [on], stays on. + If [auto], LCDproc controls backlight based on load, etc... + -exit + -quit + Duh... :) + +******************************************************************/ + +/***************************************************************** + LCDproc stuff supported in config file (loose approximation): + + Grammar is tcl-style. I.e., "command arg1 arg2 ...". + Spaces are used as argument separators, *until* it thinks it has the final + argument. So, "function thing shell myprogram arg1 arg2 arg3" would be + split into "function", "thing", "shell", and "myprogram arg1 arg2 arg3". + + User-definable functions (use built-in's to create new ones?): + Function mp3NextSong Shell /usr/local/bin/mp3player -next + Function MySequence Sequence cpu mem xload + Function OtherSequence Sequence time cd xload + + Keypad keys can be bound to any _function_: + Key A mp3NextSong + Key B HaltSystem + Key C Menu + Key D Next/+ + Key E OtherSequence + + +******************************************************************/ + +typedef struct sockaddr_in sockaddr_in; + +int init_sockaddr (sockaddr_in *name, + const char *hostname, + unsigned short int port); + +// Creates a socket in internet space +int CreateInetSocket(unsigned short int port); + +// Checks the LCDproc port for a response... +int PingLCDport(); + +int StartSocketServer(); + +int PollSockets(); + +int read_from_client (int filedes); + +int CloseAllConnections(); diff --git a/old/stat.c b/old/stat.c new file mode 100644 index 0000000..45705ec --- /dev/null +++ b/old/stat.c @@ -0,0 +1,644 @@ +#include +#include +#include +#include +#include +#include +#include +#include "stat.h" +#include "lcd.h" + + +/* + Don't use this yet! It's barely even started... + */ + + + +struct load { unsigned long total, user, system, nice, idle; }; +struct meminfo { int total, cache, buffers, free, shared; }; +static char buffer[1024]; + +// Nothing else can see these... +static int meminfo_fd, load_fd, loadavg_fd, uptime_fd; + +static char kver[SYS_NMLN]; +static char sysname[SYS_NMLN]; + +static void reread(int f, char *errmsg); +static int getentry(const char *tag, const char *bufptr); +static void get_mem_info(struct meminfo *result); +static double get_loadavg(void); +static double get_uptime(void); +static void get_load(struct load * result); + + + +int stat_init() +{ + struct utsname *unamebuf = + (struct utsname *) malloc( sizeof(struct utsname) ); + + meminfo_fd = open("/proc/meminfo",O_RDONLY); + loadavg_fd = open("/proc/loadavg",O_RDONLY); + load_fd = open("/proc/stat",O_RDONLY); + uptime_fd = open("/proc/uptime",O_RDONLY); + +#if 0 + kversion_fd = open("/proc/sys/kernel/osrelease",O_RDONLY); + + reread(kversion_fd, "main:"); + sscanf(buffer, "%s", kver); + + close(kversion_fd); +# endif + + /* Get OS name and version from uname() */ + if( uname( unamebuf ) != 0 ) { + perror( "Error calling uname:" ); + } + strcpy( kver, unamebuf->release ); + strcpy( sysname, unamebuf->sysname ); + + return 0; +} + +void stat_close() +{ + close(meminfo_fd); + close(loadavg_fd); + close(load_fd); + close(uptime_fd); +} + + +static void reread(int f, char *errmsg) +{ + if (lseek(f, 0L, 0) == 0 && read(f, buffer, sizeof(buffer) - 1 ) > 0 ) + return; + perror(errmsg); + exit(1); +} + +static int getentry(const char *tag, const char *bufptr) +{ + char *tail; + int retval, len = strlen(tag); + + while (bufptr) + { + if (*bufptr == '\n') bufptr++; + if (!strncmp(tag, bufptr, len)) + { + retval = strtol(bufptr + len, &tail, 10); + if (tail == bufptr + len) return -1; + else return retval; + } + bufptr = strchr( bufptr, '\n'); + } + return -1; +} + +static void get_mem_info(struct meminfo *result) +{ +// int i, res; char *bufptr; + + reread(meminfo_fd, "get_meminfo:"); + result[0].total = getentry("MemTotal:", buffer); + result[0].free = getentry("MemFree:", buffer); + result[0].shared = getentry("MemShared:", buffer); + result[0].buffers = getentry("Buffers:", buffer); + result[0].cache = getentry("Cached:", buffer); + result[1].total = getentry("SwapTotal:", buffer); + result[1].free = getentry("SwapFree:", buffer); +} + +static double get_loadavg(void) +{ + double load; + + reread(loadavg_fd, "get_load:"); + sscanf(buffer, "%lf", &load); + return load; +} + +static double get_uptime(void) +{ + double uptime; + + reread(uptime_fd, "get_uptime:"); + sscanf(buffer, "%lf", &uptime); + return uptime; +} + +static void get_load(struct load * result) +{ + static struct load last_load = { 0, 0, 0, 0, 0 }; struct load curr_load; + + reread(load_fd, "get_load:"); + sscanf(buffer, "%*s %lu %lu %lu %lu\n", + &curr_load.user, &curr_load.nice, &curr_load.system, &curr_load.idle); + curr_load.total = curr_load.user + curr_load.nice + + curr_load.system + curr_load.idle; + result->total = curr_load.total - last_load.total; + result->user = curr_load.user - last_load.user; + result->nice = curr_load.nice - last_load.nice; + result->system = curr_load.system - last_load.system; + result->idle = curr_load.idle - last_load.idle; + last_load.total = curr_load.total; + last_load.user = curr_load.user; + last_load.nice = curr_load.nice; + last_load.system = curr_load.system; + last_load.idle = curr_load.idle; +} + + +static char tmp[256]; + +// A couple of tables for later use... +static char *days[] = { + "Sunday, ", + "Monday, ", + "Tuesday, ", + "Wednesday,", + "Thursday, ", + "Friday, ", + "Saturday, ", +}; + +static char *months[] = { + " January", + " February", + " March", + " April", + " May", + " June", + " July", + " August", + "September", + " October", + " November", + " December", +}; + + +////////////////////////////////////////////////////////////////////////// +// CPU screen shows info about percentage of the CPU being used +// +int cpu_screen(int rep) +{ +#undef CPU_BUF_SIZE +#define CPU_BUF_SIZE 4 + int i, j, n; + float value; + static float cpu[CPU_BUF_SIZE + 1][5];// last buffer is scratch + struct load load; + + + + get_load(&load); + + // Shift values over by one + for(i=0; i<(CPU_BUF_SIZE-1); i++) + for(j=0; j<5; j++) + cpu[i][j] = cpu[i+1][j]; + + // Read new data + cpu[CPU_BUF_SIZE-1][0] = ((float)load.user / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][1] = ((float)load.system / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][2] = ((float)load.nice / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][3] = ((float)load.idle / (float)load.total) * 100.0; + cpu[CPU_BUF_SIZE-1][4] = (((float)load.user + (float)load.system + + (float)load.nice) / (float)load.total) * 100.0; + + // Only clear on first display... + if(!rep) + { + lcd.clear(); + lcd.init_hbar(); + + sprintf(tmp, "%c%c CPU LOAD %c%c", PAD, PAD, PAD, PAD); + + lcd.string(1, 1, tmp); + lcd.string(1, 2, "Usr 0.0% Nice 0.0%"); + lcd.string(1, 3, "Sys 0.0% Idle 0.0%"); + lcd.string(1, 4, "0% 100%"); + + // Make all the same, if this is the first time... + for(i=0; i= 99.9) { lcd.string(13, 1, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(13, 1, tmp); } + + value = cpu[CPU_BUF_SIZE][0]; + if (value >= 99.9) { lcd.string(5, 2, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(5, 2, tmp); } + + value = cpu[CPU_BUF_SIZE][1]; + if (value >= 99.9) { lcd.string(5, 3, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(5, 3, tmp); } + + value = cpu[CPU_BUF_SIZE][2]; + if (value >= 99.9) { lcd.string(16, 2, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(16, 2, tmp); } + + value = cpu[CPU_BUF_SIZE][3]; + if (value >= 99.9) { lcd.string(16, 3, " 100%"); } + else { sprintf(tmp, "%4.1f%%", value); lcd.string(16, 3, tmp); } + + value = cpu[CPU_BUF_SIZE][4]; + n = (int)(value * 70.0 / 100.0); + lcd.string(1, 4, "0% 100%"); + lcd.hbar(3, 4, n); + + return 0; +} // End cpu_screen() + + + +////////////////////////////////////////////////////////////////////////// +// Cpu Graph Screen shows a quick-moving histogram of CPU use. +// +int cpu_graph_screen(int rep) +{ + int i, j, n; + float value, maxload; +#undef CPU_BUF_SIZE +#define CPU_BUF_SIZE 2 + static float cpu[CPU_BUF_SIZE + 1];// last buffer is scratch + static float cpu_past[LCD_MAX_WIDTH]; + struct load load; + int status=0; + char out[LCD_MAX_WIDTH]; + + + + get_load(&load); + + // Shift values over by one + for(i=0; i<(CPU_BUF_SIZE-1); i++) + cpu[i] = cpu[i+1]; + + // Read new data + cpu[CPU_BUF_SIZE-1] = ((float)load.user + (float)load.system + + (float)load.nice) / (float)load.total; + + + // Only clear on first display... + if(!rep) + { + lcd.init_vbar(); + + // Make all the same, if this is the first time... + for(i=0; i maxload) maxload = cpu_past[i]; + } + + value = cpu[CPU_BUF_SIZE]; + n = (int)(value * 8.0 * (float)(lcd.hgt-1)); + + cpu_past[lcd.wid-1] = n; + lcd.vbar(lcd.wid, cpu_past[lcd.wid-1]); + + sprintf(out, "%c%c CPU GRAPH %c%c%c%c%c%c", PAD,PAD, + PAD,PAD,PAD,PAD,PAD,PAD); + lcd.string(1,1,out); + + + + if(n > maxload) maxload = n; + + if(cpu_past[lcd.wid-1] > 0 ) status = BACKLIGHT_ON; + if(maxload < 1) status = BACKLIGHT_OFF; + +// return status; + return 0; +} // End cpu_graph_screen() + + + +////////////////////////////////////////////////////////////////////// +// Clock Screen displays current time and date... +// +// TODO: 24-hour time, if desired. +int clock_screen(int rep) +{ + char hr[8], min[8], sec[8], ampm[8]; + char day[16], month[16]; + time_t thetime; + struct tm *rtime; + int i; + + + if(!rep) + { + lcd.clear(); + sprintf(tmp, "%c%c DATE & TIME %c%c%c%c%c", PAD, PAD, PAD, PAD, PAD, PAD, PAD); + lcd.string(1, 1, tmp); + } + + time(&thetime); + rtime = localtime(&thetime); + + strcpy(day, days[rtime->tm_wday]); + + if (rtime->tm_hour > 12) { i = 1; sprintf(hr, "%02d", (rtime->tm_hour - 12)); } + else { i = 0; sprintf(hr, "%02d", rtime->tm_hour); } + if(rtime->tm_hour == 12) i=1; + sprintf(min, "%02d", rtime->tm_min); + sprintf(sec, "%02d", rtime->tm_sec); + if (i == 1) { sprintf(ampm, "%s", "P"); } + else { sprintf(ampm, "%s", "A"); } + if (rep & 1) { sprintf(tmp, "%s:%s:%s%s %s", hr, min, sec, ampm, day); } + else { sprintf(tmp, "%s %s %s%s %s", hr, min, sec, ampm, day); } + + strcpy(month, months[rtime->tm_mon]); + + lcd.string(1, 3, tmp); + + sprintf(tmp, "%s %d, %d", month, rtime->tm_mday, (rtime->tm_year + 1900)); + lcd.string(2, 4, tmp); + + return 0; +} // End clock_screen() + + +///////////////////////////////////////////////////////////////////////// +// Mem Screen displays info about memory and swap usage... +// +int mem_screen(int rep) +{ + int n; + struct meminfo mem[2]; + + + if(!rep) + { + lcd.clear(); + lcd.init_hbar(); + sprintf(tmp, "%c%c%c MEM %c%c%c%c SWAP %c%c", + PAD,PAD,PAD,PAD,PAD,PAD,PAD,PAD,PAD); + lcd.string(1, 1, tmp); + lcd.string(9, 2, "Totl"); + lcd.string(9, 3, "Free"); + lcd.string(1, 4, "E F E F"); + } + + get_mem_info(mem); + sprintf(tmp, "%6dk", mem[0].total); + lcd.string(1, 2, tmp); + sprintf(tmp, "%6dk", mem[0].free); + lcd.string(1, 3, tmp); + sprintf(tmp, "%6dk", mem[1].total); + lcd.string(14, 2, tmp); + sprintf(tmp, "%6dk", mem[1].free); + lcd.string(14, 3, tmp); + +// This gives just main memory usage +// n = (int)(50.0 - (float)mem[0].free / (float)mem[0].total * 50.0); +// This uses main + swap usage... + + lcd.string(1, 4, "E F E F"); + + n = (int)(35.0 - + (float)mem[0].free / (float)mem[0].total + * 35.0); + lcd.hbar(2, 4, n); + + n = (int)(35.0 - + (float)mem[1].free / (float)mem[1].total + * 35.0); + lcd.hbar(13, 4, n); + + +/* + { + int i; + for(i=0; i<100; i++) + { + lcd.hbar(1,1,i); + lcd.hbar(1,2,i); + lcd.hbar(1,3,i); + lcd.hbar(1,4,i); + usleep(100000); + } + } +*/ + + return 0; +} // End mem_screen() + + +//////////////////////////////////////////////////////////////////// +// Uptime Screen shows info about system uptime and OS version +// +int uptime_screen(int rep) +{ + int i; + char date[16], hour[8], min[8], sec[8]; + double uptime; + + + if(!rep) + { + lcd.clear(); + sprintf(tmp, "%c%c SYSTEM UPTIME %c%c%c", PAD, PAD, PAD, PAD, PAD); + lcd.string(1, 1, tmp); + + sprintf(tmp, "%s %s", sysname, kver); + lcd.string(5, 4, tmp); + } + + uptime = get_uptime(); + i = (int)uptime / 86400; + sprintf(date, "%d day%s,", i, (i != 1 ? "s" : "")); + i = ((int)uptime % 86400) / 60 / 60; + sprintf(hour, "%02i",i); + i = (((int)uptime % 86400) % 3600) / 60; + sprintf(min, "%02i",i); + i = ((int)uptime % 60); + sprintf(sec, "%02i",i); + if (rep & 1) + sprintf(tmp, "%s %s:%s:%s", date, hour, min, sec); + else + sprintf(tmp, "%s %s %s %s", date, hour, min, sec); + i = ((20 - strlen(tmp)) / 2) + 1; + lcd.string(i, 3, tmp); + + + return 0; +} // End uptime_screen() + + +/////////////////////////////////////////////////////////////////////////// +// Shows a display very similar to "xload"'s histogram. +// + +int xload_screen(int rep) +{ + static float loads[LCD_MAX_WIDTH]; + static int first_time=1; + int n; + float loadmax=0, factor, x; + int status = 0; + + + if(first_time) // Only the first time this is ever called... + { + memset(loads, 0, sizeof(float)*LCD_MAX_WIDTH); + first_time = 0; + } + + if(!rep) + { + lcd.clear(); + } + + + for(n=0; n<(lcd.wid-2); n++) loads[n] = loads[n+1]; + loads[lcd.wid-2] = get_loadavg(); + + for(n=0; n loadmax) loadmax = loads[n]; + + lcd.string(20, 4, "0"); + n = (int)loadmax; + if ((float)n < loadmax) { n++; } + sprintf(tmp, "%i", n); lcd.string(20, 2, tmp); + + if (loadmax < 1.0) factor = 24.0; + else factor = 24 / (float)n; + + for(n=0; n 0.05) status = BACKLIGHT_ON; + if(loads[lcd.wid-2] > LOAD_THRESHOLD) status = BLINK_ON; + + // This must be drawn *after* the vertical bars... (?) + sprintf(tmp, "%c%c LOAD AVG %2.2f %c%c", PAD, PAD, loads[lcd.wid-2], PAD, PAD); + lcd.string(1, 1, tmp); + + if(!rep) + lcd.init_vbar(); + + + return status; +} // End xload_screen() + + + +//////////////////////////////////////////////////////////////////////// +// Credit Screen shows who wrote this... +// +int credit_screen(int rep) +{ + + if(!rep) + { + lcd.clear(); + sprintf(tmp, "%c%c LCDPROC %s %c%c%c%c", + PAD, PAD, version, PAD, PAD, PAD, PAD); + lcd.string(1, 1, tmp); + lcd.string(1, 2, " for Linux "); + lcd.string(1, 3, " by William Ferrell "); + lcd.string(1, 4, " and Scott Scriven "); + } + + return 0; +} // End credit_screen() + + +////////////////////////////////////////////////////////////////////// +// This is mostly for debugging. It should never show up. +// +int dumbass_screen(int rep) +{ + + lcd.string(1,1, "---=== Haha... ==---"); + lcd.string(1,2, " You specified an "); + lcd.string(1,3, " INVALID MODE!!! "); + lcd.string(1,4, "---== Ya LOSER! ==--"); +/* + lcd.string(1,1, "--===GO AWAY!!!===--"); + lcd.string(1,2, " You're a slimy, "); + lcd.string(1,3, " mold-ridden "); + lcd.string(1,4, " pop-tart! "); +*/ + + return BLINK_ON; +} + + +////////////////////////////////////////////////////////////////////////// +// This gets called upon program exit, to say "goodbye" +// +int goodbye_screen(int rep) +{ + + lcd.clear(); +/* + lcd.string(1,1, "---===SHUTDOWN===---"); + lcd.string(1,2, " DANGER, WILL "); + lcd.string(1,3, " ROBINSON! "); + lcd.string(1,4, "---===EJECT!!!===---"); + usleep(250000); +*/ + + lcd.string(1,1, " "); + lcd.string(1,2, " Thanks for using "); + lcd.string(1,3, " LCDproc and Linux! "); + lcd.string(1,4, " "); + + return 0; +} + + diff --git a/old/stat.h b/old/stat.h new file mode 100644 index 0000000..870e2b1 --- /dev/null +++ b/old/stat.h @@ -0,0 +1,58 @@ +#ifndef MODE_H +#define MODE_H + +/* + Don't use this yet! It's barely even started! + */ + +int stat_init(); +void stat_close(); + +typedef struct status +{ + // should hold persistent data somehow... +// data_type data; + + // Takes position onscreen (x,y), and + // format (i=int, f=float, h=horz bar, v=vert bar, 2=24-hour, 1=12-hour, + // x=xload-style, etc...) + // Each stat will only draw valid formats... + // size is max size (graphs) or num digits, etc... (0 is "max" size) + // reread specifies to re-grab the value first. + void (*draw)(int x, int y, int size, char format, int reread); + void (*read)(int reread); + + // Should also maybe be able to return the data? +// return_type (*get)(); + +}; + + +extern status cpu; +extern status cpu_nice; +extern status cpu_idle; +extern status cpu_sys; +extern status cpu_usr; + +extern status mem_free; +extern status mem_total; +extern status swap_free; +extern status swap_total; + +extern status load; + +extern status date; +extern status uptime; + +extern status os_ver; + +extern status disk_activity; +extern status disk_free; +extern status disk_total; + +extern status net_sent; +extern status net_recv; +extern status net_rate; + + +#endif diff --git a/server/Makefile b/server/Makefile new file mode 100644 index 0000000..ba832c7 --- /dev/null +++ b/server/Makefile @@ -0,0 +1,52 @@ +include ../Makefile.config + +######################################################################## +# You shouldn't need to touch anything below here. +######################################################################## + +TARGET = LCDd +DIRS = drivers +OBJ += sock.o clients.o parse.o client_functions.o client_data.o screen.o \ + widget.o screenlist.o render.o serverscreens.o main.o input.o \ + menu.o menus.o +LIB += drivers/libLCDdrivers.a ../shared/libLCDstuff.a + +ifeq ($(IRMAN),1) + LIB += ../../libirman-0.4.1b/libirman.a +endif + + +include ../Makefile.config + +################################################################### +# Compilation... +# +#all: $(OBJ) +all: $(TARGET) + +$(TARGET): $(OBJ) $(LIB) Makefile + $(GCC) -s $(MISC) -o $(TARGET) $(OBJ) $(LIB) + +%.o: %.c %.h Makefile + $(GCC) -c $(MISC) $< + + +################################################################## +# Installation +# +install: $(TARGET) + @echo Installing LCD Server... + install -m 0755 -o root -g root $(TARGET) /usr/local/bin/ + + +################################################################## +# Other stuff... +# +clean: + @for i in $(DIRS); do \ + (cd $$i; [ -f Makefile ] && $(MAKE) $@) \ + done + rm -f $(OBJ) $(TARGET) *~ core + +edit: + emacs . & diff --git a/server/client_data.c b/server/client_data.c new file mode 100644 index 0000000..af6a3a3 --- /dev/null +++ b/server/client_data.c @@ -0,0 +1,89 @@ +/* + client_data.c + + Creates and destroys a client's data structures. These are mainly + its name, screen list, and menu list. + + */ + + +#include +#include +#include + +#include "../shared/debug.h" + +#include "client_data.h" +#include "screen.h" +#include "screenlist.h" + + + +int client_data_init(client_data *d) +{ + if(!d) return -1; + + d->ack = 0; + d->name = NULL; + + d->screenlist = LL_new(); + if(!d->screenlist) + { + fprintf(stderr, "client_data_init: Error allocating screenlist\n"); + return -1; + } + /* TODO: this section... (client menus) + d->menulist = LL_new(); + if(!d->menulist) + { + fprintf(stderr, "client_data_init: Error allocating menulist\n"); + return -1; + } + */ + return 0; +} + +int client_data_destroy(client_data *d) +{ + screen *s; + + debug("client_data_destroy\n"); + + if(!d) return -1; + + d->ack = 0; + + // Clean up the name... + if(d->name) + free(d->name); + + // Clean up the screenlist... + debug("client_data_destroy: Cleaning screenlist\n"); + LL_Rewind(d->screenlist); + do { + s = (screen *)LL_Get(d->screenlist); + if(s) + { + debug("client_data_destroy: removing screen %s\n", s->id); + + // FIXME? This shouldn't be handled here... + // Now, remove it from the screenlist... + if(screenlist_remove_all(s) < 0) + { + // Not a serious error.. + fprintf(stderr, "client_data_destroy: Error dequeueing screen\n"); + return 0; + } + + // Free its memory... + screen_destroy(s); + } + } while(LL_Next(d->screenlist) == 0); + LL_Destroy(d->screenlist); + + // TODO: clean up the rest of the data... + + return 0; +} + + diff --git a/server/client_data.h b/server/client_data.h new file mode 100644 index 0000000..90d607f --- /dev/null +++ b/server/client_data.h @@ -0,0 +1,26 @@ +#ifndef CLIENT_DATA_H +#define CLIENT_DATA_H + +#include "../shared/LL.h" + + +#define CLIENT_NAME_SIZE 256 + +typedef struct client_data +{ + int ack; + char *name; + // and other stuff... doesn't matter yet + LL * screenlist; + // list of accepted keys... (?) + LL * menulist; + +} client_data; + + +// sets up an existing (empty) client_data struct +int client_data_init(client_data *d); +// destroys members of a client's data +int client_data_destroy(client_data *d); + +#endif diff --git a/server/client_functions.c b/server/client_functions.c new file mode 100644 index 0000000..d6422c1 --- /dev/null +++ b/server/client_functions.c @@ -0,0 +1,986 @@ +/* + client_functions.c + + This contains definitions for all the functions which clients can run. + The functions here are to be called only from parse.c's interpreter. + + The client's available function set is defined here, as is the syntax + for each command. + +*/ + + +#include +#include +#include +#include + +#include "../shared/debug.h" +#include "../shared/sockets.h" + +#include "drivers/lcd.h" + +#include "main.h" +#include "render.h" +#include "clients.h" +#include "parse.h" +#include "screen.h" +#include "widget.h" +#include "client_functions.h" + + +client_function commands[] = { + {"test_func", test_func_func }, + {"hello", hello_func}, + {"client_set", client_set_func}, + {"client_add_key", client_add_key_func}, + {"client_del_key", client_del_key_func}, + {"screen_add", screen_add_func}, + {"screen_del", screen_del_func}, + {"screen_set", screen_set_func}, + {"widget_add", widget_add_func}, + {"widget_del", widget_del_func}, + {"widget_set", widget_set_func}, + {"menu_add", menu_add_func}, + {"menu_del", menu_del_func}, + {"menu_set", menu_set_func}, + // TODO: Adhere these to the naming convention? + {"menu_item_add", menu_item_add_func}, + {"menu_item_del", menu_item_del_func}, + {"menu_item_set", menu_item_set_func}, + // Misc stuff... + {"backlight", backlight_func}, + {"output", output_func}, + {NULL, NULL }, +}; + + +// TODO: Maybe more error-checking for "->"'s? + + +/////////////////////////////////////////////////////////////////////////// +// Debugging only.. prints out a list of arguments it receives +// +int test_func_func(client *c, int argc, char **argv) +{ + int i; + char str[256]; + + for(i=0; i %s\n", i, argv[i]); + printf(str); + sock_send_string(c->sock, str); + } + return 0; +} + + +/////////////////////////////////////////////////////////////////////////// +// The client must say "hello" before doing anything else. +// +// It returns a string of info about the server to the client +// +int hello_func(client *c, int argc, char **argv) +{ + char str[256]; + + // TODO: Give *real* info about the server/lcd... + + debug("Hello!\n"); + + sprintf(str, + "connect LCDproc %s lcd wid %i hgt %i cellwid %i cellhgt %i\n", + version, lcd.wid, lcd.hgt, lcd.cellwid, lcd.cellhgt); + sock_send_string(c->sock, str); + + if(c->data) + c->data->ack = 1; + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// sets info about the client, such as its name +// +int client_set_func(client *c, int argc, char **argv) +{ + int i; + + if(!c->data->ack) return 1; + + for(i=1; i i+1) + { + i++; + debug("client_set: name=\"%s\"\n", argv[i]); + + // set the name... + if(c->data->name) + free(c->data->name); + c->data->name = strdup(argv[i]); + } + else + { + sock_send_string(c->sock, "huh? name requires a parameter\n"); + } + } + else + { + sock_send_string(c->sock, "huh? invalid parameter\n"); + } + } + + // If there were no parameters... + if(argc == 1) + sock_send_string(c->sock, "huh? What do you want to set?\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Tells the server the client would like to accept keypresses +// of a particular type +// +int client_add_key_func(client *c, int argc, char **argv) +{ + + + if(!c->data->ack) return 1; + + sock_send_string(c->sock, "huh? Not implemented yet.\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Tells the server the client would NOT like to accept keypresses +// of a particular type +// +int client_del_key_func(client *c, int argc, char **argv) +{ + + + if(!c->data->ack) return 1; + + sock_send_string(c->sock, "huh? Not implemented yet.\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Tells the server the client has another screen to offer +// +int screen_add_func(client *c, int argc, char **argv) +{ + int err=0; + + if(!c->data->ack) return 1; + + if(argc < 2) + { + sock_send_string(c->sock, "huh? Specify a screen #id\n"); + return 0; + } + if(argc > 2) + { + sock_send_string(c->sock, "huh? Too many parameters...\n"); + return 0; + } + + + debug("screen_add: Adding screen %s\n", argv[1]); + err = screen_add(c, argv[1]); + if(err < 0) + fprintf(stderr, "screen_add_func: Error adding screen\n"); + if(err > 0) + sock_send_string(c->sock, + "huh? You already have a screen with that id#\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Client requests that the server forget about a screen +// +int screen_del_func(client *c, int argc, char **argv) +{ + int err=0; + + if(!c->data->ack) return 1; + + if(argc < 2) + { + sock_send_string(c->sock, "huh? Specify a screen #id\n"); + return 0; + } + if(argc > 2) + { + sock_send_string(c->sock, "huh? Too many parameters...\n"); + return 0; + } + + + debug("screen_del: Deleting screen %s\n", argv[1]); + err = screen_remove(c, argv[1]); + if(err < 0) + fprintf(stderr, "screen_del_func: Error removing screen\n"); + if(err > 0) + sock_send_string(c->sock, + "huh? You don't have a screen with that id#\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Configures info about a particular screen, such as its +// name, priority, or duration +// +int screen_set_func(client *c, int argc, char **argv) +{ + int i; + + int number; + char *id; + screen *s; + + if(!c->data->ack) return 1; + + + // If there weren't enough parameters... + if(argc < 2) + { + sock_send_string(c->sock, "huh? You must specify a screen id\n"); + return 0; + } + + if(argc == 2) + { + sock_send_string(c->sock, "huh? What do you want to set?\n"); + return 0; + } + + + id = argv[1]; + s = screen_find(c, id); + if(!s) + { + sock_send_string(c->sock, "huh? Invalid screen id\n"); + return 0; + } + + // Handle the rest of the parameters + for(i=2; i i+1) + { + i++; + debug("screen_set: name=\"%s\"\n", argv[i]); + + // set the name... + if(s->name) + free(s->name); + s->name = strdup(argv[i]); + } + else + { + sock_send_string(c->sock, "huh? name requires a parameter\n"); + } + } + // Handle the "priority" parameter + else if(0 == strcmp(argv[i], "priority")) + { + if(argc > i+1) + { + i++; + debug("screen_set: priority=\"%s\"\n", argv[i]); + + // set the priority... + number = atoi(argv[i]); + if(number > 0) + s->priority = number; + } + else + { + sock_send_string(c->sock, "huh? priority requires a parameter\n"); + } + } + // Handle the "duration" parameter + else if(0 == strcmp(argv[i], "duration")) + { + if(argc > i+1) + { + i++; + debug("screen_set: duration=\"%s\"\n", argv[i]); + + // set the duration... + number = atoi(argv[i]); + if(number > 0) + s->duration = number; + } + else + { + sock_send_string(c->sock, "huh? duration requires a parameter\n"); + } + } + // Handle the "wid" parameter + else if(0 == strcmp(argv[i], "wid")) + { + if(argc > i+1) + { + i++; + debug("screen_set: wid=\"%s\"\n", argv[i]); + + // set the duration... + number = atoi(argv[i]); + if(number > 0) + s->wid = number; + } + else + { + sock_send_string(c->sock, "huh? wid requires a parameter\n"); + } + } + // Handle the "hgt" parameter + else if(0 == strcmp(argv[i], "hgt")) + { + if(argc > i+1) + { + i++; + debug("screen_set: hgt=\"%s\"\n", argv[i]); + + // set the duration... + number = atoi(argv[i]); + if(number > 0) + s->hgt = number; + } + else + { + sock_send_string(c->sock, "huh? hgt requires a parameter\n"); + } + } + else + { + sock_send_string(c->sock, "huh? invalid parameter\n"); + } + } // done checking argv + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Adds a widget to a screen, but doesn't give it a value +// +int widget_add_func(client *c, int argc, char **argv) +{ + int err; + + char *type; + char *sid; + char *wid; + char *in = NULL; + screen *s; + + + if(!c->data->ack) return 1; + + + // If there weren't enough parameters... + if(argc < 2) + { + sock_send_string(c->sock, "huh? You must specify a screen id\n"); + return 0; + } + if(argc < 3) + { + sock_send_string(c->sock, "huh? You must specify a widget id\n"); + return 0; + } + if(argc < 4) + { + sock_send_string(c->sock, "huh? You must specify a widget type\n"); + return 0; + } + if(argc > 6) + { + sock_send_string(c->sock, "huh? Too many parameters\n"); + return 0; + } + + + sid = argv[1]; + wid = argv[2]; + + s = screen_find(c, sid); + if(!s) + { + sock_send_string(c->sock, "huh? Invalid screen id\n"); + return 0; + } + + type = argv[3]; + + // Check for additional flags... + if(argc > 4) + { + // Handle the "-in" flag to place widgets in a container... + if(0 == strcmp(argv[4], "-in")) + { + if(argc < 6) + { + sock_send_string(c->sock, + "huh? Specify a frame to place widget in\n"); + return 0; + } + in = argv[5]; + } + } + + + // Add the widget and set its type... + err = widget_add(s, wid, type, in, c->sock); + if(err<0) + fprintf(stderr, "widget_add_func: Error adding widget\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Removes a widget from a screen, and forgets about it +// +int widget_del_func(client *c, int argc, char **argv) +{ + int err=0; + + char *sid; + char *wid; + screen *s; + + if(!c->data->ack) return 1; + + // Check the number of parameters... + if(argc < 2) + { + sock_send_string(c->sock, "huh? Specify a screen #id\n"); + return 0; + } + if(argc < 3) + { + sock_send_string(c->sock, "huh? Specify a widget #id\n"); + return 0; + } + if(argc > 3) + { + sock_send_string(c->sock, "huh? Too many parameters...\n"); + return 0; + } + + + sid = argv[1]; + wid = argv[2]; + + debug("screen_del: Deleting widget %s.%s\n", sid, wid); + + s = screen_find(c, sid); + if(!s) + { + sock_send_string(c->sock, "huh? Invalid screen id\n"); + } + + err = widget_remove(s, wid, c->sock); + if(err < 0) + fprintf(stderr, "widget_del_func: Error removing widget\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Configures information about a widget, such as its size, shape, +// contents, position, speed, etc... +// +// Ack! This is long! +int widget_set_func(client *c, int argc, char **argv) +{ + int i; + + int x, y; + int left, top, right, bottom; + int length, direction; + int width, height; + int speed; + char *sid, *wid; + screen *s; + widget *w; + + if(!c->data->ack) return 1; + + + // If there weren't enough parameters... + if(argc < 2) + { + sock_send_string(c->sock, "huh? You must specify a screen id\n"); + return 0; + } + if(argc < 3) + { + sock_send_string(c->sock, "huh? You must specify a widget id\n"); + return 0; + } + if(argc < 4) + { + sock_send_string(c->sock, "huh? You must send some widget data\n"); + return 0; + } + + + sid = argv[1]; + wid = argv[2]; + s = screen_find(c, sid); + if(!s) + { + sock_send_string(c->sock, "huh? Invalid screen id\n"); + return 0; + } + w = widget_find(s, wid); + if(!w) + { + sock_send_string(c->sock, "huh? Invalid widget id\n"); + // Client Debugging... + { + int i; + fprintf(stderr, "huh? Invalid widget id (%s)\n", wid); + for(i=0; itype) + { + case WID_STRING: // String takes "x y text" + if(argc != i+3) + sock_send_string(c->sock, "huh? Wrong number of arguments\n"); + else + { + if((!isdigit(argv[i][0])) || (!isdigit(argv[i+1][0]))) + { + sock_send_string(c->sock, "huh? Invalid coordinates\n"); + } + else // Set all the data... + { + x = atoi(argv[i]); + y = atoi(argv[i+1]); + w->x = x; + w->y = y; + if(w->text) + free(w->text); + w->text = strdup(argv[i+2]); + if(!w->text) + { + fprintf(stderr, + "widget_set_func: Error allocating string\n"); + return -1; + } + debug("Widget %s set to %s\n", wid, w->text); + } + } + break; + case WID_HBAR: // Hbar takes "x y length" + if(argc != i+3) + sock_send_string(c->sock, "huh? Wrong number of arguments\n"); + else + { + if((!isdigit(argv[i][0])) || (!isdigit(argv[i+1][0]))) + { + sock_send_string(c->sock, "huh? Invalid coordinates\n"); + } + else + { + x = atoi(argv[i]); + y = atoi(argv[i+1]); + length = atoi(argv[i+2]); + w->x = x; + w->y = y; + w->length = length; + } + debug("Widget %s set to %i\n", wid, w->length); + } + break; + case WID_VBAR: // Vbar takes "x y length" + if(argc != i+3) + sock_send_string(c->sock, "huh? Wrong number of arguments\n"); + else + { + if((!isdigit(argv[i][0])) || (!isdigit(argv[i+1][0]))) + { + sock_send_string(c->sock, "huh? Invalid coordinates\n"); + } + else + { + x = atoi(argv[i]); + y = atoi(argv[i+1]); + length = atoi(argv[i+2]); + w->x = x; + w->y = y; + w->length = length; + } + debug("Widget %s set to %i\n", wid, w->length); + } + break; + case WID_ICON: // Icon takes "x y binary_data" + if(argc != i+3) + sock_send_string(c->sock, "huh? Wrong number of arguments\n"); + else + { + if((!isdigit(argv[i][0])) || (!isdigit(argv[i+1][0]))) + { + sock_send_string(c->sock, "huh? Invalid coordinates\n"); + } + else + { + x = atoi(argv[i]); + y = atoi(argv[i+1]); + w->x = x; + w->y = y; + // TODO: Parse binary data and copy it to widget's data... + } + } + sock_send_string(c->sock, "huh? Widget type not yet implemented\n"); + break; + case WID_TITLE: // title takes "text" + if(argc != i+1) + sock_send_string(c->sock, "huh? Wrong number of arguments\n"); + else + { + if(w->text) + free(w->text); + w->text = strdup(argv[i]); + if(!w->text) + { + fprintf(stderr, + "widget_set_func: Error allocating string\n"); + return -1; + } + debug("Widget %s set to %s\n", wid, w->text); + } + break; + case WID_SCROLLER: // Scroller takes "left top right bottom direction speed text" + if(argc != i+7) { + sock_send_string(c->sock, "huh? Wrong number of arguments\n"); + } + else + { + if((!isdigit(argv[i][0])) || + (!isdigit(argv[i+1][0])) || + (!isdigit(argv[i+2][0])) || + (!isdigit(argv[i+3][0]))) + { + sock_send_string(c->sock, "huh? Invalid coordinates\n"); + } + else + { + left = atoi(argv[i]); + //debug("left: %d\n",left); + top = atoi(argv[i+1]); + //debug("top: %d\n",top); + right = atoi(argv[i+2]); + //debug("right: %d\n",right); + bottom = atoi(argv[i+3]); + //debug("bottom: %d\n",bottom); + direction = (int)(argv[i+4][0]); + //debug("dir: %c\n",(char)direction); + speed = atoi(argv[i+5]); + //debug("speed: %d\n",speed); + // Direction must be v or h + if(((char)direction != 'h') && ((char)direction != 'v')) + { + sock_send_string(c->sock, "huh? Invalid direction\n"); + } + else + { + w->left = left; + w->top = top; + w->right = right; + w->bottom = bottom; + w->length = direction; + w->speed = speed; + if(w->text) + free(w->text); + w->text = strdup(argv[i+6]); + if(!w->text) + { + fprintf(stderr, "widget_set_func: Error allocating string\n"); + return -1; + } + debug("Widget %s set to %s\n", wid, w->text); + } + } + } + break; + case WID_FRAME: // Frame takes "left top right bottom wid hgt direction speed" + if(argc != i+8) { + sock_send_string(c->sock, "huh? Wrong number of arguments\n"); + } + else + { + if((!isdigit(argv[i][0])) || + (!isdigit(argv[i+1][0])) || + (!isdigit(argv[i+2][0])) || + (!isdigit(argv[i+3][0])) || + (!isdigit(argv[i+4][0])) || + (!isdigit(argv[i+5][0]))) + { + sock_send_string(c->sock, "huh? Invalid coordinates\n"); + } + else + { + left = atoi(argv[i]); + //debug("left: %d\n",left); + top = atoi(argv[i+1]); + //debug("top: %d\n",top); + right = atoi(argv[i+2]); + //debug("right: %d\n",right); + bottom = atoi(argv[i+3]); + //debug("bottom: %d\n",bottom); + width = atoi(argv[i+4]); + //debug("right: %d\n",right); + height = atoi(argv[i+5]); + //debug("bottom: %d\n",bottom); + direction = (int)(argv[i+6][0]); + //debug("dir: %c\n",(char)direction); + speed = atoi(argv[i+7]); + //debug("speed: %d\n",speed); + // Direction must be v or h + if(((char)direction != 'h') && ((char)direction != 'v')) + { + sock_send_string(c->sock, "huh? Invalid direction\n"); + } + else + { + w->left = left; + w->top = top; + w->right = right; + w->bottom = bottom; + w->wid = width; + w->hgt = height; + w->length = direction; + w->speed = speed; + debug("Widget %s set to (%i,%i)-(%i,%i) %ix%i\n", + wid, left, top, right, bottom, width, height); + } + } + } + break; + case WID_NUM: // Num takes "x num" + if(argc != i+2) + sock_send_string(c->sock, "huh? Wrong number of arguments\n"); + else + { + if(!isdigit(argv[i][0])) + { + sock_send_string(c->sock, "huh? Invalid coordinates\n"); + } else if(!isdigit(argv[i+1][0])) + { + sock_send_string(c->sock, "huh? Invalid number\n"); + } else + { + x = atoi(argv[i]); + y = atoi(argv[i+1]); + w->x = x; + w->y = y; + } + debug("Widget %s set to %i\n", wid, w->y); + } + break; + case WID_NONE: + default: + sock_send_string(c->sock, "huh? Widget has no type\n"); + break; + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Adds a menu to the client; handled by the server... +// +int menu_add_func(client *c, int argc, char **argv) +{ + + + if(!c->data->ack) return 1; + + sock_send_string(c->sock, "huh? Not implemented yet.\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Removes a client's menu and all contents from the server +// +int menu_del_func(client *c, int argc, char **argv) +{ + + + if(!c->data->ack) return 1; + + sock_send_string(c->sock, "huh? Not implemented yet.\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Sets info about a menu, but not its items +// +// For example, should the menu be top-level, or buried somewhere? +// +int menu_set_func(client *c, int argc, char **argv) +{ + + + if(!c->data->ack) return 1; + + sock_send_string(c->sock, "huh? Not implemented yet.\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Adds an item to a menu +// +int menu_item_add_func(client *c, int argc, char **argv) +{ + + + if(!c->data->ack) return 1; + + sock_send_string(c->sock, "huh? Not implemented yet.\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Deletes an item from a menu +// +int menu_item_del_func(client *c, int argc, char **argv) +{ + + + if(!c->data->ack) return 1; + + sock_send_string(c->sock, "huh? Not implemented yet.\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Sets the info about a menu item +// +// For example, text displayed, widget type, value, etc... +// +int menu_item_set_func(client *c, int argc, char **argv) +{ + + + if(!c->data->ack) return 1; + + sock_send_string(c->sock, "huh? Not implemented yet.\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Toggles the backlight, if enabled. +// +int backlight_func(client *c, int argc, char **argv) +{ + if(!c->data->ack) return 1; + + // Check the number of parameters... + if(argc < 2) + { + sock_send_string(c->sock, "huh? Specify a screen #id\n"); + return 0; + } + + if(argc > 2) + { + sock_send_string(c->sock, "huh? Too many parameters...\n"); + return 0; + } + + + debug("backlight(%s)\n", argv[1]); + + + switch(backlight) + { + case BACKLIGHT_OPEN: + if(0 == strcmp("on", argv[1])) + { + backlight_state = BACKLIGHT_ON; + } + if(0 == strcmp("off", argv[1])) + { + backlight_state = BACKLIGHT_OFF; + } + if(0 == strcmp("toggle", argv[1])) + { + if(backlight_state == BACKLIGHT_ON) + backlight_state = BACKLIGHT_OFF; + else if(backlight_state == BACKLIGHT_OFF) + backlight_state = BACKLIGHT_ON; + } + if(0 == strcmp("blink", argv[1])) + { + backlight_state |= BACKLIGHT_BLINK; + } + if(0 == strcmp("flash", argv[1])) + { + backlight_state |= BACKLIGHT_FLASH; + } + break; + case BACKLIGHT_VIS: + break; + } + + return 0; + +} + +//////////////////////////////////////////////////////////////////////////// +// Sets the output port on MtxOrb LCDs +int output_func(client *c, int argc, char **argv) +{ + if(argc != 2) + { + sock_send_string(c->sock, "huh? Too many parameters...\n"); + } + else + { + if(0 == strcmp(argv[1], "on")) + output_state = 1; + else + output_state = 0; + } + return 0; +} + + +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + diff --git a/server/client_functions.h b/server/client_functions.h new file mode 100644 index 0000000..ba73584 --- /dev/null +++ b/server/client_functions.h @@ -0,0 +1,41 @@ +#ifndef CLIENT_FUNCTION_H +#define CLIENT_FUNCTION_H + + +/* + The function list for clients is stored in a table, and the items each + point to a function to call, defined below. + */ + +typedef struct client_function +{ + char *keyword; + int (*function)(client *c, int argc, char **argv); +} client_function; + +// FIXME? Do these really need to be visible from other sources? +int test_func_func(client *c, int argc, char **argv); +int hello_func(client *c, int argc, char **argv); +int client_set_func(client *c, int argc, char **argv); +int client_add_key_func(client *c, int argc, char **argv); +int client_del_key_func(client *c, int argc, char **argv); +int screen_add_func(client *c, int argc, char **argv); +int screen_del_func(client *c, int argc, char **argv); +int screen_set_func(client *c, int argc, char **argv); +int widget_add_func(client *c, int argc, char **argv); +int widget_del_func(client *c, int argc, char **argv); +int widget_set_func(client *c, int argc, char **argv); +int menu_add_func(client *c, int argc, char **argv); +int menu_del_func(client *c, int argc, char **argv); +int menu_set_func(client *c, int argc, char **argv); +int menu_item_add_func(client *c, int argc, char **argv); +int menu_item_del_func(client *c, int argc, char **argv); +int menu_item_set_func(client *c, int argc, char **argv); +int backlight_func(client *c, int argc, char **argv); +int output_func(client *c, int argc, char **argv); + +extern client_function commands[]; + + + +#endif diff --git a/server/client_menu.h b/server/client_menu.h new file mode 100644 index 0000000..d97dbde --- /dev/null +++ b/server/client_menu.h @@ -0,0 +1,27 @@ +#ifndef CLIENT_MENU_H +#define CLIENT_MENU_H + +/* + hee-hee.. this isn't implemented yet. + + Eventually, it'll handle client-supplied menus, and send back info about + what the user does. + */ + +typedef struct client_menu +{ + char id[]; + LL * items; +} client_menu; + +typedef struct client_menu_item +{ + char id[]; + int type; // Title, function, submenu, slider, checkbox, etc... + int value; // Holds stuff like "true", 43, etc... + char text[]; // Text to display here... + char child[]; // For the "submenu" type +} client_menu; + + +#endif diff --git a/server/clients.c b/server/clients.c new file mode 100644 index 0000000..a93f9f0 --- /dev/null +++ b/server/clients.c @@ -0,0 +1,266 @@ +/* + + clients.c + + Inits/shuts down client system, + creates/destroys individual clients, + enqueues/dequeues messages from clients, + and searches for clients in the list. + + :) + + */ + +#include +#include +#include +#include + +#include "clients.h" +#include "client_data.h" +#include "../shared/debug.h" + + + +LL * clients; + +// Initialize and kill client list... +int client_init() +{ + debug("client_init()\n"); + + clients = LL_new(); + if(!clients) + { + fprintf(stderr, "client_init: Unable to create client list\n"); + return -1; + } + + return 0; +} + +int client_shutdown() +{ + // TODO: Close all connections first... + client *c; + + debug("client_shutdown()\n"); + + + // Free all client structures... + // Note that the regular list loop doesn't work here, because + // client_destroy() calls LL_Remove() + for(c = LL_Pop(clients); + c; + c = LL_Pop(clients)) + { + debug("client_shutdown: ...\n"); + if(c) + { + debug("client_shutdown: ... %i ...\n", c->sock); + if(0 != client_destroy(c)) + { + fprintf(stderr, "client_shutdown: Error freeing client\n"); + } + else + { + debug("client_shutdown: Freed client...\n"); + } + } + else + { + debug("client_shutdown: No client!\n"); + } + } + + // Then, free the list... + LL_Destroy(clients); + + debug("client_shutdown: done\n"); + + return 0; +} + + +// Create and destroy clients.... +client * client_create(int sock) +{ + client *c; + + debug("client_create(%i)\n", sock); + + // Allocate new client... + c = malloc(sizeof(client)); + if(!c) + { + fprintf(stderr, "client_create: error allocating new client\n"); + return NULL; + } + + // Init struct members + c->sock = 0; + c->data = NULL; + c->messages = NULL; + + + c->sock = sock; + + // Set up message list... + c->messages = LL_new(); + if(!c->messages) + { + fprintf(stderr, "client_create: error allocating message list\n"); + free(c); + return NULL; + } + + // TODO: allocate and init client data... + c->data = malloc(sizeof(client_data)); + if(!c->data) + { + fprintf(stderr, "client_create: error allocating client data\n"); + free(c->messages); + free(c); + return NULL; + } + else if(client_data_init(c->data) < 0) + { + return NULL; + } + + // TODO: Check for errors while adding the client to the list? + LL_Push(clients, (void *)c); + + return c; +} +int client_destroy(client *c) +{ + // TODO: Close the socket connection here? + int err; + + char *str; + + debug("client_destroy()\n"); + + if(!c) return -1; + + // Eat the rest of the incoming requests... + debug("client_destroy: get_messages\n"); + while((str = client_get_message(c))) + { + if(str) { + debug("client_destroy: kill message %s\n", str); + free(str); + } + } + + err = LL_Destroy(c->messages); + + // Free client's other data + client_data_destroy(c->data); + +/* + // FIXME? Should the connection get closed here or elsewhere? + if(c->sock) close(c->sock); + c->sock = 0; +*/ + + // Remove the client from the clients list... + LL_Remove(clients, c); + + free(c); + + return 0; +} + +// Add and remove messages from the client's queue... +int client_add_message(client *c, char *message) +{ + int err = 0; + char *dup; + char *str, *cp; + char delimiters[] = "\n\r\0"; +// int len; + + //debug("client_add_message(%s)\n", message); + + if(!c) return -1; + if(!message) return -1; + +// len = strlen(message); +// if(len < 1) return 0; + + // Copy the string to avoid overwriting the original... + dup = strdup(message); + if(!dup) + { + fprintf(stderr, "client_add_message: Error allocating new string\n"); + return -1; + } + + // Now split the string into lines and enqueue each one... + for(str = strtok(dup, delimiters); str; str=strtok(NULL, delimiters)) + { + cp = strdup(str); + debug("client_add_message: %s\n", cp); + err += LL_Enqueue(c->messages, (void *)cp); + } + + //debug("client_add_message(%s): %i errors\n", message, err); + free(dup); // Fixed memory leak... + + // Err is the number of errors encountered... + return err; + +} +// Woo-hoo! A simple function. :) +char * client_get_message(client *c) +{ + char *str; + + //debug("client_get_message()\n"); + + if(!c) return NULL; + + str = (char *)LL_Dequeue(c->messages); + + //debug("client_get_message: \"%s\"\n", str); + + return str; +} + +// Get and set the client's data... +int client_set(client *c, void *data) +{ + // You know, I really doubt this function will be useful... + return 0; +} +void * client_get(client *c) +{ + // But this one might be handy... + + return NULL; +} + + +client * client_find_sock(int sock) +{ + client * c; + +// debug("client_find_sock(%i)\n", sock); + + LL_Rewind(clients); + do{ + c = (client *)LL_Get(clients); +// debug("client_find_sock: ... %i ...\n", c->sock); + if(c->sock == sock) + { +// debug("client_find_sock: ..! %i !..\n", c->sock); + return c; + } + } while(LL_Next(clients) == 0); + + debug("client_find_sock: failed\n"); + + return NULL; +} diff --git a/server/clients.h b/server/clients.h new file mode 100644 index 0000000..0700a31 --- /dev/null +++ b/server/clients.h @@ -0,0 +1,40 @@ +#ifndef CLIENTS_H +#define CLIENTS_H + +#include "client_data.h" +#include "../shared/LL.h" + +typedef struct client +{ + int sock; + LL *messages; + client_data *data; + +} client; + +extern LL *clients; + + +// Initialize and kill client list... +int client_init(); +int client_shutdown(); + + +// Create and destroy clients.... +client * client_create(int sock); +int client_destroy(client *c); + +// Add and remove messages from the client's queue... +int client_add_message(client *c, char *message); +char * client_get_message(client *c); + +// Get and set the client's data... +// Not used at all yet, and may never be. Oh, well. +int client_set(client *c, void *data); +void * client_get(client *c); + +// Search for a client with a particular filedescriptor... +client * client_find_sock(int sock); + + +#endif diff --git a/server/drivers/CFontz.c b/server/drivers/CFontz.c new file mode 100644 index 0000000..9f0b20e --- /dev/null +++ b/server/drivers/CFontz.c @@ -0,0 +1,718 @@ +#include +#include +#include +#include +#include +#include +#include +#include "lcd.h" +#include "CFontz.h" +#include "drv_base.h" + +#include "../render.h" + +#include "../../shared/debug.h" +#include "../../shared/str.h" + +static int custom=0; +typedef enum { + hbar = 1, + vbar = 2, + bign = 4, + beat = 8 } custom_type; + + + +static int fd; + +static void CFontz_linewrap(int on); +static void CFontz_autoscroll(int on); +static void CFontz_hidecursor(); +static void CFontz_reboot(); + +// TODO: Get rid of this variable? +lcd_logical_driver *CFontz; +// TODO: Get the frame buffers working right + +///////////////////////////////////////////////////////////////// +// Opens com port and sets baud correctly... +// +int CFontz_init(lcd_logical_driver *driver, char *args) +{ + char *argv[64]; + int argc; + struct termios portset; + int i; + int tmp; + int reboot=0; + + int contrast=140; + char device[256] = "/dev/lcd"; + int speed=B9600; + + CFontz = driver; + + //debug("CFontz_init: Args(all): %s\n", args); + + argc = get_args(argv, args, 64); + + /* + for(i=0; i argc) { + fprintf(stderr, "CFontz_init: %s requires an argument\n", + argv[i]); + return -1; + } + strcpy(device, argv[++i]); + } + else if(0 == strcmp(argv[i], "-c") || + 0 == strcmp(argv[i], "--contrast")) + { + if(i + 1 > argc) { + fprintf(stderr, "CFontz_init: %s requires an argument\n", + argv[i]); + return -1; + } + tmp = atoi(argv[++i]); + if((tmp < 0) || (tmp > 255)){ + fprintf(stderr, "CFontz_init: %s argument must between 0 and 255. Using default value.\n", + argv[i]); + } else contrast = tmp; + } + else if(0 == strcmp(argv[i], "-b") || + 0 == strcmp(argv[i], "--brightness")) + { + if(i + 1 > argc) { + fprintf(stderr, "CFontz_init: %s requires an argument\n", + argv[i]); + return -1; + } + tmp = atoi(argv[++i]); + if((tmp < 0) || (tmp > 255)){ + fprintf(stderr, "CFontz_init: %s argument must between 0 and 255. Using default value.\n", + argv[i]); + } else backlight_brightness = tmp; + } + else if(0 == strcmp(argv[i], "-o") || + 0 == strcmp(argv[i], "--off-bright")) + { + if(i + 1 > argc) { + fprintf(stderr, "CFontz_init: %s requires an argument\n", + argv[i]); + return -1; + } + tmp = atoi(argv[++i]); + if((tmp < 0) || (tmp > 255)){ + fprintf(stderr, "CFontz_init: %s argument must between 0 and 255. Using default value.\n", + argv[i]); + } else backlight_off_brightness = tmp; + } + else if(0 == strcmp(argv[i], "-s") || + 0 == strcmp(argv[i], "--speed")) + { + if(i + 1 > argc) { + fprintf(stderr, "CFontz_init: %s requires an argument\n", + argv[i]); + return -1; + } + tmp = atoi(argv[++i]); + if(tmp==1200) speed=B1200; + else if(tmp==2400) speed=B2400; + else if(tmp==9600) speed=B9600; + else if(tmp==19200) speed=B19200; + else { + fprintf(stderr, "CFontz_init: %s argument must be 1200, 2400, or 9600. Using default value.\n", + argv[i]); + } + } + else if(0 == strcmp(argv[i], "-h") || + 0 == strcmp(argv[i], "--help")) + { + printf("LCDproc CrystalFontz LCD driver\n" + "\t-d\t--device\tSelect the output device to use [/dev/lcd]\n" + "\t-t\t--type\t\tSelect the LCD type (size) [20x4]\n" + "\t-c\t--contrast\tSet the initial contrast [140]\n" + "\t-b\t--brightness\tSet the initial brightness [255]\n" + "\t-o\t--off-bright\tSet the initial brightness [0]\n" + "\t-s\t--speed\t\tSet the communication speed [9600]\n" + "\t-r\t--reboot\tReinitialize the LCD's BIOS\n" + "\t-h\t--help\t\tShow this help information\n"); + return -1; + } + else if(0 == strcmp(argv[i], "-r") || + 0 == strcmp(argv[i], "--reboot")) + { + printf("LCDd: rebooting CrystalFontz LCD...\n"); + reboot=1; + } + else + { + printf("Invalid parameter: %s\n", argv[i]); + } + + } + + // Set up io port correctly, and open it... + fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); + if (fd == -1) + { + fprintf(stderr, "CFontz_init: failed (%s)\n", strerror(errno)); + return -1; + } + //else fprintf(stderr, "CFontz_init: opened device %s\n", device); + tcgetattr(fd, &portset); + // This is necessary in Linux, but does not exist in irix. +#ifndef IRIX + cfmakeraw(&portset); +#endif + cfsetospeed(&portset, speed); + cfsetispeed(&portset, speed); + tcsetattr(fd, TCSANOW, &portset); + + + // Set display-specific stuff.. + if(reboot) + { + CFontz_reboot(); + sleep(4); + reboot=0; + } + sleep(1); + CFontz_hidecursor(); + CFontz_linewrap(1); + CFontz_autoscroll(0); + CFontz_backlight(backlight_brightness); + + + if(!driver->framebuf) + { + fprintf(stderr, "CFontz_init: No frame buffer.\n"); + driver->close(); + return -1; + } + + + // Set the functions the driver supports... + + driver->clear = (void *)-1; + driver->string = (void *)-1; +// driver->chr = CFontz_chr; + driver->chr = CFontz_chr; + driver->vbar = CFontz_vbar; + driver->init_vbar = CFontz_init_vbar; + driver->hbar = CFontz_hbar; + driver->init_hbar = CFontz_init_hbar; + driver->num = CFontz_num; + driver->init_num = CFontz_init_num; + + driver->init = CFontz_init; + driver->close = CFontz_close; + driver->flush = CFontz_flush; + driver->flush_box = CFontz_flush_box; + driver->contrast = CFontz_contrast; + driver->backlight = CFontz_backlight; + driver->set_char = CFontz_set_char; + driver->icon = CFontz_icon; + driver->draw_frame = CFontz_draw_frame; + + CFontz_contrast(contrast); + + lcd.cellwid = 6; + lcd.cellhgt = 8; + + debug("CFontz: foo!\n"); + + return fd; +} + + + +///////////////////////////////////////////////////////////////// +// Clean-up +// +void CFontz_close() +{ + close (fd); + + if(CFontz->framebuf) free(CFontz->framebuf); + + CFontz->framebuf = NULL; +} + + +void CFontz_flush() +{ + CFontz_draw_frame(lcd.framebuf); +} + + + +void CFontz_flush_box(int lft, int top, int rgt, int bot) +{ + int y; + char out[LCD_MAX_WIDTH]; + + +// printf("Flush (%i,%i)-(%i,%i)\n", lft, top, rgt, bot); + + for(y=top; y<=bot; y++) + { + sprintf(out, "%c%c%c", 17, lft, y); + write(fd, out, 4); + write(fd, lcd.framebuf+(y*lcd.wid)+lft, rgt-lft+1); + + } + + +} + + +///////////////////////////////////////////////////////////////// +// Prints a character on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void CFontz_chr(int x, int y, char c) +{ + y--; + x--; + + if(c < 32 && c >= 0) c += 128; + lcd.framebuf[(y*lcd.wid) + x] = c; +} + + +///////////////////////////////////////////////////////////////// +// Changes screen contrast (0-255; 140 seems good) +// +int CFontz_contrast(int contrast) +{ + int realcontrast; + char out[4]; + static int status=140; + + if(contrast > 0) + { + status=contrast; + realcontrast = (((int)(status)) * 100) / 255; + sprintf(out, "%c%c", 15, realcontrast); + write(fd, out, 3); + } + + return status; +} + + +///////////////////////////////////////////////////////////////// +// Sets the backlight on or off -- can be done quickly for +// an intermediate brightness... +// +void CFontz_backlight(int on) +{ + char out[4]; + if(on) + { + sprintf(out, "%c%c", 14, (unsigned char)(on * 100 / 255)); + //sprintf(out, "%c%c", 14, 100); + } + else + { + sprintf(out, "%c%c", 14, 0); + } + write(fd, out, 3); +} + + +///////////////////////////////////////////////////////////////// +// Toggle the built-in linewrapping feature +// +static void CFontz_linewrap(int on) +{ + char out[4]; + if(on) + sprintf(out, "%c", 23); + else + sprintf(out, "%c", 24); + write(fd, out, 1); +} + +///////////////////////////////////////////////////////////////// +// Toggle the built-in automatic scrolling feature +// +static void CFontz_autoscroll(int on) +{ + char out[4]; + if(on) + sprintf(out, "%c", 19); + else + sprintf(out, "%c", 20); + write(fd, out, 1); +} + + +///////////////////////////////////////////////////////////////// +// Get rid of the blinking curson +// +static void CFontz_hidecursor() +{ + char out[4]; + sprintf(out, "%c", 4); + write(fd, out, 1); +} + +///////////////////////////////////////////////////////////////// +// Reset the display bios +// +static void CFontz_reboot() +{ + char out[4]; + sprintf(out, "%c", 26); + write(fd, out, 1); +} + + +///////////////////////////////////////////////////////////////// +// Sets up for vertical bars. Call before lcd.vbar() +// +void CFontz_init_vbar() +{ + char a[] = { + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,1,1,1,1,1, + }; + char b[] = { + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + }; + char c[] = { + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + }; + char d[] = { + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + }; + char e[] = { + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + }; + char f[] = { + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + }; + char g[] = { + 0,0,0,0,0,0, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + 0,1,1,1,1,1, + }; + + if(custom!=vbar) { + CFontz_set_char(1,a); + CFontz_set_char(2,b); + CFontz_set_char(3,c); + CFontz_set_char(4,d); + CFontz_set_char(5,e); + CFontz_set_char(6,f); + CFontz_set_char(7,g); + custom=vbar; + } +} + +///////////////////////////////////////////////////////////////// +// Inits horizontal bars... +// +void CFontz_init_hbar() +{ + + char a[] = { + 1,0,0,0,0,0, + 1,0,0,0,0,0, + 1,0,0,0,0,0, + 1,0,0,0,0,0, + 1,0,0,0,0,0, + 1,0,0,0,0,0, + 1,0,0,0,0,0, + 1,0,0,0,0,0, + }; + char b[] = { + 1,1,0,0,0,0, + 1,1,0,0,0,0, + 1,1,0,0,0,0, + 1,1,0,0,0,0, + 1,1,0,0,0,0, + 1,1,0,0,0,0, + 1,1,0,0,0,0, + 1,1,0,0,0,0, + }; + char c[] = { + 1,1,1,0,0,0, + 1,1,1,0,0,0, + 1,1,1,0,0,0, + 1,1,1,0,0,0, + 1,1,1,0,0,0, + 1,1,1,0,0,0, + 1,1,1,0,0,0, + 1,1,1,0,0,0, + }; + char d[] = { + 1,1,1,1,0,0, + 1,1,1,1,0,0, + 1,1,1,1,0,0, + 1,1,1,1,0,0, + 1,1,1,1,0,0, + 1,1,1,1,0,0, + 1,1,1,1,0,0, + 1,1,1,1,0,0, + }; + char e[] = { + 1,1,1,1,1,0, + 1,1,1,1,1,0, + 1,1,1,1,1,0, + 1,1,1,1,1,0, + 1,1,1,1,1,0, + 1,1,1,1,1,0, + 1,1,1,1,1,0, + 1,1,1,1,1,0, + }; + char f[] = { + 1,1,1,1,1,1, + 1,1,1,1,1,1, + 1,1,1,1,1,1, + 1,1,1,1,1,1, + 1,1,1,1,1,1, + 1,1,1,1,1,1, + 1,1,1,1,1,1, + 1,1,1,1,1,1, + }; + + if(custom!=hbar) { + CFontz_set_char(1,a); + CFontz_set_char(2,b); + CFontz_set_char(3,c); + CFontz_set_char(4,d); + CFontz_set_char(5,e); + CFontz_set_char(6,f); + custom=hbar; + } +} + +///////////////////////////////////////////////////////////////// +// Draws a vertical bar... +// +void CFontz_vbar(int x, int len) +{ + char map[9] = {32, 1, 2, 3, 4, 5, 6, 7, 255 }; + + + int y; + for(y=lcd.hgt; y > 0 && len>0; y--) + { + if(len >= lcd.cellhgt) CFontz_chr(x, y, 255); + else CFontz_chr(x, y, map[len]); + + len -= lcd.cellhgt; + } + +} + +///////////////////////////////////////////////////////////////// +// Draws a horizontal bar to the right. +// +void CFontz_hbar(int x, int y, int len) +{ + char map[7] = { 32, 1, 2, 3, 4, 5, 6 }; + + for(; x<=lcd.wid && len>0; x++) + { + if(len >= lcd.cellwid) CFontz_chr(x,y,map[6]); + else CFontz_chr(x, y, map[len]); + + len -= lcd.cellwid; + + } + +} + + +///////////////////////////////////////////////////////////////// +// Sets up for big numbers. +// +void CFontz_init_num() +{ +} + + +///////////////////////////////////////////////////////////////// +// Writes a big number. +// +void CFontz_num(int x, int num) +{ + char out[5]; + sprintf(out, "%c%c%c", 28, x, num); + write(fd, out, 3); +} + + +///////////////////////////////////////////////////////////////// +// Sets a custom character from 0-7... +// +// For input, values > 0 mean "on" and values <= 0 are "off". +// +// The input is just an array of characters... +// +void CFontz_set_char(int n, char *dat) +{ + char out[4]; + int row, col; + int letter; + + if(n < 0 || n > 7) return; + if(!dat) return; + + sprintf(out, "%c%c", 25, n); + write(fd, out, 2); + + + for(row=0; row 0); + } + write(fd, &letter, 1); + } +} + + +void CFontz_icon(int which, char dest) +{ + char icons[3][6*8] = { + { + 1,1,1,1,1,1, // Empty Heart + 1,0,1,0,1,1, + 0,0,0,0,0,1, + 0,0,0,0,0,1, + 0,0,0,0,0,1, + 1,0,0,0,1,1, + 1,1,0,1,1,1, + 1,1,1,1,1,1, + }, + + { + 1,1,1,1,1,1, // Filled Heart + 1,0,1,0,1,1, + 0,1,0,1,0,1, + 0,1,1,1,0,1, + 0,1,1,1,0,1, + 1,0,1,0,1,1, + 1,1,0,1,1,1, + 1,1,1,1,1,1, + }, + + { + 0,0,0,0,0,0, // Ellipsis + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 0,0,0,0,0,0, + 1,0,1,0,1,0, + }, + + }; + + if(custom==bign) custom=beat; + CFontz_set_char(dest, &icons[which][0]); +} + + +///////////////////////////////////////////////////////////// +// Blasts a single frame onscreen, to the lcd... +// +// Input is a character array, sized lcd.wid*lcd.hgt +// +void CFontz_draw_frame(char *dat) +{ + char out[LCD_MAX_WIDTH * LCD_MAX_HEIGHT]; + int i; + + if(!dat) return; + + // Custom characters start at 128, not at 0. + /* + for(i=0; i= 0) dat[i] += 128; + } + */ + + for(i=0; i> 491000000000 +bind jvc-operate c91000000000 + +bind sony-md-power a9e000000000 +bind sony-md-eject 69e000000000 +bind -cancel 051000000000 + +alias workman-play jvc-play +alias workman-pause jvc-pause +alias workman-stop jvc-stop +alias workman-prev jvc-prev +alias workman-next jvc-next +alias workman-rew jvc-rew +alias workman-fwd jvc-fwd +#alias workman-power jvc-power +#alias workman-eject jvc-eject + +alias ircd-play jvc-play +alias ircd-pause jvc-pause +alias ircd-stop jvc-stop +alias ircd-prev jvc-rew +alias ircd-next jvc-fwd +#alias ircd-power jvc-power +#alias ircd-eject jvc-eject + +alias lcdproc-A jvc-1 +alias lcdproc-B jvc-2 +alias lcdproc-C jvc-3 +alias lcdproc-D jvc-4 +alias lcdproc-E jvc-5 +alias lcdproc-F jvc-6 +alias lcdproc-G jvc-7 +alias lcdproc-H jvc-8 +alias lcdproc-I jvc-9 +alias lcdproc-J jvc-0 +alias lcdproc-K jvc-play +alias lcdproc-L jvc-pause +alias lcdproc-M jvc-stop +alias lcdproc-N jvc-prev +alias lcdproc-O jvc-next +alias lcdproc-P jvc-fwd +alias lcdproc-Q jvc-rew +alias lcdproc-R jvc-rec +alias lcdproc-S jvc-vol+ +alias lcdproc-T jvc-vol- +alias lcdproc-U jvc-mute +alias lcdproc-V jvc-/|// +alias lcdproc-W jvc-display +alias lcdproc-X jvc-search<< +alias lcdproc-Y jvc-search>> +alias lcdproc-Z jvc-operate + + +# just an idea for 0.5 +# assign workman sony-md +# would be like: alias workman-* sony-md-* +# this allows remote level control. +# { "(remote level) control", not "remote (level control)"! } +# also +# set REMOTES /usr/local/share/libir/ +# include ${REMOTES}/sony-md +# include ${REMOTES}/philips-rc5 diff --git a/server/drivers/Makefile b/server/drivers/Makefile new file mode 100644 index 0000000..80b9ea1 --- /dev/null +++ b/server/drivers/Makefile @@ -0,0 +1,45 @@ +######################################################################## +# You shouldn't need to touch anything below here. +######################################################################## +include ../../Makefile.config + +TARGET = libLCDdrivers.a +OBJ += lcd.o drv_base.o $(DOBJ) +SOURCES = Makefile lcd.c lcd.h \ + MtxOrb.c MtxOrb.h wirz-sli.c wirz-sli.h text.c text.h \ + curses_drv.c curses_drv.h drv_base.c drv_base.h \ + hd44780.c hd44780.h port.h joy.c joy.h irman.c irman.h \ + CFontz.c CFontz.h +INCLUDE = -I../../shared + + +################################################################### +# Compilation... +# +all: $(TARGET) + + +$(TARGET): $(OBJ) Makefile + $(AR) rcs $(TARGET) $(OBJ) +#$(TARGET): $(OBJ) Makefile +# $(GCC) -s $(MISC) $(INCLUDE) -o $(TARGET) $(OBJ) $(LIB) + +%.o: %.c %.h Makefile + $(GCC) -c $(MISC) $(INCLUDE) $< + + +################################################################## +# Other stuff... +# +clean: + rm -f $(OBJ) *.o $(DOBJ) $(TARGET) *~ core + +edit: + nedit $(SOURCES) $(EXTRAS) & + +todo: + @echo ---------------=========================================== + @grep TODO $(SOURCES) | grep -v SOURCES + @grep FIXME $(SOURCES) | grep -v SOURCES + @echo ---------------=========================================== + diff --git a/server/drivers/MtxOrb.c b/server/drivers/MtxOrb.c new file mode 100644 index 0000000..798a389 --- /dev/null +++ b/server/drivers/MtxOrb.c @@ -0,0 +1,1047 @@ +#include +#include +#include +#include +#include +#include +#include +#include "lcd.h" +#include "MtxOrb.h" +#include "drv_base.h" + +#include "../../shared/debug.h" +#include "../../shared/str.h" + +static int custom=0; + +// TODO: Remove this custom_type if not in use anymore. +typedef enum { + hbar = 1, + vbar = 2, + bign = 4, + beat = 8 } custom_type; + +// TODO: This is my ugglyest piece of code. +typedef enum { + baru1 = 0, + baru2 = 1, + baru3 = 2, + baru4 = 3, + baru5 = 4, + baru6 = 5, + baru7 = 6, + bard1 = 7, + bard2 = 8, + bard3 = 9, + bard4 = 10, + bard5 = 11, + bard6 = 12, + bard7 = 13, + barr1 = 14, + barr2 = 15, + barr3 = 16, + barr4 = 17, + barl1 = 18, + barl2 = 19, + barl3 = 20, + barl4 = 21, + barw = 32, + barb = 255} bar_type; + +static int fd; +static int clear=1; + +static int def[9]={-1,-1,-1,-1,-1,-1,-1,-1,-1}; +static int use[9]={1,0,0,0,0,0,0,0,0}; + + + +static void MtxOrb_linewrap(int on); +static void MtxOrb_autoscroll(int on); +static void MtxOrb_cursorblink(int on); + +// TODO: Get rid of this variable? +lcd_logical_driver *MtxOrb; +// TODO: Get the frame buffers working right + +///////////////////////////////////////////////////////////////// +// Opens com port and sets baud correctly... +// +int MtxOrb_init(lcd_logical_driver *driver, char *args) +{ + char *argv[64]; + int argc; + struct termios portset; + int i; + int tmp; + + int contrast=140; + char device[256] = "/dev/lcd"; + int speed=B19200; + + + MtxOrb = driver; + + + //debug("MtxOrb_init: Args(all): %s\n", args); + + argc = get_args(argv, args, 64); + + /* + for(i=0; i argc) { + fprintf(stderr, "MtxOrb_init: %s requires an argument\n", + argv[i]); + return -1; + } + strcpy(device, argv[++i]); + } + else if(0 == strcmp(argv[i], "-c") || + 0 == strcmp(argv[i], "--contrast")) + { + if(i + 1 > argc) { + fprintf(stderr, "MtxOrb_init: %s requires an argument\n", + argv[i]); + return -1; + } + tmp = atoi(argv[++i]); + if((tmp < 0) || (tmp > 255)){ + fprintf(stderr, "MtxOrb_init: %s argument must between 0 and 255. Ussing default value.\n", + argv[i]); + } else contrast = tmp; + } + else if(0 == strcmp(argv[i], "-s") || + 0 == strcmp(argv[i], "--speed")) + { + if(i + 1 > argc) { + fprintf(stderr, "MtxOrb_init: %s requires an argument\n", + argv[i]); + return -1; + } + tmp = atoi(argv[++i]); + if(tmp==1200) speed=B1200; + else if(tmp==2400) speed=B2400; + else if(tmp==9600) speed=B9600; + else if(tmp==19200) speed=B19200; + else { + fprintf(stderr, "MtxOrb_init: %s argument must be 1200, 2400, 9600 or 19200. Ussing default value.\n", + argv[i]); + } + } + else if(0 == strcmp(argv[i], "-h") || + 0 == strcmp(argv[i], "--help")) + { + printf("LCDproc Matrix-Orbital LCD driver\n" + "\t-d\t--device\tSelect the output device to use [/dev/lcd]\n" + "\t-t\t--type\t\tSelect the LCD type (size) [20x4]\n" + "\t-c\t--contrast\tSet the initial contrast [140]\n" + "\t-s\t--speed\t\tSet the communication speed [19200]\n" + "\t-h\t--help\t\tShow this help information\n"); + return -1; + } + else + { + printf("Invalid parameter: %s\n", argv[i]); + } + + } + + // Set up io port correctly, and open it... + fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); + if (fd == -1) + { + fprintf(stderr, "MtxOrb_init: failed (%s)\n", strerror(errno)); + return -1; + } + //else fprintf(stderr, "MtxOrb_init: opened device %s\n", device); + tcgetattr(fd, &portset); + // This is necessary in Linux, but does not exist in irix. +#ifndef IRIX + cfmakeraw(&portset); +#endif + cfsetospeed(&portset, speed); + cfsetispeed(&portset, speed); + tcsetattr(fd, TCSANOW, &portset); + + + // Set display-specific stuff.. + MtxOrb_linewrap(1); + MtxOrb_autoscroll(1); + MtxOrb_cursorblink(0); + + + if(!driver->framebuf) + { + fprintf(stderr, "MtxOrb_init: No frame buffer.\n"); + driver->close(); + return -1; + } + + + // Set the functions the driver supports... + +// driver->clear = (void *)-1; + driver->clear = MtxOrb_clear; + driver->string = (void *)-1; +// driver->chr = MtxOrb_chr; + driver->chr = (void *)-1; + driver->vbar = MtxOrb_vbar; + driver->init_vbar = MtxOrb_init_vbar; +// driver->init_vbar = (void *)-1; + driver->hbar = MtxOrb_hbar; + driver->init_hbar = MtxOrb_init_hbar; +// driver->init_hbar = (void *)-1; + driver->num = MtxOrb_num; + driver->init_num = MtxOrb_init_num; + + driver->init = MtxOrb_init; + driver->close = MtxOrb_close; + driver->flush = MtxOrb_flush; + driver->flush_box = MtxOrb_flush_box; + driver->contrast = MtxOrb_contrast; + driver->backlight = MtxOrb_backlight; + driver->output = MtxOrb_output; + driver->set_char = MtxOrb_set_char; + driver->icon = MtxOrb_icon; + driver->draw_frame = MtxOrb_draw_frame; + + driver->getkey = MtxOrb_getkey; + + MtxOrb_contrast(contrast); + + return fd; +} + + +// TODO: Check this quick hack to detect clear of the screen. +///////////////////////////////////////////////////////////////// +// Clear: catch up when the screen get clear to be able to +// forget bar caracter not in use anymore and reuse the +// slot for another bar caracter. +// +void MtxOrb_clear() +{ +// REMOVE: fprintf(stderr, "GLU: MtxOrb_clear.\n"); + drv_base_clear(); + clear=1; +} + + +///////////////////////////////////////////////////////////////// +// Clean-up +// +void MtxOrb_close() +{ + close (fd); + + if(MtxOrb->framebuf) free(MtxOrb->framebuf); + + MtxOrb->framebuf = NULL; +} + + +void MtxOrb_flush() +{ + MtxOrb_draw_frame(lcd.framebuf); +} + + +void MtxOrb_flush_box(int lft, int top, int rgt, int bot) +{ + int y; + char out[LCD_MAX_WIDTH]; + + +// printf("Flush (%i,%i)-(%i,%i)\n", lft, top, rgt, bot); + + for(y=top; y<=bot; y++) + { + sprintf(out, "%cG%c%c", 254, lft, y); + write(fd, out, 4); + write(fd, lcd.framebuf+(y*lcd.wid)+lft, rgt-lft+1); + + } + + +} + + +///////////////////////////////////////////////////////////////// +// Prints a character on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void MtxOrb_chr(int x, int y, char c) +{ + y--; + x--; + + lcd.framebuf[(y*lcd.wid) + x] = c; +} + + +///////////////////////////////////////////////////////////////// +// Changes screen contrast (0-255; 140 seems good) +// +int MtxOrb_contrast(int contrast) +{ + char out[4]; + static int status=140; + + if(contrast > 0) + { + status=contrast; + sprintf(out, "%cP%c", 254, status); + write(fd, out, 3); + } + + return status; +} + + +///////////////////////////////////////////////////////////////// +// Sets the backlight on or off -- can be done quickly for +// an intermediate brightness... +// +void MtxOrb_backlight(int on) +{ + char out[4]; + if(on) + { + sprintf(out, "%cB%c", 254, 0); + write(fd, out, 3); + } + else + { + sprintf(out, "%cF", 254); + write(fd, out, 2); + } +} + + +///////////////////////////////////////////////////////////////// +// Sets output port on or off +void MtxOrb_output(int on) +{ + char out[4]; + if(on) + { + sprintf(out, "%cW", 254); + write(fd, out, 2); + } + else + { + sprintf(out, "%cV", 254); + write(fd, out, 2); + } +} + + +///////////////////////////////////////////////////////////////// +// Toggle the built-in linewrapping feature +// +static void MtxOrb_linewrap(int on) +{ + char out[4]; + if(on) + sprintf(out, "%cC", 254); + else + sprintf(out, "%cD", 254); + write(fd, out, 2); +} + + +///////////////////////////////////////////////////////////////// +// Toggle the built-in automatic scrolling feature +// +static void MtxOrb_autoscroll(int on) +{ + char out[4]; + if(on) + sprintf(out, "%cQ", 254); + else + sprintf(out, "%cR", 254); + write(fd, out, 2); +} + + +// TODO: make sure this doesn't mess up non-VFD displays +///////////////////////////////////////////////////////////////// +// Toggle cursor blink on/off +// +static void MtxOrb_cursorblink(int on) +{ + char out[4]; + if (on) + sprintf(out, "%cS", 254); + else + sprintf(out, "%cT", 254); + write(fd, out, 2); +} + + +//// TODO: Might not be needed anymore... +///////////////////////////////////////////////////////////////// +// Sets up for vertical bars. Call before lcd.vbar() +// +void MtxOrb_init_vbar() +{ + MtxOrb_init_all(vbar); +} + +// TODO: Might not be needed anymore... +///////////////////////////////////////////////////////////////// +// Inits horizontal bars... +// +void MtxOrb_init_hbar() +{ + MtxOrb_init_all(hbar); +} + +// TODO: Finish the support for bar growing reverse way. +// TODO: Need a "y" as input also !!! +///////////////////////////////////////////////////////////////// +// Draws a vertical bar... +// This is the new version ussing dynamic icon alocation +// +void MtxOrb_vbar(int x, int len) +{ + unsigned char mapu[9]={barw,baru1,baru2,baru3,baru4,baru5,baru6,baru7,barb}; + unsigned char mapd[9]={barw,bard1,bard2,bard3,bard4,bard5,bard6,bard7,barb}; + + int y; + +// TODO: REMOVE THE NEXT LINE FOR TESTING ONLY... +// len=-len; +// TODO: REMOVE THE PREVIOUS LINE FOR TESTING ONLY... + + if(len>0){ + for(y=lcd.hgt; y > 0 && len>0; y--) + { + if(len >= lcd.cellhgt) MtxOrb_chr(x, y, 255); + else MtxOrb_chr(x, y, MtxOrb_ask_bar(mapu[len])); + + len -= lcd.cellhgt; + } + }else{ + len=-len; + for(y=2; y <= lcd.hgt && len>0; y++) + { + if(len >= lcd.cellhgt) MtxOrb_chr(x, y, 255); + else MtxOrb_chr(x, y, MtxOrb_ask_bar(mapd[len])); + + len -= lcd.cellhgt; + } + } + +} + +// TODO: Finish the support for bar growing reverse way. +///////////////////////////////////////////////////////////////// +// Draws a horizontal bar to the right. +// This is the new version ussing dynamic icon alocation +// +void MtxOrb_hbar(int x, int y, int len) +{ + unsigned char mapr[6]={barw,barr1,barr2,barr3,barr4,barb}; + unsigned char mapl[6]={barw,barl1,barl2,barl3,barl4,barb}; + + if(len>0) + { + for(; x<=lcd.wid && len>0; x++) + { + if(len >= lcd.cellwid) MtxOrb_chr(x,y,255); + else MtxOrb_chr(x, y, MtxOrb_ask_bar(mapr[len])); + + len -= lcd.cellwid; + + } + } + else + { + len=-len; + for(; x>0 && len>0; x--) + { + if(len >= lcd.cellwid) MtxOrb_chr(x,y,255); + else MtxOrb_chr(x, y, MtxOrb_ask_bar(mapl[len])); + + len -= lcd.cellwid; + + } + } + +} + +// TODO: Might not work, bignum is untested... an untested with dynamic bar. + +///////////////////////////////////////////////////////////////// +// Sets up for big numbers. +// +void MtxOrb_init_num() +{ + char out[3]; + if(custom!=bign) { + sprintf(out, "%cn", 254); + write(fd, out, 2); + custom=bign; + } +} + +// TODO: Might not work, bignum is untested... an untested with dynamic bar. + +///////////////////////////////////////////////////////////////// +// Writes a big number. +// +void MtxOrb_num(int x, int num) +{ + char out[5]; + sprintf(out, "%c#%c%c", 254, x, num); + write(fd, out, 4); +} + + +// TODO: This could be higly optimised if data where to be pre-computed. + +///////////////////////////////////////////////////////////////// +// Sets a custom character from 0-7... +// +// For input, values > 0 mean "on" and values <= 0 are "off". +// +// The input is just an array of characters... +// +void MtxOrb_set_char(int n, char *dat) +{ + char out[4]; + int row, col; + int letter; + + if(n < 0 || n > 7) return; + if(!dat) return; + + sprintf(out, "%cN%c", 254, n); + write(fd, out, 3); + + for(row=0; row 0); + } + write(fd, &letter, 1); + } +} + + +void MtxOrb_icon(int which, char dest) +{ + char icons[3][5*8] = { + { + 1,1,1,1,1, // Empty Heart + 1,0,1,0,1, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,0,0,0,1, + 1,1,0,1,1, + 1,1,1,1,1, + }, + + { + 1,1,1,1,1, // Filled Heart + 1,0,1,0,1, + 0,1,0,1,0, + 0,1,1,1,0, + 0,1,1,1,0, + 1,0,1,0,1, + 1,1,0,1,1, + 1,1,1,1,1, + }, + + { + 0,0,0,0,0, // Ellipsis + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,0,1,0,1, + }, + + }; + + if(custom==bign) custom=beat; + MtxOrb_set_char(dest, &icons[which][0]); +} + +///////////////////////////////////////////////////////////// +// Blasts a single frame onscreen, to the lcd... +// +// Input is a character array, sized lcd.wid*lcd.hgt +// +void MtxOrb_draw_frame(char *dat) +{ + char out[LCD_MAX_WIDTH * LCD_MAX_HEIGHT]; + int i; + + if(!dat) return; + + for(i=0; i 7) return; + + if(!which){ + if(on) + sprintf(out, "%cV", 254); + else + sprintf(out, "%cW", 254); + write(fd, out, 2); + } + else{ + if(on) + sprintf(out, "%cV%c", 254, which); + else + sprintf(out, "%cW%c", 254, which); + write(fd, out, 3); + } +} + + +///////////////////////////////////////////////////////////////// +// Ask for dynamic allocation of a custom caracter to be +// a well none bar graphic. The function is suppose to +// return a value between 0 and 7 but 0 is reserver for +// heart beat. +// This function manadge a cache of graphical caracter in use. +// I really hope it is working and bug-less because it is not +// completely tested, just a quick hack. +// +int MtxOrb_ask_bar(int type) +{ + int i; + int last_not_in_use; + int pos; // 0 is icon, 1 to 7 are free, 8 is not found. + // TODO: Reuse graphic caracter 0 if heartbeat is not in use. + + // REMOVE: fprintf(stderr, "GLU: MtxOrb_ask_bar(%d).\n", type); + // Check if the screen was clear. + if (clear){ // If the screen was clear then graphic caracter are not in use. + //REMOVE: fprintf(stderr, "GLU: MtxOrb_ask_bar| clear was set.\n"); + use[0]=1; // Heartbeat is always in use (not true but it help). + for(pos=1; pos<8; pos++){ + use[pos]=0; // Other are not in use. + } + clear=0; // We made the special treatement. + }else{ + // Nothing special if some caracter a curently in use (...) ? + } + + // Search for a match with caracter already defined. + pos=8; // Not found. + last_not_in_use=8; // No empty slot to reuse. + for(i=1; i<8; i++){ // For all but first (heartbeat). + if(!use[i]) last_not_in_use=i; // New empty slot. + if(def[i]==type) pos=i; // Founded (should break now). + } + + if (pos==8){ + // REMOVE: fprintf(stderr, "GLU: MtxOrb_ask_bar| not found.\n"); + pos=last_not_in_use; + // TODO: Best match/deep search is no more graphic caracter are available. + } + + if (pos!=8){ // A caracter is found (Best match could solve our problem). + // REMOVE: fprintf(stderr, "GLU: MtxOrb_ask_bar| found at %d.\n", pos); + if(def[pos]!=type){ + MtxOrb_set_known_char(pos, type); // Define a new graphic caracter. + def[pos]=type; // Remember that now the caracter is available. + } + if (!use[pos]){ // If the caracter is no yet in use (but defined). + use[pos]=1; // Remember it is in use (so protect it from re-use). + } + } + + if (pos==8) // TODO: Choose a character to approximate the graph + { + //pos=65; // ("A")? + switch(type) + { + case baru1: pos='_'; break; + case baru2: pos='.'; break; + case baru3: pos=','; break; + case baru4: pos='o'; break; + case baru5: pos='o'; break; + case baru6: pos='O'; break; + case baru7: pos='8'; break; + + case bard1: pos='\''; break; + case bard2: pos='"'; break; + case bard3: pos='^'; break; + case bard4: pos='^'; break; + case bard5: pos='*'; break; + case bard6: pos='O'; break; + case bard7: pos='8'; break; + + case barr1: pos='-'; break; + case barr2: pos='-'; break; + case barr3: pos='='; break; + case barr4: pos='='; break; + + case barl1: pos='-'; break; + case barl2: pos='-'; break; + case barl3: pos='='; break; + case barl4: pos='='; break; + + case barw: pos=' '; break; + + case barb: pos=255; break; + + default: pos='?'; break; + } + } + + return(pos); +} + + +///////////////////////////////////////////////////////////////// +// Sets up a well known character for use. +// +void MtxOrb_set_known_char(int car, int type) +{ + char all_bar[25][5*8] = { + { + 0,0,0,0,0, // char u1[] = + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + },{ + 0,0,0,0,0, // char u2[] = + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + },{ + 0,0,0,0,0, // char u3[] = + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + },{ + 0,0,0,0,0, // char u4[] = + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + },{ + 0,0,0,0,0, // char u5[] = + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + },{ + 0,0,0,0,0, // char u6[] = + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + },{ + 0,0,0,0,0, // char u7[] = + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + },{ + 1,1,1,1,1, // char d1[] = + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + },{ + 1,1,1,1,1, // char d2[] = + 1,1,1,1,1, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + },{ + 1,1,1,1,1, // char d3[] = + 1,1,1,1,1, + 1,1,1,1,1, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + },{ + 1,1,1,1,1, // char d4[] = + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + },{ + 1,1,1,1,1, // char d5[] = + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + },{ + 1,1,1,1,1, // char d6[] = + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 0,0,0,0,0, + 0,0,0,0,0, + },{ + 1,1,1,1,1, // char d7[] = + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 0,0,0,0,0, + },{ + 1,0,0,0,0, // char r1[] = + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + },{ + 1,1,0,0,0, // char r2[] = + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + },{ + 1,1,1,0,0, // char r3[] = + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + },{ + 1,1,1,1,0, // char r4[] = + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + },{ + 0,0,0,0,1, // char l1[] = + 0,0,0,0,1, + 0,0,0,0,1, + 0,0,0,0,1, + 0,0,0,0,1, + 0,0,0,0,1, + 0,0,0,0,1, + 0,0,0,0,1, + },{ + 0,0,0,1,1, // char l2[] = + 0,0,0,1,1, + 0,0,0,1,1, + 0,0,0,1,1, + 0,0,0,1,1, + 0,0,0,1,1, + 0,0,0,1,1, + 0,0,0,1,1, + },{ + 0,0,1,1,1, // char l3[] = + 0,0,1,1,1, + 0,0,1,1,1, + 0,0,1,1,1, + 0,0,1,1,1, + 0,0,1,1,1, + 0,0,1,1,1, + 0,0,1,1,1, + },{ + 0,1,1,1,1, // char l4[] = + 0,1,1,1,1, + 0,1,1,1,1, + 0,1,1,1,1, + 0,1,1,1,1, + 0,1,1,1,1, + 0,1,1,1,1, + 0,1,1,1,1, + },{ + 1,1,1,1,1, // Empty Heart + 1,0,1,0,1, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,0,0,0,1, + 1,1,0,1,1, + 1,1,1,1,1, + },{ + 1,1,1,1,1, // Filled Heart + 1,0,1,0,1, + 0,1,0,1,0, + 0,1,1,1,0, + 0,1,1,1,0, + 1,0,1,0,1, + 1,1,0,1,1, + 1,1,1,1,1, + },{ + 0,0,0,0,0, // Ellipsis + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,0,1,0,1, + } +}; + +MtxOrb_set_char(car, &all_bar[type][0]); +} + + + +/////////////////STOP READING --- TRASH IS AT THE END//////////////// + + + +// TODO: Remove this code wich was use for developpement. +// PS: There might be reference to this code left, so keep it for some time. +void MtxOrb_init_all(int type) +{ +} + +// TODO: Remove this code wich was use for developpement. +// PS: That was the code to define unidirectionnal [h|v]bar. +/* + if(type==hbar){ + if(custom!=hbar) { + MtxOrb_set_known_char(1, barr1); + MtxOrb_set_known_char(2, barr2); + MtxOrb_set_known_char(3, barr3); + MtxOrb_set_known_char(4, barr4); + custom=hbar; + } + } + + if(type==vbar){ + if(custom!=vbar) { + MtxOrb_set_known_char(1, baru1); + MtxOrb_set_known_char(2, baru2); + MtxOrb_set_known_char(3, baru3); + MtxOrb_set_known_char(4, baru4); + MtxOrb_set_known_char(5, baru5); + MtxOrb_set_known_char(6, baru6); + MtxOrb_set_known_char(7, baru7); + custom=vbar; + } + } +*/ + + +// TODO: Remove this code wich was use for developpement. +// PS: It was a good idea, but not working (fixing take to much time). +/* +void MtxOrb_icon(int which, char dest) +{ + if(custom==bign) custom=beat; + MtxOrb_set_known_char(dest, which+21); +} +*/ + + +// TODO: Remove this code wich was use for developpement. +// PS: Temporary code used durring developpement of dynamic bar. +/* + if(type==barr1)return(1); + if(type==barr2)return(2); + if(type==barr3)return(3); + if(type==barr4)return(4); + if(type==baru1)return(1); + if(type==baru2)return(2); + if(type==baru3)return(3); + if(type==baru4)return(4); + if(type==baru5)return(5); + if(type==baru6)return(6); + if(type==baru7)return(7); +*/ + + diff --git a/server/drivers/MtxOrb.h b/server/drivers/MtxOrb.h new file mode 100644 index 0000000..d0a92e5 --- /dev/null +++ b/server/drivers/MtxOrb.h @@ -0,0 +1,31 @@ +#ifndef MTXORB_H +#define MTXORB_H + + +extern lcd_logical_driver *MtxOrb; + +int MtxOrb_init(lcd_logical_driver *driver, char *device); +void MtxOrb_clear(); +void MtxOrb_close(); +void MtxOrb_flush(); +void MtxOrb_flush_box(int lft, int top, int rgt, int bot); +void MtxOrb_chr(int x, int y, char c) ; +int MtxOrb_contrast(int contrast); +void MtxOrb_backlight(int on); +void MtxOrb_output(int on); +void MtxOrb_init_vbar(); +void MtxOrb_init_hbar(); +void MtxOrb_vbar(int x, int len); +void MtxOrb_hbar(int x, int y, int len); +void MtxOrb_init_num(); +void MtxOrb_num(int x, int num); +void MtxOrb_set_char(int n, char *dat); +void MtxOrb_icon(int which, char dest); +void MtxOrb_draw_frame(char *dat); +char MtxOrb_getkey(); + +void MtxOrb_init_all(int type); +int MtxOrb_ask_bar(int type); +void MtxOrb_set_known_char(int car, int type); + +#endif diff --git a/server/drivers/curses_drv.c b/server/drivers/curses_drv.c new file mode 100644 index 0000000..7cadb41 --- /dev/null +++ b/server/drivers/curses_drv.c @@ -0,0 +1,322 @@ +#include +#include +#include +#include +#include +#include +#include +#ifdef xBSD +#include +#else +#include +#endif + +#include "../../shared/str.h" + +#include "lcd.h" +#include "curses_drv.h" +#include "drv_base.h" + + +lcd_logical_driver *curses_drv; + +int PAD=255; +int ELLIPSIS=7; + +////////////////////////////////////////////////////////////////////////// +////////////////////// For Curses Terminal Output //////////////////////// +////////////////////////////////////////////////////////////////////////// + +static char icon_char = '@'; + + +int curses_drv_init(struct lcd_logical_driver *driver, char *args) +{ + char *argv[64]; + int argc; + int i,j; + + + argc = get_args(argv, args, 64); + + for(i=0; i argc) { + fprintf(stderr, "curses_init: %s requires an argument\n", + argv[i]); + return -1; + } + // TODO: color display in curses driver! + printf("Sorry, colors not yet implemented...\n"); + //strcpy(device, argv[++i]); + } + else if(0 == strcmp(argv[i], "-b") || + 0 == strcmp(argv[i], "--backcolor")) + { + if(i + 1 > argc) { + fprintf(stderr, "curses_init: %s requires an argument\n", + argv[i]); + return -1; + } + // TODO: color display in curses driver! + printf("Sorry, colors not yet implemented...\n"); + //strcpy(device, argv[++i]); + } + else if(0 == strcmp(argv[i], "-B") || + 0 == strcmp(argv[i], "--backlight")) + { + if(i + 1 > argc) { + fprintf(stderr, "curses_init: %s requires an argument\n", + argv[i]); + return -1; + } + // TODO: color display in curses driver! + printf("Sorry, colors not yet implemented...\n"); + //strcpy(device, argv[++i]); + } + else if(0 == strcmp(argv[i], "-h") || + 0 == strcmp(argv[i], "--help")) + { + printf("LCDproc [n]curses driver\n" + "\t-f\t--forecolor\tChange the foreground color\n" + "\t-b\t--backcolor\tChange the backlight's \"off\" color\n" + "\t-B\t--backlight\tChange the backlight's \"on\" color\n" + "\t-h\t--help\t\tShow this help information\n"); + return -1; + } + else + { + printf("Invalid parameter: %s\n", argv[i]); + } + + } + + + curses_drv = driver; + + // Init curses... + initscr(); + cbreak(); + noecho(); + nodelay(stdscr, TRUE); + nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + + curses_drv_clear(); + + // Override output functions... + driver->clear = curses_drv_clear; + driver->string = curses_drv_string; + driver->chr = curses_drv_chr; + driver->vbar = curses_drv_vbar; + driver->init_vbar = NULL; + driver->hbar = curses_drv_hbar; + driver->init_hbar = NULL; + driver->num = curses_drv_num; + driver->init_num = curses_drv_init_num; + + driver->init = curses_drv_init; + driver->close = curses_drv_close; + driver->flush = curses_drv_flush; + driver->flush_box = curses_drv_flush_box; + driver->contrast = NULL; + driver->backlight = NULL; + driver->set_char = NULL; + driver->icon = curses_drv_icon; + driver->draw_frame = curses_drv_draw_frame; + + driver->getkey = curses_drv_getkey; + + // Change the character used for padding the title bars... + PAD = '#'; + // Change the character used for "..." + ELLIPSIS = '~'; + + return 200; // 200 is arbitrary. (must be 1 or more) +} + +void curses_drv_close() +{ + // Close curses + clear(); + move(0,0); + refresh(); + endwin(); + + drv_base_close(); + +} + +///////////////////////////////////////////////////////////////// +// Clears the LCD screen +// +void curses_drv_clear() +{ + clear(); + +} + + +///////////////////////////////////////////////////////////////// +// Prints a string on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void curses_drv_string(int x, int y, char string[]) +{ + int i; + unsigned char *c; + + for(i=0; string[i]; i++) + { + c = &string[i]; + switch(*c) + { + case 0: *c = icon_char; break; + case 255: *c = '#'; break; + } + } + mvaddstr(y-1, x-1, string); +} + +///////////////////////////////////////////////////////////////// +// Prints a character on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void curses_drv_chr(int x, int y, char c) +{ + switch(c) + { + case 0: c = icon_char; break; + case -1: c = '#'; break; + } + + mvaddch(y-1, x-1, c); +} + +///////////////////////////////////////////////////////////////// +// Sets up for big numbers. +// +void curses_drv_init_num() +{ +} + +///////////////////////////////////////////////////////////////// +// Writes a big number. +// +void curses_drv_num(int x, int num) +{ + char c; + int y, dx; + + c='0'+num; +// printf(&c,"%1d",num); + + for(y=1; y<5; y++) + for(dx=0; dx<3; dx++) + curses_drv_chr(x+dx, y, c); +} + + +///////////////////////////////////////////////////////////////// +// Draws a vertical bar; erases entire column onscreen. +// +void curses_drv_vbar(int x, int len) +{ + char map[]="_.,,ooO8"; + + int y; + for(y=lcd.hgt; y > 0 && len>0; y--) + { + if(len >= lcd.cellhgt) curses_drv_chr(x, y, '8'); + else curses_drv_chr(x, y, map[len-1]); + + len -= lcd.cellhgt; + } + +// move(4-len/lcd.cellhgt, x-1); +// vline(0, len/lcd.cellhgt); + +} + +///////////////////////////////////////////////////////////////// +// Draws a horizontal bar to the right. +// +void curses_drv_hbar(int x, int y, int len) +{ + for(; x<=lcd.wid && len>0; x++) + { + if(len>=lcd.cellwid) + curses_drv_chr(x, y, '='); + else + curses_drv_chr(x, y, '-'); + + len -= lcd.cellwid; + } + + + +// move(y-1, x-1); +// hline(0, len/lcd.cellwid); +} + + +///////////////////////////////////////////////////////////////// +// Sets character 0 to an icon... +// +void curses_drv_icon(int which, char dest) +{ + if(dest == 0) + switch(which) + { + case 0: icon_char = '+'; break; + case 1: icon_char = '*'; break; + default: icon_char = '#'; break; + } + +} + +////////////////////////////////////////////////////////////////// +// Flushes all output to the lcd... +// +void curses_drv_flush() +{ + curses_drv_draw_frame(curses_drv->framebuf); +} + + +void curses_drv_flush_box(int lft, int top, int rgt, int bot) +{ + curses_drv_flush(); +} + + +void curses_drv_draw_frame(char *dat) +{ +// border(0, 0, 0, 0, 0, 0, lcd.wid+1, lcd.hgt+1); + + refresh(); + +} + + + +char curses_drv_getkey() +{ + int i; + + i = getch(); + + if(i == KEY_LEFT) return 'D'; + if(i == KEY_UP) return 'B'; + if(i == KEY_DOWN) return 'C'; + if(i == KEY_RIGHT) return 'A'; + + if(i != ERR) return i; + else return 0; + +} + diff --git a/server/drivers/curses_drv.h b/server/drivers/curses_drv.h new file mode 100644 index 0000000..3738144 --- /dev/null +++ b/server/drivers/curses_drv.h @@ -0,0 +1,24 @@ +#ifndef LCD_CURSES_H +#define LCD_CURSES_H + + +extern lcd_logical_driver *curses_drv; + +int curses_drv_init(struct lcd_logical_driver *driver, char *args); +void curses_drv_close(); +void curses_drv_clear(); +void curses_drv_flush(); +void curses_drv_string(int x, int y, char string[]); +void curses_drv_chr(int x, int y, char c); +void curses_drv_vbar(int x, int len); +void curses_drv_hbar(int x, int y, int len); +void curses_drv_icon(int which, char dest); +void curses_drv_flush(); +void curses_drv_flush_box(int lft, int top, int rgt, int bot); +void curses_drv_draw_frame(char *dat); +char curses_drv_getkey(); +void curses_drv_init_num(); +void curses_drv_num(int x, int num); + + +#endif diff --git a/server/drivers/debug.c b/server/drivers/debug.c new file mode 100644 index 0000000..9172872 --- /dev/null +++ b/server/drivers/debug.c @@ -0,0 +1,288 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../lcd.h" +#include "debug.h" + + +////////////////////////////////////////////////////////////////////////// +////////////////////// For Debugging Output ////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +// TODO: somehow allow access to the driver->framebuffer to each +// function... + + +int debug_init(struct lcd_logical_driver *driver, char *args) +{ + printf("debug_init(%s)\n", device); + + if(!driver->framebuf) + { + printf("Allocating frame buffer (%ix%i)\n", lcd.wid, lcd.hgt); + driver->framebuf = malloc(lcd.wid * lcd.hgt); + } + + + if(!driver->framebuf) + { + debug_close(); + return -1; + } + + if(driver->framebuf) printf("Frame buffer: %i\n", (int)driver->framebuf); + + debug_clear(); + + driver->clear = debug_clear; + driver->string = debug_string; + driver->chr = debug_chr; + driver->vbar = debug_vbar; + driver->hbar = debug_hbar; + driver->init_num = debug_init_num; + driver->num = debug_num; + + driver->init = debug_init; + driver->close = debug_close; + driver->flush = debug_flush; + driver->flush_box = debug_flush_box; + driver->contrast = debug_contrast; + driver->backlight = debug_backlight; + driver->set_char = debug_set_char; + driver->icon = debug_icon; + driver->init_vbar = debug_init_vbar; + driver->init_hbar = debug_init_hbar; + driver->draw_frame = debug_draw_frame; + + driver->getkey = debug_getkey; + + + return 200; // 200 is arbitrary. (must be 1 or more) +} + +void debug_close() +{ +// Ack! This shouldn't crash the program, but does.. Why?? + + + printf("debug_close()\n"); + +// This is the line which crashes. + if(driver->framebuf) free(driver->framebuf); + + if(driver->framebuf) printf("Frame buffer: %i\n", (int)driver->framebuf); + driver->framebuf = NULL; +// printf("debug_close() finished\n"); +} + +///////////////////////////////////////////////////////////////// +// Clears the LCD screen +// +void debug_clear() +{ + printf("clear()\n"); + + memset(driver->framebuf, ' ', lcd.wid*lcd.hgt); + +} + + +////////////////////////////////////////////////////////////////// +// Flushes all output to the lcd... +// +void debug_flush() +{ + printf("flush()\n"); + + lcd.draw_frame(); +} + + +///////////////////////////////////////////////////////////////// +// Prints a string on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void debug_string(int x, int y, char string[]) +{ + + int i; + + printf("string(%i, %i):%s \n", x, y, string); + + + x -= 1; // Convert 1-based coords to 0-based... + y -= 1; + + for(i=0; string[i]; i++) + { + driver->framebuf[(y*lcd.wid) + x + i] = string[i]; + } +} + +///////////////////////////////////////////////////////////////// +// Prints a character on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void debug_chr(int x, int y, char c) +{ + printf("character(%i, %i):%c\n", x, y, c); + + + y--; + x--; + + lcd.framebuf[(y*lcd.wid) + x] = c; +} + + + +void debug_contrast(int contrast) +{ + printf("Contrast: %i\n", contrast); +} + +void debug_backlight(int on) +{ + if(on) + { + printf("Backlight ON\n"); + } + else + { + printf("Backlight OFF\n"); + } +} + +void debug_init_vbar() +{ + printf("Vertical bars.\n"); +} + +void debug_init_hbar() +{ + printf("Horizontal bars.\n"); +} + +void debug_init_num() +{ + printf("Big Numbers.\n"); +} + +void debug_num(int x, int num) +{ + printf("BigNum(%i, %i)\n", x, num); +} + +void debug_set_char(int n, char *dat) +{ + printf("Set Character %i\n", n); +} + +///////////////////////////////////////////////////////////////// +// Draws a vertical bar; erases entire column onscreen. +// +void debug_vbar(int x, int len) +{ + int y; + + printf("Vbar(%i, %i)\n", x, len); + + + for(y=lcd.hgt; y > 0 && len>0; y--) + { + debug_chr(x, y, '|'); + + len -= lcd.cellhgt; + } + +} + +///////////////////////////////////////////////////////////////// +// Draws a horizontal bar to the right. +// +void debug_hbar(int x, int y, int len) +{ + printf("Hbar(%i, %i, %i)\n", x, y, len); + + + for(; x0; x++) + { + debug_chr(x,y,'-'); + + len -= lcd.cellwid; + } + +} + + +///////////////////////////////////////////////////////////////// +// Sets character 0 to an icon... +// +void debug_icon(int which, char dest) +{ + printf("Char %i is icon %i\n", dest, which); +} + + +void debug_flush_box(int lft, int top, int rgt, int bot) +{ + printf("Flush Box(%i, %i)-(%i, %i)\n", lft, top, rgt, bot); + + + debug_flush(); + +} + + +void debug_draw_frame(char *dat) +{ + int i, j; + + char out[LCD_MAX_WIDTH]; + + printf("draw_frame()\n"); + + + if(!dat) return; + +// printf("Frame (%ix%i): \n%s\n", lcd.wid, lcd.hgt, dat); + + for(i=0; i +#include +#include +#include +#include +#include +#include + +#include "lcd.h" +#include "drv_base.h" + + +////////////////////////////////////////////////////////////////////////// +////////////////////// Base "class" to derive from /////////////////////// +////////////////////////////////////////////////////////////////////////// + +lcd_logical_driver *drv_base; + +// TODO: Get lcd.framebuf to properly work as whatever driver is running... + + +//////////////////////////////////////////////////////////// +// init() should set up any device-specific stuff, and +// point all the function pointers. +int drv_base_init(struct lcd_logical_driver *driver, char *args) +{ +// printf("drv_base_init()\n"); + + drv_base = driver; + + driver->wid = 20; + driver->hgt = 4; + + // You must use driver->framebuf here, but may use lcd.framebuf later. + if(!driver->framebuf) + driver->framebuf = malloc(driver->wid * driver->hgt); + + if(!driver->framebuf) + { + drv_base_close(); + return -1; + } +// Debugging... +// if(lcd.framebuf) printf("Frame buffer: %i\n", (int)lcd.framebuf); + + memset(driver->framebuf, ' ', driver->wid*driver->hgt); +// drv_base_clear(); + + driver->cellwid = 5; + driver->cellhgt = 8; + + driver->clear = drv_base_clear; + driver->string = drv_base_string; + driver->chr = drv_base_chr; + driver->vbar = drv_base_vbar; + driver->init_vbar = drv_base_init_vbar; + driver->hbar = drv_base_hbar; + driver->init_hbar = drv_base_init_hbar; + driver->num = drv_base_num; + driver->init_num = drv_base_init_num; + + driver->init = drv_base_init; + driver->close = drv_base_close; + driver->flush = drv_base_flush; + driver->flush_box = drv_base_flush_box; + driver->contrast = drv_base_contrast; + driver->backlight = drv_base_backlight; + driver->set_char = drv_base_set_char; + driver->icon = drv_base_icon; + driver->draw_frame = drv_base_draw_frame; + + driver->getkey = drv_base_getkey; + + + return 200; // 200 is arbitrary. (must be 1 or more) +} + + +// Below here, you may use either lcd.framebuf or driver->framebuf.. +// lcd.framebuf will be set to the appropriate buffer before calling +// your driver. + +void drv_base_close() +{ + if(lcd.framebuf != NULL) free(lcd.framebuf); + + lcd.framebuf = NULL; +} + +///////////////////////////////////////////////////////////////// +// Clears the LCD screen +// +void drv_base_clear() +{ + memset(lcd.framebuf, ' ', lcd.wid*lcd.hgt); + +} + + +////////////////////////////////////////////////////////////////// +// Flushes all output to the lcd... +// +void drv_base_flush() +{ + //lcd.draw_frame(lcd.framebuf); +} + + +///////////////////////////////////////////////////////////////// +// Prints a string on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void drv_base_string(int x, int y, char string[]) +{ + int i; + + x -= 1; // Convert 1-based coords to 0-based... + y -= 1; + + for(i=0; string[i]; i++) + { + // Check for buffer overflows... + if((y*lcd.wid) + x + i > (lcd.wid*lcd.hgt)) break; + lcd.framebuf[(y*lcd.wid) + x + i] = string[i]; + } +} + +///////////////////////////////////////////////////////////////// +// Prints a character on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void drv_base_chr(int x, int y, char c) +{ + y--; + x--; + + lcd.framebuf[(y*lcd.wid) + x] = c; +} + + +////////////////////////////////////////////////////////////////////// +// Sets the contrast of the display. Value is 0-255, where 140 is +// what I consider "just right". +// +int drv_base_contrast(int contrast) +{ +// printf("Contrast: %i\n", contrast); + return -1; +} + +////////////////////////////////////////////////////////////////////// +// Turns the lcd backlight on or off... +// +void drv_base_backlight(int on) +{ + /* + if(on) + { + printf("Backlight ON\n"); + } + else + { + printf("Backlight OFF\n"); + } + */ +} + +////////////////////////////////////////////////////////////////////// +// Tells the driver to get ready for vertical bargraphs. +// +void drv_base_init_vbar() +{ +// printf("Vertical bars.\n"); +} + +////////////////////////////////////////////////////////////////////// +// Tells the driver to get ready for horizontal bargraphs. +// +void drv_base_init_hbar() +{ +// printf("Horizontal bars.\n"); +} + +////////////////////////////////////////////////////////////////////// +// Tells the driver to get ready for big numbers, if possible. +// +void drv_base_init_num() +{ +// printf("Big Numbers.\n"); +} + +////////////////////////////////////////////////////////////////////// +// Draws a big (4-row) number. +// +void drv_base_num(int x, int num) +{ +// printf("BigNum(%i, %i)\n", x, num); +} + +////////////////////////////////////////////////////////////////////// +// Changes the font data of character n. +// +void drv_base_set_char(int n, char *dat) +{ +// printf("Set Character %i\n", n); +} + +///////////////////////////////////////////////////////////////// +// Draws a vertical bar, from the bottom of the screen up. +// +void drv_base_vbar(int x, int len) +{ + int y; + for(y=lcd.hgt; y > 0 && len>0; y--) + { + drv_base_chr(x, y, '|'); + + len -= lcd.cellhgt; + } + +} + +///////////////////////////////////////////////////////////////// +// Draws a horizontal bar to the right. +// +void drv_base_hbar(int x, int y, int len) +{ + for(; x<=lcd.wid && len>0; x++) + { + drv_base_chr(x,y,'-'); + + len -= lcd.cellwid; + } + +} + + +///////////////////////////////////////////////////////////////// +// Sets character 0 to an icon... +// +void drv_base_icon(int which, char dest) +{ +// printf("Char %i set to icon %i\n", dest, which); +} + + +////////////////////////////////////////////////////////////////////// +// Send a rectangular area to the display. +// +// I've just called drv_base_flush() because there's not much point yet +// in flushing less than the entire framebuffer. +// +void drv_base_flush_box(int lft, int top, int rgt, int bot) +{ + //drv_base_flush(); + +} + +////////////////////////////////////////////////////////////////////// +// Draws the framebuffer on the display. +// +// The commented-out code is from the text driver. +// +void drv_base_draw_frame(char *dat) +{ +/* + int i, j; + + char out[LCD_MAX_WIDTH]; + + if(!dat) return; + + for(i=0; iclear = new_driver_clear; // We want to handle this one + driver->string = (void *)-1; // Leave this to the default + driver->getkey = NULL; // This should never get called + + The convention here is to set NULL for all the functions which + your driver doesn't handle (and which you don't want the default + functions to be called for). Or, set -1 to indicate that the + driver should support the function but can use the default + behavior in drv_base.c. Or, to indicate that your driver should + handle a function, just set it like clear() above. + + 6. Add the driver to lcd.c, in the physical drivers section, protected + by an #ifdef like the rest of the drivers are. + + 7. Add your driver to the Makefile, and Makefile.config, in the same + style as the existing ones. + + + Notes: + + Don't call lcd.whatever() functions within your driver. This causes + a lot of potentially puzzling problems. + + However, feel free to access lcd.framebuf in your driver (but not in + your init() function!). It will always point to the frame buffer + you should be writing to. This will usually be your own frame + buffer, but could potentially be another frame buffer, if another + driver wants to access your functions. + + Your driver will be provided with a frame buffer which contains one + byte per character on the LCD. The default is a 20x4, so that's 80 + bytes. You can free this and reallocate it to something else if you + need to. A graphical driver may want to do this, for example. + + If you don't set a function pointer, it will default to NULL, since + they get nullified before the driver's init() is called. + + Assume that your driver may be added or removed dynamically, and + that more than one instance may exist at a time. In other words, it + should init and close cleanly, and not depend on global variables. + + Special arguments will be passed through the "args" variable to your + _init() function. This is just a string, and you determine the + syntax of it. Please document the syntax so that it can easily be + included in the lcdproc config file. I suggest arguments such as + "port=0x378" or "-device /dev/ttyS0". These come directly from the + lcdproc server config file, so they should be human-readable. An + example may look like this: + + # Set up two MtxOrb LCD's and a curses display on VT 2 + Driver MtxOrb -device /dev/ttyS0 -keypad on + Driver curses -color off -size 20x4 -vt 2 + Driver MtxOrb -device /dev/ttyS3 -size 20x2 -keypad off + # Before you ask, no, not all of these options are implemented yet. + + Also, the driver API (if it can be called that) may change soon. + There seem to be several functions which just don't do anything + important... and there are other potential improvements too. + + And... When in doubt, look at how the other drivers do it. :) + +******************************************************************/ + +extern lcd_logical_driver *drv_base; + +int drv_base_init(struct lcd_logical_driver *driver, char *args); +void drv_base_close(); +void drv_base_clear(); +void drv_base_flush(); +void drv_base_string(int x, int y, char string[]); +void drv_base_chr(int x, int y, char c); +int drv_base_contrast(int contrast); +void drv_base_backlight(int on); +void drv_base_output(int on); +void drv_base_vbar(int x, int len); +void drv_base_init_vbar(); +void drv_base_hbar(int x, int y, int len); +void drv_base_init_hbar(); +void drv_base_num(int x, int num); +void drv_base_init_num(); +void drv_base_set_char(int n, char *dat); +void drv_base_icon(int which, char dest); +void drv_base_flush_box(int lft, int top, int rgt, int bot); +void drv_base_draw_frame(char *dat); +char drv_base_getkey(); + + +#endif diff --git a/server/drivers/hd44780.c b/server/drivers/hd44780.c new file mode 100644 index 0000000..0062e96 --- /dev/null +++ b/server/drivers/hd44780.c @@ -0,0 +1,562 @@ +/* Driver module for Hitachi HD44780 based Optrex DMC-20481 LCD display + * The module is operated in it's 4 bit-mode to be connected to a single + * 8 bit-port + * + * Copyright (c) 1998 Richard Rognlie GNU Public License + * + * + * Large quantities of this code lifted (nearly verbatim) from + * the lcd4.c module of lcdtext. Copyright (C) 1997 Matthias Prinke + * and covered by GNU's GPL. + * In particular, this program is free software and comes WITHOUT + * ANY WARRANTY. + * + * Matthias stole (er, adapted) the code from the package lcdtime by + * Benjamin Tse (blt@mundil.cs.mu.oz.au), August/October 1995 + * which uses the LCD-controller's 8 bit-mode. + * References: port.h by + * Data Sheet LTN211, Philips + * Various FAQs and TXTs about Hitachi's LCD Controller HD44780 - + * www.paranoia.com/~filipg is a good starting point ??? + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../shared/str.h" + +#include "lcd.h" +#include "hd44780.h" +#include "drv_base.h" + + +lcd_logical_driver *HD44780; + +#define EN 64 +#define RW 32 +#define RS 16 + +#ifndef LPTPORT +unsigned int port = 0x378; +#else +unsigned int port = LPTPORT; +#endif + +static int lcd_x=0; +static int lcd_y=0; + +static void HD44780_linewrap(int on); +static void HD44780_autoscroll(int on); + +static int lp; + +static void HD44780_senddata(unsigned char flags, unsigned char ch) +{ + unsigned char h = ch >> 4; + unsigned char l = ch & 15; + + port_out(lp, 128 | EN | flags | h); usleep(1); port_out(lp, 128 | flags | h); + port_out(lp, 128 | EN | flags | l); usleep(1); port_out(lp, 128 | flags | l); +} + +///////////////////////////////////////////////////////////////// +// Opens com port and sets baud correctly... +// +int HD44780_init(lcd_logical_driver *driver, char *args) +{ + char *argv[64]; + int argc; + int i; + + + HD44780 = driver; + + + argc = get_args(argv, args, 64); + + for(i=0; i argc) { + fprintf(stderr, "HD44780_init: %s requires an argument\n", + argv[i]); + return -1; + } + printf("Sorry, runtime lpt-port switching not yet implemented...\n"); + //strcpy(device, argv[++i]); + } + else if(0 == strcmp(argv[i], "-c") || + 0 == strcmp(argv[i], "--contrast")) + { + if(i + 1 > argc) { + fprintf(stderr, "HD44780_init: %s requires an argument\n", + argv[i]); + return -1; + } + printf("Sorry, contrast changing not yet implemented...\n"); + //contrast = atoi(argv[++i]); + } + else if(0 == strcmp(argv[i], "-h") || + 0 == strcmp(argv[i], "--help")) + { + printf("LCDproc HD44780 driver\n" + "\t-p\t--port\tSelect the output device to use [0x%x]\n" + "\t-c\t--contrast\tSet the initial contrast [default]\n" + "\t-h\t--help\t\tShow this help information\n", + port); + return -1; + } + else + { + printf("Invalid parameter: %s\n", argv[i]); + } + + } + + + + // Set up io port correctly, and open it... + if ((ioperm(port,1,1)) == -1) { + fprintf(stderr, "HD44780_init: failed (%s)\n", strerror(errno)); + return -1; + } + + lp = port; + + // init HD44780 + port_out(lp, 128 | EN | 3); usleep(1); port_out(lp, 128 | 3); usleep(5000); + port_out(lp, 128 | EN | 3); usleep(1); port_out(lp, 128 | 3); usleep(150); + port_out(lp, 128 | EN | 3); usleep(1); port_out(lp, 128 | 3); + // now in 8-bit mode... set 4-bit mode + port_out(lp, 128 | EN | 2); usleep(1); port_out(lp, 128 | 2); + // now in 4-bit mode... set 2 line, small char mode + HD44780_senddata(0, 32 | 8); + + //clear + HD44780_senddata(0, 1); + // set lcd on (4), cursor_on (2), and cursor_blink(1) + HD44780_senddata(0, 8 | 4 | 0 | 0); + + // Set display-specific stuff.. + //HD44780_linewrap(1); + //HD44780_autoscroll(1); + + // Make sure the frame buffer is there... + if (!HD44780->framebuf) + HD44780->framebuf = (unsigned char *) malloc(lcd.wid * lcd.hgt); + + if (!HD44780->framebuf) { + //HD44780_close(); + return -1; + } + + + // Set the functions the driver supports... + + driver->clear = (void *)-1; + driver->string = (void *)-1; + driver->chr = (void *)-1; + driver->vbar = HD44780_vbar; + driver->init_vbar = HD44780_init_vbar; + driver->hbar = HD44780_hbar; + driver->init_hbar = HD44780_init_hbar; + driver->num = HD44780_num; + driver->init_num = HD44780_init_num; + + driver->init = HD44780_init; + driver->close = (void *)-1; + driver->flush = HD44780_flush; + driver->flush_box = HD44780_flush_box; + driver->contrast = HD44780_contrast; + driver->backlight = HD44780_backlight; + driver->set_char = HD44780_set_char; + driver->icon = HD44780_icon; + driver->draw_frame = HD44780_draw_frame; + + driver->getkey = NULL; + + return lp; +} + + + +///////////////////////////////////////////////////////////////// +// Clean-up +// +/* +void HD44780_close() +{ + drv_base_close(); +} +*/ + +static void HD44780_position(int x, int y) +{ + int val = x + (y%2) * 0x40; + if (y>=2) val += 20; + + HD44780_senddata(0,128|val); + + lcd_x = x; + lcd_y = y; +} + +void HD44780_flush() +{ + HD44780_draw_frame(lcd.framebuf); +} + + +void HD44780_flush_box(int lft, int top, int rgt, int bot) +{ + int x,y; + +// printf("Flush (%i,%i)-(%i,%i)\n", lft, top, rgt, bot); + + for (y=top; y<=bot; y++) { + HD44780_position(lft,y); + + for (x=lft ; x<=rgt ; x++) { + HD44780_senddata(RS,lcd.framebuf[(y*20)+x]); + } + //write(fd, lcd.framebuf[(y*20)+lft, rgt-lft+1]); + } + +} + + +///////////////////////////////////////////////////////////////// +// Changes screen contrast (0-255; 140 seems good) +// +int HD44780_contrast(int contrast) +{ + return 0; +} + +///////////////////////////////////////////////////////////////// +// Sets the backlight on or off -- can be done quickly for +// an intermediate brightness... +// +void HD44780_backlight(int on) +{ +} + + +///////////////////////////////////////////////////////////////// +// Toggle the built-in linewrapping feature +// +static void HD44780_linewrap(int on) +{ +} + +///////////////////////////////////////////////////////////////// +// Toggle the built-in automatic scrolling feature +// +static void HD44780_autoscroll(int on) +{ + HD44780_senddata(0,4 | on * 2); +} + + +///////////////////////////////////////////////////////////////// +// Sets up for vertical bars. Call before lcd.vbar() +// +void HD44780_init_vbar() +{ + char a[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + }; + char b[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char c[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char d[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char e[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char f[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char g[] = { + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + + HD44780_set_char(1,a); + HD44780_set_char(2,b); + HD44780_set_char(3,c); + HD44780_set_char(4,d); + HD44780_set_char(5,e); + HD44780_set_char(6,f); + HD44780_set_char(7,g); + +} + +///////////////////////////////////////////////////////////////// +// Inits horizontal bars... +// +void HD44780_init_hbar() +{ + + char a[] = { + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + }; + char b[] = { + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + }; + char c[] = { + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + }; + char d[] = { + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + }; + + HD44780_set_char(1,a); + HD44780_set_char(2,b); + HD44780_set_char(3,c); + HD44780_set_char(4,d); + +} + +///////////////////////////////////////////////////////////////// +// Draws a vertical bar... +// +void HD44780_vbar(int x, int len) +{ + char map[9] = {32, 1, 2, 3, 4, 5, 6, 7, 255 }; + + int y; + for(y=lcd.hgt; y > 0 && len>0; y--) { + if (len >= lcd.cellhgt) + drv_base_chr(x, y, 255); + else + drv_base_chr(x, y, map[len]); + + len -= lcd.cellhgt; + } + +} + +///////////////////////////////////////////////////////////////// +// Draws a horizontal bar to the right. +// +void HD44780_hbar(int x, int y, int len) +{ + char map[6] = { 32, 1, 2, 3, 4, 255 }; + + for (; x<=lcd.wid && len>0; x++) { + if (len >= lcd.cellwid) + drv_base_chr(x,y,255); + else + drv_base_chr(x, y, map[len]); + + len -= lcd.cellwid; + + } +} + + +///////////////////////////////////////////////////////////////// +// Sets up for big numbers. +// +void HD44780_init_num() +{ + char out[3]; + sprintf(out, "%cn", 254); + //write(fd, out, 2); +} + + +///////////////////////////////////////////////////////////////// +// Writes a big number. +// +void HD44780_num(int x, int num) +{ + char out[5]; + sprintf(out, "%c#%c%c", 254, x, num); + //write(fd, out, 4); +} + + +///////////////////////////////////////////////////////////////// +// Sets a custom character from 0-7... +// +// For input, values > 0 mean "on" and values <= 0 are "off". +// +// The input is just an array of characters... +// +void HD44780_set_char(int n, char *dat) +{ + int row, col; + int letter; + + if(n < 0 || n > 7) return; + if(!dat) return; + + HD44780_senddata(0, 64 | n*8); + + for(row=0; row 0); + } + HD44780_senddata(RS, letter); + } + +} + + +void HD44780_icon(int which, char dest) +{ + char icons[3][5*8] = { + { + 1,1,1,1,1, // Empty Heart + 1,0,1,0,1, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,0,0,0,1, + 1,1,0,1,1, + 1,1,1,1,1, + }, + + { + 1,1,1,1,1, // Filled Heart + 1,0,1,0,1, + 0,1,0,1,0, + 0,1,1,1,0, + 0,1,1,1,0, + 1,0,1,0,1, + 1,1,0,1,1, + 1,1,1,1,1, + }, + + { + 0,0,0,0,0, // Ellipsis + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,0,1,0,1, + }, + + }; + + + HD44780_set_char(dest, &icons[which][0]); +} + + +///////////////////////////////////////////////////////////// +// Blasts a single frame onscreen, to the lcd... +// +// Input is a character array, sized lcd.wid*lcd.hgt +// +void HD44780_draw_frame(char *dat) +{ + int x,y; + + if (!dat) return; + + for (y=0; y<=3; y++) { + HD44780_position(0,y); + + for (x=0 ; x<=19 ; x++) { + HD44780_senddata(RS,dat[(y*lcd.wid)+x]); + } + } + +} + diff --git a/server/drivers/hd44780.h b/server/drivers/hd44780.h new file mode 100644 index 0000000..55d3d67 --- /dev/null +++ b/server/drivers/hd44780.h @@ -0,0 +1,49 @@ +/* Driver module for Hitachi HD44780 based Optrex DMC-20481 LCD display + * The module is operated in it's 4 bit-mode to be connected to a single + * 8 bit-port + * + * Copyright (c) 1998 Richard Rognlie GNU Public License + * + * + * Large quantities of this code lifted (nearly verbatim) from + * the lcd4.c module of lcdtext. Copyright (C) 1997 Matthias Prinke + * and covered by GNU's GPL. + * In particular, this program is free software and comes WITHOUT + * ANY WARRANTY. + * + * Matthias stole (er, adapted) the code from the package lcdtime by + * Benjamin Tse (blt@mundil.cs.mu.oz.au), August/October 1995 + * which uses the LCD-controller's 8 bit-mode. + * References: port.h by + * Data Sheet LTN211, Philips + * Various FAQs and TXTs about Hitachi's LCD Controller HD44780 - + * www.paranoia.com/~filipg is a good starting point ??? + */ + +#ifndef HD44780_H +#define HD44780_H + +#include "port.h" + + +extern lcd_logical_driver *hd44780; + +int HD44780_init(struct lcd_logical_driver *driver, char *args); +void HD44780_close(); +void HD44780_flush(); +void HD44780_flush_box(int lft, int top, int rgt, int bot); +int HD44780_contrast(int contrast); +void HD44780_backlight(int on); +void HD44780_init_vbar(); +void HD44780_init_hbar(); +void HD44780_vbar(int x, int len); +void HD44780_hbar(int x, int y, int len); +void HD44780_init_num(); +void HD44780_num(int x, int num); +void HD44780_set_char(int n, char *dat); +void HD44780_icon(int which, char dest); +void HD44780_draw_frame(char *dat); + + + +#endif diff --git a/server/drivers/ideas.txt b/server/drivers/ideas.txt new file mode 100644 index 0000000..d778e4b --- /dev/null +++ b/server/drivers/ideas.txt @@ -0,0 +1,21 @@ +Hmm... + +How to do multiple drivers... + + +lcd_sample_func(parameters) +{ + D'oh.. +} + +lcd_driver_caller() +{ + foreach driver (@drivers) + { + if(driver supports function) + call driver's function + else if(driver uses defaults) + call default function + else don't do anything + } +} diff --git a/server/drivers/irmanin.c b/server/drivers/irmanin.c new file mode 100644 index 0000000..97bc033 --- /dev/null +++ b/server/drivers/irmanin.c @@ -0,0 +1,218 @@ +/* irmanin.c - test/demo of LIBIR's to interface with lcdproc (LCDd) */ +/* Copyright (C) 1999 David Glaude loosely based on workmanir.c */ +/* workmanir.c - test/demo of LIBIR's high level command functions */ +/* Copyright (C) 1998 Tom Wheeley, see file COPYING for details */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define __u32 unsigned int +#define __u8 unsigned char + + +#include "../../shared/debug.h" +#include "../../shared/str.h" + +#define NAME_LENGTH 128 + +#include "lcd.h" +#include "irmanin.h" +#include "../../../libirman-0.4.1b/irman.h" + + +char *progname = "irmanin"; + +char *codes[] = { + /* dummy */ NULL, + /* KeyToLcd */ "lcdproc-A", + /* KeyToLcd */ "lcdproc-B", + /* KeyToLcd */ "lcdproc-C", + /* KeyToLcd */ "lcdproc-D", + /* KeyToLcd */ "lcdproc-E", + /* KeyToLcd */ "lcdproc-F", + /* KeyToLcd */ "lcdproc-G", + /* KeyToLcd */ "lcdproc-H", + /* KeyToLcd */ "lcdproc-I", + /* KeyToLcd */ "lcdproc-J", + /* KeyToLcd */ "lcdproc-K", + /* KeyToLcd */ "lcdproc-L", + /* KeyToLcd */ "lcdproc-M", + /* KeyToLcd */ "lcdproc-N", + /* KeyToLcd */ "lcdproc-O", + /* KeyToLcd */ "lcdproc-P", + /* KeyToLcd */ "lcdproc-Q", + /* KeyToLcd */ "lcdproc-R", + /* KeyToLcd */ "lcdproc-S", + /* KeyToLcd */ "lcdproc-T", + /* KeyToLcd */ "lcdproc-U", + /* KeyToLcd */ "lcdproc-V", + /* KeyToLcd */ "lcdproc-W", + /* KeyToLcd */ "lcdproc-X", + /* KeyToLcd */ "lcdproc-Y", + /* KeyToLcd */ "lcdproc-Z", + /* end */ NULL +}; + + + +////////////////////////////////////////////////////////////////////////// +////////////////////// Base "class" to derive from /////////////////////// +////////////////////////////////////////////////////////////////////////// + +lcd_logical_driver *irmanin; + +//void sigterm(int sig) +//{ +// ir_free_commands(); +// ir_finish(); +// raise(sig); +//} + +//////////////////////////////////////////////////////////// +// init() should set up any device-specific stuff, and +// point all the function pointers. +int irmanin_init(struct lcd_logical_driver *driver, char *args) +{ + char device[256]; + char *ptrdevice; + char config[256]; + char *ptrconfig; + + char *portname; + + char *argv[64]; + int argc, i, j; + char *filename; + + ptrconfig=NULL; + ptrdevice=NULL; + + irmanin = driver; + + argc = get_args(argv, args, 64); + + for(i=0; i argc) { + fprintf(stderr, "irmanin_init: %s requires an argument\n", + argv[i]); + return -1; + } + strcpy(device, argv[++i]); + ptrdevice=device; + } + else if(0 == strcmp(argv[i], "-c") || + 0 == strcmp(argv[i], "--config")) + { + if(i + 1 > argc) { + fprintf(stderr, "irmanin_init: %s requires an argument\n", + argv[i]); + return -1; + } + strcpy(config, argv[++i]); + ptrconfig=config; + } + else if(0 == strcmp(argv[i], "-h") || + 0 == strcmp(argv[i], "--help")) + { + printf("LCDproc IrMan input driver\n" + "\t-d\t--device\tSelect the input device to use\n" + "\t-d\t--config\tSelect the configuration file to use\n" + "\t-h\t--help\t\tShow this help information\n"); + return -1; + } + else + { + printf("Invalid parameter: %s\n", argv[i]); + } + } + + if (ir_init_commands(ptrconfig, 1) < 0) { + fprintf(stderr, "error initialising commands: %s\n", strerror(errno)); + exit(1); + } + + portname = ir_default_portname(); + if(portname==NULL){ + if(ptrdevice==NULL){ + portname=ptrdevice; + }else{ + fprintf(stderr, "error no device defined\n"); + exit(1); + } + } + + driver->getkey = irmanin_getkey; + driver->close = irmanin_close; + + for (i=1; codes[i] != NULL; i++) { + if (ir_register_command(codes[i], i) < 0) { + if (errno == ENOENT) { + fprintf(stderr, "%s: no code set for `%s'\n", progname, codes[i]); + } else { + fprintf(stderr, "error registering `%s': `%s'\n", codes[i], strerror(errno)); + } + } + } + + errno = 0; + if (ir_init(portname) < 0) { + fprintf(stderr, "%s: error initialising Irman: `%s'\n", strerror(errno), portname); + exit(1); + } + + return 1; // 200 is arbitrary. (must be 1 or more) +} + + +void irmanin_close() +{ + if(irmanin->framebuf != NULL) free(irmanin->framebuf); + + irmanin->framebuf = NULL; + + ir_free_commands(); + ir_finish(); +} + + +////////////////////////////////////////////////////////////////////// +// Tries to read a character from an input device... +// +// Return 0 for "nothing available". +// +char irmanin_getkey() +{ + int i; + int cmd; + char key; + + key=(char)0; + switch (cmd=ir_poll_command()) { + case IR_CMD_ERROR: + fprintf(stderr, "%s: error reading command: %s\n", progname, strerror(errno)); + break; + case IR_CMD_UNKNOWN: + break; + default: + key=(char)('A'-1+cmd); + break; + } + + return key; +} + +/* end of irmanin.c */ diff --git a/server/drivers/irmanin.h b/server/drivers/irmanin.h new file mode 100644 index 0000000..8af1895 --- /dev/null +++ b/server/drivers/irmanin.h @@ -0,0 +1,12 @@ +#ifndef LCD_IRMANIN__H +#define LCD_IRMANIN_H + + +extern lcd_logical_driver *joy; + +int irmanin_init(struct lcd_logical_driver *driver, char *args); +void irmanin_close(); +char irmanin_getkey(); + + +#endif diff --git a/server/drivers/joy.c b/server/drivers/joy.c new file mode 100644 index 0000000..2d53fae --- /dev/null +++ b/server/drivers/joy.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define __u32 unsigned int +#define __u8 unsigned char +#include + + +#include "../../shared/debug.h" +#include "../../shared/str.h" + +#define NAME_LENGTH 128 + + + +#include "lcd.h" +#include "joy.h" + + + +////////////////////////////////////////////////////////////////////////// +////////////////////// Base "class" to derive from /////////////////////// +////////////////////////////////////////////////////////////////////////// + +lcd_logical_driver *joy; + +int fd; + +struct js_event js; + +char axes = 2; +char buttons = 2; +int jsversion = 0x000800; +char jsname[NAME_LENGTH] = "Unknown"; + +int *axis; +int *button; + + +// Configured for a Gravis Gamepad (2 axis, 4 button) +char *axismap = "EFGHIJKLMNOPQRST"; +char *buttonmap = "BDACEFGHIJKLMNOP"; + + +//////////////////////////////////////////////////////////// +// init() should set up any device-specific stuff, and +// point all the function pointers. +int joy_init(struct lcd_logical_driver *driver, char *args) +{ + char device[256]; + char *argv[64]; + int argc, i, j; + + joy = driver; + + + strcpy(device, "/dev/js0"); + + argc = get_args(argv, args, 64); + + for(i=0; i argc) { + fprintf(stderr, "joy_init: %s requires an argument\n", + argv[i]); + return -1; + } + strcpy(device, argv[++i]); + } + else if(0 == strcmp(argv[i], "-a") || + 0 == strcmp(argv[i], "--axes")) + { + if(i + 1 > argc) { + fprintf(stderr, "joy_init: %s requires an argument\n", + argv[i]); + return -1; + } + strncpy(axismap, argv[++i], 16); + } + else if(0 == strcmp(argv[i], "-b") || + 0 == strcmp(argv[i], "--buttons")) + { + if(i + 1 > argc) { + fprintf(stderr, "joy_init: %s requires an argument\n", + argv[i]); + return -1; + } + strncpy(buttonmap, argv[++i], 16); + } + else if(0 == strcmp(argv[i], "-h") || + 0 == strcmp(argv[i], "--help")) + { + printf("LCDproc Joystick input driver\n" + "\t-d\t--device\tSelect the input device to use [/dev/js0]\n" + "\t-a\t--axes\t\tModify the axis map [%s]\n" + "\t-b\t--buttons\tModify the button map [%s]\n" + "\t-h\t--help\t\tShow this help information\n", + axismap, buttonmap); + return -1; + } + else + { + printf("Invalid parameter: %s\n", argv[i]); + } + + } + + + + + + driver->getkey = joy_getkey; + driver->close = joy_close; + + + /* FIXME: This crashes! + if(args) + { + if(strlen(args) > 0) + strcpy(device, args); + } + */ + + fd = open (device, O_RDONLY); + fcntl(fd, F_SETFL, O_NONBLOCK); + + if(fd < 0) return -1; + + ioctl(fd, JSIOCGVERSION, &jsversion); + ioctl(fd, JSIOCGAXES, &axes); + ioctl(fd, JSIOCGBUTTONS, &buttons); + ioctl(fd, JSIOCGNAME(NAME_LENGTH), jsname); + + debug("Joystick (%s) has %d axes and %d buttons. Driver version is %d.%d.%d.\n", + jsname, axes, buttons, + jsversion >> 16, (jsversion >> 8) & 0xff, jsversion & 0xff); + + axis = calloc(axes, sizeof(int)); + button = calloc(buttons, sizeof(char)); + + return fd; // 200 is arbitrary. (must be 1 or more) +} + + +void joy_close() +{ + if(joy->framebuf != NULL) free(joy->framebuf); + close(fd); + + joy->framebuf = NULL; + + // Why do I have so much trouble getting memory freed without segfaults?? + //if(axis) free(axis); + //if(button) free(button); + +} + + +////////////////////////////////////////////////////////////////////// +// Tries to read a character from an input device... +// +// Return 0 for "nothing available". +// +char joy_getkey() +{ + int i; + int err; + + err = read(fd, &js, sizeof(struct js_event)); + if (err <= 0) return 0; + if (err != sizeof(struct js_event)) { + fprintf(stderr, "\nerror reading joystick\n"); + return 0; + } + +// if(js.type & JS_EVENT_INIT) return 0; + + switch(js.type & ~JS_EVENT_INIT) { + case JS_EVENT_BUTTON: + button[js.number] = js.value; + break; + case JS_EVENT_AXIS: + axis[js.number] = js.value; + break; + } + + if (buttons) { + //printf("Buttons: "); + for (i = 0; i < buttons; i++) + //printf("%2d:%s ", i, button[i] ? "on " : "off"); + if(button[i]) return buttonmap[i]; + } + + if (axes) { + //printf("Axes: "); + for (i = 0; i < axes; i++) + { + //printf("%2d:%6d ", i, axis[i]); + // Eliminate noise... + if(axis[i] > 20000) return axismap[(2*i) + 1]; + if(axis[i] < -20000) return axismap[(2*i)]; + } + } + + return 0; +} diff --git a/server/drivers/joy.h b/server/drivers/joy.h new file mode 100644 index 0000000..d5a0d88 --- /dev/null +++ b/server/drivers/joy.h @@ -0,0 +1,12 @@ +#ifndef LCD_JOY_H +#define LCD_JOY_H + + +extern lcd_logical_driver *joy; + +int joy_init(struct lcd_logical_driver *driver, char *args); +void joy_close(); +char joy_getkey(); + + +#endif diff --git a/server/drivers/lcd.c b/server/drivers/lcd.c new file mode 100644 index 0000000..cb18f63 --- /dev/null +++ b/server/drivers/lcd.c @@ -0,0 +1,727 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "LL.h" + +#include "lcd.h" + +#include "drv_base.h" + +#ifdef MTXORB_DRV +#include "MtxOrb.h" +#endif + +#ifdef CFONTZ_DRV +#include "CFontz.h" +#endif + +#ifdef TEXT_DRV +#include "text.h" +#endif + +#ifdef DEBUG_DRV +#include "debug.h" +#endif + +#ifdef CURSES_DRV +#include "curses_drv.h" +#endif + +#ifdef HD44780_DRV +#include "hd44780.h" +#endif + +#ifdef SLI_DRV +#include "wirz-sli.h" +#endif + +#ifdef JOY_DRV +#include "joy.h" +#endif + +#ifdef IRMANIN_DRV +#include "irmanin.h" +#endif + +// TODO: Make a Windows server, and clients...? + + +lcd_logical_driver lcd; + +lcd_physical_driver drivers[] = +{ + { "base", drv_base_init, }, +#ifdef MTXORB_DRV + { "MtxOrb", MtxOrb_init, }, +#endif +#ifdef CFONTZ_DRV + { "CFontz", CFontz_init, }, +#endif +#ifdef HD44780_DRV + { "HD44780", HD44780_init, }, +#endif +#ifdef SLI_DRV + { "sli", sli_init, }, +#endif +#ifdef TEXT_DRV + { "text", text_init, }, +#endif +#ifdef DEBUG_DRV + { "debug", debug_init, }, +#endif +#ifdef CURSES_DRV + { "curses", curses_drv_init, }, +#endif +#ifdef JOY_DRV + { "joy", joy_init, }, +#endif +#ifdef IRMANIN_DRV + { "irmanin", irmanin_init, }, +#endif + { NULL, NULL, }, + +}; + +LL *list; + +//////////////////////////////////////////////////////////// +// This sets up which driver to use and initializes stuff. +// +int lcd_init(char *args) +{ +// int i; + int err; + + list = LL_new(); + if(!list) + { + printf("Error allocating driver list.\n"); + return -1; + } + + lcd_drv_init(NULL, NULL); + + err = lcd_add_driver("base", args); + + lcd.wid = 20; + lcd.hgt = 4; + + return err; + + /* + drv_base_init(args); + + for(i=0; drivers[i].name; i++) + { + if(!strcmp(driver, drivers[i].name)) + { + return drivers[i].init(args); + } + } + + printf("Invalid driver: %s\n", driver); + return -1; + */ + +} + + +// TODO: lcd_remove_driver() + +int lcd_add_driver(char *driver, char *args) +{ + int i; + + lcd_logical_driver *add; + + for(i=0; drivers[i].name; i++) + { + + //printf("Checking driver: %s\n", drivers[i].name); + + if(0 == strcmp(driver, drivers[i].name)) + { + + //printf("Found driver: %s (%s)\n", drivers[i].name, driver); + + add = malloc(sizeof(lcd_logical_driver)); + if(!add) + { + printf("Couldn't allocate driver \"%s\".\n", driver); + return -1; + } + //printf("Allocated driver\n"); + memset(add, 0, sizeof(lcd_logical_driver)); + + add->wid = lcd.wid; add->hgt = lcd.hgt; + add->cellwid = lcd.cellwid; add->cellhgt = lcd.cellhgt; + +// printf("LCD driver info:\n\twid: %i\thgt: %i\n", +// add->wid, add->hgt); + + add->framebuf = malloc(add->wid * add->hgt); + + if(!add->framebuf) + { + printf("Couldn't allocate framebuffer for driver \"%s\".\n", + driver); + free(add); + return -1; + } + //printf("Allocated frame buffer\n"); + + LL_Push(list, (void *)add); + + return drivers[i].init(add, args); + } + } + + return -1; +} + +// TODO: Put lcd_shutdown in the shutdown function... +int lcd_shutdown() +{ + lcd_logical_driver *driver; + + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + //printf("driver...\n"); + lcd.framebuf = driver->framebuf; + + if((int)driver->close > 0) + { + driver->close(); + } + else if((int)driver->close == -1) + { + drv_base->close(); + } + + LL_Shift(list); + // FIXME: This crashes! + //if(driver) free(driver); + //printf("...freed\n"); + } + + } while(LL_Length(list) > 0); + + return 0; +} + + + +int lcd_drv_init(struct lcd_logical_driver *driver, char *args) +{ +// printf("lcd_drv_init()\n"); + + lcd.wid = LCD_MAX_WID; + lcd.hgt = LCD_MAX_HGT; + + lcd.framebuf = NULL; +/* + if(!lcd.framebuf) + lcd.framebuf = malloc(lcd.wid * lcd.hgt); + + if(!lcd.framebuf) + { + lcd_drv_close(); + return -1; + } + memset(lcd.framebuf, ' ', lcd.wid*lcd.hgt); +*/ +// Debugging... +// if(lcd.framebuf) printf("Frame buffer: %i\n", (int)lcd.framebuf); + + lcd.cellwid = 5; + lcd.cellhgt = 8; + + // Set up these wrapper functions... + lcd.clear = lcd_drv_clear; + lcd.string = lcd_drv_string; + lcd.chr = lcd_drv_chr; + lcd.vbar = lcd_drv_vbar; + lcd.hbar = lcd_drv_hbar; + lcd.init_num = lcd_drv_init_num; + lcd.num = lcd_drv_num; + + lcd.init = lcd_drv_init; + lcd.close = lcd_drv_close; + lcd.flush = lcd_drv_flush; + lcd.flush_box = lcd_drv_flush_box; + lcd.contrast = lcd_drv_contrast; + lcd.backlight = lcd_drv_backlight; + lcd.output = lcd_drv_output; + lcd.set_char = lcd_drv_set_char; + lcd.icon = lcd_drv_icon; + lcd.init_vbar = lcd_drv_init_vbar; + lcd.init_hbar = lcd_drv_init_hbar; + lcd.draw_frame = lcd_drv_draw_frame; + + lcd.getkey = lcd_drv_getkey; + + + return 1; // 1 is arbitrary. (must be 1 or more) +} + + + +////////////////////////////////////////////////////////////////////// +// All functions below here call their respective driver functions... +// +// The way it works is this: +// It loops through the list of drivers, calling each one to keep +// them all synchronized. During this loop... +// - First, set the framebuffer to point to the drivers' framebuffer. +// (this ensures that whatever driver gets called will operate on +// the correct buffer) +// - Then, it checks to see what sort of call to make. +// driver->func() > 0 means it should call the driver function. +// driver->func() == NULL means it should not make a call. +// driver->func() == -1 means it should call the generic driver. +////////////////////////////////////////////////////////////////////// + + +void lcd_drv_close() +{ + lcd_logical_driver *driver; + +// printf("lcd_drv_close()\n"); + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->close > 0) + { + printf("Calling close()\n"); + driver->close(); + } + else if((int)driver->close == -1) + { + drv_base->close(); + } + } + } while(LL_Next(list) == 0); + +} + +void lcd_drv_clear() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->clear > 0) + driver->clear(); + else if((int)driver->clear == -1) + { + drv_base->clear(); + } + } + } while(LL_Next(list) == 0); + +} + + +void lcd_drv_flush() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->flush > 0) + driver->flush(); + else if((int)driver->flush == -1) + { + drv_base->flush(); + } + } + } while(LL_Next(list) == 0); +} + + +void lcd_drv_string(int x, int y, char string[]) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->string > 0) + driver->string(x,y,string); + else if((int)driver->string == -1) + { + drv_base->string(x,y,string); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_chr(int x, int y, char c) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->chr > 0) + driver->chr(x,y,c); + else if((int)driver->chr == -1) + { + drv_base->chr(x,y,c); + } + } + } while(LL_Next(list) == 0); +} + + + +int lcd_drv_contrast(int contrast) +{ + int res=0; + + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->contrast > 0) + { + res=driver->contrast(contrast); + if(res >= 0) return res; + } + /* + else if((int)driver->contrast == -1) + { + res=drv_base->contrast(contrast); + } + */ + } + } while(LL_Next(list) == 0); + + return res; +} + +void lcd_drv_backlight(int on) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->backlight > 0) + driver->backlight(on); + else if((int)driver->backlight == -1) + { + drv_base->backlight(on); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_output(int on) +{ + lcd_logical_driver *driver; + LL_Rewind(list); + do + { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + if((int)driver->output > 0) + driver->output(on); + else if((int)driver->output == -1) + { + drv_base->output(on); + } + } + } while(LL_Next(list) == 0); +} + + +void lcd_drv_init_vbar() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->init_vbar > 0) + driver->init_vbar(); + else if((int)driver->init_vbar == -1) + { + drv_base->init_vbar(); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_init_hbar() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->init_hbar > 0) + driver->init_hbar(); + else if((int)driver->init_hbar == -1) + { + drv_base->init_hbar(); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_init_num() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->init_num > 0) + driver->init_num(); + else if((int)driver->init_num == -1) + { + drv_base->init_num(); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_num(int x, int num) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->num > 0) + driver->num(x,num); + else if((int)driver->num == -1) + { + drv_base->num(x,num); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_set_char(int n, char *dat) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->set_char > 0) + driver->set_char(n,dat); + else if((int)driver->set_char == -1) + { + drv_base->set_char(n,dat); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_vbar(int x, int len) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->vbar > 0) + driver->vbar(x,len); + else if((int)driver->vbar == -1) + { + drv_base->vbar(x,len); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_hbar(int x, int y, int len) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->hbar > 0) + driver->hbar(x,y,len); + else if((int)driver->hbar == -1) + { + drv_base->hbar(x,y,len); + } + } + } while(LL_Next(list) == 0); +} + + +void lcd_drv_icon(int which, char dest) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->icon > 0) + driver->icon(which,dest); + else if((int)driver->icon == -1) + { + drv_base->icon(which,dest); + } + } + } while(LL_Next(list) == 0); +} + + +void lcd_drv_flush_box(int lft, int top, int rgt, int bot) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->flush_box > 0) + driver->flush_box(lft,top,rgt,bot); + else if((int)driver->flush_box == -1) + { + drv_base->flush_box(lft,top,rgt,bot); + } + } + } while(LL_Next(list) == 0); + +} + + +// TODO: Check whether lcd.draw_frame() should really take a framebuffer +// TODO: as an argument, or if it should always use lcd.framebuf +void lcd_drv_draw_frame(char *dat) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->draw_frame > 0) + driver->draw_frame(dat); + else if((int)driver->draw_frame == -1) + { + drv_base->draw_frame(dat); + } + } + } while(LL_Next(list) == 0); + +} + + +char lcd_drv_getkey() +{ + lcd_logical_driver *driver; + + char key; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if((int)driver->getkey > 0) + { + key = driver->getkey(); + if(key) return key; + } + else if((int)driver->getkey == -1) + { + key = drv_base->getkey(); + if(key) return key; + } + } + } while(LL_Next(list) == 0); + + return 0; +} diff --git a/server/drivers/lcd.h b/server/drivers/lcd.h new file mode 100644 index 0000000..fa1d79d --- /dev/null +++ b/server/drivers/lcd.h @@ -0,0 +1,95 @@ +#ifndef LCD_H +#define LCD_H + +// Maximum supported sizes +#define LCD_MAX_WID 256 +#define LCD_MAX_WIDTH 256 +#define LCD_MAX_HGT 256 +#define LCD_MAX_HEIGHT 256 + + +int lcd_init(char *args); +int lcd_add_driver(char *driver, char *args); +int lcd_shutdown(); + + + +///////////////////////////////////////////////////////////////// +// Driver functions / info held here... +// +// Feel free to override any/all functions here with real driver +// functions... +// +typedef struct lcd_logical_driver +{ + // Size in cells of the LCD + int wid, hgt; + // Size of each LCD cell, in pixels + int cellwid, cellhgt; + // Frame buffer... + char *framebuf; + + // Functions which might be the same for all drivers... + void (*clear)(); + void (*string)(int x, int y, char lcd[]); + + void (*chr)(int x, int y, char c); + void (*vbar)(int x, int len); + void (*hbar)(int x, int y, int len); + void (*init_num)(); + void (*num)(int x, int num); + + // Functions which should probably be implemented in each driver... + int (*init)(struct lcd_logical_driver *driver, char *args); + void (*close)(); + void (*flush)(); + void (*flush_box)(int lft, int top, int rgt, int bot); + int (*contrast)(int contrast); + void (*backlight)(int on); + void (*output)(int on); + void (*set_char)(int n, char *dat); + void (*icon)(int which, char dest); + void (*init_vbar)(); + void (*init_hbar)(); + void (*draw_frame)(); + + // Returns 0 for "no key pressed", or (A-Z). + char (*getkey)(); + + // more? + +} lcd_logical_driver; + +typedef struct lcd_physical_driver +{ + char *name; + int (*init)(struct lcd_logical_driver *driver, char *device); +} lcd_physical_driver; + + +extern lcd_logical_driver lcd; + + +int lcd_drv_init(lcd_logical_driver *driver, char *args); +void lcd_drv_close(); +void lcd_drv_clear(); +void lcd_drv_flush(); +void lcd_drv_string(int x, int y, char string[]); +void lcd_drv_chr(int x, int y, char c); +int lcd_drv_contrast(int contrast); +void lcd_drv_backlight(int on); +void lcd_drv_output(int on); +void lcd_drv_init_vbar(); +void lcd_drv_init_hbar(); +void lcd_drv_init_num(); +void lcd_drv_num(int x, int num); +void lcd_drv_set_char(int n, char *dat); +void lcd_drv_vbar(int x, int len); +void lcd_drv_hbar(int x, int y, int len); +void lcd_drv_icon(int which, char dest); +void lcd_drv_flush_box(int lft, int top, int rgt, int bot); +void lcd_drv_draw_frame(); +char lcd_drv_getkey(); + +#endif + diff --git a/server/drivers/lcddriver.c b/server/drivers/lcddriver.c new file mode 100644 index 0000000..8e2a821 --- /dev/null +++ b/server/drivers/lcddriver.c @@ -0,0 +1,124 @@ +/* lcddriver.cd - test/demo of LIBIR's to interface with lcdproc (LCDd) */ +/* Copyright (C) 1999 David Glaude loosely based on workmanir.c */ +/* workmanir.c - test/demo of LIBIR's high level command functions */ +/* Copyright (C) 1998 Tom Wheeley, see file COPYING for details */ + +#include + +#include +#include +#include +#include +#include + +#include "irman.h" + +char *progname = "lcddriver"; + +char *codes[] = { + /* dummy */ NULL, + /* KeyToLcd */ "lcdproc-A", + /* KeyToLcd */ "lcdproc-B", + /* KeyToLcd */ "lcdproc-C", + /* KeyToLcd */ "lcdproc-D", + /* KeyToLcd */ "lcdproc-E", + /* KeyToLcd */ "lcdproc-F", + /* KeyToLcd */ "lcdproc-G", + /* KeyToLcd */ "lcdproc-H", + /* KeyToLcd */ "lcdproc-I", + /* KeyToLcd */ "lcdproc-J", + /* KeyToLcd */ "lcdproc-K", + /* KeyToLcd */ "lcdproc-L", + /* KeyToLcd */ "lcdproc-M", + /* KeyToLcd */ "lcdproc-N", + /* KeyToLcd */ "lcdproc-O", + /* KeyToLcd */ "lcdproc-P", + /* KeyToLcd */ "lcdproc-Q", + /* KeyToLcd */ "lcdproc-R", + /* KeyToLcd */ "lcdproc-S", + /* KeyToLcd */ "lcdproc-T", + /* KeyToLcd */ "lcdproc-U", + /* KeyToLcd */ "lcdproc-V", + /* KeyToLcd */ "lcdproc-W", + /* KeyToLcd */ "lcdproc-X", + /* KeyToLcd */ "lcdproc-Y", + /* KeyToLcd */ "lcdproc-Z", + /* end */ NULL +}; + + +//void sigterm(int sig) +//{ +// ir_free_commands(); +// ir_finish(); +// raise(sig); +//} + + +// INIT $$$ +int INIT() +{ + int i; + char *filename; + + if (ir_init_commands(NULL, 1) < 0) { + fprintf(stderr, "error initialising commands: %s\n", strerror(errno)); + exit(1); + } + + filename = ir_default_portname(); + filename = "option"; + } + + for (i=1; codes[i] != NULL; i++) { + if (ir_register_command(codes[i], i) < 0) { + if (errno == ENOENT) { + fprintf(stderr, "%s: no code set for `%s'\n", progname, codes[i]); + } else { + fprintf(stderr, "error registering `%s': `%s'\n", codes[i], strerror(errno)); + } + } + } + + errno = 0; + if (ir_init(filename) < 0) { + fprintf(stderr, "%s: error initialising Irman: `%s'\n", strerror(errno)); + exit(1); + } + + return 0; +} + +// KEY $$$ +int KEY(void) +{ + int i; + int cmd; + char key; + + key=(char)0; + for(i=1;i;) { + switch (cmd=ir_get_command()) { + case IR_CMD_ERROR: + fprintf(stderr, "%s: error reading command: %s\n", progname, strerror(errno)); +// No exit in LCDd !!! +// exit(1); + + case IR_CMD_UNKNOWN: + fprintf(stderr,"IR unknown command\n"); + default: key='A'-1+cmd; break; + } + } +} + + +// CLOSE $$$ +int CLOSE() +{ + ir_free_commands(); + ir_finish(); + + return 0; +} + +/* end of lcddriver.c */ diff --git a/server/drivers/port.h b/server/drivers/port.h new file mode 100644 index 0000000..7553743 --- /dev/null +++ b/server/drivers/port.h @@ -0,0 +1,51 @@ +/*----------------------------------------------------------------------------- + * port.h (by damianf@wpi.edu) + * Low level I/O functions taken from led-stat.txt + * + * Jan 22 95 + * + * DOS part (tested only with DOS version of GCC, DJGPP) + * by M.Prinke 3/97 + */ + +/* #define DOS */ + +#ifndef PORT_H +#define PORT_H +#endif + +#ifndef DOS +static inline int port_in( int port ) +{ + unsigned char value; + __asm__ volatile ("inb %1,%0" + : "=a" (value) + : "d" ((unsigned short)port)); + return value; +} + +static inline void port_out( unsigned short int port, unsigned char val ) +{ + __asm__ volatile ( + "outb %0,%1\n" + : + : "a" (val), "d" (port) + ); +} +#else +#include + +static inline int port_in( int port ) +{ + unsigned char value; + value = inportb((unsigned short) port); + return (int)value; +} + +static inline void port_out( unsigned int port, unsigned char val ) +{ + outportb((unsigned short) port, val); +} +#endif + +/**** END OF FILE ****/ diff --git a/server/drivers/text.c b/server/drivers/text.c new file mode 100644 index 0000000..90f40e0 --- /dev/null +++ b/server/drivers/text.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "lcd.h" +#include "text.h" +#include "drv_base.h" + + +lcd_logical_driver *text; + +////////////////////////////////////////////////////////////////////////// +////////////////////// For Text-Mode Output ////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +int text_init(lcd_logical_driver *driver, char *args) +{ + text = driver; + + if(!driver->framebuf) + { + driver->close(); + return -1; + } + + + driver->wid = 20; + driver->hgt = 4; + driver->cellwid = 5; + driver->cellhgt = 8; + + driver->clear = (void *)-1; + driver->string = (void *)-1; + driver->chr = (void *)-1; + driver->vbar = text_vbar; + driver->init_vbar = NULL; + driver->hbar = text_hbar; + driver->init_hbar = NULL; + driver->num = (void *)-1; + driver->init_num = NULL; + + driver->init = text_init; + driver->close = text_close; + driver->flush = text_flush; + driver->flush_box = NULL; + driver->contrast = NULL; + driver->backlight = NULL; + driver->set_char = NULL; + driver->icon = NULL; + driver->draw_frame = text_draw_frame; + + driver->getkey = NULL; + + + return 200; // 200 is arbitrary. (must be 1 or more) +} + +void text_close() +{ + drv_base_close(); +} + +///////////////////////////////////////////////////////////////// +// Clears the LCD screen +// +void text_clear() +{ + memset(lcd.framebuf, ' ', lcd.wid*lcd.hgt); + +} + + +////////////////////////////////////////////////////////////////// +// Flushes all output to the lcd... +// +void text_flush() +{ + text_draw_frame(lcd.framebuf); +} + + +///////////////////////////////////////////////////////////////// +// Prints a string on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void text_string(int x, int y, char string[]) +{ + int i; + + x -= 1; // Convert 1-based coords to 0-based... + y -= 1; + + for(i=0; string[i]; i++) + { + lcd.framebuf[(y*lcd.wid) + x + i] = string[i]; + } +} + +///////////////////////////////////////////////////////////////// +// Prints a character on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void text_chr(int x, int y, char c) +{ + y--; + x--; + + lcd.framebuf[(y*lcd.wid) + x] = c; +} + + + +int text_contrast(int contrast) +{ +// printf("Contrast: %i\n", contrast); + return 0; +} + +void text_backlight(int on) +{ +/* + if(on) + { + printf("Backlight ON\n"); + } + else + { + printf("Backlight OFF\n"); + } +*/ +} + +void text_init_vbar() +{ +// printf("Vertical bars.\n"); +} + +void text_init_hbar() +{ +// printf("Horizontal bars.\n"); +} + +void text_init_num() +{ +// printf("Big Numbers.\n"); +} + +void text_num(int x, int num) +{ +// printf("BigNum(%i, %i)\n", x, num); +} + +void text_set_char(int n, char *dat) +{ +// printf("Set Character %i\n", n); +} + +///////////////////////////////////////////////////////////////// +// Draws a vertical bar; erases entire column onscreen. +// +void text_vbar(int x, int len) +{ + int y; + for(y=lcd.hgt; y > 0 && len>0; y--) + { + text_chr(x, y, '|'); + + len -= lcd.cellhgt; + } + +} + +///////////////////////////////////////////////////////////////// +// Draws a horizontal bar to the right. +// +void text_hbar(int x, int y, int len) +{ + for(; x<=lcd.wid && len>0; x++) + { + text_chr(x,y,'-'); + + len -= lcd.cellwid; + } + +} + + +void text_flush_box(int lft, int top, int rgt, int bot) +{ + text_flush(); + +} + + +void text_draw_frame(char *dat) +{ + int i, j; + + char out[LCD_MAX_WIDTH]; + + if(!dat) return; + +// printf("Frame (%ix%i): \n%s\n", lcd.wid, lcd.hgt, dat); + + for(i=0; i - Released under GPL + + LCD info: http://www.wirz.com/sli/ */ + +#include +#include +#include +#include +#include +#include +#include +#include "lcd.h" +#include "wirz-sli.h" +#include "drv_base.h" + +#include "../../shared/debug.h" +#include "../../shared/str.h" + +static int custom=0; +typedef enum { + hbar = 1, + vbar = 2, + bign = 4, + beat = 8 } custom_type; + +static int fd; +static char lastframe[32]; + +lcd_logical_driver *sli; + +///////////////////////////////////////////////////////////////// +// Opens com port and sets baud correctly... +// +int sli_init(lcd_logical_driver *driver, char *args) +{ + char *argv[64]; + int argc; + struct termios portset; + int i; + int tmp; + char out[2]; + + char device[256] = "/dev/lcd"; + int speed=B19200; + + sli = driver; + + //debug("sli_init: Args(all): %s\n", args); + + argc = get_args(argv, args, 64); + + /* + for(i=0; i argc) { + fprintf(stderr, "sli_init: %s requires an argument\n", + argv[i]); + return -1; + } + strcpy(device, argv[++i]); + } + else if(0 == strcmp(argv[i], "-s") || + 0 == strcmp(argv[i], "--speed")) + { + if(i + 1 > argc) { + fprintf(stderr, "sli_init: %s requires an argument\n", + argv[i]); + return -1; + } + tmp = atoi(argv[++i]); + if(tmp==1200) speed=B1200; + else if(tmp==2400) speed=B2400; + else if(tmp==9600) speed=B9600; + else if(tmp==19200) speed=B19200; + else if(tmp==38400) speed=B38400; + else if(tmp==57600) speed=B57600; + else if(tmp==115200) speed=B115200; + else { + fprintf(stderr, "sli_init: %s argument must be 1200, 2400, 9600, 19200, 38400, 57600, or 115200. Using default value (19200).\n", + argv[i]); + } + } + else if(0 == strcmp(argv[i], "-h") || + 0 == strcmp(argv[i], "--help")) + { + printf("LCDproc Wirz SLI LCD driver\n" + "\t-d\t--device\tSelect the output device to use [/dev/lcd]\n" + "\t-s\t--speed\t\tSet the communication speed [19200]\n" + "\t-h\t--help\t\tShow this help information\n"); + return -1; + } + else + { + printf("Invalid parameter: %s\n", argv[i]); + } + + } + + // Set up io port correctly, and open it... + fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); + if (fd == -1) + { + fprintf(stderr, "sli_init: failed (%s)\n", strerror(errno)); + return -1; + } + //else fprintf(stderr, "sli_init: opened device %s\n", device); + tcgetattr(fd, &portset); + // This is necessary in Linux, but does not exist in irix. +#ifndef IRIX + cfmakeraw(&portset); +#endif + cfsetospeed(&portset, speed); + tcsetattr(fd, TCSANOW, &portset); + + /* Initialize SLI using autobaud detection, and then turn off cursor + and clear screen */ + usleep(150000); /* 150ms delay to allow SLI to power on */ + out[0]=13; /* CR for SLI autobaud */ + write(fd, out, 1); + usleep(3000); /* 3ms delay.. wait for it to autobaud */ + out[0]=0x0FE; + out[1]=0x00C; /* No cursor */ + write(fd, out, 2); + out[0]=0x0FE; + out[1]=0x001; /* Clear LCD, not sure if this belongs here */ + write(fd, out, 2); + + + if(!driver->framebuf) + { + fprintf(stderr, "sli_init: No frame buffer.\n"); + driver->close(); + return -1; + } + + // Set LCD parameters (I use a 16x2 LCD) -- small but still useful + // Its also much cheaper than the higher quality Matrix Orbital modules + // Currently, $30 for interface kit and 16x2 non-backlit LCD... + driver->wid = 15; + driver->hgt = 2; + + + // Set the functions the driver supports... + + driver->clear = (void *)-1; + driver->string = (void *)-1; + driver->chr = (void *)-1; + driver->vbar = sli_vbar; + driver->init_vbar = sli_init_vbar; + driver->hbar = sli_hbar; + driver->init_hbar = sli_init_hbar; + driver->num = (void *)-1; + driver->init_num = (void *)-1; + + driver->init = sli_init; + driver->close = sli_close; + driver->flush = sli_flush; + driver->flush_box = sli_flush_box; + driver->contrast = (void *)-1; + driver->backlight = (void *)-1; + driver->set_char = sli_set_char; + driver->icon = sli_icon; + driver->draw_frame = sli_draw_frame; + + driver->getkey = (void *)-1; + + return fd; +} + + +/* Clean-up */ +void sli_close() +{ + close(fd); + + if(sli->framebuf) free(sli->framebuf); + + sli->framebuf = NULL; +} + + +void sli_flush() +{ + sli_draw_frame(lcd.framebuf); +} + + +/* no bounds checking is done in MtxOrb.c (which I shamelessly ripped) + this is bad imho, so I added it.. may remove later + speed is not a huge issue though, this isnt a + device driver or anything ;) */ +void sli_flush_box(int lft, int top, int rgt, int bot) +{ + int y; + char out[2]; /* Why does the matrix driver allocate so much here? */ + + /* simple bounds checking */ + if((top>lcd.hgt)|(bot>lcd.hgt)) + return; + + if((lft>lcd.wid)|(rgt>lcd.wid)) + return; + +// printf("Flush (%i,%i)-(%i,%i)\n", lft, top, rgt, bot); + +/* I like having hex, everywhere and all the time */ + for(y=top; y<=bot; y++) + { + if(y==1) + sprintf(out, "%c%c", 0x0FE, 0x080+lft); + if(y==2) + sprintf(out, "%c%c", 0x0FE, 0x0C0+lft); + write(fd, out, 0x002); + write(fd, lcd.framebuf+(y*lcd.wid)+lft, rgt-lft+1); + } + + +} + +///////////////////////////////////////////////////////////////// +// Prints a character on the lcd display, at position (x,y). The +// upper-left is (1,1), and the lower right should be (20,4). +// +void sli_chr(int x, int y, char c) +{ + y--; + x--; + + lcd.framebuf[(y*lcd.wid) + x] = c; +} + + +///////////////////////////////////////////////////////////////// +// Sets up for vertical bars. Call before lcd.vbar() +// + +/* Because of the way we do this (custom characters in CGRAM) + we can't have both horizontal and vertical bars at once... + this also appears to be a limitation of the Matrix Orbital + modules so I will assume that all client coders know about it + + I think it would be cool to use triangular stuff for the non-full + characters, so that you can do both bar types at once.. maybe I + will release a new version of the SLI driver that attempts this */ + +void sli_init_vbar() +{ + char a[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + }; + char b[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char c[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char d[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char e[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char f[] = { + 0,0,0,0,0, + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + char g[] = { + 0,0,0,0,0, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + 1,1,1,1,1, + }; + + if(custom!=vbar) { + sli_set_char(1,a); + sli_set_char(2,b); + sli_set_char(3,c); + sli_set_char(4,d); + sli_set_char(5,e); + sli_set_char(6,f); + sli_set_char(7,g); + custom=vbar; + } +} + +///////////////////////////////////////////////////////////////// +// Inits horizontal bars... +// +void sli_init_hbar() +{ + + char a[] = { + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + 1,0,0,0,0, + }; + char b[] = { + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + 1,1,0,0,0, + }; + char c[] = { + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + 1,1,1,0,0, + }; + char d[] = { + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + 1,1,1,1,0, + }; + + if(custom!=hbar) { + sli_set_char(1,a); + sli_set_char(2,b); + sli_set_char(3,c); + sli_set_char(4,d); + custom=hbar; + } +} + +///////////////////////////////////////////////////////////////// +// Draws a vertical bar... +// + +/* It would be cool if you could start a vertical bar at any y + like the horizontal bar routine can start at any x... but + since we only have 2 lines anyway this is rather pointless + for me to add */ + +void sli_vbar(int x, int len) +{ + char map[9] = {32, 1, 2, 3, 4, 5, 6, 7, 255 }; + + + int y; + for(y=lcd.hgt; y > 0 && len>0; y--) + { + if(len >= lcd.cellhgt) sli_chr(x, y, 255); + else sli_chr(x, y, map[len]); + + len -= lcd.cellhgt; + } + +} + +///////////////////////////////////////////////////////////////// +// Draws a horizontal bar to the right. +// +void sli_hbar(int x, int y, int len) +{ + char map[6] = { 32, 1, 2, 3, 4, 255 }; + + for(; x<=lcd.wid && len>0; x++) + { + if(len >= lcd.cellwid) sli_chr(x,y,255); + else sli_chr(x, y, map[len]); + + len -= lcd.cellwid; + + } + +} + + +///////////////////////////////////////////////////////////////// +// Sets a custom character from 0-7... +// +// For input, values > 0 mean "on" and values <= 0 are "off". +// +// The input is just an array of characters... +// +void sli_set_char(int n, char *dat) +{ + char out[2]; + int row, col; + int letter; + + /* SLI also has 8 user definable characters */ + if(n < 0 || n > 7) return; + if(!dat) return; + + /* Move cursor to CGRAM */ + out[0]=0x0FE; + out[1]=0x040+8*n; + write(fd, out, 2); + + for(row=0; row 0); + } + letter|=0x020; /* SLI can't accept CR, LF, etc in this character! */ + write(fd, &letter, 1); + } + + /* Move cursor back to DDRAM */ + out[0]=0x0FE; + out[1]=0x080; + write(fd, out, 2); +} + + +void sli_icon(int which, char dest) +{ + char icons[3][5*8] = { + { + 1,1,1,1,1, // Empty Heart + 1,0,1,0,1, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,0,0,0,1, + 1,1,0,1,1, + 1,1,1,1,1, + }, + + { + 1,1,1,1,1, // Filled Heart + 1,0,1,0,1, + 0,1,0,1,0, + 0,1,1,1,0, + 0,1,1,1,0, + 1,0,1,0,1, + 1,1,0,1,1, + 1,1,1,1,1, + }, + + { + 0,0,0,0,0, // Ellipsis + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 1,0,1,0,1, + }, + + }; + + if(custom==bign) custom=beat; + sli_set_char(dest, &icons[which][0]); +} + + +///////////////////////////////////////////////////////////// +// Blasts a single frame onscreen, to the lcd... +// +// Input is a character array, sized lcd.wid*lcd.hgt +// +void sli_draw_frame(char *dat) +{ + char out[2]; /* Again, why does the Matrix driver allocate so much here? */ + int y; + + if(!dat) return; + + /* + out[0]=0x0FE; + out[1]=0x001; + write(fd, out, 2); + */ + + /* Don't update if we have no new data + this keeps me from getting a migraine + (just like those copyleft penguin mints... mmmmmm) */ + + // if (!strncmp(dat,lastframe,32)) /* Nothing has changed */ + // return; + + /* Do the actual refresh */ + out[0]=0x0FE; + out[1]=0x080; + write(fd, out, 2); + write(fd, &dat[0], 16); + usleep(10); + write(fd, &dat[16],15); + + // strncpy(lastframe,dat,32); // Update lastframe... + +} diff --git a/server/drivers/wirz-sli.h b/server/drivers/wirz-sli.h new file mode 100644 index 0000000..5469f50 --- /dev/null +++ b/server/drivers/wirz-sli.h @@ -0,0 +1,33 @@ +/* wirz-sli.h -- Header file for LCDproc Wirz SLI driver + Copyright (C) 1999 Horizon Technologies-http://horizon.pair.com/ + Written by Bryan Rittmeyer - Released under GPL + + LCD info: http://www.wirz.com/sli/ */ + +#ifndef SLI_H +#define SLI_H + + +extern lcd_logical_driver *sli; + +int sli_init(lcd_logical_driver *driver, char *device); +void sli_close(); +void sli_flush(); +void sli_flush_box(int lft, int top, int rgt, int bot); +void sli_chr(int x, int y, char c) ; +int sli_contrast(int contrast); +void sli_backlight(int on); +void sli_init_vbar(); +void sli_init_hbar(); +void sli_vbar(int x, int len); +void sli_hbar(int x, int y, int len); +void sli_init_num(); +void sli_num(int x, int num); +void sli_set_char(int n, char *dat); +void sli_icon(int which, char dest); +void sli_draw_frame(char *dat); +char sli_getkey(); + + + +#endif diff --git a/server/input.c b/server/input.c new file mode 100644 index 0000000..720a683 --- /dev/null +++ b/server/input.c @@ -0,0 +1,131 @@ +/* + + input.c + + Handles keypad (and other?) input from the user. + + Currently, the keys are as follows: + + Context Key Function + ------- --- -------- + Normal "normal" context is handled in this source file. + A Pause/Continue + B Back(Go to previous screen) + C Forward(Go to next screen) + D Open main menu + E-Z Sent to client, if any; ignored otherwise + + (menu keys are not handled here, but in the menu code) + Menu + A Enter/select + B Up/Left + C Down/Right + D Exit/Cancel + E-Z Ignored +*/ + +#include +#include + +#include "../shared/sockets.h" +#include "../shared/debug.h" + +#include "drivers/lcd.h" + +#include "client_data.h" +#include "clients.h" +#include "screen.h" +#include "screenlist.h" +#include "menus.h" + +#include "input.h" + + +int server_input(int key); + +// FIXME! The server tends to crash when "E" is pressed.. (?!) +// (but only when the joystick driver is the last one on the list...) + +// Checks for keypad input, and dispatches it +int handle_input() +{ + char str[256]; + int key; + screen *s; + client *c; + + key = lcd.getkey(); + + if (!key) return 0; + + debug("handle_input(%c)\n", (char)key); + + if(key) + { + s = screenlist_current(); + if(s) + { + c = s->parent; + if(c) + { + // TODO: Interpret and translate keys! + // If the client should have this keypress... + // Send keypress to client + if(key >= 'E' && key <= 'Z') + { + // TODO: Implement client "acceptable key" lists + sprintf(str, "key %c\n", key); + sock_send_string(c->sock, str); + } + // Otherwise, tell the server about it. + else + { + server_input(key); + } + } + else + { + // If no parent, it means we're on the server screen. + // so, the server gets all keypresses there. + server_input(key); + } + } + } + + return 0; +} + + + +int server_input(int key) +{ + debug("server_input(%c)\n", (char)key); + + switch(key) + { + case 'A': + if(screenlist_action == SCR_HOLD) + screenlist_action = 0; + else + screenlist_action = SCR_HOLD; + break; + case 'B': + screenlist_action = SCR_BACK; + screenlist_prev(); + break; + case 'C': + screenlist_action = SCR_SKIP; + screenlist_next(); + break; + case 'D': + debug("got the menu key!\n"); + server_menu(); + break; + default: + debug("server_input: Invalid key \"%c\" (%i)\n", + (char)key, key); + break; + } + + return 0; +} diff --git a/server/input.h b/server/input.h new file mode 100644 index 0000000..95caa03 --- /dev/null +++ b/server/input.h @@ -0,0 +1,9 @@ +#ifndef INPUT_H +#define INPUT_H + + +// Accepts and uses keypad input while displaying screens... +int handle_input(); + + +#endif diff --git a/server/main.c b/server/main.c new file mode 100644 index 0000000..71d3877 --- /dev/null +++ b/server/main.c @@ -0,0 +1,369 @@ +/* + main.c for LCDd + + Contains main(), plus signal callback functions and a help screen. + + Program init, command-line handling, and the main loop are + implemented here. Also, minimal data about the program such as + the revision number. + + Some of this stuff should probably be move elsewhere eventually, + such as command-line handling and the main loop. main() is supposed + to be "dumb". + + */ + +#include +#include +#include +#include +#include + +#include "../shared/debug.h" + +#include "drivers/lcd.h" +#include "sock.h" +#include "clients.h" +#include "screenlist.h" +#include "screen.h" +#include "parse.h" +#include "render.h" +#include "serverscreens.h" +#include "input.h" +#include "main.h" + + +char *version = VERSION; +char *build_date = __DATE__; + + +/* no longer needed +static screen_size sizes[] = +{ + {"16x2", 16, 2}, + {"16x4", 16, 4}, + {"20x2", 20, 2}, + {"20x4", 20, 4}, + {"40x2", 40, 2}, + {"40x4", 40, 4}, + {NULL , 0, 0}, +}; +*/ + +// This is currently only a list of available arguments, but doesn't +// really *do* anything. It just helps to figure out which parameters +// go to the server, and which ones go to individual drivers... +static parameter args[] = +{ + {"-h", "--help"}, + {"-d", "--driver"}, + {"-t", "--type"}, + {"-f", "--foreground"}, + {"-b", "--backlight"}, + {NULL, NULL}, +}; + + +void exit_program(int val); +void HelpScreen(); + + +int main(int argc, char **argv) +{ + // TODO: Use a config file! + //char cfgfile[256] = "/etc/LCDd.cf"; + int i, err, tmp; + int daemon_mode=1; + int disable_server_screen=0; + int child; + screen *s = NULL; + char *str, *ing; // strings for commandline handling +// screen_size *size = &sizes[0]; // No longer needed + + + + // Ctrl-C will cause a clean exit... + signal(SIGINT, exit_program); + // and "kill"... + signal(SIGTERM, exit_program); + // and "kill -HUP" (hangup)... + signal(SIGHUP, exit_program); + // and just in case, "kill -KILL" (which cannot be trapped; but oh well) + signal(SIGKILL, exit_program); + + + + // If no paramaters given, give the help screen. + if(argc == 1) HelpScreen(); + + // Don't spawn a child if we're using the curses driver + for(i=1; i i+1) + { + int j, skip=0; + for(j=1; args[j].lg; j++) // check each option except "help" + if(! strcmp(argv[i+1], args[j].sh) || + ! strcmp(argv[i+1], args[j].lg)) skip=1; + + if(! skip) + { + ing = argv[++i]; + } + //else i++; + } + err = lcd_add_driver(str, ing); + if(err <= 0) + { + printf("Error loading driver %s. Continuing anyway...\n", + str); + } + if((err > 0) && (0 == strcmp(str, "curses"))) daemon_mode=0; + } + else if(0 == strcmp(argv[i], "-h") || + 0 == strcmp(argv[i], "--help")) + { + HelpScreen(); + } + // Redundant, but it prevents errors... + else if(0 == strcmp(argv[i], "-f") || + 0 == strcmp(argv[i], "--foreground")) + { + daemon_mode = 0; + } + else if(0 == strcmp(argv[i], "-b") || + 0 == strcmp(argv[i], "--backlight")) + { + if(argc <= i+1) HelpScreen(); + str = argv[++i]; + if(0 == strcmp(str, "off")) + backlight_state = backlight = BACKLIGHT_OFF; + else if(0 == strcmp(str, "on")) + backlight_state = backlight = BACKLIGHT_ON; + else if(0 == strcmp(str, "open")) + backlight = BACKLIGHT_OPEN; + else HelpScreen(); + } + else if(0 == strcmp(argv[i], "-t") || + 0 == strcmp(argv[i], "--type")) + { + if(i + 1 > argc) + HelpScreen(); + else + { + int wid, hgt; + + i++; + sscanf(argv[i], "%ix%i", &wid, &hgt); + if(wid>80 || wid<16 || hgt>25 || hgt<2) + { + fprintf(stderr, + "LCDd: Invalid lcd size \"%s\". Using 20x4.\n", + argv[i]); + lcd.wid = 20; + lcd.hgt = 4; + } + else + { + lcd.wid = wid; + lcd.hgt = hgt; + } + +/* no longer needed + int j=0, valid=0; + i++; + for(j=0; sizes[j].size; j++) + { + if(0 == strcmp(sizes[j].size, argv[i])) + { + valid = 1; + size = &sizes[j]; + lcd.wid = size->wid; + lcd.hgt = size->hgt; + } + } + if(!valid) + { + fprintf(stderr, "LCDd: Invalid lcd size \"%s\". Using 20x4.\n", argv[i]); + } +*/ + } + } + else if(0 == strcmp(argv[i], "-i") || + 0 == strcmp(argv[i], "--serverinfo")) + { + if(i + 1 > argc) + HelpScreen(); + else + { + i++; + if(0 == strcmp(argv[i], "off")) disable_server_screen = 1; + } + } + else + { + // otherwise... Get help! + printf("Invalid parameter: %s\n", argv[i]); + HelpScreen(); + } + } + + + + // Now init a bunch of required stuff... + + if(sock_create_server() <= 0) + { + printf("Error opening socket.\n"); + return 1; + } + + if(client_init() < 0) + { + printf("Error initializing client list\n"); + return 1; + } + + if(screenlist_init() < 0) + { + printf("Error initializing screen list\n"); + return 1; + } + + // Make sure the server screen shows up every once in a while.. + if(server_screen_init() < 0) + { + printf("Error initializing server screens\n"); + return 1; + } + else if(disable_server_screen) + { + server_screen->priority = 256; + } + + + + + + // Main loop... + while(1) + { + sock_poll_clients(); + parse_all_client_messages(); + handle_input(); + + // TODO: Move this code to screenlist.c... + // ... it should just say "handle_screens();" + // Timer gets reset by screenlist_next() + timer++; + // this line's here because s was getting overwritten at one time... + //s = screenlist_current(); + if(s && (timer >= s->duration)) + { + screenlist_next(); + } + // Just in case it gets out of hand... + if(timer >= 0x10000) timer = 0; + update_server_screen(timer); + s = screenlist_current(); + + // render something here... + if(s) draw_screen(s, timer); + else no_screen_screen(timer); + + usleep(TIME_UNIT); + } + + + // Quit! + exit_program(0); + + return 0; +} + + +void exit_program(int val) +{ + // TODO: These things shouldn't be so interdependent. The order + // things are shut down in shouldn't matter... + + // Say goodbye! + goodbye_screen(); + // Can go anywhere... + lcd_shutdown(); + + // Must come before screenlist_shutdown + client_shutdown(); + // Must come after client_shutdown + screenlist_shutdown(); + // Should come after client_shutdown + sock_close_all(); + + exit(0); + +} + + +void HelpScreen() +{ + printf("LCDproc server daemon, %s\n", version); + printf("Copyright (c) 1999 Scott Scriven, William Ferrell, and misc contributors\n"); + printf("This program is freely redistributable under the terms of the GNU Public License\n\n"); + printf("Usage: lcdproc [options]\n"); + printf("\tOptions in []'s are optional. Available options are:\n"); + printf("\t-h\t--help\n\t\t\tDisplay this help screen\n"); + printf("\t-t\t--type \n\t\t\tSelect an LCD size (20x4, 16x2, etc...)\n"); + printf("\t-d\t--driver [args]\n\t\t\tAdd a driver to use:\n"); + printf("\t\t\tCFontz, curses, HD44780, irmanin, joy,\n\t\t\tMtxOrb, text\n"); + printf("\t\t\t(args will be passed to the driver for init)\n"); + printf("\t-f\t--foreground\n\t\t\tRun in the foreground (no daemon)\n"); + printf("\t-b\t--backlight \n\t\t\tSet backlight mode (on, off, open)\n"); + printf("\t-i\t--serverinfo off\n\t\t\tSet the server screen to low priority\n"); + printf("\n"); + printf("\tUse \"man LCDd\" for more info.\n"); + printf("\tHelp on each driver's parameters are obtained upon request:\n\t\t\"LCDd -d driver --help\"\n"); + printf("Example:\n"); + printf("\tLCDd -d MtxOrb \"--device /dev/lcd --contrast 200\" -d joy\n"); + printf("\n"); + exit(0); +} + diff --git a/server/main.h b/server/main.h new file mode 100644 index 0000000..44df1ac --- /dev/null +++ b/server/main.h @@ -0,0 +1,31 @@ +#ifndef MAIN_H +#define MAIN_H + +/* + contains a few things that other parts of the program might want + to know about... + */ + +extern char *version; +extern char *build_date; + +void exit_program(int val); + +// 1/8th second is a single time unit... +#define TIME_UNIT 125000 +// But I plan to double the framerate soon, or make it variable... +//#define TIME_UNIT (125000/2) + +typedef struct screen_size +{ + char * size; + int wid, hgt; +} screen_size; + +typedef struct parameter +{ + char * sh, * lg; // short and long versions +} parameter; + + +#endif diff --git a/server/menu.c b/server/menu.c new file mode 100644 index 0000000..8567ffa --- /dev/null +++ b/server/menu.c @@ -0,0 +1,355 @@ +/* + menu.c + + Handles server-supplied menus defined by a table. Read menu.h for + more information. + + Menus are similar to "pull-down" menus, but have some extra features. + They can contain "normal" menu items, checkboxes, sliders, "movers", + etc.. + + I should probably find a more elegant way of doing this in order + to handle dynamically-changing menus such as the client list. Tcl/Tk + has neat ways to do it. Hmm... + + */ + +#include +#include +#include +#include + +#include "parse.h" +#include "sock.h" +#include "render.h" +#include "main.h" + +#include "drivers/lcd.h" +#include "menu.h" + +// FIXME: Implement this where it is supposed to be... +#include +void framedelay() +{ + sock_poll_clients(); + parse_all_client_messages(); + + usleep(TIME_UNIT); +} + +static void draw_heartbeat() +{ + static int timer = 0; + + if(heartbeat) + { + // Set this to pulsate like a real heart beat... + // (binary is fun... :) + lcd.icon(!((timer+4)&5), 0); + lcd.chr(lcd.wid, 1, 0); + } + lcd.flush(); + + timer++; + timer &= 0x0f; +} + +static int PAD = 255; + + + +typedef struct menu_info +{ + int selected; + int length; +} menu_info; + + + +static int draw_menu(Menu menu, menu_info *info); +static int fill_menu_info(Menu menu, menu_info *info); +static int menu_handle_action(menu_item *item); + +static int slid_func(menu_item *item); + + +int do_menu(Menu menu) +{ + menu_info info; + int key=0; + int status=MENU_OK; + int done=0; + + int (*func)(); + int (*readfunc)(int); + + + if(!menu) return MENU_ERROR; + + fill_menu_info(menu, &info); + + + while(!done) + { + // Keep the cursor off titles... (?) + while(menu[info.selected].type == TYPE_TITL) + { + info.selected++; + // If the title is the last thing in the menu... + if(!menu[info.selected].text) info.selected -= 2; + } + + + draw_menu(menu, &info); + + // FIXME: This should use a better keypress interface, which + // FIXME: handles things according to keybindings... + + for(key = lcd.getkey(); key==0; key = lcd.getkey()) + { + // sleep for 1/8th second... + framedelay(); + // do the heartbeat... + draw_heartbeat(); + // Check for client input... + } + + + // Handle the key according to the keybindings... + switch(key) + { + case 'D': done=1; break; + case 'B': if(info.selected > 0) info.selected--; + while(menu[info.selected].type == TYPE_TITL) + { + if(info.selected > 0) + info.selected--; + else break; + } + break; + case 'C': if(menu[info.selected+1].text) info.selected++; break; + case 'A': + switch(menu[info.selected].type) + { + case TYPE_MENU: status = do_menu(menu[info.selected].data); + break; + case TYPE_FUNC: + func = menu[info.selected].data; + if(func) + status = func(); + break; + case TYPE_CHEK: + readfunc = menu[info.selected].data; + if(readfunc) + status = readfunc(MENU_CHECK); + status &= 0xffff0000; + break; + case TYPE_SLID: + func = menu[info.selected].data; + if(func) + status = slid_func(&menu[info.selected]); + break; + default: + break; + } + + switch(status) + { + case MENU_OK: + break; + case MENU_CLOSE: + return MENU_OK; + case MENU_QUIT: + return MENU_QUIT; +// case MENU_KILL: +// return MENU_KILL; + case MENU_ERROR: + return MENU_ERROR; + } + + // status = menu_handle_action(&menu[info.selected]); + // TODO: It should now do special stuff for "mover" widgets, + // TODO: and handle the return code appropriately. + break; + default: break; + } + + } + + return status; + +} + +static int draw_menu(Menu menu, menu_info *info) +{ + int i; + int x=1, y=1; + int top=0, bottom=0; + + int (*readfunc)(int); + + // these should maybe be removed: + int wid=lcd.wid, hgt=lcd.hgt; + + + if(!menu) return MENU_ERROR; + + lcd.clear(); + + + // Scroll down until the selected item is centered, if possible... + top = info->selected - (hgt/2); + if(top<0) top=0; + bottom = top+hgt; + if(bottom > info->length) bottom=info->length; + top = bottom-hgt; + if(top<0) top=0; + + + + // Draw all visible items... + for(i=top; iselected) lcd.chr(2,y,'>'); + + switch(menu[i].type) + { + case TYPE_TITL: + lcd.chr(1,y,PAD); + lcd.chr(2,y,PAD); + lcd.string(4,y,menu[i].text); + for(x=strlen(menu[i].text)+5; x <= wid; x++) + lcd.chr(x,y,PAD); + break; + case TYPE_MENU: + lcd.string(3,y,menu[i].text); + lcd.chr(wid,y,'>'); + break; + case TYPE_FUNC: + lcd.string(3,y,menu[i].text); + break; + case TYPE_CHEK: + if(menu[i].data) + { + readfunc = menu[i].data; + if(readfunc(MENU_READ)) + lcd.chr(wid,y,'Y'); + else + lcd.chr(wid,y,'N'); + } + lcd.string(3,y,menu[i].text); + break; + case TYPE_SLID: + lcd.string(3,y,menu[i].text); + break; + case TYPE_MOVE: + break; + default: + break; + } + } + + if(top != 0) + lcd.chr(1,1,'^'); + if(bottom < info->length) + lcd.chr(1,hgt,'v'); + + + draw_heartbeat(); + //lcd.flush(); + + return 0; +} + + +static int fill_menu_info(Menu menu, menu_info *info) +{ + int i; + + info->selected = 0; + + // count the entries in the menu + for(i=0; menu[i].text; i++); + + info->length = i; + + return 0; + +} + +static int menu_handle_action(menu_item *item) +{ + return MENU_OK; +} + + +static int slid_func(menu_item *item) +{ + char str[16]; + int key = 0; + int value = 0; + int x, y=1; + int (*readfunc)(int); + + readfunc = item->data; + + lcd.init_hbar(); + + while(key != 'A' && key != 'D') + { + // Draw the title... + lcd.clear(); + lcd.chr(1,y,PAD); + lcd.chr(2,y,PAD); + lcd.string(4,y,item->text); + for(x=strlen(item->text)+5; x <= lcd.wid; x++) + lcd.chr(x,y,PAD); + + // Draw the slider now... + value = readfunc(MENU_READ); + if(value < 0 || value >= MENU_CLOSE) + return value; + sprintf(str, "%i", value); + if(lcd.hgt >= 4) + { + lcd.string(8, 4, str); + value = (lcd.wid * lcd.cellwid * value / 256); + lcd.hbar(1, 3, value); + } + else + { + lcd.string(17, 2, str); + value = ((lcd.wid-4) * lcd.cellwid * value / 256); + lcd.hbar(1, 2, value); + } + //lcd.flush(); + + for(key = lcd.getkey(); key==0; key = lcd.getkey()) + { + // do the heartbeat... + draw_heartbeat(); + // sleep for 1/8th second... + framedelay(); + // Check for client input... + } + + switch(key) + { + case 'B': + value = readfunc(MENU_MINUS); + break; + case 'C': + value = readfunc(MENU_PLUS); + break; + } + + if(value >= MENU_CLOSE + || value < 0 + || key == 'A' + || key == 'D') + return value; + } + + return MENU_OK; +} + diff --git a/server/menu.h b/server/menu.h new file mode 100644 index 0000000..31f2a21 --- /dev/null +++ b/server/menu.h @@ -0,0 +1,143 @@ +#ifndef MENU_H +#define MENU_H + + +#if 0 +/************************************************************************* + Menus! + +This is how the LCDproc menu stuff works... + +Each item has three values: + + Title -- Text + Type -- menu, function, checkbox, slider, mover + Data -- Child, ExecFunc, CheckFunc, SlidFunc, ??? + +When an item is picked, do_menu() decides what to do based on type. +--"Menus" will recurse into the "data", assuming it is a child menu. +--"Function"-type items will have their function called. +--CheckBox-type items will have their function called with a "read" + parameter to get an on/off signal, and called with a "set" signal when + picked. +--Sliders will have the same "read" thing, and the "set" function will + take a plus or minus parameter. +--The Movers will act like a label until picked, and then the +/- keys + will both rearrange the menu, and send the item a signal of some sort + to indicate what happened. It will act like a label again after the + user presses Enter again. + +The "Data" field will really be a "void *", which is the "generic" +data type in C... + +Anyway, this sort of thing would be declared this way: + +======================================================================== + +menu_item MainMenu[] = { + "MENU", 0, 0, // Title + "Options", TYPE_MENU, (void *)OptionsMenu, + "Kill LCDproc", TYPE_FUNC, (void *)Shutdown_func, + 0, 0, 0, +}; + +menu_item OptionsMenu[] = { + "OPTIONS", TYPE_TITL, 0, // Title + "24-hour Time", TYPE_CHEK, (void *)Time24_func, + "Contrast...", TYPE_SLID, (void *)Contrast_func, + 0, 0, 0, +}; + + +///////////////// Elsewhere, we declare these... + +void Shutdown_func() +{ + // Do something here... + return MENU_KILL; // or MENU_CLOSE, or MENU_OK, or MENU_ERROR +} + +int Time24_func(int input) +{ + if(input == MENU_READ) return status; + if(input == MENU_CHECK) toggle_status(); // does something. + return (status | MENU_OK); + // The status is "or"-ed with the MENU value to let do_menu() + // know what to do after selecting the item. (two return + // values in one. :) + + // Also, "MENU_OK" happens to be zero, so it does not matter + // unless you want something else (like MENU_CLOSE) +} + +int Contrast_func(int input) +{ + if(input == MENU_READ) return status; + if(input == MENU_PLUS) increment_status(); // does something. + if(input == MENU_MINUS) decrement_status();// does something. + return (status | MENU_OK); +} + +===================================================================== + +Function return values: + MENU_OK Keeps menu open. + MENU_CLOSE Closes menu after item is picked. + Leaves the parent menus open. + MENU_QUIT Closes all menus after item is picked. + Like a normal pulldown menu. + MENU_KILL Same as MENU_QUIT, so far. + MENU_ERROR Um, for errors? :) + +Also, functions for sliders and checkboxes should return a status value +binary OR-ed with the MENU_ return value. Checkboxes should return 0 or 1, +and sliders should return 0-255. + +**************************************************************************/ +#endif + + +// Return codes from selected menu items... +#define MENU_ERROR -0x7FFF0000 +#define MENU_OK 0 +#define MENU_CLOSE 0x10000 +#define MENU_QUIT 0x20000 +#define MENU_KILL 0x20000 + +// Menu item Types... +#define TYPE_TITL 0 +#define TYPE_MENU 1 +#define TYPE_FUNC 2 +#define TYPE_CHEK 3 +#define TYPE_SLID 4 +#define TYPE_MOVE 5 + +#define CLIENT_MENU 0x100 +#define CLIENT_FUNC 0x101 +#define CLIENT_CHEK 0x102 +#define CLIENT_SLID 0x103 +#define CLIENT_MOVE 0x104 + +// User actions, sent to item-handling functions as input. +#define MENU_SELECT 1 +#define MENU_CHECK 2 +#define MENU_PLUS 3 +#define MENU_MINUS 4 +#define MENU_READ 5 + + +typedef struct menu_item +{ + char *text; + int type; + void *data; +} menu_item; + + +#define Menu menu_item * + + +int do_menu(Menu menu); + + +#endif diff --git a/server/menus.c b/server/menus.c new file mode 100644 index 0000000..e99beae --- /dev/null +++ b/server/menus.c @@ -0,0 +1,339 @@ +/* + menus.c + + Defines the default menus the server provides. Also includes the + plug-in functions attached to menu items... + + So far, all menus are static, and not dynamically generated. I'll + have to find a way to fix this, since many menu items will be dynamic. + (clients connected, screens available, etc...) + + */ + + +#include +#include +#include + +#include "../shared/debug.h" + +#include "drivers/lcd.h" + +#include "main.h" +#include "menus.h" +#include "render.h" +#include "serverscreens.h" + + +int Shutdown_func(); +int System_halt_func(); +int Reboot_func(); +int Close_func(); +int OK_func(); +int Time24_func(int input); +int Heartbeat_func(int input); +int Backlight_func(int input); +int Server_screen_func(int input); +int Contrast_func(int input); +int Backlight_Brightness_func(int input); +int Backlight_Off_Brightness_func(int input); +int Backlight_Off_func(); +int Backlight_On_func(); +int Backlight_Open_func(); + + +menu_item main_menu[] = { + { "LCDproc", 0, 0 },// Title + { "Options", TYPE_MENU, (void *)options_menu}, + { "Screens", TYPE_MENU, (void *)screens_menu}, + { "Shutdown", TYPE_MENU, (void *)shutdown_menu }, + { 0, 0, 0 }, + +}; + +menu_item options_menu[] = { + { "OPTIONS", TYPE_TITL, 0}, // Title +// "24-hour Time", TYPE_CHEK, (void *)Time24_func, + { "Contrast...", TYPE_SLID, (void *)Contrast_func}, + { "Backlight", TYPE_MENU, (void *)Backlight_menu}, + { "Heartbeat", TYPE_CHEK, (void *)Heartbeat_func}, +// { "Backlight...", TYPE_SLID, (void *)Backlight_func}, +// "OK", TYPE_FUNC, (void *)OK_func, +// "Close Menu", TYPE_FUNC, (void *)Close_func, +// "Exit Program", TYPE_FUNC, (void *)Shutdown_func, +// "Another Title",TYPE_TITL, 0, +// "Main menu?", TYPE_MENU, (void *)main_menu, +// "Nothing!", TYPE_FUNC, 0, + { 0, 0, 0}, +}; + +menu_item screens_menu[] = { + { "SCREENS", TYPE_TITL, 0}, // Title + { "Server Scr",TYPE_CHEK, (void *)Server_screen_func}, + { 0, 0, 0}, +}; + +menu_item shutdown_menu[] = { + { "Shut Down...", TYPE_TITL, 0}, // Title + { "Kill LCDproc", TYPE_FUNC, (void *)Shutdown_func}, + { "System halt", TYPE_FUNC, (void *)System_halt_func}, + { "Reboot", TYPE_FUNC, (void *)Reboot_func}, + { 0, 0, 0}, +}; + +menu_item Backlight_menu[] = { + { "BACKLIGHT MENU", TYPE_TITL, 0}, // Title + { "Brightness...", TYPE_SLID, (void *)Backlight_Brightness_func}, + { "\"Off\" Brightness", TYPE_SLID, (void *)Backlight_Off_Brightness_func}, + { "Backlight Mode:", TYPE_FUNC, 0}, // Label + { " - Off", TYPE_FUNC, Backlight_Off_func}, + { " - On", TYPE_FUNC, Backlight_On_func}, + { " - Open", TYPE_FUNC, Backlight_Open_func}, + { 0, 0, 0}, +}; + + + +/////////////////////////////////////////////////////////////////////// +// Plug-in functions for menu items +// + +// Exits the program. +int Shutdown_func() +{ + exit_program(0); + + return MENU_KILL; +} + +// Shuts down the system, if possible +int System_halt_func() +{ + int err; + uid_t id; + + id = geteuid(); + + err = system("init 0"); + + if(err < 0) return MENU_KILL; + if(err == 127) return MENU_KILL; + + // If we're root, exit + if(id == 0) exit_program(0); + + // Otherwise, assume shutdown will fail; and show more stats. + return MENU_KILL; +} + +// Shuts down the system and restarts it +int Reboot_func() +{ + int err; + uid_t id; + + id = geteuid(); + + err = system("init 6"); + + if(err < 0) return MENU_KILL; + if(err == 127) return MENU_KILL; + + // If we're root, exit + if(id == 0) exit_program(0); + + // Otherwise, assume shutdown will fail; and show more stats. + return MENU_KILL; +} + +int Close_func() +{ + return MENU_CLOSE; +} + +int OK_func() +{ + return MENU_OK; +} + + +int Time24_func(int input) +{ + static int status=0; + + if(input == MENU_READ) return status; + if(input == MENU_CHECK) status ^= 1; // does something. + return (status | MENU_OK); + // The status is "or"-ed with the MENU value to let do_menu() + // know what to do after selecting the item. (two return + // values in one. :) + + // Also, "MENU_OK" happens to be zero, so it does not matter + // unless you want something else (like MENU_CLOSE) +} + +int Heartbeat_func(int input) +{ + if(input == MENU_READ) return (heartbeat != HEART_OFF); + if(input == MENU_CHECK) + { + if(heartbeat) heartbeat = HEART_OFF; + else heartbeat = HEART_OPEN; + } + return ((heartbeat != HEART_OFF) | MENU_OK); +} + +int Backlight_func(int input) +{ + int status = 128; + + switch(backlight) + { + case BACKLIGHT_OFF: + if(input == MENU_READ) status = 0; + if(input == MENU_PLUS) + { + backlight = BACKLIGHT_OPEN; + status = 128; + } + if(input == MENU_MINUS) + { + status = 0; + } + break; + case BACKLIGHT_ON: + if(input == MENU_READ) status = 255; + if(input == MENU_PLUS) + { + status = 255; + } + if(input == MENU_MINUS) + { + backlight = BACKLIGHT_OPEN; + status = 128; + } + break; + case BACKLIGHT_OPEN: + if(input == MENU_READ) status = 128; + if(input == MENU_PLUS) + { + backlight = BACKLIGHT_ON; + backlight_state = BACKLIGHT_ON; + status = 255; + } + if(input == MENU_MINUS) + { + backlight = BACKLIGHT_OFF; + backlight_state = BACKLIGHT_OFF; + status = 0; + } + break; + } + + /* + if(input == MENU_READ) return (backlight != BACKLIGHT_OFF); + if(input == MENU_CHECK) + { + if(backlight) backlight = BACKLIGHT_OFF; + else backlight = BACKLIGHT_OPEN; + } + */ + lcd.backlight(backlight_state & BACKLIGHT_ON); + + return (status | MENU_OK); +} + +int Server_screen_func(int input) +{ + if(input == MENU_READ) return (server_screen->priority < 256); + if(input == MENU_CHECK) + { + if(server_screen->priority < 256) server_screen->priority = 256; + else server_screen->priority = 128; + } + + return (MENU_OK | (server_screen->priority < 256)); +} + +int Contrast_func(int input) +{ + int status; + + status=lcd.contrast(-1); + + if(input == MENU_READ) return status; + if(input == MENU_PLUS) status+=5; // does something. + if(input == MENU_MINUS) status-=5; // does something. + + if(status<0) status=0; + if(status>255) status=255; + lcd.contrast(status); + + return (status | MENU_OK); +} + + +void server_menu() +{ + debug("server_menu()\n"); + + do_menu(main_menu); + +} + +int Backlight_Brightness_func(int input) +{ + int status = backlight_brightness; + + if(input == MENU_READ) return status; + if(input == MENU_PLUS) status+=5; // does something. + if(input == MENU_MINUS) status-=5; // does something. + + if(status<0) status=0; + if(status>255) status=255; + lcd.backlight(status); + + backlight_brightness = status; + + return (status | MENU_OK); +} + +int Backlight_Off_Brightness_func(int input) +{ + int status = backlight_off_brightness; + + if(input == MENU_READ) return status; + if(input == MENU_PLUS) status+=5; // does something. + if(input == MENU_MINUS) status-=5; // does something. + + if(status<0) status=0; + if(status>255) status=255; + lcd.backlight(status); + + backlight_off_brightness = status; + + return (status | MENU_OK); +} + +int Backlight_Off_func() +{ + backlight_state = BACKLIGHT_OFF; + backlight = BACKLIGHT_OFF; + lcd.backlight(backlight_off_brightness); + return MENU_OK; +} + +int Backlight_On_func() +{ + backlight_state = BACKLIGHT_ON; + backlight = BACKLIGHT_ON; + lcd.backlight(backlight_brightness * (backlight_state & BACKLIGHT_ON)); + return MENU_OK; +} + +int Backlight_Open_func() +{ + backlight = BACKLIGHT_OPEN; + return MENU_OK; +} + diff --git a/server/menus.h b/server/menus.h new file mode 100644 index 0000000..1d70c27 --- /dev/null +++ b/server/menus.h @@ -0,0 +1,16 @@ +#ifndef MENUS_H +#define MENUS_H + +#include "menu.h" + +// These probably don't need to be defined here... +extern menu_item main_menu[]; +extern menu_item options_menu[]; +extern menu_item screens_menu[]; +extern menu_item shutdown_menu[]; +extern menu_item Backlight_menu[]; + +// Brings up the main menu... +void server_menu(); + +#endif diff --git a/server/parse.c b/server/parse.c new file mode 100644 index 0000000..4f2c0e5 --- /dev/null +++ b/server/parse.c @@ -0,0 +1,148 @@ +/* + parse.c + + Handles input commands from clients, by splitting strings into tokens + and passing arguments to the appropriate handler. + + It works much like a command line. Only the first token is used to + determine what function to call. + + */ + + +#include +#include +#include + +#include "../shared/LL.h" +#include "../shared/sockets.h" +#include "../shared/debug.h" +#include "clients.h" +#include "client_functions.h" +#include "parse.h" + + + +int parse_all_client_messages() +{ + int i, j; + int newtoken, inquote; + client *c; + char *str; +// char *tok; + int argc; + char *argv[256]; + char delimiters[] = " \0"; + char leftquote[] = "\0\"'`([{\0"; + char rightquote[] = "\0\"'`)]}\0"; + char errmsg[256]; + int invalid=0; + + //debug("parse: Rewinding list...\n"); + LL_Rewind(clients); + do { + // Get the next client... + //debug("parse: Getting client...\n"); + c = LL_Get(clients); + if(c) + { + // And parse all its messages... + //debug("parse: Getting messages...\n"); + for(str = client_get_message(c); str; str = client_get_message(c)) + { + debug("parse: ...%s\n", str); + // Now, split up the string... + //len = strlen(str); + argc=0; + newtoken=1; + inquote=0; + for(i=0; str[i]; i++) + { + if(inquote) // Scan for the end of the quote + { + if(str[i] == rightquote[inquote]) + { // Found the end of the quote + inquote=0; + str[i] = 0; + newtoken=1; + } + } + else // Normal operation; split at delimiters + { + for(j=1; leftquote[j]; j++) + { + // Found the beginning of a new quote... + if(str[i] == leftquote[j]) + { + inquote = j; + str[i] = 0; + continue; + } + } + for(j=0; delimiters[j]; j++) + { + // Break into a new string... + if(str[i] == delimiters[j]) + { + str[i] = 0; + newtoken = 1; + continue; + } + } + } + if(newtoken && str[i]) + { + newtoken=0; + argv[argc] = str + i; + argc++; + } + else + { + } + } + if(inquote) + { + sprintf(errmsg, "huh? Unterminated string: missing %c\n", + rightquote[inquote]); + sock_send_string(c->sock, errmsg); + continue; + } +/* + for(tok = strtok(str, delimiters); + tok; + tok=strtok(NULL, delimiters)) + { + argv[argc] = tok; + argc++; + } +*/ + argv[argc] = NULL; + if(argc < 1) continue; + + // Now find and call the appropriate function... +// debug("parse: Finding function...\n"); + invalid = 1; + for(i=0; commands[i].keyword; i++) + { +// debug("(checking %s)\n", commands[i].keyword); + if(0 == strcmp(argv[0], commands[i].keyword)) + { +// debug("(FOUND %s)\n", commands[i].keyword); + invalid = commands[i].function(c, argc, argv); +// debug("parse: Returned %i...\n", err); + } + } + if(invalid) + { + // FIXME: Check for buffer overflows here... + sprintf(errmsg, "huh? Invalid command \"%s\"\n", argv[0]); + sock_send_string(c->sock, errmsg); + } + + free(str); // fixed memory leak? + } // end for(str...) + } // end if (c) + } while (LL_Next(clients) == 0); + + return 0; +} diff --git a/server/parse.h b/server/parse.h new file mode 100644 index 0000000..97bab26 --- /dev/null +++ b/server/parse.h @@ -0,0 +1,7 @@ +#ifndef PARSE_H +#define PARSE_H + +// This should be pretty self-explanatory... +int parse_all_client_messages(); + +#endif diff --git a/server/render.c b/server/render.c new file mode 100644 index 0000000..5235743 --- /dev/null +++ b/server/render.c @@ -0,0 +1,526 @@ +/* + render.c + + Draws screens on the LCD. + + This needs to be greatly expanded and redone for greater flexibility. + For example, it should support multiple screen sizes, more flexible + widgets, and multiple simultaneous screens. + + This will probably take a while to do. :( + + + THIS FILE IS MESSY! Anyone care to rewrite it nicely? Please?? :) + + */ + + +#include +#include + +#include "../shared/debug.h" +#include "../shared/LL.h" + +#include "drivers/lcd.h" + +#include "screen.h" +#include "screenlist.h" +#include "widget.h" +#include "render.h" + + + +int heartbeat=HEART_OPEN; +int backlight=BACKLIGHT_OPEN; +int backlight_state = BACKLIGHT_OPEN; +int backlight_brightness=255; +int backlight_off_brightness=0; +int output_state = 0; + +static int reset; + +#define BUFSIZE 1024 + +static int draw_frame(LL *list, char fscroll, + int left, int top, int right, int bottom, + int fwid, int fhgt, + int fspeed, int timer); + + +int draw_screen(screen *s, int timer) +{ + static screen *old_s=NULL; + int tmp=0; + + //debug("Render...\n"); + //return 0; + + reset = 1; + + //debug("draw_screen: %8x, %i\n", (int)s, timer); + + if(!s) return -1; + + if(s == old_s) reset = 0; + old_s = s; + + + + lcd.clear(); + + + switch(backlight_state) + { + case BACKLIGHT_OFF: + lcd.backlight(backlight_off_brightness); + break; + case BACKLIGHT_ON: + lcd.backlight(backlight_brightness); + break; + default: + if(backlight_state & BACKLIGHT_FLASH) + { + tmp = (!((timer&7) == 7)); + if(backlight_state & 1) + lcd.backlight(tmp?backlight_brightness:backlight_off_brightness); + //lcd.backlight(backlight_brightness * (!((timer&7) == 7))); + else + lcd.backlight(!tmp?backlight_brightness:backlight_off_brightness); + //lcd.backlight(backlight_brightness * ((timer&7) == 7)); + } + else if(backlight_state & BACKLIGHT_BLINK) + { + tmp = (!((timer&14) == 14)); + if(backlight_state & 1) + lcd.backlight(tmp?backlight_brightness:backlight_off_brightness); + //lcd.backlight(backlight_brightness * (!((timer&14) == 14))); + else + lcd.backlight(!tmp?backlight_brightness:backlight_off_brightness); + //lcd.backlight(backlight_brightness * ((timer&14) == 14)); + } + break; + } + + lcd.output(output_state); + + draw_frame(s->widgets, 'v', + 0, 0, lcd.wid, lcd.hgt, + s->wid, s->hgt, + s->duration/s->hgt, timer); + + + //debug("draw_screen done\n"); + + + if(heartbeat) + { + if(s->heartbeat || heartbeat == HEART_ON) + { + // Set this to pulsate like a real heart beat... + // (binary is fun... :) + lcd.icon(!((timer+4)&5), 0); + lcd.chr(lcd.wid, 1, 0); + } + } + + lcd.flush(); + + //debug("draw_screen: %8x, %i\n", s, timer); + + return 0; + +} + +static int draw_frame(LL *list, char fscroll, + int left, int top, int right, int bottom, + int fwid, int fhgt, + int fspeed, int timer) +{ + char str[BUFSIZE]; // scratch buffer + widget *w; + + int wid, hgt; // Width and height of visible frame area + int x, y; + int fx, fy; // Scrolling offset for the frame... + int length, speed; + //int lines; + + int reset = 1; + + wid = right - left; // This is the size of the visible frame area + hgt = bottom - top; + + fx = 0; + fy = 0; + if(fscroll == 'v') + { + + if(fspeed > 0) + fy = (timer-fspeed) / fspeed; + if(fspeed < 0) + fy = (-fspeed) * timer; + if(fy < 0) fy = 0; + + // Make sure the whole frame gets displayed, at least... + if(!screenlist_action) screenlist_action = RENDER_HOLD; + if((fy) > fhgt - 1) + { + // Release hold after it has been displayed + if(!screenlist_action || screenlist_action == RENDER_HOLD) + screenlist_action = 0; + } + + fy %= fhgt; + if(fy > fhgt - hgt) fy = fhgt - hgt; + } + else if (fscroll == 'h') + { // TODO: Frames don't scroll horizontally yet! + + } + + //debug("draw_screen: %8x, %i\n", s, timer); + + if(!list) return -1; + + //debug("draw_frame: %8x, %i\n", frame, timer); + + + + LL_Rewind(list); + do { + w = (widget *)LL_Get(list); + if(!w) return -1; + + // TODO: Make this cleaner and more flexible! + switch(w->type) + { + case WID_STRING: + if((w->x > 0) && (w->y > 0) && (w->text)) + { + if((w->y <= hgt + fy) && + (w->y > fy)) + { + strncpy(str, w->text, wid - w->x + 1); + str[wid - w->x + 1] = 0; + lcd.string(w->x + left, + w->y + top - fy, + str); + } + } + break; + case WID_HBAR: + if(reset) + { + lcd.init_hbar(); + reset = 0; + } + if((w->x > 0) && (w->y > 0)) + { + if((w->y <= hgt + fy) && + (w->y > fy)) + { + if(w->length > 0) + { + if((w->length / lcd.cellwid) < wid - w->x + 1) + lcd.hbar(w->x + left, + w->y + top - fy, + w->length); + else + lcd.hbar(w->x + left, + w->y + top - fy, + wid * lcd.cellwid); + } + else if(w->length < 0) + { + // TODO: Rearrange stuff to get left-extending + // hbars to draw correctly... + // .. er, this'll require driver modifications, + // so I'll leave it out for now. + } + } + } + break; + case WID_VBAR: // FIXME: Vbars don't work in frames! + if(reset) + { + lcd.init_vbar(); + reset = 0; + } + if((w->x > 0) && (w->y > 0)) + { + if(w->length > 0) + { + lcd.vbar(w->x, w->length); + } + else if(w->length < 0) + { + // TODO: Rearrange stuff to get down-extending + // vbars to draw correctly... + // .. er, this'll require driver modifications, + // so I'll leave it out for now. + } + } + break; + case WID_ICON: // FIXME: Not implemented + break; + case WID_TITLE: // FIXME: Doesn't work quite right in frames... + if(!w->text) break; + if(wid < 8) break; + + memset(str, 255, wid); + str[2] = ' '; + length = strlen(w->text); + if(length <= wid-6) + { + memcpy(str+3, w->text, length); + str[length+3] = ' '; + } + else // Scroll the title, if it doesn't fit... + { + speed = 1; + x = timer / speed; + y = x / length; + + // Make sure the whole title gets displayed, at least... + if(!screenlist_action) screenlist_action = RENDER_HOLD; + if(x > length - 6) + { + // Release hold after it has been displayed + if(!screenlist_action || screenlist_action == RENDER_HOLD) + screenlist_action = 0; + } + x %= (length); + x -= 3; + if(x < 0) x = 0; + if(x > length - (wid-6)) x = length - (wid-6); + + if(y&1) // Scrolling backwards... + { + x = (length-(wid-6)) - x; + } + strncpy(str+3, w->text+x, (wid-6)); + str[wid-3] = ' '; + } + str[wid] = 0; + + lcd.string(1 + left, 1 + top, str); + break; + case WID_SCROLLER: // FIXME: doesn't work in frames... + { + int offset; + int screen_width; + if (!w->text) break; + if (w->right < w->left) break; + //printf("rendering: %s %d\n",w->text,timer); + screen_width = w->right - w->left + 1; + switch (w->length) + { // actually, direction... + // FIXED: Horz scrollers don't show the + // last letter in the string... (1-off error?) + case 'h': + length = strlen(w->text) + 1; + if (length <= screen_width) + { + /* it fits within the box, just render it */ + lcd.string(w->left,w->top,w->text); + } + else + { + int effLength = length - screen_width; + int necessaryTimeUnits = 0; + if (!screenlist_action) screenlist_action = RENDER_HOLD; + if (w->speed > 0) { + necessaryTimeUnits = effLength * w->speed; + if (((timer / (effLength*w->speed)) % 2) == 0) { + //wiggle one way + offset = (timer % (effLength*w->speed)) + / w->speed; + } + else + { + //wiggle the other + offset = (((timer % (effLength*w->speed)) + - (effLength*w->speed) + 1) + / w->speed) * -1; + } + } + else if (w->speed < 0) + { + necessaryTimeUnits = effLength / (w->speed * -1); + if (((timer / (effLength/(w->speed*-1))) % 2) == 0) + { + offset = (timer % (effLength/(w->speed*-1))) + * w->speed * -1; + } + else + { + offset = (((timer % (effLength/(w->speed*-1))) + * w->speed * -1) - effLength + 1) * -1; + } + } + else + { + offset = 0; + if(screenlist_action == RENDER_HOLD) + screenlist_action = 0; + } + if (timer > necessaryTimeUnits) + { + if(screenlist_action == RENDER_HOLD) + screenlist_action = 0; + } + if (offset <= length) + { + strncpy(str,&((w->text)[offset]),screen_width); + str[screen_width] = '\0'; + //printf("%s : %d\n",str,length-offset); + } + else + { + str[0] = '\0'; + } + lcd.string(w->left,w->top,str); + } + break; + // FIXME: Vert scrollers don't always seem to scroll + // back up after hitting the bottom. They jump back to + // the top instead... (nevermind?) + case 'v': + { + int i=0; + length = strlen(w->text); + if (length <= screen_width) + { + /* no scrolling required...*/ + lcd.string(w->left,w->top,w->text); + } + else + { + int lines_required = + (length / screen_width) + + (length % screen_width ? 1 : 0); + int available_lines = (w->bottom - w->top + 1); + if (lines_required <= available_lines) + { + // easy... + for(i=0;itext)[i*screen_width]), + screen_width); + str[screen_width] = '\0'; + lcd.string(w->left,w->top + i,str); + } + } + else + { + int necessaryTimeUnits = 0; + int effLines = lines_required - available_lines + 1; + int begin = 0; + if (!screenlist_action) + screenlist_action = RENDER_HOLD; + //printf("length: %d sw: %d lines req: %d avail lines: %d effLines: %d \n",length,screen_width,lines_required,available_lines,effLines); + if (w->speed > 0) + { + necessaryTimeUnits = effLines * w->speed; + if (((timer / (effLines*w->speed)) % 2) == 0) + { + //printf("up "); + begin = (timer % (effLines*w->speed)) + / w->speed; + } + else + { + //printf("down "); + begin = (((timer % (effLines*w->speed)) + - (effLines*w->speed) + 1)/w->speed) + * -1; + } + } + else if (w->speed < 0) + { + necessaryTimeUnits = effLines / (w->speed * -1); + if (((timer / (effLines/(w->speed*-1))) % 2) == 0) + { + begin = (timer % (effLines/(w->speed*-1))) + * w->speed * -1; + } + else + { + begin = (((timer % (effLines/(w->speed*-1))) + * w->speed * -1) - effLines + 1) + * -1; + } + } + else + { + begin = 0; + } + //printf("rendering begin: %d timer: %d effLines: %d\n",begin,timer,effLines); + for(i=begin;itext)[i*(screen_width)]), + screen_width); + str[screen_width] = '\0'; + //printf("rendering: '%s' of %s\n", + //str,w->text); + lcd.string(w->left,w->top + (i-begin),str); + } + if (timer > necessaryTimeUnits) + { + if(screenlist_action == RENDER_HOLD) + screenlist_action = 0; + } + } + } + break; + } + } + break; + } + case WID_FRAME: + { + // FIXME: doesn't handle nested frames quite right! + // doesn't handle scrolling in nested frames at all... + int new_left, new_top, new_right, new_bottom; + new_left = left + w->left - 1; + new_top = top + w->top - 1; + new_right = left + w->right; + new_bottom = top + w->bottom; + if(new_right > right) new_right = right; + if(new_bottom > bottom) new_bottom = bottom; + if(new_left >= right || + new_top >= bottom) + { // Do nothing if it's invisible... + } + else + { + draw_frame(w->kids, w->length, + new_left, new_top, new_right, new_bottom, + w->wid, w->hgt, + w->speed, timer); + } + } + break; + case WID_NUM: // FIXME: doesn't work in frames... + if((w->x > 0) && (w->y >= 0) && (w->y <= 9)) + { + if(reset) + { + lcd.init_num(); + reset = 0; + } + lcd.num(w->x + left, w->y); + } + break; + case WID_NONE: + default: + break; + } + } while(LL_Next(list) == 0); + + + return 0; +} + diff --git a/server/render.h b/server/render.h new file mode 100644 index 0000000..36e8d2d --- /dev/null +++ b/server/render.h @@ -0,0 +1,29 @@ +#ifndef RENDER_H +#define RENDER_H + +#include "screen.h" + + +#define HEART_OFF 0 +#define HEART_ON 1 +#define HEART_OPEN 2 + +#define BACKLIGHT_OFF 0 +#define BACKLIGHT_ON 1 +#define BACKLIGHT_OPEN 2 +#define BACKLIGHT_LOAD 3 +#define BACKLIGHT_VIS 4 + +#define BACKLIGHT_BLINK 0x100 +#define BACKLIGHT_FLASH 0x200 + +extern int heartbeat; +extern int backlight; +extern int backlight_state; +extern int backlight_brightness; +extern int backlight_off_brightness; +extern int output_state; +int draw_screen(screen *s, int timer); + + +#endif diff --git a/server/screen.c b/server/screen.c new file mode 100644 index 0000000..15ba5c5 --- /dev/null +++ b/server/screen.c @@ -0,0 +1,171 @@ +#include +#include +#include + +#include "../shared/debug.h" + +#include "drivers/lcd.h" + +#include "clients.h" +#include "client_data.h" +#include "widget.h" +#include "screenlist.h" +#include "screen.h" + + +screen * screen_create() +{ + screen *s; + + s = malloc(sizeof(screen)); + if(!s) + { + fprintf(stderr, "screen_create: Error allocating new screen\n"); + return NULL; + } + + s->id=NULL; + s->name=NULL; + s->priority=128; + // TODO: Make the screen duration configurable! + s->duration = 32; + s->heartbeat = 1; + s->wid = lcd.wid; + s->hgt = lcd.hgt; + s->parent = NULL; + s->widgets=NULL; + + s->widgets = LL_new(); + if(!s->widgets) + { + fprintf(stderr, "screen_create: Error allocating widget list\n"); + return NULL; + } + + return s; +} + +int screen_destroy(screen *s) +{ + widget *w; + + if(!s) return -1; + + LL_Rewind(s->widgets); + do { + // Free a widget... + w = LL_Get(s->widgets); + widget_destroy(w); + } while (LL_Next(s->widgets) == 0); + LL_Destroy(s->widgets); + + + if(s->id) + free(s->id); + if(s->name) + free(s->name); + + free(s); + + return 0; +} + + +screen *screen_find(client *c, char *id) +{ + screen *s; + + if(!c) return NULL; + if(!id) return NULL; + + debug("client_find_screen(%s)\n", id); + + LL_Rewind(c->data->screenlist); + do { + s = LL_Get(c->data->screenlist); + if( (s) && (0 == strcmp(s->id, id))) + { + debug("client_find_screen: Found %s\n", id); + return s; + } + } while(LL_Next(c->data->screenlist) == 0); + + return NULL; +} + + +int screen_add(client *c, char *id) +{ + screen *s; + + if(!c) return -1; + if(!id) return -1; + + // Make sure this screen doesn't already exist... + s = screen_find(c, id); + if(s) + { + return 1; + } + + s = screen_create(); + if(!s) + { + fprintf(stderr, "screen_add: Error creating screen\n"); + return -1; + } + + s->parent = c; + + s->id = strdup(id); + if(!s->id) + { + fprintf(stderr, "screen_add: Error allocating name\n"); + return -1; + } + + // TODO: Check for errors here? + LL_Push(c->data->screenlist, (void *)s); + + + // Now, add it to the screenlist... + if(screenlist_add(s) < 0) + { + fprintf(stderr, "screen_add: Error queueing new screen\n"); + return -1; + } + + return 0; +} + +int screen_remove(client *c, char *id) +{ + screen *s; + + if(!c) return -1; + if(!id) return -1; + + // Make sure this screen *does* exist... + s = screen_find(c, id); + if(!s) + { + fprintf(stderr, "screen_remove: Error finding screen %s\n", id); + return 1; + } + + // TODO: Check for errors here? + LL_Remove(c->data->screenlist, (void *)s); + + // ... and here? + screen_destroy(s); + + // Now, remove it from the screenlist... + if(screenlist_remove_all(s) < 0) + { + // Not a serious error.. + fprintf(stderr, "screen_remove: Error dequeueing screen\n"); + return 0; + } + + return 0; +} diff --git a/server/screen.h b/server/screen.h new file mode 100644 index 0000000..1d64060 --- /dev/null +++ b/server/screen.h @@ -0,0 +1,29 @@ +#ifndef SCREEN_H +#define SCREEN_H + +#include "../shared/LL.h" +#include "clients.h" + +typedef struct screen +{ + char *id; + char *name; + int wid, hgt; + int priority; + int duration; + int heartbeat; + LL * widgets; + client *parent; +} screen; + + +screen * screen_create(); +int screen_destroy(screen *s); + +screen * screen_find(client *c, char *id); + +int screen_add(client *c, char *id); +int screen_remove(client *c, char *id); + + +#endif diff --git a/server/screenlist.c b/server/screenlist.c new file mode 100644 index 0000000..1df65b7 --- /dev/null +++ b/server/screenlist.c @@ -0,0 +1,273 @@ +#include +#include + +#include "../shared/LL.h" +#include "../shared/sockets.h" +#include "../shared/debug.h" +#include "screenlist.h" +#include "screen.h" +#include "clients.h" + + + +int screenlist_action=0; + +int timer=0; + +LL * screenlist; + + +int screenlist_add_end(screen *screen); +screen * screenlist_next_roll(); +screen * screenlist_prev_roll(); +screen * screenlist_next_priority(); + +int compare_priority(void *one, void *two); +int compare_addresses(void *one, void *two); + + +int screenlist_init() +{ + debug("screenlist_init()\n"); + + screenlist = LL_new(); + if(!screenlist) + { + fprintf(stderr, "screenlist_init: Error allocating list\n"); + return -1; + } + + screenlist_action = 0; + timer = 0; + + return 0; +} + +int screenlist_shutdown() +{ + debug("screenlist_shutdown()\n"); + + LL_Destroy(screenlist); + + return 0; +} + +int screenlist_remove(screen *s) +{ + debug("screenlist_remove()\n"); + + if(!LL_Remove(screenlist, s)) + return -1; + else return 0; +} + +int screenlist_remove_all(screen *s) +{ + int i=0; + + debug("screenlist_remove_all()\n"); + + while(LL_Remove(screenlist, s)) + i++; + + debug("screenlist_remove_all()... got %i\n", i); + + return i; +} + +LL * screenlist_getlist() +{ + debug("screenlist_getlist()\n"); + + return screenlist; +} + +screen * screenlist_current() +{ + char str[256]; + screen *s; + static screen *old_s = NULL; + client *c; + + + //debug("screenlist_current:\n"); + //LL_dprint(screenlist); + + + s = (screen *)LL_GetFirst(screenlist); + + // FIXME: Make sure the screen/client exists! + if(s != old_s) + { + debug("screenlist_current: new screen\n"); + timer = 0; + + // Tell the client we're done with the current screen + if(old_s) + { + //debug("screenlist_current: ignoring old screen\n"); + LL_Rewind(screenlist); + if(old_s != LL_Find(screenlist, compare_addresses, old_s)) + { + debug("screenlist: Didn't find screen 0x%8x!\n", (int)old_s); + } + else { + //debug("screenlist_current: ... sending ignore\n"); + c = old_s->parent; + if(c) // Tell the client we're not listening any more... + { + sprintf(str, "ignore %s\n", old_s->id); + sock_send_string(c->sock, str); + } + else // The server has the display, so do nothing + { + } + //debug("screenlist_current: ... sent ignore\n"); + } + } + if(s) + { + //debug("screenlist_current: listening to new screen\n"); + c = s->parent; + if(c) // Tell the client we're paying attention... + { + sprintf(str, "listen %s\n", s->id); + sock_send_string(c->sock, str); + } + else // The server has the display, so do nothing + { + } + } + } + + + + old_s = s; + + //debug("screenlist_current: return %8x\n", s); + + return s; +} + +int screenlist_add(screen *s) +{ + // TODO: Different queueing modes... + return screenlist_add_end(s); +} + +screen * screenlist_next() +{ + screen *s; + + //debug("Screenlist_next()\n"); + + s = screenlist_current(); + + // If we're on hold, don't advance! + if(screenlist_action == SCR_HOLD) return s; + if(screenlist_action == RENDER_HOLD) return s; + + // Otherwise, reset it to regular operation + screenlist_action = 0; + + + //debug("Screenlist_next: calling handler...\n"); + + // Call the selected queuing function... + // TODO: Different queueing modes... + s = screenlist_next_priority(); + //s = screenlist_next_roll(); + + //debug("Screenlist_next() done\n"); + + return s; +} + +screen * screenlist_prev() +{ + screen *s; + + s = screenlist_current(); + + // If we're on hold, don't advance! + if(screenlist_action == SCR_HOLD) return s; + if(screenlist_action == RENDER_HOLD) return s; + + // Otherwise, reset it no regular operation + screenlist_action = 0; + + + // Call the selected queuing function... + // TODO: Different queueing modes... + s = screenlist_prev_roll(); + + return s; +} + + +// Adds new screens to the end of the screenlist... +int screenlist_add_end(screen *screen) +{ + debug("screenlist_add_end()\n"); + + return LL_Push(screenlist, (void *)screen); +} + +// Simple round-robin approach to screen cycling... +screen * screenlist_next_roll() +{ + //debug("screenlist_next_roll()\n"); + + if(LL_UnRoll(screenlist) != 0) return NULL; + + return screenlist_current(); +} + +// Strict priority queue approach... +screen * screenlist_next_priority() +{ + //screen *s, *t; + //debug("screenlist_next_priority\n"); + + if(LL_UnRoll(screenlist) != 0) return NULL; + + LL_Sort(screenlist, compare_priority); + + return screenlist_current(); +} + +// Simple round-robin approach to screen cycling... +screen * screenlist_prev_roll() +{ + //debug("screenlist_prev_roll()\n"); + + if(LL_Roll(screenlist) != 0) return NULL; + + return screenlist_current(); +} + + +int compare_priority(void *one, void *two) +{ + screen *a, *b; + + //debug("compare_priority: %8x %8x\n", one, two); + + if(!one) return 0; + if(!two) return 0; + + a = (screen *)one; + b = (screen *)two; + + //debug("compare_priority: done?\n"); + + return (a->priority - b->priority); +} + +int compare_addresses(void *one, void *two) +{ + //printf("compare_addresses: 0x%x == 0x%x ???\n", one, two); + //if(one == two) printf("Yes!\n"); + //else printf("No!\n"); + return (one != two); +} diff --git a/server/screenlist.h b/server/screenlist.h new file mode 100644 index 0000000..4a2407b --- /dev/null +++ b/server/screenlist.h @@ -0,0 +1,31 @@ +#ifndef SCREENLIST_H +#define SCREENLIST_H + +#include "screen.h" + + +#define SCR_HOLD 1 +#define SCR_SKIP 2 +#define SCR_BACK 3 +#define RENDER_HOLD 11 +#define RENDER_SKIP 12 +#define RENDER_BACK 13 + +extern int screenlist_action; +extern int timer; + +int screenlist_init(); +int screenlist_shutdown(); + +LL * screenlist_getlist(); +screen * screenlist_current(); + +int screenlist_add(screen *s); +screen * screenlist_next(); +screen * screenlist_prev(); + +int screenlist_remove(screen *s); +int screenlist_remove_all(screen *s); + + +#endif diff --git a/server/serverscreens.c b/server/serverscreens.c new file mode 100644 index 0000000..e7d80c8 --- /dev/null +++ b/server/serverscreens.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include + +#include "../shared/debug.h" + +#include "drivers/lcd.h" + +#include "clients.h" +#include "screen.h" +#include "screenlist.h" +#include "widget.h" + +#include "serverscreens.h" + +screen *server_screen; +char *id = "ClientList"; +char *name = "Client List"; + +char title[256] = "LCDproc Server"; +char one[256] = ""; +char two[256] = ""; +char three[256] = ""; + +int server_screen_init() +{ + widget *w; + + debug("server_screen_init\n"); + + server_screen = screen_create(); + + if(!server_screen) + { + fprintf(stderr, "server_screen_init: Error allocating screen\n"); + return -1; + } + + server_screen->id = id; + server_screen->name = name; + server_screen->duration = 8; // 1 second, instead of 4... + + // TODO: Error-checking? + widget_add(server_screen, "title", "title", NULL, 1); + widget_add(server_screen, "one" , "string", NULL, 1); + widget_add(server_screen, "two" , "string", NULL, 1); + widget_add(server_screen, "three", "string", NULL, 1); + + + // Now, initialize all the widgets... + w = widget_find(server_screen, "title"); + if(w) + { + w->text = title; + } + else + { + fprintf(stderr, "server_screen_init: Can't find title\n"); + } + + w = widget_find(server_screen, "one"); + if(w) + { + w->x = 1; + w->y = 2; + w->text = one; + } + else + { + fprintf(stderr, "server_screen_init: Can't find widget one\n"); + } + + w = widget_find(server_screen, "two"); + if(w) + { + w->x = 1; + w->y = 3; + w->text = two; + } + else + { + fprintf(stderr, "server_screen_init: Can't find widget two\n"); + } + + w = widget_find(server_screen, "three"); + if(w) + { + w->x = 1; + w->y = 4; + w->text = three; + } + else + { + fprintf(stderr, "server_screen_init: Can't find widget three\n"); + } + + + + // And enqueue the screen + screenlist_add(server_screen); + + debug("server_screen_init done\n"); + + return 0; +} + + +int update_server_screen(int timer) +{ + client *c; + int num_clients; + screen *s; + int num_screens; + + + // Draw a title... + //strcpy(title, "LCDproc Server"); + + + // Now get info on the number of connected clients... + num_clients=0; num_screens=0; + LL_Rewind(clients); + do { + c = LL_Get(clients); + if(c) + { + num_clients++; + LL_Rewind(c->data->screenlist); + do { + s = LL_Get(c->data->screenlist); + if(s) + { + num_screens++; + } + } while(LL_Next(c->data->screenlist) == 0); + } + } while(LL_Next(clients) == 0); + + if(lcd.hgt >= 3) + { + sprintf(one, "Clients: %i", num_clients); + sprintf(two, "Screens: %i", num_screens); + } + else + { + if(lcd.wid >= 20) + sprintf(one, "%i Client%s, %i Screen%s", + num_clients, (num_clients==1)?"":"s", + num_screens, (num_screens==1)?"":"s"); + else // 16x2 size + sprintf(one, "%i Cli%s, %i Scr%s", + num_clients, (num_clients==1)?"":"s", + num_screens, (num_screens==1)?"":"s"); + } + + return 0; +} + +int no_screen_screen(int timer) +{ + + lcd.clear(); + + lcd.string(1, 1, "Error: No screen!"); + + lcd.flush(); + + return 0; +} + +int goodbye_screen() +{ + char + *b20 = " ", + *t20 = " Thanks for using ", +#ifdef LINUX + *l20 = " LCDproc and Linux! ", +#else + *l20 = " LCDproc! ", +#endif + *b16 = " ", + *t16 = "Thanks for using", +#ifdef LINUX + *l16 = " LCDproc+Linux! ", +#else + *l16 = " LCDproc! ", +#endif + *nil = ""; + + lcd.clear(); + + if(lcd.hgt >= 4) + { + if(lcd.wid >= 20) + { + lcd.string(1, 1, b20); + lcd.string(1, 2, t20); + lcd.string(1, 3, l20); + lcd.string(1, 4, b20); + } + else + { + lcd.string(1, 1, b16); + lcd.string(1, 2, t16); + lcd.string(1, 3, l16); + lcd.string(1, 4, b16); + } + } + else + { + if(lcd.wid >= 20) + { + lcd.string(1, 1, t20); + lcd.string(1, 2, l20); + } + else + { + lcd.string(1, 1, t16); + lcd.string(1, 2, l16); + } + } + + lcd.flush(); + + return 0; +} + diff --git a/server/serverscreens.h b/server/serverscreens.h new file mode 100644 index 0000000..0382490 --- /dev/null +++ b/server/serverscreens.h @@ -0,0 +1,14 @@ +#ifndef SRVSTATS_H +#define SRVSTATS_H + +#include "screen.h" + + +extern screen *server_screen; + +int server_screen_init(); +int update_server_screen(int timer); +int no_screen_screen(int timer); +int goodbye_screen(); + +#endif diff --git a/server/sock.c b/server/sock.c new file mode 100644 index 0000000..eb69b39 --- /dev/null +++ b/server/sock.c @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../shared/sockets.h" +#include "sock.h" +#include "clients.h" +#include "../shared/debug.h" + + +/************************************************** + LCDproc sockets code... + + This is messy, and needs to be finished. +**************************************************/ + +fd_set active_fd_set, read_fd_set; +int orig_sock; + +// Length of longest transmission allowed at once... +#define MAXMSG 8192 + + +int read_from_client (int filedes); + + +// Creates a socket in internet space +int sock_create_inet_socket(unsigned short int port) +{ + struct sockaddr_in name; + int sock; + + debug("sock_create_inet_socket(%i)\n", port); + + /* Create the socket. */ + //debug("Creating Inet Socket\n"); + sock = socket (PF_INET, SOCK_STREAM, 0); + if (sock < 0) + { + perror("Error creating socket"); + return -1; + } + + /* Give the socket a name. */ + //debug("Binding Inet Socket\n"); + name.sin_family = AF_INET; + name.sin_port = htons (port); + name.sin_addr.s_addr = htonl (INADDR_ANY); + if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) + { + perror("Error binding socket"); + return -1; + } + + return sock; + +} + +//int StartSocketServer() +int sock_create_server() +{ + int sock; + + debug("sock_create_server()\n"); + + /* Create the socket and set it up to accept connections. */ + sock = sock_create_inet_socket(LCDPORT); + if(sock < 0) + { + perror("sock_create_server: Error creating socket"); + return -1; + } + + + if (listen (sock, 1) < 0) + { + perror("sock_create_server: Listen error"); + return -1; + } + + /* Initialize the set of active sockets. */ + FD_ZERO (&active_fd_set); + FD_SET (sock, &active_fd_set); + + orig_sock = sock; + +/* + { + int val, len, sock; + sock = new; + + len = sizeof(int); + getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, &len); + printf("SEND buffer: %i bytes\n", val); + + len = sizeof(int); + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, &len); + printf("RECV buffer: %i bytes\n", val); + } +*/ + + return sock; +} + + +int sock_poll_clients() +{ + int i; + int err; + struct sockaddr_in clientname; + size_t size; + struct timeval t; + client *c; + + //debug("sock_poll_clients()\n"); + + t.tv_sec = 0; + t.tv_usec = 0; + + /* Block until input arrives on one or more active sockets. */ + read_fd_set = active_fd_set; + + if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, &t) < 0) + { + perror("sock_poll_clients: Select error"); + return -1; + } + + /* Service all the sockets with input pending. */ + for (i = 0; i < FD_SETSIZE; ++i) + { + if (FD_ISSET (i, &read_fd_set)) + { + if (i == orig_sock) + { + /* Connection request on original socket. */ + int new; + size = sizeof (clientname); + new = accept (orig_sock, + (struct sockaddr *) &clientname, + &size); + if (new < 0) + { + perror("sock_poll_clients: Accept error"); + return -1; + } + debug("sock_poll_clients: connect from host %s, port %hd.\n", + inet_ntoa (clientname.sin_addr), + ntohs (clientname.sin_port)); + FD_SET (new, &active_fd_set); + + fcntl(new, F_SETFL, O_NONBLOCK); + + + // TODO: Create new "client" here... (done?) + if ( client_create(new) == NULL) + { + fprintf(stderr, + "sock_poll_clients: error creating client %i\n", + i); + return -1; + } + } + else + { + /* Data arriving on an already-connected socket. */ + err = 0; + do { + debug("sock_poll_clients: reading...\n"); + err = read_from_client(i); + debug("sock_poll_clients: ...done\n"); + if (err < 0) + { + // TODO: Destroy a "client" here... (done?) + c = client_find_sock(i); + if(c) + { + //sock_send_string(i, "bye\n"); + client_destroy(c); + close (i); + FD_CLR (i, &active_fd_set); + debug("sock_poll_clients: Closed connection %i\n", i); + } + else fprintf(stderr, + "sock_poll_clients: Can't find client %i\n", + i); + } + } while (err > 0); + + } + } + } + return 0; +} + + +int read_from_client (int filedes) +{ + char buffer[MAXMSG]; + int nbytes, i; + client *c; + +// nbytes = read (filedes, buffer, MAXMSG); + //debug("read_from_client(%i): reading...\n", filedes); + nbytes = sock_recv (filedes, buffer, MAXMSG); + //debug("read_from_client(%i): ...done\n", filedes); + debug("read_from_client(%i): %i bytes\n", filedes, nbytes); + + + if (nbytes < 0) // Read error? No data available? + { + // TODO: check errno here! + //fprintf (stderr,"read_from_client: Read error\n"); + return 0; + } + else if (nbytes == 0) // EOF + return -1; + else if (nbytes > (MAXMSG - (MAXMSG / 8))) // Very noisy client... + { + sock_send_string(filedes, "huh? Shut up!\n"); + return -1; + } + else // Data Read + { + buffer[nbytes] = 0; + // Now, replace zeros with linefeeds... + for(i=0; i +#include +#include + +#include "../shared/sockets.h" +#include "../shared/debug.h" + +#include "screen.h" +#include "widget.h" + + +char *types[] = {"none", + "string", + "hbar", + "vbar", + "icon", + "title", + "scroller", + "frame", + "num", + //"", + NULL, + }; + + +static widget * widget_finder(LL *list, char *id); +static int widget_remover(LL *list, widget *w); + + +widget * widget_create() +{ + widget *w; + + debug("widget_create()\n"); + + w = malloc(sizeof(widget)); + if(!w) + { + fprintf(stderr, "widget_create: Error allocating widget\n"); + return NULL; + } + + w->id = NULL; + w->type = 0; + w->x = 1; + w->y = 1; + w->wid = 0; + w->hgt = 0; + w->left = 1; + w->top = 1; + w->right = 0; + w->bottom = 0; + w->length = 1; + w->speed = 1; + w->text = NULL; + w->kids = NULL; + + return w; +} + +int widget_destroy(widget *w) +{ + LL * list; + widget *foo; + + if(!w) return -1; + + debug("widget_destroy(%s)\n", w->id); + + if(w->id) free(w->id); + //debug("widget_destroy: id...\n"); + if(w->text) free(w->text); + //debug("widget_destroy: text...\n"); + + // TODO: Free kids! + if(w->kids) + { + list = w->kids; + LL_Rewind(list); + do { + foo = LL_Get(list); + if(foo) + widget_destroy(foo); + } while( 0 == LL_Next(list) ); + + LL_Destroy(list); + w->kids = NULL; + } + + free(w); + //debug("widget_destroy: widget...\n"); + + return 0; +} + +widget * widget_find(screen *s, char *id) +{ + //widget *w, *err; + + if(!s) return NULL; + if(!id) return NULL; + + debug("widget_find(%s)\n", id); + + return widget_finder(s->widgets, id); +/* + LL_Rewind(s->widgets); + do { + w = LL_Get(s->widgets); + if( (w) && (0 == strcmp(w->id, id))) + { + debug("widget_find: Found %s\n", id); + return w; + } + // TODO: Search kids too! + if( w->type == WID_FRAME ) + { + err = widget_finder(w->kids, id); + if(err) return err; + } + + } while(LL_Next(s->widgets) == 0); + + return NULL; +*/ +} + +widget * widget_finder(LL *list, char *id) +{ + widget *w, *err; + + if(!list) return NULL; + if(!id) return NULL; + + debug("widget_finder(%s)\n", id); + + LL_Rewind(list); + do { + //debug("widget_finder: Iteration\n"); + w = LL_Get(list); + if(w) + { + //debug("widget_finder: ...\n"); + if(0 == strcmp(w->id, id)) + { + debug("widget_finder: Found %s\n", id); + return w; + } + // Search kids recursively + //debug("widget_finder: ...\n"); + if( w->type == WID_FRAME ) + { + err = widget_finder(w->kids, id); + if(err) return err; + } + //debug("widget_finder: ...\n"); + } + + } while(LL_Next(list) == 0); + + return NULL; +} + +int widget_add(screen *s, char *id, char *type, char *in, int sock) +{ + int i; + int valid=0; + int wid_type=0; + widget *w, *parent; + LL *list; + + debug("widget_add(%s, %s, %s)\n", id, type, in); + + + if(!s) return -1; + if(!id) return -1; + + list = s->widgets; + + + if(0 == strcmp(id, "heartbeat")) + { + s->heartbeat = 1; + return 0; + } + + // Make sure this screen doesn't already exist... + w = widget_find(s, id); + if(w) + { + // already exists + sock_send_string(sock, + "huh? You already have a widget with that id#\n"); + return 1; + } + + // Make sure the container, if any, is real + if(in) + { + parent = widget_find(s, in); + if(!parent) + { + // no frame to use as parent + sock_send_string(sock, "huh? Frame doesn't exist\n"); + return 3; + } + else + { + if(parent->type == WID_FRAME) + { + list = parent->kids; + if(!list) fprintf(stderr, "widget_add: Parent has no kids\n"); + } + else + { + // no frame to use as parent + sock_send_string(sock, "huh? Not a frame\n"); + return 4; + } + } + } + + // Make sure it's a valid widget type + for(i=1; types[i]; i++) + { + if(0 == strcmp(types[i], type)) + { + valid=1; + wid_type=i; + } + } + if(!valid) + { + // invalid widget type + sock_send_string(sock, "huh? Invalid widget type\n"); + return 2; + } + + + debug("widget_add: making widget\n"); + + + // Now, make it... + w = widget_create(); + if(!w) + { + fprintf(stderr, "widget_add: Error creating widget\n"); + return -1; + } + + w->id = strdup(id); + if(!w->id) + { + fprintf(stderr, "widget_add: Error allocating id\n"); + return -1; + } + + w->type = wid_type; + + // Set up the container's widget list... + if(w->type == WID_FRAME) + { + if(!w->kids) + { + w->kids = LL_new(); + if(!w->kids) + { + fprintf(stderr, "widget_add: error allocating kids for frame\n"); + return -1; + } + } + } + + + // TODO: Check for errors here? + LL_Push(list, (void *)w); + + + return 0; +} + +int widget_remove(screen *s, char *id, int sock) +{ + widget *w; + LL *list; + + debug("widget_remove(%s)\n", id); + + if(!s) return -1; + if(!id) return -1; + + list = s->widgets; + + + if(0 == strcmp(id, "heartbeat")) + { + s->heartbeat = 0; + return 0; + } + + // Make sure this screen *does* exist... + w = widget_find(s, id); + if(!w) + { + sock_send_string(sock, + "huh? You don't have a widget with that id#\n"); + debug("widget_remove: Error finding widget %s\n", id); + return 1; + } + +/* + // TODO: Check for errors here? + // TODO: Make this work with frames... +// LL_Remove(list, (void *)w); + + + // TODO: Check for errors here? +// widget_destroy(w); +*/ + + return widget_remover(list, w); + +// return 0; +} + + +int widget_remover(LL *list, widget *w) +{ + widget *foo, *bar; + int err; + + debug("widget_remover\n"); + + if(!list) return 0; + if(!w) return 0; + + + // Search through the list... + LL_Rewind(list); + do { + // Test each item + foo = LL_Get(list); + if(foo) + { + // Frames require recursion to search and/or destroy + if(foo->type == WID_FRAME) + { + // If removing a frame, kill all its kids, too... + if(foo == w) + { + if(!foo->kids) + { + fprintf(stderr, "widget_remover: frame has no kids\n"); + } + else // Kill the kids... + { + LL_Rewind(foo->kids); + do { + bar = LL_Get(foo->kids); + err = widget_remover(foo->kids, bar); + } while(0 == LL_Next(foo->kids)); + + // Then kill the parent... + LL_Remove(list, (void *)w); + widget_destroy(w); + } + + } + else // Otherwise, search the frame recursively... + { + if(!foo->kids) + { + fprintf(stderr, "widget_remover: frame has no kids\n"); + } + else err = widget_remover(foo->kids, w); + + } + } + else // If not a frame, remove it if it matches... + { + if(foo == w) + { + LL_Remove(list, (void *)w); + widget_destroy(w); + } + } + } + } while(0 == LL_Next(list)); + + return 0; +} diff --git a/server/widget.h b/server/widget.h new file mode 100644 index 0000000..cc6e757 --- /dev/null +++ b/server/widget.h @@ -0,0 +1,45 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include "screen.h" + +typedef struct widget +{ + char *id; + int type; + // some sort of data here... + int x, y; // Position + int wid, hgt; // Size + int left, top, right, bottom; // bounding rectangle + int length; // size or direction + int speed; // For scroller... + char *text; // text or binary data + LL *kids; // Frames can contain more widgets... +} widget; + +// These correspond to the index into the "types" array... +#define WID_NONE 0 +#define WID_STRING 1 +#define WID_HBAR 2 +#define WID_VBAR 3 +#define WID_ICON 4 +#define WID_TITLE 5 +#define WID_SCROLLER 6 +#define WID_FRAME 7 +#define WID_NUM 8 + +#define WID_MAX_DIR 4 + +extern char *types[]; + + +widget * widget_create(); +int widget_destroy(widget *w); + +widget * widget_find(screen *s, char *id); + +int widget_add(screen *s, char *id, char *type, char *in, int sock); +int widget_remove(screen *s, char *id, int sock); + + +#endif diff --git a/shared/LL.c b/shared/LL.c new file mode 100644 index 0000000..aaf53a6 --- /dev/null +++ b/shared/LL.c @@ -0,0 +1,728 @@ +#include +#include +#include "LL.h" + +#ifdef DEBUG +#undef DEBUG +#endif + +//TODO: Comment everything +//TODO: Test everything? + +////////////////////////////////////////////////////////////////////// +// Creates a new list... +LL * LL_new() +{ + LL *list; + + list = malloc(sizeof(LL)); + if(!list) return NULL; + + list->head.data=NULL; + list->head.prev=NULL; + list->head.next=&list->tail; + list->tail.data=NULL; + list->tail.prev=&list->head; + list->tail.next=NULL; + list->current = &list->head; + + return list; +} + +////////////////////////////////////////////////////////////////////// +// TODO: test this function +// Destroys the entire list +// Warning! Does not free the list data! (only the list itself) +int LL_Destroy(LL *list) +{ + LL_node *node, *next; + + if(!list) return -1; + + node = &list->head; + + for(node = node->next; node && node->next; node = next) + { + // Avoid accessing "node" after it's freed.. :) + next = node->next; + if(LL_node_Destroy(node) < 0) return -1; + } + + free(list); + + return 0; +} + +////////////////////////////////////////////////////////////////////// +// TODO: test this function +// Warning! This does not assert that the node data is free! +int LL_node_Destroy(LL_node *node) +{ + if(!node) return -1; + + if(LL_node_Unlink(node) < 0) return -1; + + free(node); + + return 0; +} + +////////////////////////////////////////////////////////////////////// +int LL_node_Unlink(LL_node *node) +{ + LL_node *next, *prev; + + if(!node) return -1; + + next = node->next; + prev = node->prev; + + if(next) + next->prev = prev; + if(prev) + prev->next = next; + + node->next = NULL; + node->prev = NULL; + + return 0; +} + +////////////////////////////////////////////////////////////////////// +// Frees the data in a list node, if not NULL... +int LL_node_DestroyData(LL_node *node) +{ + if(!node) return -1; + + if(node->data) free(node->data); + else return -1; + return 0; +} + + +////////////////////////////////////////////////////////////////////// +// Returns to the beginning of the list... +int LL_Rewind(LL *list) +{ + if(!list) return -1; +/* + printf("LL_Rewind: list=%8x\n", list); + printf("LL_Rewind: list.head=%8x\n", &list->head); + printf("LL_Rewind: list.tail=%8x\n", &list->tail); +*/ + + if(list->head.next != &list->tail) + list->current = list->head.next; + else + list->current = &list->head; + + return 0; +} + +////////////////////////////////////////////////////////////////////// +// Goes to the end of the list... +int LL_End(LL *list) +{ + if(!list) return -1; + + if(list->tail.prev != &list->head) + list->current = list->tail.prev; + else + list->current = &list->tail; + + return 0; +} + +////////////////////////////////////////////////////////////////////// +// Go to the next node +int LL_Next(LL *list) +{ + if(!list) return -1; + if(!list->current) return -1; + + if(list->current->next != &list->tail) + { + list->current = list->current->next; + return 0; + } + else + { + return -1; + } +} + +////////////////////////////////////////////////////////////////////// +// Go to the previous node +int LL_Prev(LL *list) +{ + if(!list) return -1; + if(!list->current) return -1; + + if(list->current->prev != &list->head) + { + list->current = list->current->prev; + return 0; + } + else + { + return -1; + } +} + + +////////////////////////////////////////////////////////////////////// +// Data manipulation +void * LL_Get(LL *list) +{ + if(!list) return NULL; + if(!list->current) return NULL; + + return list->current->data; +} + +////////////////////////////////////////////////////////////////////// +int LL_Put(LL *list, void *data) +{ + if(!list) return -1; + if(!list->current) return -1; + + list->current->data = data; + + return 0; +} + + +////////////////////////////////////////////////////////////////////// +LL_node * LL_GetNode(LL *list) +{ + if(!list) return NULL; + + return list->current; +} + +////////////////////////////////////////////////////////////////////// +// Don't use this unless you know what you're doing. +int LL_PutNode(LL *list, LL_node *node) +{ + if(!list) return -1; + if(!node) return -1; + + list->current = node; + + return 0; +} + + +////////////////////////////////////////////////////////////////////// +void * LL_GetFirst(LL *list) // gets data from first node +{ + if(!list) return NULL; + + if(0> LL_Rewind(list)) return NULL; + + return LL_Get(list); +} + +////////////////////////////////////////////////////////////////////// +// +void * LL_GetNext (LL *list) // ... next node +{ + if(!list) return NULL; + + if(0 > LL_Next(list)) return NULL; + + return LL_Get(list); +} + +////////////////////////////////////////////////////////////////////// +void * LL_GetPrev (LL *list) // ... prev node +{ + if(!list) return NULL; + + if(0 > LL_Prev(list)) return NULL; + + return LL_Get(list); +} + +////////////////////////////////////////////////////////////////////// +void * LL_GetLast (LL *list) // ... last node +{ + if(!list) return NULL; + + if(0 > LL_End(list)) return NULL; + + return LL_Get(list); +} + +////////////////////////////////////////////////////////////////////// +int LL_AddNode(LL *list, void * add) // Adds node AFTER current one +{ + LL_node *node; + + if(!list) return -1; + //if(!add) return -1; // Nevermind.. NULL entries can be good... + if(!list->current) return -1; + + //LL_dprint(list); + + + node = malloc(sizeof(LL_node)); + if(!node) return -1; + //printf("Allocated node\n"); + +/* printf("Current: prev: %8x\tnode: %8x\tnext: %8x\n", */ +/* (int)list->current->prev, */ +/* (int)list->current, */ +/* (int)list->current->next); */ + if(list->current == &list->tail) + { + list->current = list->current->prev; +/* printf("Was at end of list...\n"); */ +/* printf("Current: prev: %8x\tnode: %8x\tnext: %8x\n", */ +/* (int)list->current->prev, */ +/* (int)list->current, */ +/* (int)list->current->next); */ + } + +// printf("Setting node data\n"); + node->next = list->current->next; + node->prev = list->current; + node->data = add; +// printf("...done\n"); +/* printf("NewNode: prev: %8x\tnode: %8x\tnext: %8x\n", */ +/* (int)node->prev, */ +/* (int)node, */ +/* (int)node->next); */ + +// printf("Relinking...\n"); + if(node->next) + node->next->prev = node; +// printf("...\n"); + list->current->next = node; +// printf("...done\n"); + + list->current = node; + +// printf("Added node\n"); +// LL_dprint(list); + + return 0; +} + +////////////////////////////////////////////////////////////////////// +int LL_InsertNode(LL *list, void * add)// Adds node BEFORE current one +{ + LL_node *node; + + if(!list) return -1; + if(!add) return -1; + if(!list->current) return -1; + + node = malloc(sizeof(LL_node)); + if(!node) return -1; + + if(list->current == &list->head) list->current = list->current->next; + + node->next = list->current; + node->prev = list->current->prev; + node->data = add; + + if(list->current->prev) + list->current->prev->next = node; + + list->current->prev = node; + + list->current = node; + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// Removes a node from the link +// ... and advances one node forward +void * LL_DeleteNode(LL *list) +{ + LL_node *next, *prev; + void *data; + + if(!list) return NULL; + if(!list->current) return NULL; + if(list->current == &list->head) return NULL; + if(list->current == &list->tail) return NULL; + + #ifdef DEBUG + printf("LL_DeleteNode: Before...\n"); + LL_dprint(list); + #endif + + + next = list->current->next; + prev = list->current->prev; + data = list->current->data; + + if(prev) + prev->next = next; + + if(next) + next->prev = prev; + + list->current->prev = NULL; + list->current->next = NULL; + // This should not free things; the user should do it explicitly. + //if(list->current->data) free(list->current->data); + list->current->data = NULL; + + free(list->current); + + list->current = next; + + #ifdef DEBUG + printf("LL_DeleteNode: After...\n"); + LL_dprint(list); + #endif + + return data; +} +////////////////////////////////////////////////////////////////////// +// Removes a specific node... +void * LL_Remove(LL *list, void * data) +{ + void *find; + + if(!list) return NULL; + + LL_Rewind(list); + do { + find = LL_Get(list); + if(find == data) return LL_DeleteNode(list); + } while (LL_Next(list) == 0); + + return NULL; +} + + +////////////////////////////////////////////////////////////////////// +// Stack operations +int LL_Push(LL *list, void *add) // Add node to end of list +{ + if(!list) return -1; + if(!add) return -1; + +// printf("Going to end of list...\n"); + LL_End(list); + +// printf("Adding node...\n"); + return LL_AddNode(list, add); +} + +////////////////////////////////////////////////////////////////////// +void * LL_Pop(LL *list) // Remove node from end of list +{ + if(!list) return NULL; + + if(0 > LL_End(list)) return NULL; + + return LL_DeleteNode(list); +} + +////////////////////////////////////////////////////////////////////// +void * LL_Top(LL *list) // Peek at end node +{ + return LL_GetLast(list); +} + +////////////////////////////////////////////////////////////////////// +void * LL_Shift(LL *list) // Remove node from start of list +{ + if(!list) return NULL; + + if(0 > LL_Rewind(list)) return NULL; + + return LL_DeleteNode(list); +} + +////////////////////////////////////////////////////////////////////// +void * LL_Look(LL *list) // Peek at first node +{ + return LL_GetFirst(list); +} + +////////////////////////////////////////////////////////////////////// +int LL_Unshift(LL *list, void *add) // Add node to beginning of list +{ + if(!list) return -1; + if(!add) return -1; + + LL_Rewind(list); + + return LL_InsertNode(list, add); +} + +////////////////////////////////////////////////////////////////////// +int LL_Roll(LL *list) // Make last node first +{ + LL_node *node, *next; + + if(!list) return -1; + //if(!list->current) return -1; + + if(0 > LL_End(list)) return -1; + + // Avoid rolling an empty list, or unlinking the head/tail... + if(list->current == &list->head) list->current = list->current->next; + if(list->current == &list->tail) list->current = list->current->prev; + // List is empty + if(list->current == &list->head) return 0; + // List has one item + if(list->current->prev == &list->head) return 0; + + node = list->current; + + LL_node_Unlink(node); + + if(0 > LL_Rewind(list)) return -1; + + next = list->head.next; + + list->head.next = node; + next->prev = node; + node->prev = &list->head; + node->next = next; + + return 0; +} + +////////////////////////////////////////////////////////////////////// +int LL_UnRoll(LL *list)// Roll the other way... +{ + LL_node *node, *prev; + + if(!list) return -1; + //if(!list->current) return -1; + + if(0 > LL_Rewind(list)) return -1; + + // Avoid rolling an empty list, or unlinking the head/tail... + if(list->current == &list->tail) list->current = list->current->prev; + if(list->current == &list->head) list->current = list->current->next; + // List is empty + if(list->current == &list->tail) return 0; + // List has one item + if(list->current->next == &list->tail) return 0; + + node = list->current; + + LL_node_Unlink(node); + + if(0 > LL_End(list)) return -1; + + prev = list->tail.prev; + + list->tail.prev = node; + prev->next = node; + node->next = &list->tail; + node->prev = prev; + + return 0; +} + + + +////////////////////////////////////////////////////////////////////// +// Add an item to the end of its "priority group" +// The list is assumed to be sorted already... +int LL_PriorityEnqueue(LL *list, void *add, int compare(void *, void *)) +{ + void *data; + int i; + + if(!list) return -1; + if(!add) return -1; + if(!compare) return -1; + + // From the end of the list, keep searching while we're "less than" + // the given nodes... + LL_End(list); + do { + data = LL_Get(list); + if(data) + { + i = compare(add, data); + if(i >= 0) // If we're in the right place, add it and exit + { + LL_AddNode(list, add); + return 0; + } + } + } while(LL_Prev(list) == 0); + + // If we're less than *everything*, put it at the beginning + LL_Unshift(list, add); + + return 0; +} + + + +////////////////////////////////////////////////////////////////////// +int LL_SwapNodes(LL_node *one, LL_node *two) // Switch two nodes positions... +{ + LL_node *firstprev, *firstnext; + LL_node *secondprev, *secondnext; + + if(!one || !two) return -1; + if(one == two) return 0; // Do nothing + + firstprev = one->prev; // Look up the nodes neighbors... + firstnext = one->next; + secondprev = two->prev; + secondnext = two->next; + + if(firstprev != NULL) firstprev->next = two; // Swap the neighboring + if(firstnext != NULL) firstnext->prev = two; // nodes pointers... + if(secondprev != NULL) secondprev->next = one; + if(secondprev != NULL) secondnext->prev = one; + + one->next = secondnext; // Swap the nodes pointers + one->prev = secondprev; + two->next = firstnext; + two->prev = firstprev; + + if(firstnext == two) one->prev = two; // Fix things in case + if(firstprev == two) one->next = two; // they were next to + if(secondprev == one) two->next = one; // each other... + if(secondnext == one) two->prev = one; + + + return 0; + +} +////////////////////////////////////////////////////////////////////// +int LL_nSwapNodes(int one, int two) // Switch two nodes positions... +{ + return -1; +} + +////////////////////////////////////////////////////////////////////// +int LL_Length(LL *list) // Returns # of nodes in entire list +{ + LL_node *node; + int num = 0; + + if(!list) return -1; + + node = &list->head; + + for(num = -1; + node != &list->tail; + num++) + node = node->next; + + return num; +} + +////////////////////////////////////////////////////////////////////// +// Searching... +// Goes to the list item which matches "value", and returns the +// data found there. +// +// The "compare" function should return 0 for a "match" +// +// Note that this does *not* rewind the list first! You should do +// it yourself if you want to start from the beginning! +void * LL_Find(LL *list, int compare(void *, void *), void *value) +{ + void *data; + + if(!list) return NULL; + if(!compare) return NULL; + if(!value) return NULL; + + do{ + data = LL_Get(list); + if( 0 == compare(data, value) ) return data; + + } while(LL_Next(list) == 0); + + return NULL; +} + + +////////////////////////////////////////////////////////////////////// +// Sorts the list, then rewinds it... +// +int LL_Sort(LL *list, int compare(void *, void *)) +{ + int i,j; // Junk / loop variables + int numnodes; // number of nodes in list + LL_node *best, *last; // best match and last node in the list + LL_node *current; + + + if(!list) return -1; + if(!compare) return -1; + + numnodes = LL_Length(list); // get the number of nodes... + if(0 > LL_End(list)) return -1; // Find the last node. + last = LL_GetNode(list); + + if(numnodes < 2) return 0; + + + for(i=numnodes-1; i>0; i--) + { + LL_Rewind(list); // get the first node again + best = last; // reset our "best" node + + for(j=0; jdata, best->data) > 0) + { + best = current; // keep track of the "best" match + } + LL_Next(list); // Go to the next node. + } + + LL_SwapNodes(last, best); // Switch two nodes... + if(best) last = best->prev; + else return -1; + + //last = LL_FindPrev(best); // And go backwards by one node. + } + + //return LLFindFirst(current); // return pointer to the first node. + LL_Rewind(list); + + return 0; + +} + +void LL_dprint(LL *list) +{ + LL_node *current; + + current = &list->head; + + printf("Head: prev:\t0x%8x\taddr:\t0x%8x\tnext:\t0x%8x\n", + (int)list->head.prev, + (int)&list->head, + (int)list->head.next); + + for(current = current->next; + current != &list->tail; + current = current->next) + { + printf("node: prev:\t0x%8x\taddr:\t0x%8x\tnext:\t0x%8x\n", + (int)current->prev, + (int)current, + (int)current->next); + + } + + printf("Tail: prev:\t0x%8x\taddr:\t0x%8x\tnext:\t0x%8x\n", + (int)list->tail.prev, + (int)&list->tail, + (int)list->tail.next); +} diff --git a/shared/LL.h b/shared/LL.h new file mode 100644 index 0000000..e022192 --- /dev/null +++ b/shared/LL.h @@ -0,0 +1,209 @@ +#ifndef LL_H +#define LL_H + + + +/*********************************************************************** + Linked Lists! (Doubly-Linked Lists) + ******************************************************************* + + To create a list, do the following: + + LL *list; + list = LL_new(); + if(!list) handle_an_error(); + + The list can hold any type of data. You will need to typecast your + datatype to a "void *", though. So, to add something to the list, + the following would be a good way to start: + + typedef struct my_data { + char string[16]; + int number; + } my_data; + + my_data *thingie; + + for(something to something else) + { + thingie = malloc(sizeof(my_data)); + LL_AddNode(list, (void *)thingie); // typecast it to a "void *" + } + + For errors, the general convention is that "0" means success, and + a negative number means failure. Check LL.c to be sure, though. + + ******************************************************************* + + To change the data, try this: + + thingie = (my_data *)LL_Get(list); // typecast it back to "my_data" + thingie->number = another_number; + + You don't need to "Put" the data back, but it doesn't hurt anything. + + LL_Put(list, (void *)thingie); + + However, if you want to point the node's data somewhere else, you'll + need to get the current data first, keep track of it, then set the data + to a new location: + + my_data * old_thingie, new_thingie; + + old_thingie = (my_data *)LL_Get(list); + LL_Put(list, (void *)new_thingie); + + // Now, do something with old_thingie. (maybe, free it?) + + Or, you could just delete the node entirely and then add a new one: + + my_data * thingie; + + thingie = (my_data *)LL_DeleteNode(list); + free(thingie); + + thingie->number = 666; + + LL_InsertNode(list, (void *)thingie); + + ******************************************************************* + + To operate on each list item, try this: + + LL_Rewind(list); + do { + my_data = (my_data *)LL_Get(list); + ... do something to it ... + } while(LL_Next(list) == 0); + + ******************************************************************* + + You can also treat the list like a stack, or a queue. Just use the + following functions: + + LL_Push() // Regular stack stuff: add, remove, peek, rotate + LL_Pop() + LL_Top() + LL_Roll() + + LL_Shift() // Other end of the stack (like in perl) + LL_Unshift() + LL_Look() + LL_UnRoll() + + LL_Enqueue() // Standard queue operations + LL_Dequeue() + + There are also other goodies, like sorting and searching. + + ******************************************************************* + + Array-like operations will come later, to allow numerical indexing: + + LL_nGet(list, 3); + LL_nSwap(list, 6, 13); + LL_nPut(list, -4, data); // Puts item at 4th place from the end.. + + More ideas for later: + + LL_MoveNode(list, amount); // Slides a node to another spot in the list + -- LL_MoveNode(list, -1); // moves a node back one toward the head + + ... um, more? + + ******************************************************************* + That's about it, for now... Be sure to free the list when you're done! +***********************************************************************/ + + +// See LL.c for more detailed descriptions of these functions. + +typedef struct LL_node +{ + struct LL_node *next, *prev; + void *data; +} LL_node; + +typedef struct LL +{ + LL_node head, tail; + LL_node *current; +} LL; + + + +// Creates a new list... +LL * LL_new(); +// Destroying lists... +int LL_Destroy(LL *list); +int LL_node_Destroy(LL_node *node); +int LL_node_Unlink(LL_node *node); +int LL_node_DestroyData(LL_node *node); + +// Returns to the beginning of the list... +int LL_Rewind(LL *list); +// Goes to the end of the list... +int LL_End(LL *list); +// Go to the next node +int LL_Next(LL *list); +// Go to the previous node +int LL_Prev(LL *list); + +// Data manipulation +void * LL_Get(LL *list); +int LL_Put(LL *list, void *data); +// Don't use these next two unless you really know what you're doing. +LL_node * LL_GetNode(LL *list); +int LL_PutNode(LL *list, LL_node *node); + +void * LL_GetFirst(LL *list); // gets data from first node +void * LL_GetNext (LL *list); // ... next node +void * LL_GetPrev (LL *list); // ... prev node +void * LL_GetLast (LL *list); // ... last node + +int LL_AddNode(LL *list, void * add); // Adds node AFTER current one +int LL_InsertNode(LL *list, void * add);// Adds node BEFORE current one +// Removes a node from the link; returns the data from the node +void * LL_DeleteNode(LL *list); +// Removes a specific node... +void * LL_Remove(LL *list, void * data); + +// Stack operations +int LL_Push(LL *list, void *add); // Add node to end of list +void * LL_Pop(LL *list); // Remove node from end of list +void * LL_Top(LL *list); // Peek at end node +void * LL_Shift(LL *list); // Remove node from start of list +void * LL_Look(LL *list); // Peek at first node +int LL_Unshift(LL *list, void *add); // Add node to beginning of list + +int LL_Roll(LL *list); // Make first node last +int LL_UnRoll(LL *list);// Roll the other way... + +// Queue operations... +//int LL_Enqueue(LL *list, void *add); +//void * LL_Dequeue(LL *list); +////////////////////////////////////////////////////////////////////// +// Queue operations... +#define LL_Enqueue(list,add) LL_Push(list,add) + +#define LL_Dequeue(list) LL_Shift(list) + +int LL_PriorityEnqueue(LL *list, void *add, int compare(void *, void *)); + + +int LL_SwapNodes(LL_node *one, LL_node *two); // Switch two nodes positions... +int LL_nSwapNodes(int one, int two); // Switch two nodes positions... + +int LL_Length(LL *list); // Returns # of nodes in entire list + +// Searching... +void * LL_Find(LL *list, int compare(void *, void *), void *value); + +// Sorts the list... +int LL_Sort(LL *list, int compare(void *, void *)); + + +// Debugging... +void LL_dprint(LL *list); + +#endif diff --git a/shared/Makefile b/shared/Makefile new file mode 100644 index 0000000..2bb0e27 --- /dev/null +++ b/shared/Makefile @@ -0,0 +1,41 @@ +######################################################################## +# You shouldn't need to touch anything below here. +######################################################################## +include ../Makefile.config + + +TARGET = libLCDstuff.a +OBJ = LL.o sockets.o str.o +#OBJ = LL.o config.o sockets.o +#TODO: config and sockets stuff... + +################################################################### +# Compilation... +# +all: $(TARGET) + +$(TARGET): $(OBJ) Makefile + ar rcs $(TARGET) $(OBJ) +#$(TARGET): $(OBJ) Makefile +# $(GCC) -s $(MISC) -o $(TARGET) $(OBJ) $(LIB) + +%.o: %.c %.h Makefile + $(GCC) -c $(MISC) $< + + +################################################################## +# Installation +# +install: $(TARGET) + @echo No shared stuff will be installed... + + +################################################################## +# Other stuff... +# +clean: + rm -f $(OBJ) $(TARGET) *~ core + +edit: + emacs . & + diff --git a/shared/config.c b/shared/config.c new file mode 100644 index 0000000..9eac53a --- /dev/null +++ b/shared/config.c @@ -0,0 +1,158 @@ +#include "config.h" + + +typedef struct command +{ + char *text; + struct command *child; + int (*func)(char *line); +}; + +command main_list[] = { + "Key", NULL, Key_func, + "Driver", Driver_commands,NULL, + NULL, NULL, NULL, +}; + +command Driver_commands[] = { + "MtxOrb", NULL, MtxOrb_drv_init, + "curses", NULL, curses_drv_init, + "hd44780", NULL, hd44780_drv_init, +// "X11", NULL, X11_drv_init, +// "debug", NULL, debug_drv_init, + "text", NULL, text_drv_init, +}; + + + +// Interpret a line... +int parse_line(char *line); +// Interpret the rest of the line... +int parse_rest(char *line, command *commands); + + +////////// Helper functions for line parsing ///////////////// +// Pops off the first word of the string. +char *shift(char *string); + + +////////////// Config Functions ///////////////////////////////// +int Key_func(char *line) +{ + // uh, interpret the command... + return 0; +} + + +int parse_line(char *line, command *commands) +{ + int i, j; + int newtoken, inquote; + char *str; +// char *tok; + int argc; + char *argv[256]; + char delimiters[] = " \0"; + char leftquote[] = "\0\"'`([{\0"; + char rightquote[] = "\0\"'`)]}\0"; + char errmsg[256]; + int invalid=0; + int err=0; + + // And parse all its messages... + //debug("parse: Getting messages...\n"); + str = strdup(line); + debug("parse: ...%s\n", str); + // Now, split up the string... + //len = strlen(str); + argc=0; + newtoken=1; + inquote=0; + for(i=0; str[i]; i++) + { + if(inquote) // Scan for the end of the quote + { + if(str[i] == rightquote[inquote]) + { // Found the end of the quote + inquote=0; + str[i] = 0; + newtoken=1; + } + } + else // Normal operation; split at delimiters + { + for(j=1; leftquote[j]; j++) + { + // Found the beginning of a new quote... + if(str[i] == leftquote[j]) + { + inquote = j; + str[i] = 0; + continue; + } + } + for(j=0; delimiters[j]; j++) + { + // Break into a new string... + if(str[i] == delimiters[j]) + { + str[i] = 0; + newtoken = 1; + continue; + } + } + } + if(newtoken && str[i]) + { + newtoken=0; + argv[argc] = str + i; + argc++; + } + else + { + } + } + if(inquote) + { + sprintf(errmsg, "huh? Unterminated string: missing %c\n", + rightquote[inquote]); + sock_send_string(c->sock, errmsg); + continue; + } +/* + for(tok = strtok(str, delimiters); + tok; + tok=strtok(NULL, delimiters)) + { + argv[argc] = tok; + argc++; + } +*/ + argv[argc] = NULL; + if(argc < 1) continue; + + // Now find and call the appropriate function... +// debug("parse: Finding function...\n"); + invalid = 1; + for(i=0; commands[i].keyword; i++) + { +// debug("(checking %s)\n", commands[i].keyword); + if(0 == strcmp(argv[0], commands[i].keyword)) + { +// debug("(FOUND %s)\n", commands[i].keyword); + invalid = commands[i].function(c, argc, argv); +// debug("parse: Returned %i...\n", err); + } + } + if(invalid) + { + // FIXME: Check for buffer overflows here... + err = 1; + //sprintf(errmsg, "huh? Invalid command \"%s\"\n", argv[0]); + //sock_send_string(c->sock, errmsg); + } + + free(str); // Don't want to forget this... :) + + return err; +} diff --git a/shared/config.h b/shared/config.h new file mode 100644 index 0000000..bfad8c2 --- /dev/null +++ b/shared/config.h @@ -0,0 +1,12 @@ +#ifndef CONFIG_H +#define CONFIG_H + + +// Read entire config file +int config_load_file(char *file); + +// Save new options +int config_save_file(char *file); + + +#endif diff --git a/shared/debug.h b/shared/debug.h new file mode 100644 index 0000000..6ebd2ab --- /dev/null +++ b/shared/debug.h @@ -0,0 +1,14 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#ifdef DEBUG + +#define debug printf + +#else + +#define debug /* printf */ + +#endif + +#endif diff --git a/shared/sockets.c b/shared/sockets.c new file mode 100644 index 0000000..49271c1 --- /dev/null +++ b/shared/sockets.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "sockets.h" + + +/************************************************** + LCDproc client sockets code... + + Feel free to use this in your own clients... :) +**************************************************/ + + +// Length of longest transmission allowed at once... +#define MAXMSG 8192 + + +typedef struct sockaddr_in sockaddr_in; + + +static int sock_init_sockaddr (sockaddr_in *name, + const char *hostname, + unsigned short int port) +{ + struct hostent *hostinfo; + + name->sin_family = AF_INET; + name->sin_port = htons (port); + hostinfo = gethostbyname (hostname); + if (hostinfo == NULL) + { + fprintf (stderr,"sock_init_sockaddr: Unknown host %s.\n", hostname); + return -1; + } + name->sin_addr = *(struct in_addr *) hostinfo->h_addr; + + return 0; + +} + + // Client functions... +int sock_connect(char *host, unsigned short int port) +{ + struct sockaddr_in servername; + int sock; + int err=0; + + + debug("sock_connect: Creating socket\n"); + sock = socket(PF_INET, SOCK_STREAM, 0); + if(sock < 0) + { + perror("sock_connect: Error creating socket"); + return sock; + } + debug("sock_connect: Created socket (%i)\n", sock); + + sock_init_sockaddr(&servername, host, port); + + err = connect (sock, + (struct sockaddr *) &servername, + sizeof (servername)); + if(err<0) + { + perror("sock_connect: connect failed"); + shutdown(sock, 2); + return 0; // Normal exit if server doesn't exist... + } + + fcntl(sock, F_SETFL, O_NONBLOCK); + + + return sock; +} + +int sock_close(int fd) +{ + int err; + + err=shutdown(fd, 2); + + return err; +} + +// Send/receive lines of text +int sock_send_string(int fd, char *string) +{ + int err; + + if(!string) return -1; + + err = write (fd, string, strlen(string) + 1); + if (err < 0) + { + perror ("sock_send_string: socket write error"); + printf("Message was: %s\n", string); + //shutdown(fd, 2); + return err; + } + + //printf("sock_send_string: %i bytes\n", err); + + return err; +} + +// Recv gives only one line per call... +int sock_recv_string(int fd, char *dest, size_t maxlen) +{ + char * err; + int i; + + // TODO: Get this function to work right somehow... + return -1; + + if(!dest) return -1; + if(maxlen <= 0) return 0; + + // Read in characters until the end of the line... + for(i=0; + i 0); + i++) + if(dest[i] == 0 || dest[i] == '\n') break; + + if (err == NULL) + { + perror("sock_recv_string: socket read error"); + //shutdown(fd, 2); + return -1; + } + printf("sock_recv_string: Got message \"%s\"\n", dest); + + return strlen(dest); +} + +// Send/receive raw data +int sock_send(int fd, void *src, size_t size) +{ + int err; + + if(!src) return -1; + + err = write (fd, src, size); + if (err < 0) + { + perror("sock_send: socket write error"); + //shutdown(fd, 2); + return err; + } + + return err; +} + +int sock_recv(int fd, void *dest, size_t maxlen) +{ + int err; + + if(!dest) return -1; + if(maxlen <= 0) return 0; + + err = read (fd, dest, maxlen); + if (err < 0) + { + //fprintf (stderr,"sock_recv: socket read error\n"); + //shutdown(fd, 2); + return err; + } + //debug("sock_recv: Got message \"%s\"\n", (char *)dest); + + return err; +} diff --git a/shared/sockets.h b/shared/sockets.h new file mode 100644 index 0000000..3d96ae0 --- /dev/null +++ b/shared/sockets.h @@ -0,0 +1,87 @@ +#ifndef SOCKETS_H +#define SOCKETS_H + +#include + +#ifndef LCDPORT +#define LCDPORT 13666 +#endif + + + +/* + Socket functions available to server and clients... + (ignore the rest of the comments... I was babbling out random ideas) + + This should have stuff to read/write sockets, open/close them, etc... + */ + + +// Client functions... +int sock_connect(char *host, unsigned short int port); +int sock_close(int fd); +// Send/receive lines of text +int sock_send_string(int fd, char *string); +// Recv gives only one line per call... +int sock_recv_string(int fd, char *dest, size_t maxlen); +// Send/receive raw data +int sock_send(int fd, void *src, size_t size); +int sock_recv(int fd, void *dest, size_t maxlen); + + +// Er, ignore the rest of this file. I'll clean it up sometime... + +/***************************************************************** + LCDproc command line interface?: (while running) + + -command + Tells LCDproc to interpret stdin as raw commands to send through + the socket. Input must be formatted as above, in socket interface. + -function f + Runs LCDproc external function f, where f is one of the predefined + functions which can be assigned to keypad keys. (like NEXTMODE, etc) + -key x + Simulates keypad press of key 'x', where 'x' is (A-Z). + -print [time] + Prints stdin on LCD one line at a time, with no line-wrapping (raw), + with [time] frames between updates (lines). + -wrap [time] + Prints stdin as with "-print", but with line wrapping when possible. + -contrast xxx + Sets contrast to xxx (decimal) + -backlight [on/off] + Turns backlight [on/off/auto], or toggles it. + If [off], stays off. + If [on], stays on. + If [auto], LCDproc controls backlight based on load, etc... + -exit + -quit + Duh... :) + +******************************************************************/ + +/***************************************************************** + LCDproc stuff supported in config file (loose approximation): + + Grammar is tcl-style. I.e., "command arg1 arg2 ...". + Spaces are used as argument separators, *until* it thinks it has the final + argument. So, "function thing shell myprogram arg1 arg2 arg3" would be + split into "function", "thing", "shell", and "myprogram arg1 arg2 arg3". + + User-definable functions (use built-in's to create new ones?): + Function mp3NextSong Shell /usr/local/bin/mp3player -next + Function MySequence Sequence cpu mem xload + Function OtherSequence Sequence time cd xload + + Keypad keys can be bound to any _function_: + Key A mp3NextSong + Key B HaltSystem + Key C Menu + Key D Next/+ + Key E OtherSequence + + +******************************************************************/ + + +#endif diff --git a/shared/str.c b/shared/str.c new file mode 100644 index 0000000..9dc566f --- /dev/null +++ b/shared/str.c @@ -0,0 +1,34 @@ +#include +#include +#include + +#include "debug.h" +#include "str.h" + +int get_args(char **argv, char *str, int max_args) +{ + char *delimiters = " \n\0"; + char *item; + int i=0; + + if(!argv) return -1; + if(!str) return 0; + if(max_args < 1) return 0; + + //debug("get_args(%i): string=%s\n", max_args, str); + + // Parse the command line... + for(item = strtok(str, delimiters); item; item=strtok(NULL, delimiters)) + { + //debug("get_args: item=%s\n", item); + if(i < max_args) + { + argv[i] = item; + i++; + } + else return i; + } + + return i; +} + diff --git a/shared/str.h b/shared/str.h new file mode 100644 index 0000000..39560ac --- /dev/null +++ b/shared/str.h @@ -0,0 +1,6 @@ +#ifndef STR_H +#define STR_H + +int get_args(char **argv, char *str, int max_args); + +#endif diff --git a/tests/LL_test.c b/tests/LL_test.c new file mode 100644 index 0000000..84985a5 --- /dev/null +++ b/tests/LL_test.c @@ -0,0 +1,156 @@ +#include +#include +#include "LL.h" + + + +/* Tested functions: + LL_New(); + LL_Rewind(); + LL_AddNode(); + LL_Next(); + LL_Get(); + LL_Push(); + LL_Unshift(); + LL_InsertNode(); + LL_Roll(); + LL_UnRoll(); + LL_SwapNodes(); + LL_Sort(); + LL_Find(); + */ + +typedef struct my_struct +{ + int num; + char str[16]; +} my_struct; + + +int list_list(LL *list) +{ + my_struct *foo; + + + if(!list) return -1; + + printf("Listing the list contents...\n"); + printf(" Items: %i\n", LL_Length(list)); + + + LL_Rewind(list); + + do{ + foo = (my_struct *)LL_Get(list); + if(!foo) + { + printf("Can't read list data\n"); + return -1; + } + printf("\tItem: %i\n", foo->num); + + } while(LL_Next(list) == 0); + + + return 0; +} + +int compare(void *one, void *two) +{ + my_struct *a, *b; + + if(!one || !two) return 0; + + + a = (my_struct *)one; + b = (my_struct *)two; + + return (a->num - b->num); + +} + + + +int main() +{ + LL *list = NULL; + my_struct *foo; + my_struct bar; + int i,j; + + + list = LL_new(); + if(!list) + { + printf("Cannot create list.\n"); + return -1; + } + + for(i=0; i<10; i++) + { + foo = malloc(sizeof(my_struct)); + if(!foo) + { + printf("Can't allocate new struct\n"); + return -1; + } + + foo->num = i; + + LL_InsertNode(list, (void *)foo); + printf("Added node: %i\n", foo->num); + + } + + if(list_list(list) != 0) return -1; + + printf("Sorting the list...\n"); + + if(LL_Sort(list, compare) < 0) + { + printf("Error sorting.\n"); + return -1; + } + + if(list_list(list) != 0) return -1; + + bar.num = 5; + + printf("Searching for item \"5\"\n"); + LL_Rewind(list); + + foo = LL_Find(list, compare, &bar); + if(foo) + { + printf(" Found... %i\n", foo->num); + } + + + printf("Deallocating list...\n"); + LL_Rewind(list); + do{ + foo = LL_Get(list); + free(foo); + + } while(LL_Next(list) == 0); + + if(LL_Destroy(list) == 0) return 0; + + + printf("Attempting to access list...\n"); + + printf("List = %x\n", list); + + LL_Rewind(list); + + do{ + foo = LL_Get(list); + if(foo) printf(" Item: %i\n", foo->num); + + } while(LL_Next(list) == 0); + + + + return 0; + +} diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..1956a52 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,128 @@ +include ../Makefile.config + +######################################################################## +# Modify these variables to fit your system. +######################################################################## + +##################### Serial device +# This should be whatever your display is connected to. +# "make install" will create a link from /dev/lcd to DEVICE +DEVICE = /dev/ttyS0 + +##################### Operating System +# Uncomment the line for your OS. +OS=-DLINUX +#OS=-DIRIX + +##################### Modescreen Options + +##### Load Screen +# Max: Load Avg at which the backlight will start blinking +MISC += -DLOAD_MAX=1.3 +# Min: Load Avg at which the backlight will turn off (asleep) +MISC += -DLOAD_MIN=0.05 + +##### Filesystems to display stats for... (comment out ones you don't want) +# NFS (Network File System) +MISC += -DSTAT_NFS +# SMBFS (Samba filesystem -- Windows drives) +MISC += -DSTAT_SMBFS + + +##################### Drivers +# Comment out each section you don't want. + +# Matrix-Orbital displays +DRIVERS += -DMTXORB_DRV +OBJ += MtxOrb.o + +# Curses text-based output +DRIVERS += -DCURSES_DRV +OBJ += curses_drv.o +LIB += -lncurses + +# Regular text output (ugly) +DRIVERS += -DTEXT_DRV +OBJ += text.o + +# Debugging output (very ugly) +DRIVERS += -DDEBUG_DRV +OBJ += debug.o + +# HD44780 parallel port lcd displays +#DRIVERS += -DHD44780_DRV +#OBJ += hd44780.o +# Pick one of the following ports to use +#LPTPORT = 0x378 +#LPTPORT = 0x278 +#LPTPORT = 0x3bc + + + +######################################################################## +# You shouldn't need to touch anything below here. +######################################################################## + +#GCC = gcc -Wall -Wp,-lang-c-c++-comments -O6 +#OBJ += main.o mode.o lcd.o sockets.o config.o drv_base.o +#MISC += $(OS) $(DRIVERS) +#VERSION = 0.4 + + +################################################################### +# Compilation... +# +#MISC=-DCURSES_DRV -g -DDEBUG + +test: + $(GCC) -c $(MISC) menutest.c + $(GCC) -c $(MISC) lcd.c + $(GCC) -c $(MISC) menu.c + $(GCC) -c $(MISC) drivers/curses_drv.c + $(GCC) -c $(MISC) drivers/drv_base.c + $(GCC) -o menutest curses_drv.o menutest.o lcd.o drv_base.o menu.o -lncurses + +test2: + $(GCC) -c $(MISC) LL.c + $(GCC) -c $(MISC) LL_test.c + $(GCC) -o LL_test LL_test.o LL.o + +test3: + $(GCC) -c $(MISC) config.c + $(GCC) -c $(MISC) config_test.c + $(GCC) -o config_test config.o config_test.o + +driver_test: + $(GCC) -g -c $(MISC) drv_test.c + $(GCC) -g -o drv_test drv_test.o ../server/drivers/libLCDdrivers.a \ + ../shared/libLCDstuff.a -lncurses + +socktest: +# $(GCC) -g -c $(MISC) socktest.c +# $(GCC) -g -o st socktest.o ../server/drivers/libLCDdrivers.a \ +# ../shared/libLCDstuff.a -lncurses + $(GCC) -c $(MISC) srvtest.c + $(GCC) -c $(MISC) ../server/sock.c + $(GCC) $(MISC) -o srv srvtest.o ../server/*.o \ + ../server/drivers/libLCDdrivers.a \ + ../shared/libLCDstuff.a -lncurses + + + + + +################################################################## +# Installation +# +install: + @echo Nothing to install in tests... + +################################################################## +# Other stuff... +# +clean: + rm -f *.o core *~ + +edit: + emacs . & + diff --git a/tests/bartest b/tests/bartest new file mode 100644 index 0000000..1f9ecdf --- /dev/null +++ b/tests/bartest @@ -0,0 +1,42 @@ +hello +screen_add one + +widget_add one v string +widget_set one v 1 1 "VBars" +widget_add one h string +widget_set one h 10 1 "HBars" + +widget_add one h1 hbar +widget_add one h2 hbar +widget_add one h3 hbar +widget_set one h1 10 2 28 +widget_set one h2 10 3 27 +widget_set one h3 10 4 26 + +widget_add one v1 vbar +widget_add one v2 vbar +widget_add one v3 vbar +widget_add one v4 vbar +widget_set one v1 1 4 15 +widget_set one v2 2 4 14 +widget_set one v3 3 4 13 +widget_set one v4 4 4 12 +widget_add one v5 vbar +widget_set one v5 5 4 11 +widget_set one v5 5 4 12 +widget_set one v5 5 4 10 +widget_set one v5 5 4 8 +widget_set one v5 5 4 18 +widget_set one v5 5 4 17 +widget_set one v5 5 4 16 +widget_set one v5 5 4 15 +widget_set one v5 5 4 14 +widget_set one v5 5 4 13 +widget_set one v5 5 4 12 +widget_set one v5 5 4 11 +widget_del one h3 +widget_add one h3 hbar +widget_set one h3 10 4 16 +widget_set one h3 10 4 26 +widget_set one h3 10 4 27 +widget_set one h3 10 4 25 diff --git a/tests/ctest.c b/tests/ctest.c new file mode 100644 index 0000000..30331e6 --- /dev/null +++ b/tests/ctest.c @@ -0,0 +1,30 @@ +#include + +void main() +{ + char string[64]; + + int done=0; + int key=0; + + + initscr(); + cbreak(); + noecho(); + nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + + + while(!done) + { + key=getch(); + if(key == KEY_BACKSPACE) done=1; + sprintf(string, "Key: %i", key); + + mvaddstr(0,0,string); + + + } + +} diff --git a/tests/drv_test.c b/tests/drv_test.c new file mode 100644 index 0000000..20598e8 --- /dev/null +++ b/tests/drv_test.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include "../server/drivers/lcd.h" + +int main() +{ + int err; + int len; + + srand(time(NULL)); + + err = lcd_init(""); + + err = lcd_add_driver("joy", ""); + err = lcd_add_driver("curses", "Booger"); +// err = lcd_add_driver("text", "Booger"); + err = lcd_add_driver("MtxOrb", ""); + + lcd.clear(); + + lcd.init_hbar(); + + lcd.string(1,1,"Booger!"); + len = rand()%100; + lcd.hbar(1,2,len ); + lcd.flush(); + + for(err=0; err!='Z'; err=lcd.getkey()) + { +// if(err) + { + if(err == 'B') len--; + if(err == 'C') len++; + if(err == 'D') len--; + if(err == 'E') len-=5; + if(err == 'F') len+=5; + + lcd.clear(); + lcd.string(1,1,"Booger!"); + lcd.hbar(1,2,len ); + lcd.chr(1,3,(char)err); + + lcd.flush(); + } + usleep(125000); + } + +// sleep(1); + + lcd_shutdown(); + + return 0; +} diff --git a/tests/lcd.c b/tests/lcd.c new file mode 100644 index 0000000..efa279b --- /dev/null +++ b/tests/lcd.c @@ -0,0 +1,638 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "LL.h" + +#include "lcd.h" + +#include "drv_base.h" + +#ifdef MTXORB_DRV +#include "MtxOrb.h" +#endif + +#ifdef TEXT_DRV +#include "text.h" +#endif + +#ifdef DEBUG_DRV +#include "debug.h" +#endif + +#ifdef CURSES_DRV +#include "curses_drv.h" +#endif + +#ifdef HD44780_DRV +#include "hd44780.h" +#endif + +// TODO: Make a Windows server, and clients...? + + +lcd_logical_driver lcd; + +lcd_physical_driver drivers[] = +{ + { "base", drv_base_init, }, +#ifdef MTXORB_DRV + { "MtxOrb", MtxOrb_init, }, +#endif +#ifdef HD44780_DRV + { "HD44780", HD44780_init, }, +#endif +#ifdef TEXT_DRV + { "text", text_init, }, +#endif +#ifdef DEBUG_DRV + { "debug", debug_init, }, +#endif +#ifdef CURSES_DRV + { "curses", curses_drv_init, }, +#endif + { NULL, NULL, }, + +}; + +LL *list; + +//////////////////////////////////////////////////////////// +// This sets up which driver to use and initializes stuff. +// +int lcd_init(char *args) +{ +// int i; + + list = LL_new(); + if(!list) + { + printf("Error allocating driver list.\n"); + return -1; + } + + lcd_drv_init(NULL, NULL); + + return lcd_add_driver("base", args); + + /* + drv_base_init(args); + + for(i=0; drivers[i].name; i++) + { + if(!strcmp(driver, drivers[i].name)) + { + return drivers[i].init(args); + } + } + + printf("Invalid driver: %s\n", driver); + return -1; + */ + +} + + +// TODO: lcd_remove_driver() + +int lcd_add_driver(char *driver, char *args) +{ + int i; + + lcd_logical_driver *add; + + for(i=0; drivers[i].name; i++) + { + + //printf("Checking driver: %s\n", drivers[i].name); + + if(0 == strcmp(driver, drivers[i].name)) + { + + //printf("Found driver: %s (%s)\n", drivers[i].name, driver); + + add = malloc(sizeof(lcd_logical_driver)); + if(!add) + { + printf("Couldn't allocate driver \"%s\".\n", driver); + return -1; + } + //printf("Allocated driver\n"); + memset(add, 0, sizeof(lcd_logical_driver)); + + add->wid = lcd.wid; add->hgt = lcd.hgt; + add->cellwid = lcd.cellwid; add->cellhgt = lcd.cellhgt; + + //printf("LCD driver info:\n\twid: %i\thgt: %i\n", + // add->wid, add->hgt); + + add->framebuf = malloc(add->wid * add->hgt); + + if(!add->framebuf) + { + printf("Couldn't allocate framebuffer for driver \"%s\".\n", + driver); + free(add); + return -1; + } + //printf("Allocated frame buffer\n"); + + LL_Push(list, (void *)add); + + return drivers[i].init(add, args); + } + } + + return -1; +} + +// TODO: Put lcd_shutdown in the shutdown function... +int lcd_shutdown() +{ + lcd_logical_driver *del; + + LL_Rewind(list); + do { + del = (lcd_logical_driver *)LL_DeleteNode(list); + if(del->close) del->close(); + free(del); + } while(LL_Length(list) > 0); + + return 0; +} + + + +int lcd_drv_init(struct lcd_logical_driver *driver, char *args) +{ +// printf("lcd_drv_init()\n"); + + lcd.wid = 20; + lcd.hgt = 4; + + lcd.framebuf = NULL; +/* + if(!lcd.framebuf) + lcd.framebuf = malloc(lcd.wid * lcd.hgt); + + if(!lcd.framebuf) + { + lcd_drv_close(); + return -1; + } + memset(lcd.framebuf, ' ', lcd.wid*lcd.hgt); +*/ +// Debugging... +// if(lcd.framebuf) printf("Frame buffer: %i\n", (int)lcd.framebuf); + + lcd.cellwid = 5; + lcd.cellhgt = 8; + + // Set up these wrapper functions... + lcd.clear = lcd_drv_clear; + lcd.string = lcd_drv_string; + lcd.chr = lcd_drv_chr; + lcd.vbar = lcd_drv_vbar; + lcd.hbar = lcd_drv_hbar; + lcd.init_num = lcd_drv_init_num; + lcd.num = lcd_drv_num; + + lcd.init = lcd_drv_init; + lcd.close = lcd_drv_close; + lcd.flush = lcd_drv_flush; + lcd.flush_box = lcd_drv_flush_box; + lcd.contrast = lcd_drv_contrast; + lcd.backlight = lcd_drv_backlight; + lcd.set_char = lcd_drv_set_char; + lcd.icon = lcd_drv_icon; + lcd.init_vbar = lcd_drv_init_vbar; + lcd.init_hbar = lcd_drv_init_hbar; + lcd.draw_frame = lcd_drv_draw_frame; + + lcd.getkey = lcd_drv_getkey; + + + return 1; // 1 is arbitrary. (must be 1 or more) +} + + + +////////////////////////////////////////////////////////////////////// +// All functions below here call their respective driver functions... +// +// The way it works is this: +// It loops through the list of drivers, calling each one to keep +// them all synchronized. During this loop... +// - First, set the framebuffer to point to the drivers' framebuffer. +// (this ensures that whatever driver gets called will operate on +// the correct buffer) +// - Then, it checks to see what sort of call to make. +// driver->func() > 0 means it should call the driver function. +// driver->func() == NULL means it should not make a call. +// driver->func() == -1 means it should call the generic driver. +////////////////////////////////////////////////////////////////////// + + +void lcd_drv_close() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->close > 0) + driver->close(); + else if((int)driver->close == -1) + { + drv_base->close(); + } + } + } while(LL_Next(list) == 0); + +} + +void lcd_drv_clear() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->clear > 0) + driver->clear(); + else if((int)driver->clear == -1) + { + drv_base->clear(); + } + } + } while(LL_Next(list) == 0); + +} + + +void lcd_drv_flush() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->flush > 0) + driver->flush(); + else if((int)driver->flush == -1) + { + drv_base->flush(); + } + } + } while(LL_Next(list) == 0); +} + + +void lcd_drv_string(int x, int y, char string[]) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->string > 0) + driver->string(x,y,string); + else if((int)driver->string == -1) + { + drv_base->string(x,y,string); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_chr(int x, int y, char c) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->chr > 0) + driver->chr(x,y,c); + else if((int)driver->chr == -1) + { + drv_base->chr(x,y,c); + } + } + } while(LL_Next(list) == 0); +} + + + +void lcd_drv_contrast(int contrast) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->contrast > 0) + driver->contrast(contrast); + else if((int)driver->contrast == -1) + { + drv_base->contrast(contrast); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_backlight(int on) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->backlight > 0) + driver->backlight(on); + else if((int)driver->backlight == -1) + { + drv_base->backlight(on); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_init_vbar() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->init_vbar > 0) + driver->init_vbar(); + else if((int)driver->init_vbar == -1) + { + drv_base->init_vbar(); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_init_hbar() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->init_hbar > 0) + driver->init_hbar(); + else if((int)driver->init_hbar == -1) + { + drv_base->init_hbar(); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_init_num() +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->init_num > 0) + driver->init_num(); + else if((int)driver->init_num == -1) + { + drv_base->init_num(); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_num(int x, int num) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->num > 0) + driver->num(x,num); + else if((int)driver->num == -1) + { + drv_base->num(x,num); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_set_char(int n, char *dat) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->set_char > 0) + driver->set_char(n,dat); + else if((int)driver->set_char == -1) + { + drv_base->set_char(n,dat); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_vbar(int x, int len) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->vbar > 0) + driver->vbar(x,len); + else if((int)driver->vbar == -1) + { + drv_base->vbar(x,len); + } + } + } while(LL_Next(list) == 0); +} + +void lcd_drv_hbar(int x, int y, int len) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->hbar > 0) + driver->hbar(x,y,len); + else if((int)driver->hbar == -1) + { + drv_base->hbar(x,y,len); + } + } + } while(LL_Next(list) == 0); +} + + +void lcd_drv_icon(int which, char dest) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->icon > 0) + driver->icon(which,dest); + else if((int)driver->icon == -1) + { + drv_base->icon(which,dest); + } + } + } while(LL_Next(list) == 0); +} + + +void lcd_drv_flush_box(int lft, int top, int rgt, int bot) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->flush_box > 0) + driver->flush_box(lft,top,rgt,bot); + else if((int)driver->flush_box == -1) + { + drv_base->flush_box(lft,top,rgt,bot); + } + } + } while(LL_Next(list) == 0); + +} + + +// TODO: Check whether lcd.draw_frame() should really take a framebuffer +// TODO: as an argument, or if it should always use lcd.framebuf +void lcd_drv_draw_frame(char *dat) +{ + lcd_logical_driver *driver; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->draw_frame > 0) + driver->draw_frame(dat); + else if((int)driver->draw_frame == -1) + { + drv_base->draw_frame(dat); + } + } + } while(LL_Next(list) == 0); + +} + + +char lcd_drv_getkey() +{ + lcd_logical_driver *driver; + + char key; + + LL_Rewind(list); + do { + driver = (lcd_logical_driver *)LL_Get(list); + if(driver) + { + lcd.framebuf = driver->framebuf; + + if(driver->getkey > 0) + { + key = driver->getkey(); + if(key) return key; + } + else if((int)driver->getkey == -1) + { + key = drv_base->getkey(); + if(key) return key; + } + } + } while(LL_Next(list) == 0); + + return 0; +} diff --git a/tests/menutest.c b/tests/menutest.c new file mode 100644 index 0000000..eb5fd56 --- /dev/null +++ b/tests/menutest.c @@ -0,0 +1,88 @@ +#include "lcd.h" +#include "menu.h" + + + +extern menu_item MainMenu[]; +extern menu_item OptionsMenu[]; +extern int Shutdown_func(); +extern int Close_func(); +extern int OK_func(); +extern int Time24_func(); +extern int Contrast_func(); + + +menu_item MainMenu[] = { + "MAIN MENU", 0, 0, // Title + "Options", TYPE_MENU, (void *)OptionsMenu, + "Kill LCDproc", TYPE_FUNC, (void *)Shutdown_func, + "OK", TYPE_FUNC, (void *)OK_func, + 0, 0, 0, + +}; + +menu_item OptionsMenu[] = { + "OPTIONS MENU", TYPE_TITL, 0, // Title + "24-hour Time", TYPE_CHEK, (void *)Time24_func, + "Contrast...", TYPE_SLID, (void *)Contrast_func, + "OK", TYPE_FUNC, (void *)OK_func, + "Close Menu", TYPE_FUNC, (void *)Close_func, + "Exit Program", TYPE_FUNC, (void *)Shutdown_func, + "Another Title",TYPE_TITL, 0, + 0, 0, 0, +}; + + +///////////////// Elsewhere, we declare these... + +int Shutdown_func() +{ + // Do something here... + return MENU_KILL; +} + +int Close_func() +{ + return MENU_CLOSE; +} + +int OK_func() +{ + return MENU_OK; +} + + +int Time24_func(int input) +{ + static int status=0; + + if(input == MENU_READ) return status; + if(input == MENU_CHECK) status ^= 1; // does something. + return (status | MENU_OK); + // The status is "or"-ed with the MENU value to let do_menu() + // know what to do after selecting the item. (two return + // values in one. :) + + // Also, "MENU_OK" happens to be zero, so it does not matter + // unless you want something else (like MENU_CLOSE) +} + +int Contrast_func(int input) +{ + static int status=128; + + + if(input == MENU_READ) return status; + if(input == MENU_PLUS) status++; // does something. + if(input == MENU_MINUS) status--; // does something. + return (status | MENU_OK); +} + + +void main() +{ + lcd_init("", "curses"); + + do_menu(MainMenu); + +} diff --git a/tests/script b/tests/script new file mode 100644 index 0000000..a5acd05 --- /dev/null +++ b/tests/script @@ -0,0 +1,20 @@ +hello +screen_add_widget one w1 string +screen_add one +screen_add two +screen_add_widget one w1 string +screen_add_widget one w2 vbar +screen_add_widget two w1 hbar +screen_add_widget two w2 scroller +screen_del two +screen_add two +screen_del_widget w1 +screen_del_widget two w1 +screen_del_widget one w2 +screen_add_widget two w1 icon +screen_add_widget two w2 title +screen_add three +screen_add_widget three w1 string +screen_add_widget three w2 hbar +screen_add_widget one w2 string +screen_add_widget one w2 hbar diff --git a/tests/script.1 b/tests/script.1 new file mode 100644 index 0000000..8f97131 --- /dev/null +++ b/tests/script.1 @@ -0,0 +1,23 @@ +hello + +screen_add one +screen_widget_add one w1 string +screen_widget_set one w1 1 2 "Hello?" +screen_widget_add one title title +screen_widget_set one title "TEST SCREEN ONE" + +screen_add two +screen_widget_add two title title +screen_widget_add two 0% string +screen_widget_add two 100% string +screen_widget_add two cpubar hbar +screen_widget_set two title "CPU: 57.6%" +screen_widget_set two 0% 1 4 0% +screen_widget_set two 100% 17 4 100% +screen_widget_set two cpubar 3 4 47 + +screen_add three +screen_widget_add three w1 string +screen_widget_set three w1 1 3 "Me too!" +screen_widget_add three title title +screen_widget_set three title "TEST THREE" diff --git a/tests/script.2 b/tests/script.2 new file mode 100644 index 0000000..b516534 --- /dev/null +++ b/tests/script.2 @@ -0,0 +1,11 @@ +hello +screen_add one +screen_widget_add one w1 string +screen_widget_set one w1 7 2 CENTER +screen_widget_add one w2 string +screen_widget_set one w2 7 3 CENTER +screen_widget_add one title string +screen_widget_set one title 1 1 "## BOOGER! ##########" +screen_widget_set one title 1 1 "## BOOGER! #########" +screen_widget_set one w1 8 2 CENTER +screen_widget_set one w2 8 3 CENTER diff --git a/tests/script.3 b/tests/script.3 new file mode 100644 index 0000000..f5a212a --- /dev/null +++ b/tests/script.3 @@ -0,0 +1,21 @@ +hello +screen_add one +screen_add two +screen_add three +screen_add four +widget_add one title title +widget_add two title title +widget_add three title title +widget_add four title title +widget_set one title "One" +widget_set two title "Two" +widget_set three title "Three" +widget_set four title "Four" +widget_add one dot string +widget_add two dot string +widget_add three dot string +widget_add four dot string +widget_set one dot 1 2 . +widget_set two dot 2 2 . +widget_set three dot 3 2 . +widget_set four dot 4 2 . diff --git a/tests/socktest.c b/tests/socktest.c new file mode 100644 index 0000000..d7176dd --- /dev/null +++ b/tests/socktest.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +#define LCDPORT 13667 + +#include "../shared/sockets.h" + + +int main() +{ + char string[1024]; + char string2[1024]; + int sock; + int err; + + memset(string, 0, 1024); + + fcntl(stdin, F_SETFL, O_NONBLOCK); + + sock = sock_connect("localhost", LCDPORT); + + if(sock <= 0) + { + printf("Error opening socket.\n"); + return 1; + } + + + while(string[0] != 'q') + { + do { + err = sock_recv(sock, string2, 1024); + if (err > 0) printf("Received message: %s\n", string2); + } while(err > 0); + printf("Enter a string to send:\n\t"); + gets(string); + sock_send_string(sock, string); + } + sock_close(sock); + + return 0; +} diff --git a/tests/srvtest.c b/tests/srvtest.c new file mode 100644 index 0000000..f0fd699 --- /dev/null +++ b/tests/srvtest.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include + +// For debugging purposes... +// ... should not be defined in a release. +// (defaults to 13666) +//#define LCDPORT 13667 + +#include "../server/drivers/lcd.h" +#include "../server/sock.h" +#include "../server/clients.h" +#include "../server/screenlist.h" +#include "../server/screen.h" +#include "../server/parse.h" +#include "../server/render.h" +#include "../server/serverscreens.h" + + +void exit_program(int val); + + +int main() +{ + char string[1024]; + int sock; + screen *s; + int timer=0; + + + + // Ctrl-C will cause a clean exit... + signal(SIGINT, exit_program); + // and "kill"... + signal(SIGTERM, exit_program); + // and "kill -HUP" (hangup)... + signal(SIGHUP, exit_program); + // and just in case, "kill -KILL" (which cannot be trapped; but oh well) + signal(SIGKILL, exit_program); + + + memset(string, 0, 1024); + + lcd_init(""); + + // Feel free to add as many drivers as you like... :) + //lcd_add_driver("joy", ""); + //lcd_add_driver("curses", "Booger"); + lcd_add_driver("MtxOrb", ""); + + + + sock = sock_create_server(); + + if(sock <= 0) + { + printf("Error opening socket.\n"); + return 1; + } + + if(client_init() < 0) + { + printf("Error initializing client list\n"); + return 1; + } + + if(screenlist_init() < 0) + { + printf("Error initializing screen list\n"); + return 1; + } + + // Make sure the server screen shows up every once in a while.. + server_screen_init(); + + // Main loop... + while(1) + { + sock_poll_clients(); + parse_all_client_messages(); + // TODO: Check for and handle keypresses here... + //handle_input(); + + timer++; + if(timer >= 32) + { + timer = 0; + // TODO: Notify clients of "listen" and "ignore" + s = screenlist_next(); + if(s) + { + printf("Screen: %s\n", s->id); + } + } + draw_server_screen(timer); + s = screenlist_current(); + if(s) + { + // render something here... + draw_screen(s, timer); + } + else + { + no_screen_screen(timer); + } + + usleep(125000); + } + + // Say goodbye! + goodbye_screen(); + + // Can go anywhere... + lcd_shutdown(); + // Must come before screenlist_shutdown + client_shutdown(); + // Must come after client_shutdown + screenlist_shutdown(); + // Should come after client_shutdown + sock_close_all(); + + return 0; +} + + +void exit_program(int val) +{ + // Say goodbye! + goodbye_screen(); + + // Can go anywhere... + lcd_shutdown(); + // Must come before screenlist_shutdown + client_shutdown(); + // Must come after client_shutdown + screenlist_shutdown(); + // Should come after client_shutdown + sock_close_all(); + + exit(0); + +} diff --git a/tests/test b/tests/test new file mode 100644 index 0000000..3b760a2 --- /dev/null +++ b/tests/test @@ -0,0 +1,75 @@ +hello + +screen_add one + +widget_add one f frame +widget_set one f 1 2 10 3 20 4 v 2 +widget_add one g frame -in f +widget_set one g 5 1 15 3 20 4 v 2 + +widget_add one s string +widget_add one s string -in f +widget_add one s string -in g +widget_set one s 1 1 "123456789012345678901234567890" +widget_set one s 1 2 "123456789012345678901234567890" +widget_set one s 1 3 "123456789012345678901234567890" +widget_set one s 1 4 "123456789012345678901234567890" +widget_del one s + +widget_add one h hbar +widget_add one h hbar -in f +widget_add one h hbar -in g +widget_set one h 1 2 13 +widget_set one h 1 2 43 +widget_set one h 1 2 83 +widget_del one h + +widget_add one t title +widget_add one t title -in f +widget_add one t title -in g +widget_set one t Hello +widget_set one t "Hello there" +widget_set one t "Hi, there. Watch me scroll!" +widget_del one t + + +------------------------ Disk Screen test... +hello +screen_add D +widget_add D t title +widget_set D t "Disk Use" +widget_add D f frame +widget_set D f 1 2 20 4 20 8 v 8 +widget_add D s1 string -in f +widget_add D s2 string -in f +widget_add D s3 string -in f +widget_add D s4 string -in f +widget_add D s5 string -in f +widget_add D s6 string -in f +widget_add D s7 string -in f +widget_add D s8 string -in f +widget_add D h1 hbar -in f +widget_add D h2 hbar -in f +widget_add D h3 hbar -in f +widget_add D h4 hbar -in f +widget_add D h5 hbar -in f +widget_add D h6 hbar -in f +widget_add D h7 hbar -in f +widget_add D h8 hbar -in f +widget_set D s1 1 1 /foo +widget_set D s2 1 2 /bar +widget_set D s3 1 3 /baz +widget_set D s4 1 4 /quux +widget_set D s5 1 5 /foobar +widget_set D s6 1 6 /tmp +widget_set D s7 1 7 /snot +widget_set D s8 1 8 /booger +widget_set D h1 10 1 3 +widget_set D h2 10 2 6 +widget_set D h3 10 3 9 +widget_set D h4 10 4 12 +widget_set D h5 10 5 15 +widget_set D h6 10 6 18 +widget_set D h7 10 7 21 +widget_set D h8 10 8 24 +---------------------------