From 2635c3085d0efae33ca91cf89d8d1eceff03dccd Mon Sep 17 00:00:00 2001 From: William Ferrell Date: Thu, 9 Dec 1999 23:15:14 +0000 Subject: [PATCH] Initial revision --- BUGS | 13 + COPYING | 339 ++++++++++ INSTALL | 160 +++++ Makefile | 133 ++++ Makefile.config | 136 ++++ README | 64 ++ README.IRman | 65 ++ TODO | 86 +++ WHATSNEW | 108 ++++ clients/Makefile | 39 ++ clients/examples/fortune.pl | 75 +++ clients/examples/iosock.pl | 85 +++ clients/examples/tail.pl | 121 ++++ clients/examples/x11amp.pl | 85 +++ clients/headlines/lcdheadlines | 293 +++++++++ clients/lcdproc/Makefile | 41 ++ clients/lcdproc/batt.c | 193 ++++++ clients/lcdproc/batt.h | 10 + clients/lcdproc/chrono.c | 566 ++++++++++++++++ clients/lcdproc/chrono.h | 12 + clients/lcdproc/cpu.c | 365 +++++++++++ clients/lcdproc/cpu.h | 12 + clients/lcdproc/disk.c | 322 ++++++++++ clients/lcdproc/disk.h | 9 + clients/lcdproc/load.c | 152 +++++ clients/lcdproc/load.h | 19 + clients/lcdproc/main.c | 440 +++++++++++++ clients/lcdproc/main.h | 37 ++ clients/lcdproc/mem.c | 466 ++++++++++++++ clients/lcdproc/mem.h | 11 + clients/lcdproc/mode.c | 282 ++++++++ clients/lcdproc/mode.h | 31 + docs/README.dg | 68 ++ docs/README.dg2 | 74 +++ docs/hd44780_howto.txt | 49 ++ docs/lcdproc.1 | 119 ++++ docs/lcdproc.sgml | 674 +++++++++++++++++++ docs/menustuff.txt | 126 ++++ docs/netstuff.txt | 298 +++++++++ old/LCDproc_objectmethods.txt | 49 ++ old/LCDproc_objects.txt | 92 +++ old/cfg.c | 443 +++++++++++++ old/cfg.h | 70 ++ old/cfg_test.c | 76 +++ old/cfg_testfile.cfg | 15 + old/change.log | 73 +++ old/llistd.c | 429 +++++++++++++ old/llistd.h | 63 ++ old/main.c | 318 +++++++++ old/main.h | 16 + old/menu.c | 162 +++++ old/menu.h | 58 ++ old/mode.c | 1107 ++++++++++++++++++++++++++++++++ old/mode.h | 30 + old/sockets.c | 273 ++++++++ old/sockets.h | 99 +++ old/stat.c | 644 +++++++++++++++++++ old/stat.h | 58 ++ server/Makefile | 52 ++ server/client_data.c | 89 +++ server/client_data.h | 26 + server/client_functions.c | 986 ++++++++++++++++++++++++++++ server/client_functions.h | 41 ++ server/client_menu.h | 27 + server/clients.c | 266 ++++++++ server/clients.h | 40 ++ server/drivers/CFontz.c | 718 +++++++++++++++++++++ server/drivers/CFontz.h | 26 + server/drivers/DOTirmanrc | 92 +++ server/drivers/Makefile | 45 ++ server/drivers/MtxOrb.c | 1047 ++++++++++++++++++++++++++++++ server/drivers/MtxOrb.h | 31 + server/drivers/curses_drv.c | 322 ++++++++++ server/drivers/curses_drv.h | 24 + server/drivers/debug.c | 288 +++++++++ server/drivers/debug.h | 26 + server/drivers/drv_base.c | 311 +++++++++ server/drivers/drv_base.h | 119 ++++ server/drivers/hd44780.c | 562 ++++++++++++++++ server/drivers/hd44780.h | 49 ++ server/drivers/ideas.txt | 21 + server/drivers/irmanin.c | 218 +++++++ server/drivers/irmanin.h | 12 + server/drivers/joy.c | 218 +++++++ server/drivers/joy.h | 12 + server/drivers/lcd.c | 727 +++++++++++++++++++++ server/drivers/lcd.h | 95 +++ server/drivers/lcddriver.c | 124 ++++ server/drivers/port.h | 51 ++ server/drivers/text.c | 236 +++++++ server/drivers/text.h | 25 + server/drivers/wirz-sli.c | 562 ++++++++++++++++ server/drivers/wirz-sli.h | 33 + server/input.c | 131 ++++ server/input.h | 9 + server/main.c | 369 +++++++++++ server/main.h | 31 + server/menu.c | 355 ++++++++++ server/menu.h | 143 +++++ server/menus.c | 339 ++++++++++ server/menus.h | 16 + server/parse.c | 148 +++++ server/parse.h | 7 + server/render.c | 526 +++++++++++++++ server/render.h | 29 + server/screen.c | 171 +++++ server/screen.h | 29 + server/screenlist.c | 273 ++++++++ server/screenlist.h | 31 + server/serverscreens.c | 228 +++++++ server/serverscreens.h | 14 + server/sock.c | 275 ++++++++ server/sock.h | 18 + server/widget.c | 391 +++++++++++ server/widget.h | 45 ++ shared/LL.c | 728 +++++++++++++++++++++ shared/LL.h | 209 ++++++ shared/Makefile | 41 ++ shared/config.c | 158 +++++ shared/config.h | 12 + shared/debug.h | 14 + shared/sockets.c | 183 ++++++ shared/sockets.h | 87 +++ shared/str.c | 34 + shared/str.h | 6 + tests/LL_test.c | 156 +++++ tests/Makefile | 128 ++++ tests/bartest | 42 ++ tests/ctest.c | 30 + tests/drv_test.c | 54 ++ tests/lcd.c | 638 ++++++++++++++++++ tests/menutest.c | 88 +++ tests/script | 20 + tests/script.1 | 23 + tests/script.2 | 11 + tests/script.3 | 21 + tests/socktest.c | 44 ++ tests/srvtest.c | 144 +++++ tests/test | 75 +++ 139 files changed, 24298 insertions(+) create mode 100644 BUGS create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 Makefile.config create mode 100644 README create mode 100644 README.IRman create mode 100644 TODO create mode 100644 WHATSNEW create mode 100644 clients/Makefile create mode 100755 clients/examples/fortune.pl create mode 100755 clients/examples/iosock.pl create mode 100755 clients/examples/tail.pl create mode 100755 clients/examples/x11amp.pl create mode 100755 clients/headlines/lcdheadlines create mode 100644 clients/lcdproc/Makefile create mode 100644 clients/lcdproc/batt.c create mode 100644 clients/lcdproc/batt.h create mode 100644 clients/lcdproc/chrono.c create mode 100644 clients/lcdproc/chrono.h create mode 100644 clients/lcdproc/cpu.c create mode 100644 clients/lcdproc/cpu.h create mode 100644 clients/lcdproc/disk.c create mode 100644 clients/lcdproc/disk.h create mode 100644 clients/lcdproc/load.c create mode 100644 clients/lcdproc/load.h create mode 100644 clients/lcdproc/main.c create mode 100644 clients/lcdproc/main.h create mode 100644 clients/lcdproc/mem.c create mode 100644 clients/lcdproc/mem.h create mode 100644 clients/lcdproc/mode.c create mode 100644 clients/lcdproc/mode.h create mode 100644 docs/README.dg create mode 100644 docs/README.dg2 create mode 100644 docs/hd44780_howto.txt create mode 100644 docs/lcdproc.1 create mode 100644 docs/lcdproc.sgml create mode 100644 docs/menustuff.txt create mode 100644 docs/netstuff.txt create mode 100644 old/LCDproc_objectmethods.txt create mode 100644 old/LCDproc_objects.txt create mode 100644 old/cfg.c create mode 100644 old/cfg.h create mode 100644 old/cfg_test.c create mode 100644 old/cfg_testfile.cfg create mode 100644 old/change.log create mode 100644 old/llistd.c create mode 100644 old/llistd.h create mode 100644 old/main.c create mode 100644 old/main.h create mode 100644 old/menu.c create mode 100644 old/menu.h create mode 100644 old/mode.c create mode 100644 old/mode.h create mode 100644 old/sockets.c create mode 100644 old/sockets.h create mode 100644 old/stat.c create mode 100644 old/stat.h create mode 100644 server/Makefile create mode 100644 server/client_data.c create mode 100644 server/client_data.h create mode 100644 server/client_functions.c create mode 100644 server/client_functions.h create mode 100644 server/client_menu.h create mode 100644 server/clients.c create mode 100644 server/clients.h create mode 100644 server/drivers/CFontz.c create mode 100644 server/drivers/CFontz.h create mode 100644 server/drivers/DOTirmanrc create mode 100644 server/drivers/Makefile create mode 100644 server/drivers/MtxOrb.c create mode 100644 server/drivers/MtxOrb.h create mode 100644 server/drivers/curses_drv.c create mode 100644 server/drivers/curses_drv.h create mode 100644 server/drivers/debug.c create mode 100644 server/drivers/debug.h create mode 100644 server/drivers/drv_base.c create mode 100644 server/drivers/drv_base.h create mode 100644 server/drivers/hd44780.c create mode 100644 server/drivers/hd44780.h create mode 100644 server/drivers/ideas.txt create mode 100644 server/drivers/irmanin.c create mode 100644 server/drivers/irmanin.h create mode 100644 server/drivers/joy.c create mode 100644 server/drivers/joy.h create mode 100644 server/drivers/lcd.c create mode 100644 server/drivers/lcd.h create mode 100644 server/drivers/lcddriver.c create mode 100644 server/drivers/port.h create mode 100644 server/drivers/text.c create mode 100644 server/drivers/text.h create mode 100644 server/drivers/wirz-sli.c create mode 100644 server/drivers/wirz-sli.h create mode 100644 server/input.c create mode 100644 server/input.h create mode 100644 server/main.c create mode 100644 server/main.h create mode 100644 server/menu.c create mode 100644 server/menu.h create mode 100644 server/menus.c create mode 100644 server/menus.h create mode 100644 server/parse.c create mode 100644 server/parse.h create mode 100644 server/render.c create mode 100644 server/render.h create mode 100644 server/screen.c create mode 100644 server/screen.h create mode 100644 server/screenlist.c create mode 100644 server/screenlist.h create mode 100644 server/serverscreens.c create mode 100644 server/serverscreens.h create mode 100644 server/sock.c create mode 100644 server/sock.h create mode 100644 server/widget.c create mode 100644 server/widget.h create mode 100644 shared/LL.c create mode 100644 shared/LL.h create mode 100644 shared/Makefile create mode 100644 shared/config.c create mode 100644 shared/config.h create mode 100644 shared/debug.h create mode 100644 shared/sockets.c create mode 100644 shared/sockets.h create mode 100644 shared/str.c create mode 100644 shared/str.h create mode 100644 tests/LL_test.c create mode 100644 tests/Makefile create mode 100644 tests/bartest create mode 100644 tests/ctest.c create mode 100644 tests/drv_test.c create mode 100644 tests/lcd.c create mode 100644 tests/menutest.c create mode 100644 tests/script create mode 100644 tests/script.1 create mode 100644 tests/script.2 create mode 100644 tests/script.3 create mode 100644 tests/socktest.c create mode 100644 tests/srvtest.c create mode 100644 tests/test 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 +---------------------------