Initial revision
This commit is contained in:
@@ -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...
|
||||
@@ -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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
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.
|
||||
|
||||
<signature of Ty Coon>, 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.
|
||||
@@ -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).
|
||||
@@ -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!
|
||||
|
||||
+136
@@ -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 ---------------===========================================
|
||||
@@ -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.
|
||||
|
||||
@@ -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 <dglaude@comtech.be>
|
||||
|
||||
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).
|
||||
|
||||
@@ -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.. :)
|
||||
|
||||
----------------------------------------
|
||||
@@ -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 <frame_name>" 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...
|
||||
|
||||
@@ -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 . &
|
||||
|
||||
Executable
+75
@@ -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";
|
||||
|
||||
}
|
||||
Executable
+85
@@ -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;
|
||||
Executable
+121
@@ -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;
|
||||
Executable
+85
@@ -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;
|
||||
Executable
+293
@@ -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...
|
||||
# <daeron@shadowmere.student.utwente.nl>
|
||||
#
|
||||
# Proxy support based on code provided by Dan Gundlach...
|
||||
# <dan@msl.net>
|
||||
#
|
||||
# Proper HTTP/1.1 calls by Kjeld Hoyer Mortensen...
|
||||
# <khm@daimi.au.dk>
|
||||
#
|
||||
# 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 = <SOCK>)) {
|
||||
$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 = <TMPFILE>;
|
||||
}
|
||||
|
||||
unless (eof(MENUFILE)) {
|
||||
$menuline = <MENUFILE>;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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 . &
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef BATT_H
|
||||
#define BATT_H
|
||||
|
||||
int batt_init();
|
||||
int batt_close();
|
||||
|
||||
int battery_screen(int rep, int display);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,566 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#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()
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,365 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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<CPU_BUF_SIZE-1; i++)
|
||||
for(j=0; j<5; j++)
|
||||
cpu[i][j] = cpu[CPU_BUF_SIZE-1][j];
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Average values for final result
|
||||
for(i=0; i<5; i++)
|
||||
{
|
||||
value = 0;
|
||||
for(j=0; j<CPU_BUF_SIZE; j++)
|
||||
{
|
||||
value += cpu[j][i];
|
||||
}
|
||||
value /= CPU_BUF_SIZE;
|
||||
cpu[CPU_BUF_SIZE][i] = value;
|
||||
}
|
||||
|
||||
|
||||
if(lcd_hgt >= 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<CPU_BUF_SIZE-1; i++)
|
||||
cpu[i] = cpu[CPU_BUF_SIZE-1];
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
// Average values for final result
|
||||
value = 0;
|
||||
for(j=0; j<CPU_BUF_SIZE; j++)
|
||||
{
|
||||
value += cpu[j];
|
||||
}
|
||||
value /= (float)CPU_BUF_SIZE;
|
||||
cpu[CPU_BUF_SIZE] = value;
|
||||
|
||||
|
||||
maxload=0;
|
||||
for(i=0; i<lcd_wid-1; i++)
|
||||
{
|
||||
cpu_past[i] = cpu_past[i+1];
|
||||
|
||||
j = cpu_past[i];
|
||||
sprintf(tmp, "widget_set G %i %i %i %i\n",
|
||||
i+1, i+1, lcd_hgt, j);
|
||||
if(display) sock_send_string(sock, tmp);
|
||||
|
||||
if(cpu_past[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()
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,322 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef LINUX
|
||||
#include <sys/vfs.h>
|
||||
#else
|
||||
#ifdef xBSD
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#else
|
||||
#include <sys/statfs.h>
|
||||
#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<count; i++)
|
||||
{
|
||||
if(strlen(mnt[i].mpoint) > 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<count; i++)
|
||||
{
|
||||
if(table[i].dev[0] == 0) continue;
|
||||
if(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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef DISK_H
|
||||
#define DISK_H
|
||||
|
||||
int disk_init();
|
||||
int disk_close();
|
||||
|
||||
int disk_screen(int rep, int display);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,152 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#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<lcd_wid; i++)
|
||||
{
|
||||
sprintf(tmp, "widget_add X %i vbar\n", i);
|
||||
sock_send_string(sock, tmp);
|
||||
sprintf(tmp, "widget_set X %i %i %i 0\n", i, i, lcd_hgt);
|
||||
sock_send_string(sock, tmp);
|
||||
}
|
||||
// And add a title...
|
||||
if(lcd_hgt >= 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<lcd_wid-1; n++)
|
||||
if(loads[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<lcd_wid-1; n++)
|
||||
{
|
||||
x = (loads[n] * factor);
|
||||
|
||||
sprintf(tmp, "widget_set X %i %i %i %i\n", n+1, n+1, lcd_hgt, (int)x);
|
||||
//if(display) sock_send_string(sock, tmp);
|
||||
sock_send_string(sock, tmp);
|
||||
}
|
||||
|
||||
if(loadmax < LOAD_MIN)
|
||||
{
|
||||
status = BACKLIGHT_OFF;
|
||||
}
|
||||
if(loadmax > 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()
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,440 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#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<argc; i++)
|
||||
{
|
||||
if(argv[i][0] == '-') switch(argv[i][1])
|
||||
{
|
||||
// s is for server
|
||||
case 'S':
|
||||
case 's': if(argc < i+1) HelpScreen();
|
||||
strcpy(server, argv[++i]);
|
||||
break;
|
||||
// p is for port
|
||||
case 'P':
|
||||
case 'p': if(argc < i+1) HelpScreen();
|
||||
port = atoi(argv[++i]);
|
||||
if(port < 1 && port > 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<argc; i++) argv[i]=NULL; // Get rid of old tokens
|
||||
argc = 0; newtoken = 1;
|
||||
for(i=0; i<len; i++)
|
||||
{
|
||||
if(buf[i]) // For regular letters, keep tokenizing...
|
||||
{
|
||||
switch(buf[i])
|
||||
{
|
||||
case ' ':
|
||||
newtoken = 1;
|
||||
buf[i] = 0;
|
||||
break;
|
||||
case '\n':
|
||||
buf[i] = 0;
|
||||
default:
|
||||
if(newtoken)
|
||||
{
|
||||
argv[argc] = buf+i;
|
||||
argc++;
|
||||
}
|
||||
newtoken = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else // If we've got a zero, it's the end of a string...
|
||||
{
|
||||
if(argc > 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<argc; a++)
|
||||
{
|
||||
if(0 == strcmp(argv[a], "wid"))
|
||||
lcd_wid = atoi(argv[++a]);
|
||||
else if(0 == strcmp(argv[a], "hgt"))
|
||||
lcd_hgt = atoi(argv[++a]);
|
||||
else if(0 == strcmp(argv[a], "cellwid"))
|
||||
lcd_cellwid = atoi(argv[++a]);
|
||||
else if(0 == strcmp(argv[a], "cellhgt"))
|
||||
lcd_cellhgt = atoi(argv[++a]);
|
||||
}
|
||||
}
|
||||
else if(0 == strcmp(argv[0], "bye"))
|
||||
{
|
||||
//printf("Exiting LCDproc\n");
|
||||
exit_program(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int j;
|
||||
for(j=0; j<argc; j++)
|
||||
printf("%s ", argv[j]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
argc = 0; newtoken = 1;
|
||||
}
|
||||
}
|
||||
|
||||
len = sock_recv(sock, buf, 8000);
|
||||
//debug("\n");
|
||||
}
|
||||
|
||||
// Gather stats...
|
||||
// Update screens...
|
||||
for(i=0; sequence[i].which > 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<sequence[i].num_times && !Quit); j++)
|
||||
{
|
||||
switch(sequence[i].which)
|
||||
{
|
||||
case 'g':
|
||||
case 'G': status = cpu_graph_screen(j); break;
|
||||
case 'c':
|
||||
case 'C': status = cpu_screen(j); break;
|
||||
case 'o':
|
||||
case 'O': status = clock_screen(j); break;
|
||||
case 'k':
|
||||
case 'K': status = big_clock_screen(j); break;
|
||||
case 'm':
|
||||
case 'M': status = mem_screen(j); break;
|
||||
case 'u':
|
||||
case 'U': status = uptime_screen(j); break;
|
||||
case 't':
|
||||
case 'T': status = time_screen(j); break;
|
||||
case 'd':
|
||||
case 'D': status = disk_screen(j); break;
|
||||
case 'x':
|
||||
case 'X': status = xload_screen(j); break;
|
||||
case 'b':
|
||||
case 'B': status = battery_screen(j); break;
|
||||
case 'a':
|
||||
case 'A': status = credit_screen(j); break;
|
||||
default: status = dumbass_screen(j); break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for(k=0; k<sequence[i].delay_time; k++)
|
||||
{
|
||||
usleep(TIME_UNIT); timer++;
|
||||
// Modify lcd status here... (blinking, for example)
|
||||
switch(status)
|
||||
{
|
||||
case BLINK_ON : blink=1; break;
|
||||
case BLINK_OFF: blink=0; lcd.backlight(1); break;
|
||||
case BACKLIGHT_OFF: blink=0; lcd.backlight(0); break;
|
||||
case BACKLIGHT_ON : blink=0; lcd.backlight(1); break;
|
||||
case CONTINUE : hold=0; break;
|
||||
}
|
||||
status=0;
|
||||
|
||||
if(blink) lcd.backlight(! ((timer&15) == 15));
|
||||
|
||||
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();
|
||||
|
||||
PollSockets();
|
||||
}
|
||||
}
|
||||
i++;
|
||||
if(sequence[i].which < 2) i=0;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
extern int Quit;
|
||||
extern int sock;
|
||||
extern char * version;
|
||||
extern char * build_date;
|
||||
|
||||
extern int lcd_wid;
|
||||
extern int lcd_hgt;
|
||||
extern int lcd_cellwid;
|
||||
extern int lcd_cellhgt;
|
||||
|
||||
|
||||
typedef struct mode {
|
||||
char which; // Which screen is it?
|
||||
int on_time; // How often to update while visible?
|
||||
int off_time; // How often to get stats while not visible?
|
||||
int show_invisible; // Send stats while not visible?
|
||||
int timer; // Time since last update
|
||||
int visible; // Can we be seen right now?
|
||||
} mode;
|
||||
|
||||
|
||||
|
||||
#define BLINK_ON 0x10
|
||||
#define BLINK_OFF 0x11
|
||||
#define BACKLIGHT_OFF 0x20
|
||||
#define BACKLIGHT_ON 0x21
|
||||
#define HOLD_SCREEN 0x30
|
||||
#define CONTINUE 0x31
|
||||
|
||||
|
||||
#define LCD_MAX_WIDTH 80
|
||||
#define LCD_MAX_HEIGHT 80
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,466 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef IRIX
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#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()
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* This file contains status-gathering code *and* modescreen functions.
|
||||
* It's long, and messy.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef IRIX
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#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()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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---
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
(this text taken from a message by Bill Farrow, more info coming later)
|
||||
<bfarrow@arrow.bsee.swin.edu.au>
|
||||
|
||||
|
||||
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.
|
||||
|
||||
+119
@@ -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.
|
||||
@@ -0,0 +1,674 @@
|
||||
<!DOCTYPE book PUBLIC "-//Davenport//DTD DocBook V3.0//EN">
|
||||
|
||||
<book>
|
||||
<bookinfo>
|
||||
<date>1999-02-08</date>
|
||||
<title>LCDproc User's Guide</title>
|
||||
<subtitle>Installation and Client Development Guide</subtitle>
|
||||
</bookinfo>
|
||||
<toc></toc>
|
||||
|
||||
<chapter>
|
||||
<title>Introduction</title>
|
||||
<para>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.
|
||||
</para>
|
||||
<para>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.
|
||||
</para>
|
||||
<sect1>
|
||||
<title>Supported Hardware</title>
|
||||
<para>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.
|
||||
</para>
|
||||
<sect2>
|
||||
<title>Matrix Orbital LCD Modules</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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).
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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).
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>HD44780 Controller-Based LCDs</title>
|
||||
<para>
|
||||
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].
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>LCD Emulation</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>LCDproc Documentation</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
This documentation was written in SGML and
|
||||
<ULINK URL="http://www.oasis-open.org/docbook/">DocBook</ULINK>. 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.
|
||||
</para>
|
||||
<para>
|
||||
In Linux, one can produce DVI, PostScript, HTML, Unix Manual Pages and Info
|
||||
pages from the same SGML/DocBook source using
|
||||
<ULINK URL="http://www.sgmltools.org/">SGMLtools</ULINK>. 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.
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<title>Installation</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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).
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<sect1>
|
||||
<title>Hardware Installation</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<Warning>
|
||||
<Title>Warning!</Title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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).
|
||||
</para>
|
||||
</Warning>
|
||||
<sect2>
|
||||
<title>Matrix Orbital LCD/VFD Module Installation</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<Tip>
|
||||
<Title>Before you start</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</tip>
|
||||
<sect3>
|
||||
<title>Power Cable Modification</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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]
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<Warning>
|
||||
<title>Warning!</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</Warning>
|
||||
<para>
|
||||
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]
|
||||
</para>
|
||||
<para>
|
||||
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]
|
||||
</para>
|
||||
<para>
|
||||
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]
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<Caution>
|
||||
<Title>Caution</Title>
|
||||
<para>
|
||||
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),
|
||||
<EMPHASIS>immediately</EMPHASIS> 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.
|
||||
</para>
|
||||
</Caution>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<Note>
|
||||
<title>Note</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</Note>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>Serial Connection</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Other Display Types</title>
|
||||
<para>
|
||||
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
|
||||
(<ULINK URL="mailto:choadster@earthlink.net">choadster@earthlink.net</ULINK>).
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
<chapter>
|
||||
<title>LCDproc Distribution Layout</title>
|
||||
<para>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]</para>
|
||||
|
||||
<sect1>
|
||||
<title>Basic Layout</title>
|
||||
<para>
|
||||
LCDproc is distributed in a single archive containing both the client(s)
|
||||
and the server:
|
||||
<SimpleList columns=2>
|
||||
<Member>clients/</Member>
|
||||
<Member>docs/</Member>
|
||||
<Member>old/</Member>
|
||||
<Member>server/</Member>
|
||||
<Member>server/drivers/</Member>
|
||||
<Member>shared/</Member>
|
||||
<Member>tests/</Member>
|
||||
<Member>BUGS</Member>
|
||||
<Member>COPYING</Member>
|
||||
<Member>INSTALL</Member>
|
||||
<Member>Makefile</Member>
|
||||
<Member>Makefile.config</Member>
|
||||
<Member>README</Member>
|
||||
<Member>TODO</Member>
|
||||
<Member>WHATSNEW</Member>
|
||||
<Member>Contains the LCDproc client and the sample Perl client</Member>
|
||||
<Member>Documentation (sparse at the moment)</Member>
|
||||
<Member>Contains older source code, unused in compiling v0.4</Member>
|
||||
<Member>Contains the LCDproc server</Member>
|
||||
<Member>Contains LCDproc's device drivers</Member>
|
||||
<Member>Contains shared code</Member>
|
||||
<Member>Contains test code not used in compiling</Member>
|
||||
<Member>A list of known bugs in the current version</Member>
|
||||
<Member>The GNU General Public License</Member>
|
||||
<Member>Installation Instructions</Member>
|
||||
<Member>File for the "make" utility, used to compile LCDproc</Member>
|
||||
<Member>Contains compile-time user-tunable defaults for LCDproc</Member>
|
||||
<Member>Read this file first! Contains basic information regarding LCDproc,
|
||||
what it does, how it works, and how to start building it.</Member>
|
||||
<Member>List of planned changes and improvements.</Member>
|
||||
<Member>List of revisions that have been made to LCDproc throughout its
|
||||
development. [This should be changed to ChangeLog]</Member>
|
||||
</Simplelist>
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>A Stroll Through the Code</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<sect2>
|
||||
<title>The LCDproc Server, LCDd</title>
|
||||
<para>
|
||||
LCDd is the central component of LCDproc. It is responsible for several
|
||||
different activities:
|
||||
|
||||
<SimpleList>
|
||||
<Member>Initializing the output device</Member>
|
||||
<Member>Initializing the incoming socket</Member>
|
||||
<Member>Listening for client connections and accepting them</Member>
|
||||
<Member>Storing screens provided by clients</Member>
|
||||
<Member>Storing stats provided by clients</Member>
|
||||
<Member>Choose the best screen to display on the LCD based on order of
|
||||
client and screen arrival, and by priority</Member>
|
||||
<Member>Provide a rich screen-drawing widget set for clients to use</Member>
|
||||
<Member>Render screens to the LCD</Member>
|
||||
<Member>Gracefully handle dead sockets and clients</Member>
|
||||
<Member>Gracefully remove screens and clients when asked to by clients or
|
||||
the user</Member>
|
||||
</SimpleList>
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<sect3>
|
||||
<title>server/client_data.c</title>
|
||||
<para>
|
||||
This file appears to contain code that handles the creation and destruction
|
||||
of linked lists for client data.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/client_functions.c</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
Here the functions that clients call when connected to LCDd are actually
|
||||
defined and performed.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/clients.c</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/input.c</title>
|
||||
<para>
|
||||
This file contains functions that handle input from keypads, joysticks,
|
||||
etc.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/main.c</title>
|
||||
<para>
|
||||
Where the action is.
|
||||
</para>
|
||||
<para>
|
||||
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.</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
Also present are functions to handle graceful exits when various signals
|
||||
are received, and a help screen.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/menu.c</title>
|
||||
<para>
|
||||
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]
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/parse.c</title>
|
||||
<para>
|
||||
This file contains code that parses input from the clients.
|
||||
parse_all_client_messages() is called once each time through main()'s loop.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/render.c</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/screen.c</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/screenlist.c</title>
|
||||
<para>
|
||||
This appears to be the screenlist handler that decides which screen to
|
||||
display based on priorities and screen creation order.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/serverscreens.c</title>
|
||||
<para>
|
||||
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).
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/sock.c</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/widget.c</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>server/drivers/*</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
Currently, drivers provided are MtxOrb, hd44780, curses, and joy. The
|
||||
joystick (joy) driver doesn't provide output, but only input.
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>The LCDproc Client</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
The client appears to use files from the share/ tree as well.
|
||||
</para>
|
||||
<sect3>
|
||||
<title>clients/lcdproc/batt.c, chrono.c, cpu.c, disk.c, load.c, mem.c</title>
|
||||
<para>
|
||||
These files contain the functions implementing all the screens provided by
|
||||
LCDproc.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>clients/lcdproc/main.c</title>
|
||||
<para>
|
||||
This file contains the LCDproc client's main() function, as well as a few
|
||||
supporting functions.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>clients/lcdproc/mode.c</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
This file also contains reread() and getentry() functions which are used by
|
||||
many of the mode screens.
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>Shared Files</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<sect3>
|
||||
<title>shared/config.c</title>
|
||||
<para>
|
||||
This file contains the beginnings of configuration file code.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>shared/LL.c</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>shared/sockets.c</title>
|
||||
<para>
|
||||
This file contains all the functions used in implementing LCDproc's socket
|
||||
handling capabilities. Full bi-directional communication is implemented by
|
||||
these functions.
|
||||
</para>
|
||||
</sect3>
|
||||
<sect3>
|
||||
<title>shared/str.c</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
</book>
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cfg.h"
|
||||
|
||||
|
||||
|
||||
/**************************
|
||||
* PUBLIC METHODS
|
||||
*/
|
||||
|
||||
void cfg_free(cfg *self) {
|
||||
struct cfg_node *ptr, *nextptr;
|
||||
int i;
|
||||
|
||||
for(i=0;i<CFG_HASHSIZE;i++) {
|
||||
if(self->cfg_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<CFGF_MAXLINES)) {
|
||||
rd=fgets(buffer,CFGF_LINELEN-1,fh);
|
||||
if (rd&&strlen(buffer)) {
|
||||
if (buffer[strlen(buffer)-1]=='\n') {
|
||||
buffer[strlen(buffer)-1]='\0';
|
||||
}
|
||||
if (buffer[0]=='#') {
|
||||
comment=1;
|
||||
} else {
|
||||
comment=0;
|
||||
}
|
||||
if (comment) {
|
||||
outbuf[linenum]=strdup(buffer);
|
||||
} else {
|
||||
if (self->_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<linenum;i++) {
|
||||
fprintf(fh,"%s\n",outbuf[i]);
|
||||
free(outbuf[i]);
|
||||
}
|
||||
fclose(fh);
|
||||
self->_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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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!
|
||||
@@ -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.
|
||||
+429
@@ -0,0 +1,429 @@
|
||||
#include <stdio.h> // 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<i; j++)
|
||||
{
|
||||
if(compare(current, best) > 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.
|
||||
}
|
||||
@@ -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
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#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<argc; i++)
|
||||
{
|
||||
if(argv[i][0] == '-') switch(argv[i][1])
|
||||
{
|
||||
// "C is for cookie (erm, contrast), and that is good enough for me..."
|
||||
case 'C':
|
||||
case 'c': if(argc < i+1) HelpScreen();
|
||||
contrast = atoi(argv[++i]);
|
||||
if(contrast <= 0) HelpScreen();
|
||||
break;
|
||||
// D for Device...
|
||||
case 'D':
|
||||
case 'd': if(argc < i+1) HelpScreen();
|
||||
strcpy(device, argv[++i]);
|
||||
break;
|
||||
case 'L':
|
||||
case 'l': if(argc < i+1) HelpScreen();
|
||||
strcpy(driver, argv[++i]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Init the com port
|
||||
if(lcd_init(device, driver) < 1)
|
||||
{
|
||||
printf("Cannot initialize %s.\n", device);
|
||||
exit(1);
|
||||
}
|
||||
mode_init();
|
||||
lcd.contrast(contrast);
|
||||
|
||||
main_loop(sequence);
|
||||
|
||||
// Clean up
|
||||
exit_program(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void HelpScreen()
|
||||
{
|
||||
printf("LCDproc, %s\n", version);
|
||||
printf("Usage: lcdproc [-d device] [-c contrast] [modelist]\n");
|
||||
printf("\tOptions in []'s are optional.\n");
|
||||
printf("\t-l driver is the output driver to use:\n");
|
||||
printf("\t\tMtxOrb, curses, text, debug\n");
|
||||
printf("\t-d device is what the lcd display is hooked to. (/dev/cua0?)\n");
|
||||
printf("\t-c contrast sets the screen contrast (0 - 255)\n");
|
||||
printf("\tmodelist is \"mode [mode mode ...]\"\n");
|
||||
printf("\tMode letters: [C]pu [G]raph [T]ime [M]emory [X]load [D]isk [B]attery [O]ld Time screen [U]ptime [A]bout\n");
|
||||
printf("\n");
|
||||
printf("\tUse \"man lcdproc\" for more info.\n");
|
||||
printf("Example:\n");
|
||||
printf("\tlcdproc -d /dev/cua1 C M X -l MtxOrb\n");
|
||||
printf("\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Called upon TERM and INTR signals...
|
||||
//
|
||||
void exit_program(int val)
|
||||
{
|
||||
Quit = 1;
|
||||
//unlock(); // Not needed any more...
|
||||
CloseAllConnections();
|
||||
goodbye_screen(0);
|
||||
lcd.flush();
|
||||
lcd.backlight(1);
|
||||
lcd.close();
|
||||
mode_close();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Main program loop...
|
||||
//
|
||||
void main_loop(mode *sequence)
|
||||
{
|
||||
int i, j, k;
|
||||
int Quit=0;
|
||||
int status=0;
|
||||
int timer=0;
|
||||
|
||||
int blink=0;
|
||||
int hold=0;
|
||||
int heartbeat=1;
|
||||
|
||||
// Main loop
|
||||
// Run whatever screen we want, then wait. Woo-hoo!
|
||||
for(i=0; !Quit; )
|
||||
{
|
||||
timer=0;
|
||||
for(j=0; hold || (j<sequence[i].num_times && !Quit); j++)
|
||||
{
|
||||
switch(sequence[i].which)
|
||||
{
|
||||
case 'g':
|
||||
case 'G': status = cpu_graph_screen(j); break;
|
||||
case 'c':
|
||||
case 'C': status = cpu_screen(j); break;
|
||||
case 'o':
|
||||
case 'O': status = clock_screen(j); break;
|
||||
case 'm':
|
||||
case 'M': status = mem_screen(j); break;
|
||||
case 'u':
|
||||
case 'U': status = uptime_screen(j); break;
|
||||
case 't':
|
||||
case 'T': status = time_screen(j); break;
|
||||
case 'd':
|
||||
case 'D': status = disk_screen(j); break;
|
||||
case 'x':
|
||||
case 'X': status = xload_screen(j); break;
|
||||
case 'b':
|
||||
case 'B': status = battery_screen(j); break;
|
||||
case 'a':
|
||||
case 'A': status = credit_screen(j); break;
|
||||
default: status = dumbass_screen(j); break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for(k=0; k<sequence[i].delay_time; k++)
|
||||
{
|
||||
usleep(TIME_UNIT); timer++;
|
||||
// Modify lcd status here... (blinking, for example)
|
||||
switch(status)
|
||||
{
|
||||
case BLINK_ON : blink=1; break;
|
||||
case BLINK_OFF: blink=0; lcd.backlight(1); break;
|
||||
case BACKLIGHT_OFF: blink=0; lcd.backlight(0); break;
|
||||
case BACKLIGHT_ON : blink=0; lcd.backlight(1); break;
|
||||
case HOLD_SCREEN : hold=1; break;
|
||||
case CONTINUE : hold=0; break;
|
||||
}
|
||||
status=0;
|
||||
|
||||
if(blink) lcd.backlight(! ((timer&15) == 15));
|
||||
|
||||
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();
|
||||
|
||||
PollSockets();
|
||||
}
|
||||
}
|
||||
i++;
|
||||
if(sequence[i].which < 2) i=0;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
extern char version[];
|
||||
extern char build_date[];
|
||||
extern int Quit;
|
||||
|
||||
#define BLINK_ON 0x10
|
||||
#define BLINK_OFF 0x11
|
||||
#define BACKLIGHT_OFF 0x20
|
||||
#define BACKLIGHT_ON 0x21
|
||||
#define HOLD_SCREEN 0x30
|
||||
#define CONTINUE 0x31
|
||||
|
||||
|
||||
#endif
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
#include "menu.h"
|
||||
|
||||
/////////////////////////////////////////
|
||||
// THIS IS NOT READY YET!
|
||||
/////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// Read menu.h to find out how this works.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
// Internal record of all important menu info...
|
||||
typedef struct MenuInfo
|
||||
{
|
||||
MenuItem *menu; // User-specified menu information
|
||||
struct MenuInfo *parent; // NULL if root-level
|
||||
int items; // number of items in the menu
|
||||
int sel; // selected item
|
||||
} MenuInfo;
|
||||
|
||||
|
||||
|
||||
// Main menu function...
|
||||
int do_menu(MenuItem *menu, MenuInfo *parent);
|
||||
|
||||
|
||||
void FillMenuInfo(MenuInfo *m, MenuItem *menu, MenuInfo *parent);
|
||||
|
||||
void DrawMenu(MenuInfo *m);
|
||||
void DrawMenuItem(MenuInfo *m, int item);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// User-callable function...
|
||||
//
|
||||
int menu(MenuItem *menu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
CreateArrows(); // Set custom characters for menu use...
|
||||
|
||||
ret = do_menu(menu, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int do_menu(MenuItem *menu, MenuInfo *parent)
|
||||
{
|
||||
int current;
|
||||
int uparrow;
|
||||
int downarrow;
|
||||
|
||||
int key;
|
||||
int err=0;
|
||||
|
||||
|
||||
while(! err)
|
||||
{
|
||||
// Draw the menu...
|
||||
|
||||
// Wait for input
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int do_menu(MenuItem *menu, MenuInfo *parent)
|
||||
{
|
||||
int i;
|
||||
int items;
|
||||
MenuInfo ThisMenu;
|
||||
int old_sel;
|
||||
int redraw=1;
|
||||
int ret=0;
|
||||
|
||||
FillMenuInfo(&ThisMenu, menu, parent);
|
||||
|
||||
//FIXME: Get input here... Move the selection thingy
|
||||
|
||||
DrawMenu(&ThisMenu);
|
||||
|
||||
|
||||
do{
|
||||
//FIXME: Get input here... Move the selection thingy
|
||||
|
||||
// Figure out which button should be highlighted...
|
||||
|
||||
// And... if the "execute" button was pressed...
|
||||
if()
|
||||
{
|
||||
ThisMenu.sel = i;
|
||||
}
|
||||
|
||||
DrawMenu(&ThisMenu);
|
||||
redraw = 0;
|
||||
|
||||
// Dismiss menu?
|
||||
if( // cancel was pressed...
|
||||
)
|
||||
ret = GUI_CONT;
|
||||
|
||||
// pop up another menu?
|
||||
if( // execute was pressed...
|
||||
&&ThisMenu.sel >= 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; i<m->items; 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...
|
||||
}
|
||||
|
||||
|
||||
|
||||
+58
@@ -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
|
||||
+1107
File diff suppressed because it is too large
Load Diff
+30
@@ -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
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#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;
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
+644
@@ -0,0 +1,644 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/utsname.h>
|
||||
#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<CPU_BUF_SIZE-1; i++)
|
||||
for(j=0; j<5; j++)
|
||||
cpu[i][j] = cpu[CPU_BUF_SIZE-1][j];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Average values for final result
|
||||
for(i=0; i<5; i++)
|
||||
{
|
||||
value = 0;
|
||||
for(j=0; j<CPU_BUF_SIZE; j++)
|
||||
{
|
||||
value += cpu[j][i];
|
||||
}
|
||||
value /= CPU_BUF_SIZE;
|
||||
cpu[CPU_BUF_SIZE][i] = value;
|
||||
}
|
||||
|
||||
|
||||
value = cpu[CPU_BUF_SIZE][4];
|
||||
n = (int)(value * 70.0);
|
||||
if (value >= 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<CPU_BUF_SIZE-1; i++)
|
||||
cpu[i] = cpu[CPU_BUF_SIZE-1];
|
||||
|
||||
}
|
||||
|
||||
//lcd.clear();
|
||||
for(i=2; i<=lcd.hgt; i++)
|
||||
lcd.string(1,i," ");
|
||||
|
||||
|
||||
// Average values for final result
|
||||
value = 0;
|
||||
for(j=0; j<CPU_BUF_SIZE; j++)
|
||||
{
|
||||
value += cpu[j];
|
||||
}
|
||||
value /= (float)CPU_BUF_SIZE;
|
||||
cpu[CPU_BUF_SIZE] = value;
|
||||
|
||||
|
||||
maxload=0;
|
||||
for(i=0; i<lcd.wid-1; i++)
|
||||
{
|
||||
cpu_past[i] = cpu_past[i+1];
|
||||
lcd.vbar(i+1, cpu_past[i]);
|
||||
if(cpu_past[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<lcd.wid-1; n++)
|
||||
if(loads[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<lcd.wid-1; n++)
|
||||
{
|
||||
x = (loads[n] * factor);
|
||||
lcd.vbar(n+1, (int)x);
|
||||
}
|
||||
|
||||
if(loadmax < 0.05) status = BACKLIGHT_OFF;
|
||||
if(loadmax > 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;
|
||||
}
|
||||
|
||||
|
||||
+58
@@ -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
|
||||
@@ -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 . &
|
||||
@@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#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<argc; i++)
|
||||
{
|
||||
sprintf(str, "test_func_func: %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<argc; i++)
|
||||
{
|
||||
// Handle the "name" parameter
|
||||
if(0 == strcmp(argv[i], "name"))
|
||||
{
|
||||
if(argc > 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<argc; i++)
|
||||
{
|
||||
// Handle the "name" parameter
|
||||
if(0 == strcmp(argv[i], "name"))
|
||||
{
|
||||
if(argc > 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; i<argc; i++)
|
||||
fprintf(stderr, "%s ", argv[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// FIXME? Shouldn't this be handled in widget.c?
|
||||
i = 3;
|
||||
switch(w->type)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,718 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#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; i++)
|
||||
{
|
||||
printf("Arg(%i): %s\n", i, argv[i]);
|
||||
}
|
||||
*/
|
||||
|
||||
for(i=0; i<argc; i++)
|
||||
{
|
||||
//printf("Arg(%i): %s\n", i, argv[i]);
|
||||
if(0 == strcmp(argv[i], "-d") ||
|
||||
0 == strcmp(argv[i], "--device"))
|
||||
{
|
||||
if(i + 1 > 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<lcd.cellhgt; row++)
|
||||
{
|
||||
letter = 0;
|
||||
for(col=0; col<lcd.cellwid; col++)
|
||||
{
|
||||
letter <<= 1;
|
||||
letter |= (dat[(row*lcd.cellwid) + col] > 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<lcd.wid*lcd.hgt; i++)
|
||||
{
|
||||
if(dat[i] < 32 && dat[i] >= 0) dat[i] += 128;
|
||||
}
|
||||
*/
|
||||
|
||||
for(i=0; i<lcd.hgt; i++)
|
||||
{
|
||||
sprintf(out, "%c%c%c", 17, 0, i);
|
||||
write(fd, out, 3);
|
||||
write(fd, dat+(lcd.wid*i), lcd.wid);
|
||||
}
|
||||
/*
|
||||
sprintf(out, "%c", 1);
|
||||
write(fd, out, 1);
|
||||
write(fd, dat, lcd.wid*lcd.hgt);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef CFONTZ_H
|
||||
#define CFONTZ_H
|
||||
|
||||
|
||||
extern lcd_logical_driver *CFontz;
|
||||
|
||||
int CFontz_init(lcd_logical_driver *driver, char *device);
|
||||
void CFontz_close();
|
||||
void CFontz_flush();
|
||||
void CFontz_flush_box(int lft, int top, int rgt, int bot);
|
||||
void CFontz_chr(int x, int y, char c) ;
|
||||
int CFontz_contrast(int contrast);
|
||||
void CFontz_backlight(int on);
|
||||
void CFontz_init_vbar();
|
||||
void CFontz_init_hbar();
|
||||
void CFontz_vbar(int x, int len);
|
||||
void CFontz_hbar(int x, int y, int len);
|
||||
void CFontz_init_num();
|
||||
void CFontz_num(int x, int num);
|
||||
void CFontz_set_char(int n, char *dat);
|
||||
void CFontz_icon(int which, char dest);
|
||||
void CFontz_draw_frame(char *dat);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
# example irmanrc file for libirman 0.4.1
|
||||
# should be either /usr/local/etc/irmanrc.conf or ~/.irmanrc
|
||||
|
||||
# set the default port name
|
||||
port /dev/ttyS0
|
||||
|
||||
bind jvc-play 7ddfd7fc0000
|
||||
bind jvc-pause 7dddd7fc0000
|
||||
bind jvc-stop 7ddd7ffc0000
|
||||
bind jvc-prev 7ddff5fc0000
|
||||
bind jvc-next 7dddf5fc0000
|
||||
bind jvc-fwd 7ddf5ffc0000
|
||||
bind jvc-rew 7ddd5ffc0000
|
||||
bind jvc-1 7ffdff7c0000
|
||||
bind jvc-2 7fff7f7c0000
|
||||
bind jvc-3 7ffd7f7c0000
|
||||
bind jvc-4 7fffdf7c0000
|
||||
bind jvc-5 7ffddf7c0000
|
||||
bind jvc-6 7fff5f7c0000
|
||||
bind jvc-7 7ffd5f7c0000
|
||||
bind jvc-8 7ffff77c0000
|
||||
bind jvc-9 7ffdf77c0000
|
||||
bind jvc-0 7fffff7c0000
|
||||
bind jvc-rec e51000000000
|
||||
bind jvc-vol+ b91000000000
|
||||
bind jvc-vol- ad1000000000
|
||||
bind jvc-mute f91000000000
|
||||
bind jvc-/|// f11000000000
|
||||
bind jvc-display 151000000000
|
||||
bind jvc-search<< 351000000000
|
||||
bind jvc-search>> 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
|
||||
@@ -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 ---------------===========================================
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -0,0 +1,322 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
#ifdef xBSD
|
||||
#include <ncurses.h>
|
||||
#else
|
||||
#include <curses.h>
|
||||
#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; i++)
|
||||
{
|
||||
if(0 == strcmp(argv[i], "-f") ||
|
||||
0 == strcmp(argv[i], "--forecolor"))
|
||||
{
|
||||
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], "--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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,288 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#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(; x<lcd.wid && len>0; 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<lcd.wid; i++)
|
||||
{
|
||||
out[i] = '-';
|
||||
}
|
||||
out[lcd.wid] = 0;
|
||||
printf("+%s+\n", out);
|
||||
|
||||
|
||||
for(i=0; i<lcd.hgt; i++)
|
||||
{
|
||||
for(j=0; j<lcd.wid; j++)
|
||||
{
|
||||
out[j] = dat[j+(i*lcd.wid)];
|
||||
}
|
||||
out[lcd.wid] = 0;
|
||||
printf("|%s|\n", out);
|
||||
|
||||
}
|
||||
|
||||
for(i=0; i<lcd.wid; i++)
|
||||
{
|
||||
out[i] = '-';
|
||||
}
|
||||
out[lcd.wid] = 0;
|
||||
printf("+%s+\n", out);
|
||||
|
||||
}
|
||||
|
||||
|
||||
char debug_getkey()
|
||||
{
|
||||
printf("Trying to grab keypress.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef LCD_DEBUG_H
|
||||
#define LCD_DEBUG_H
|
||||
|
||||
|
||||
int debug_init(struct lcd_logical_driver *driver, char *args);
|
||||
void debug_close();
|
||||
void debug_clear();
|
||||
void debug_flush();
|
||||
void debug_string(int x, int y, char string[]);
|
||||
void debug_chr(int x, int y, char c);
|
||||
void debug_contrast(int contrast);
|
||||
void debug_backlight(int on);
|
||||
void debug_init_vbar();
|
||||
void debug_init_hbar();
|
||||
void debug_init_num();
|
||||
void debug_vbar(int x, int len);
|
||||
void debug_hbar(int x, int y, int len);
|
||||
void debug_num(int x, int num);
|
||||
void debug_set_char(int n, char *dat);
|
||||
void debug_icon(int which, char dest);
|
||||
void debug_flush_box(int lft, int top, int rgt, int bot);
|
||||
void debug_draw_frame(char *dat);
|
||||
char debug_getkey();
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,311 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#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; i<lcd.wid; i++)
|
||||
{
|
||||
out[i] = '-';
|
||||
}
|
||||
out[lcd.wid] = 0;
|
||||
printf("+%s+\n", out);
|
||||
|
||||
|
||||
for(i=0; i<lcd.hgt; i++)
|
||||
{
|
||||
for(j=0; j<lcd.wid; j++)
|
||||
{
|
||||
out[j] = dat[j+(i*lcd.wid)];
|
||||
}
|
||||
out[lcd.wid] = 0;
|
||||
printf("|%s|\n", out);
|
||||
|
||||
}
|
||||
|
||||
for(i=0; i<lcd.wid; i++)
|
||||
{
|
||||
out[i] = '-';
|
||||
}
|
||||
out[lcd.wid] = 0;
|
||||
printf("+%s+\n", out);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Tries to read a character from an input device...
|
||||
//
|
||||
// Return 0 for "nothing available".
|
||||
//
|
||||
char drv_base_getkey()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
#ifndef LCD_DRV_BASE_H
|
||||
#define LCD_DRV_BASE_H
|
||||
|
||||
/********************************************************************
|
||||
How to make a driver for LCDproc
|
||||
|
||||
Note: Insert the name of your driver in place of the phrase "new_driver".
|
||||
|
||||
1. Copy drv_base.c and drv_base.h to new_driver.c and new_driver.h.
|
||||
|
||||
2. Decide which functions you want to override, which ones you want
|
||||
to leave alone, and which ones you don't want at all. If you
|
||||
write your own driver functions, they will get called when
|
||||
appropriate. Or, you can let the default driver "drv_base"
|
||||
handle a function for you. But, if you really don't want a
|
||||
function, you can completely prevent your driver from providing
|
||||
it. This is discussed in step 5.
|
||||
|
||||
2.1. Remove all functions which you don't want to override, and the
|
||||
ones you don't want at all.
|
||||
|
||||
3. Rename all functions from "drv_base_*" to "new_driver_*".
|
||||
|
||||
4. Write the new driver functions.
|
||||
Be sure to do one of the following in/for your new_driver_close():
|
||||
- free the framebuffer lcd.framebuf
|
||||
- let the default driver handle close()
|
||||
- call drv_base_close()
|
||||
This will ensure that the frame buffer gets freed.
|
||||
|
||||
5. Register your functions in your new_driver_init(), like the following:
|
||||
driver->clear = 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
|
||||
@@ -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
|
||||
* <rrognlie@gamerz.net>
|
||||
*
|
||||
* Large quantities of this code lifted (nearly verbatim) from
|
||||
* the lcd4.c module of lcdtext. Copyright (C) 1997 Matthias Prinke
|
||||
* <m.prinke@trashcan.mcnet.de> 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 <damianf@wpi.edu>
|
||||
* Data Sheet LTN211, Philips
|
||||
* Various FAQs and TXTs about Hitachi's LCD Controller HD44780 -
|
||||
* www.paranoia.com/~filipg is a good starting point ???
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/perm.h>
|
||||
|
||||
#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; i++)
|
||||
{
|
||||
//printf("Arg(%i): %s\n", i, argv[i]);
|
||||
if(0 == strcmp(argv[i], "-p") ||
|
||||
0 == strcmp(argv[i], "--port"))
|
||||
{
|
||||
if(i + 1 > 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<lcd.cellhgt; row++) {
|
||||
letter = 0;
|
||||
for(col=0; col<lcd.cellwid; col++) {
|
||||
letter <<= 1;
|
||||
letter |= (dat[(row*lcd.cellwid) + col] > 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]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
* <rrognlie@gamerz.net>
|
||||
*
|
||||
* Large quantities of this code lifted (nearly verbatim) from
|
||||
* the lcd4.c module of lcdtext. Copyright (C) 1997 Matthias Prinke
|
||||
* <m.prinke@trashcan.mcnet.de> 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 <damianf@wpi.edu>
|
||||
* 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
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#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; i++)
|
||||
{
|
||||
//printf("Arg(%i): %s\n", i, argv[i]);
|
||||
if(0 == strcmp(argv[i], "-d") ||
|
||||
0 == strcmp(argv[i], "--device"))
|
||||
{
|
||||
if(i + 1 > 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 */
|
||||
@@ -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
|
||||
@@ -0,0 +1,218 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
#define __u32 unsigned int
|
||||
#define __u8 unsigned char
|
||||
#include <linux/joystick.h>
|
||||
|
||||
|
||||
#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; i++)
|
||||
{
|
||||
//printf("Arg(%i): %s\n", i, argv[i]);
|
||||
if(0 == strcmp(argv[i], "-d") ||
|
||||
0 == strcmp(argv[i], "--device"))
|
||||
{
|
||||
if(i + 1 > 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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,727 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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 */
|
||||
@@ -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 <m.prinke@trashcan.mcnet.de> 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 <pc.h>
|
||||
|
||||
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 ****/
|
||||
@@ -0,0 +1,236 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#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<lcd.wid; i++)
|
||||
{
|
||||
out[i] = '-';
|
||||
}
|
||||
out[lcd.wid] = 0;
|
||||
printf("+%s+\n", out);
|
||||
|
||||
|
||||
for(i=0; i<lcd.hgt; i++)
|
||||
{
|
||||
for(j=0; j<lcd.wid; j++)
|
||||
{
|
||||
out[j] = dat[j+(i*lcd.wid)];
|
||||
}
|
||||
out[lcd.wid] = 0;
|
||||
printf("|%s|\n", out);
|
||||
|
||||
}
|
||||
|
||||
for(i=0; i<lcd.wid; i++)
|
||||
{
|
||||
out[i] = '-';
|
||||
}
|
||||
out[lcd.wid] = 0;
|
||||
printf("+%s+\n", out);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef LCD_TEXT_H
|
||||
#define LCD_TEXT_H
|
||||
|
||||
extern lcd_logical_driver *text;
|
||||
|
||||
int text_init(struct lcd_logical_driver *driver, char *args);
|
||||
void text_close();
|
||||
void text_clear();
|
||||
void text_flush();
|
||||
void text_string(int x, int y, char string[]);
|
||||
void text_chr(int x, int y, char c);
|
||||
int text_contrast(int contrast);
|
||||
void text_backlight(int on);
|
||||
void text_init_vbar();
|
||||
void text_init_hbar();
|
||||
void text_init_num();
|
||||
void text_vbar(int x, int len);
|
||||
void text_hbar(int x, int y, int len);
|
||||
void text_num(int x, int num);
|
||||
void text_set_char(int n, char *dat);
|
||||
void text_flush_box(int lft, int top, int rgt, int bot);
|
||||
void text_draw_frame(char *dat);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,562 @@
|
||||
/* wirz-sli.c -- Source file for LCDproc Wirz SLI driver
|
||||
Copyright (C) 1999 Horizon Technologies-http://horizon.pair.com/
|
||||
Written by Bryan Rittmeyer <bryanr@pair.com> - Released under GPL
|
||||
|
||||
LCD info: http://www.wirz.com/sli/ */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#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; i++)
|
||||
{
|
||||
printf("Arg(%i): %s\n", i, argv[i]);
|
||||
}
|
||||
*/
|
||||
|
||||
for(i=0; i<argc; i++)
|
||||
{
|
||||
//printf("Arg(%i): %s\n", i, argv[i]);
|
||||
if(0 == strcmp(argv[i], "-d") ||
|
||||
0 == strcmp(argv[i], "--device"))
|
||||
{
|
||||
if(i + 1 > 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<lcd.cellhgt; row++)
|
||||
{
|
||||
letter = 0;
|
||||
for(col=0; col<lcd.cellwid; col++)
|
||||
{
|
||||
letter <<= 1;
|
||||
letter |= (dat[(row*lcd.cellwid) + col] > 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...
|
||||
|
||||
}
|
||||
@@ -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 <bryanr@pair.com> - 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
|
||||
+131
@@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef INPUT_H
|
||||
#define INPUT_H
|
||||
|
||||
|
||||
// Accepts and uses keypad input while displaying screens...
|
||||
int handle_input();
|
||||
|
||||
|
||||
#endif
|
||||
+369
@@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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<argc; i++)
|
||||
{
|
||||
if(0 == strcmp(argv[i], "-f") ||
|
||||
0 == strcmp(argv[i], "--foreground") ||
|
||||
0 == strcmp(argv[i], "curses"))
|
||||
daemon_mode = 0;
|
||||
}
|
||||
|
||||
// Now, go into daemon mode...
|
||||
#ifndef DEBUG
|
||||
if(daemon_mode)
|
||||
{
|
||||
if ((child = fork()) != 0)
|
||||
{
|
||||
usleep(1500000); // Wait for child to initialize
|
||||
exit(0); /* PARENT EXITS */
|
||||
}
|
||||
// This line removed because it eats error messages...
|
||||
//setsid(); /* RELEASE TTY */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Set up lcd driver base system
|
||||
lcd_init("");
|
||||
|
||||
|
||||
// Parse the command line now...
|
||||
// TODO: Move this to a separate function?
|
||||
for(i=1; i<argc; i++)
|
||||
{
|
||||
if(0 == strcmp(argv[i], "-d") ||
|
||||
0 == strcmp(argv[i], "--driver"))
|
||||
{
|
||||
if(argc <= i+1) HelpScreen();
|
||||
str = argv[++i];
|
||||
ing = NULL;
|
||||
|
||||
// Check to see if the next parameter is intended for LCDd,
|
||||
// or if it should be passed to the driver...
|
||||
if(argc > 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 <size>\n\t\t\tSelect an LCD size (20x4, 16x2, etc...)\n");
|
||||
printf("\t-d\t--driver <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 <mode>\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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
+355
@@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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 <time.h>
|
||||
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; i<bottom; i++, y++)
|
||||
{
|
||||
if(i == info->selected) 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;
|
||||
}
|
||||
|
||||
+143
@@ -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
|
||||
+339
@@ -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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user