Compare commits

..
Author SHA1 Message Date
Giacomo Catenazzi 9404a6167d Import Upstream version 1.9.0-wip.20070910 2019-04-29 15:43:00 +02:00
Giacomo Catenazzi a60b7c6315 Import Upstream version 1.9.0 2019-04-29 15:42:59 +02:00
61 changed files with 7155 additions and 6 deletions

No files matched your search

-3
View File
@@ -1,3 +0,0 @@
*.tar.* filter=lfs diff=lfs merge=lfs -text
*.tar.*.asc -filter -diff merge=binary -text
*.dsc -filter !diff merge=binary !text
+19
View File
@@ -0,0 +1,19 @@
Mike Lampard <mlampard@users.sf.net>
- primary developer
Sven Ludwig
- Python bindings
James Green
- Documentaion updates
Anthony J. Mirabella
- numerous miscellaneous fixes and improvements to just about everything.
Lars Sanders
- Clock plugin fixes
Fabrizio Sestito
- changes required to compile on OS-X
- OS-X kext file
+340
View File
@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 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) <year> <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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) year 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.
+97
View File
@@ -0,0 +1,97 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 295 $ - $Date: 2007-09-09 06:37:50 +0200 (Sun, 09 Sep 2007) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
Version 1.0-pre0
- Initial release
1.1 21/07/2006
- Add WBMP support and Perl bindings.
1.2 31/07/2006
** IMPORTANT NOTE **
This release has changed the LCD screen switch function to the MR key to
allow clients use of all 'L' keys.
**
- reduce per-thread stack usage - default was 8Mb on i386 linux. now 256k
this makes top output look much nicer ;)
- optimize lcd buffer path, removing a conversion step. and reducing the
buffer size from 7k to 1k
- misc other memory optimisations.
- added python bindings (thanks muhgatus)
- added ability for lcd clients to receive L G & M key keypresses directly
- moved lcd display/client switch from L1 to MR
- MR key is now backlit when clients are attached.
- Added ability for lcd clients to change backlight brightness
- Added ability for lcd clients to toggle M-key LEDs
- Added libG15Render client support.
- Added ability for hidden lcd clients to bring themselves to the foreground
- clients change only their own backlight/mkey led status
1.2.1 06/08/2006
- Fix bug which could cause client screens to be lost under certain circumstances.
1.2.2 28/10/2006
- Vastly improve latency issues when using 'G' keys
- Documentation updates
- includes xkb patch for xorg 7.1 for native g15 keyboard layout in X11 (contrib directory)
1.2.3 30/10/2006
- improved the Xmodmaprc configuration, it now has parity with the xkb version
1.2.4 01/11/2006
- Users can now choose to use the L1 key to switch between client screens instead of MR.
- L1 is the small round black button directly below the LCD.
- Use -s on the commandline to activate the change.
1.2.5 05/11/2006
- Add ability for clients to request all M and G keypresses be 'pushed' to them,
rather than having to request them repeatedly. If a client uses this
option, no keyboard processing is done by the daemon, and the client must
be prepared to do uinput processing itself, if necessary. This limitation
may be removed in future versions of the API. Normal processing will
resume when the client that requested this feature exits or closes its
connection.
- Add manpage for the daemon.
- Fix automake bug that caused documentation not to be installed by default.
- Fix the daemons cmdline processing to handle more than one commandline option.
- Refactored the code slightly to allow for easier modification in the future.
- Handle long commandline arguments such as --help --version --kill --switch.
- Greatly improve error reporting.
- Add client development documentation (man g15daemon_client_devel / README.client_devel)
- Added a 'debug' mode (-d or --debug) cmdline switch to keep the daemon in the foreground
rather than daemonising. All errors and other info will be reported to STDERR in this mode.
- If compiled with libg15 1.1.0 or greater (or svn versions later than 3/11/06), the daemon
will now reset the keyboard to defaults on exit.
- make distcheck && make dist now work as expected.
- libg15daemon_client is now slightly more useful
- debian packaging now installs manpages
1.2.5svn -> current
- Add compiletime check for uinput version, should resolve compilation problems on some distro's
- Security improved - the daemon now sets its effective uid to nobody as soon as possible.
1.9.0SVN
- Add plugin API
- partially rewritten event core
- updated g15daemon_xmms_spectrum plugin with new features, available in trunk/g15daemon_audio_plugins (SVN)
- Clock is now a plugin
- dependency on libdaemon is now removed
- g15daemon is now dependant on libg15render.
- Clock now includes analog clock thanks to Rasta Freak <igor.jusic@zg.t-com.hr>
- Moved g15daemon_xmms_spectrum plugin to separate package
- Plugins are now installed in ${PREFIX}/lib/g15daemon/${VERSION}/plugins
- OS-X support thanks to Fabrizio Sestito.
+247
View File
@@ -0,0 +1,247 @@
G15daemon Client Development() G15daemon Client Development()
SYNOPSIS
#include <libg15.h>
#include <g15daemon_client.h>
link with
-lg15daemon_client
int new_g15_screen(int screentype);
int g15_close_screen(int sock);
int g15_send(int sock, char *buf, unsigned int len);
int g15_recv(int sock, char *buf, unsigned int len);
G15Daemon Server / Client communication
G15Daemon uses INET sockets to talk to its clients, listening on local-
host port 15550 for connection requests. Once connected, the server
sends the text string "G15 daemon HELLO" to confirm to the client that
it is a valid g15daemon process, creates a new screen, and waits for
LCD buffers or commands to be sent from the client. Clients are able
to create multiple screens simply by opening more socket connections to
the server process. If the socket is closed or the client exits, all
LCD buffers and the screen associated with that socket are automati-
cally destroyed.
Clients wishing to display on the LCD must send entire screens in the
format of their choice. Currently partial screen updates (icons etc)
are not supported.
G15Daemon commands are sent to the daemon via the OOB (out-of-band)
messagetype, replies are sent inband back to the client.
int new_g15_screen(int screentype)
Opens a new connection and returns a network socket for use. Creates a
screen with one of the following pixel formats defined in g15dae-
mon_client.h:
G15_PIXELBUF: this buffer must be exactly 6880 bytes, and uses 1 byte
per pixel.
G15_TEXTBUF: currently ignored by the daemon.
G15_WBMPBUF: this is a packed pixel buffer in WBMP format with 8 pix-
els per byte. Useful for perl programmers using the GD:: and G15Dae-
mon.pm (see lang_bindings directory) perl modules.
G15_G15RBUF: another packed pixel buffer type, also with 8 pix-
els/byte, and is the native libg15render format.
Example of use:
int screen_fd = new_g15_screen( G15_WBMPBUF );
int g15_close_screen (int screen_fd)
Simply closes a socket previously opened with new_g15_screen(). The
daemon will automatically clean up any buffers and remove the LCD
screen from the display list.
Returns 0 if successful, or errno if there was an error.
Example:
int retval = 0; int screen_fd = new_g15_screen( G15_WBMPBUF );
retval = g15_close_screen( screen_fd );
int g15_send (int sock, char *buf, unsigned int len)
A simple wrapper around send() to ensure that all 'len' bytes of data
is sent to the daemon. It simply uses poll() to block until the entire
message is sent.
Returns 0 on success, -1 if the send failed due to timeout or socket
error.
int g15_recv (int sock, char *buf, unsigned int len)
A simple wrapper around recv() to ensure that all 'len' bytes of data
are received from the daemon. It simply uses poll() to block until the
entire message is received.
Returns 0 on success, -1 if the recv failed due to timeout or socket
error.
G15Daemon Command Types
Commands and requests to the daemon are sent via OOB data packets.
Changes to the backlight and mkey state will only affect the calling
client. The following commands are supported as defined in g15dae-
mon_client.h:
G15DAEMON_KEY_HANDLER
Requests that all M and G key presses are sent to this client.
All keys are packed into an unsigned int, and sent to the client
inband when a key is pressed.
G15DAEMON_MKEYLEDS
Sets the M key LED state. In order to change LED state, each
LED that is to be turned on is OR'd with the command byte. See
libg15.h for values. For examples see the end of this document.
G15DAEMON_BACKLIGHT
Sets the LCD Backlight brightness. Brightness level (0|1|2) is
OR'd with the command byte. For examples see the end of this
document.
G15DAEMON_CONTRAST
Sets the LCD contrast. Contrast level (0|1|2) is OR'd with the
command byte. For examples see the end of this document.
G15DAEMON_GET_KEYSTATE
Requests a packet containing the current keystate. The daemon
will return an unsigned int containing any keys pressed. See
libg15.h for details on key values, and lcdclient_test.c in the
source distribution for an example.
G15DAEMON_SWITCH_PRIORITIES
Toggles the client's LCD screen to/from the front. Clients can
check their foreground/background state with the following:
G15DAEMON_IS_FOREGROUND
On reciept of this command, G15Daemon will send a 1 byte packet
back with the value 1 if the client is foreground, or 0 if not.
G15DAEMON_IS_USER_SELECTED
On reciept of this command, G15daemon will return a byte indi-
cating if the user selected the client be foreground or back-
ground.
EXAMPLES
Below is a completely nonsensical client which demonstrates most of the
commands.
--- Cut here ---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <poll.h>
#include <g15daemon_client.h>
#include <libg15.h>
int main(int argc, char *argv[]) {
int g15screen_fd, retval;
char lcdbuffer[6880];
unsigned int keystate;
char msgbuf[256];
if((g15screen_fd = new_g15_screen(G15_PIXELBUF))<0){
printf("Sorry, cant connect to the G15daemon0);
return -1;
}else
printf("Connected to g15daemon. sending image\n"); /*
create a half black image */
memset(lcdbuffer,0,6880);
memset(lcdbuffer,1,6880/2);
/* send the image to the daemon */
retval = g15_send(g15screen_fd,(char*)lcdbuffer,6880);
printf("checking key status - press G1 to exit0,retval);
while(1){
keystate = 0;
memset(msgbuf,0,256); /* request key status
*/
if(send(g15screen_fd, G15DAEMON_GET_KEYSTATE, 1,
MSG_OOB)<1)
printf("Error in send0);
retval = recv(g15screen_fd, &keystate ,
sizeof(keystate),0);
if(keystate)
printf("keystate = %i0,keystate);
/* quit if G1 is pressed */
if(keystate & G15_KEY_G1 ) /* See libg15.h for details on
key values. */
break;
memset(msgbuf,0,5);
/* G2,G3 & G4 change LCD backlight */
if(keystate & G15_KEY_G2 ){
msgbuf[0]=G15_BRIGHTNESS_DARK|G15DAEMON_BACKLIGHT;
send(g15screen_fd,msgbuf,1,MSG_OOB);
}
if(keystate & G15_KEY_G3 ){
msgbuf[0]=G15_BRIGHTNESS_MEDIUM|G15DAEMON_BACKLIGHT;
send(g15screen_fd,msgbuf,1,MSG_OOB);
}
if(keystate & G15_KEY_G4 ){
msgbuf[0]=G15_BRIGHTNESS_BRIGHT|G15DAEMON_BACKLIGHT;
send(g15screen_fd,msgbuf,1,MSG_OOB);
}
msgbuf[0]=G15DAEMON_IS_FOREGROUND; /* are we viewable? */
send(g15screen_fd,msgbuf,1,MSG_OOB);
recv(g15screen_fd,msgbuf,1,0);
if(msgbuf[0])
printf("Hey, we are in the foreground, Doc0);
else
printf("What dastardly wabbit put me in the back-
ground?0);
if(msgbuf[0]){ /* we've been backgrounded! */
sleep(2); /* remain in the background for a bit */
msgbuf[0] = G15DAEMON_SWITCH_PRIORITIES; /* switch pri-
orities */
send(g15screen_fd,msgbuf,1,MSG_OOB);
sleep(2);
send(g15screen_fd,msgbuf,1,MSG_OOB);
}
usleep(5000);
}
g15_close_screen(g15screen_fd);
return 0; }
-- end cutting --
G15Daemon 1.0 G15daemon Client Development()
+162
View File
@@ -0,0 +1,162 @@
.TH "G15Daemon" "1" "1.3" "G15tools - G15Daemon" "1"
.SH "NAME"
g15daemon \- provides access to extra keys and the LCD available on the logitech G15 keyboard.
.SH "DESCRIPTION"
G15Daemon allows users access to all extra keys by decoding them and pushing them back into the kernel via the linux UINPUT driver. This driver must be loaded before g15daemon can be used for keyboard access.
The G15 LCD is also supported. By default, with no other clients active, g15daemon will display a clock. Client applications and scripts can access the LCD via a simple API.
.SH "OPTIONS"
The current version of G15Daemon understands the following options:
.br
.P
.HP
\-v Show version info.
.P
.HP
\-s By default, g15daemon uses the MR key to switch between client screens. Using this switch on the cmdline alters this, making L1 (the small, round, black button below the LCD) the button to achieve this function.
.P
.HP
\-k Stop a previously running copy of G15Daemon. For the keys and LCD to work, you'll have to restart the daemon manually.
.P
.HP
\-h Show a brief summary of commandline options available.
.SH "BASIC USAGE"
G15Daemon must be run as the root user, either from a startup script (sample scripts are available in the contrib folder) or manually, via the su command.
To run the daemon with default options, run:
g15daemon
or
g15daemon \-s
to have the L1 key as the client screen switch.
If all required libraries are installed and in locations known to your operating system, the daemon will slip quietly into the background and a clock will appear on the LCD.
Congratulations! The linux kernel will now output keycodes for all your extra keys.
.SH "Using the keys in X11"
Current versions of the Xorg Xserver dont have support for the extra keys that g15daemon provides. This support will be available in the next release of Xorg (7.2).
For now, if you want access to the extra keys for hotkey support in X11, you need to run the xmodmaprc script on each start of X. This script is available in the contrib folder (if g15daemon is installed in the default location, the contrib folder is in /usr/share/doc/g15daemon\-${VERSION}/contrib
Depending on your linux distribution, copying the xmodmaprc file (or pasting the text below) into ~/.Xmodmap may be all that's required.
.SH "Xmodmaprc file"
Copy the following into ~/.Xmodmap (depending on your distribution) for X11 to recognise all extra G15 keys:
\-\- cut here \-\-
.br
keycode 93 = XF86Launch1
.br
keycode 129 = XF86Launch8
.br
keycode 130 = XF86Launch9
.br
keycode 131 = XF86Launch2
.br
keycode 132 = XF86Phone
.br
keycode 133 = XF86Messenger
.br
keycode 136 = XF86LaunchD
.br
keycode 137 = XF86Support
.br
keycode 138 = XF86Word
.br
keycode 143 = XF86LaunchF
.br
keycode 144 = XF86AudioPrev
.br
keycode 150 = XF86LogOff
.br
keycode 152 = XF86Launch5
.br
keycode 153 = XF86AudioNext
.br
keycode 160 = XF86AudioMute
.br
keycode 161 = XF86Travel
.br
keycode 162 = XF86AudioPlay
.br
keycode 163 = XF86Spell
.br
keycode 164 = XF86AudioStop
.br
keycode 170 = XF86VendorHome
.br
keycode 174 = XF86AudioLowerVolume
.br
keycode 176 = XF86AudioRaiseVolume
.br
keycode 177 = XF86Launch4
.br
keycode 178 = XF86HomePage
.br
keycode 182 = XF86Away
.br
keycode 183 = XF86WebCam
.br
keycode 184 = XF86Launch0
.br
keycode 188 = XF86Music
.br
keycode 190 = XF86Launch6
.br
keycode 194 = XF86Forward
.br
keycode 195 = XF86Send
.br
keycode 205 = XF86Calendar
.br
keycode 208 = XF86Launch7
.br
keycode 209 = XF86LaunchB
.br
keycode 210 = XF86LaunchC
.br
keycode 215 = XF86Save
.br
keycode 219 = XF86WWW
.br
keycode 220 = XF86LaunchE
.br
keycode 223 = XF86Sleep
.br
keycode 228 = XF86Pictures
.br
keycode 231 = XF86LaunchA
.br
keycode 236 = XF86Mail
.br
keycode 237 = XF86AudioMedia
.br
keycode 246 = XF86iTouch
.br
keycode 247 = XF86Launch3
.br
keycode 249 = XF86ToDoList
.br
keycode 251 = XF86Calculater
.br
\-\- end cutting \-\-
.SH "AUTHORS"
The latest release of g15daemon is available at
.P
http://g15daemon.sourceforge.net
.P
G15daemon was written by Mike Lampard mlampard@users.sourceforge.net and uses the libg15 library by Philip Lawatsch and Anthony J. Mirabella of the g15tools project. (g15tools.sourceforge.net)
.P
The Python bindings for libg15daemon_client were written by Sven Ludwig.
.P
Many thanks to everyone who has assisted in reporting bugs, misfeatures and made feature requests.
An up to date list of all authors is available in the AUTHORS file distributed in the source.
.SH "LICENSE"
G15daemon, libg15daemon_client and other sourcecode in this package are licensed under the GPL (General Public License), version 2 or later. Details on this license are available in the LICENSE document in the root directory of the source package, and at http://www.fsf.org
+219
View File
@@ -0,0 +1,219 @@
.TH "G15daemon Client Development" "" "1.0" "G15Daemon" ""
.SH "SYNOPSIS"
#include <libg15.h>
.br
#include <g15daemon_client.h>
link with
\-lg15daemon_client
int new_g15_screen(int screentype);
.br
int g15_close_screen(int sock);
.br
int g15_send(int sock, char *buf, unsigned int len);
.br
int g15_recv(int sock, char *buf, unsigned int len);
.br
int g15_send_cmd (int sock, unsigned char command, unsigned char value);
.br
.SH "G15Daemon Server / Client communication"
G15Daemon uses INET sockets to talk to its clients, listening on localhost port 15550 for connection requests. Once connected, the server sends the text string "G15 daemon HELLO" to confirm to the client that it is a valid g15daemon process, creates a new screen, and waits for LCD buffers or commands to be sent from the client. Clients are able to create multiple screens simply by opening more socket connections to the server process. If the socket is closed or the client exits, all LCD buffers and the screen associated with that socket are automatically destroyed.
Clients wishing to display on the LCD must send entire screens in the format of their choice. Currently partial screen updates (icons etc) are not supported.
G15Daemon commands are sent to the daemon via the OOB (out\-of\-band) messagetype, replies are sent inband back to the client.
.SH "int new_g15_screen(int screentype)"
Opens a new connection and returns a network socket for use. Creates a screen with one of the following pixel formats defined in g15daemon_client.h:
G15_PIXELBUF: this buffer must be exactly 6880 bytes, and uses 1 byte per pixel.
G15_TEXTBUF: currently ignored by the daemon.
G15_WBMPBUF: this is a packed pixel buffer in WBMP format with 8 pixels per byte. Useful for perl programmers using the GD:: and G15Daemon.pm (see lang_bindings directory) perl modules.
G15_G15RBUF: another packed pixel buffer type, also with 8 pixels/byte, and is the native libg15render format.
Example of use:
int screen_fd = new_g15_screen( G15_WBMPBUF );
.SH "int g15_close_screen (int screen_fd)"
Simply closes a socket previously opened with new_g15_screen(). The daemon will automatically clean up any buffers and remove the LCD screen from the display list.
Returns 0 if successful, or errno if there was an error.
Example:
int retval = 0;
int screen_fd = new_g15_screen( G15_WBMPBUF );
... do processing and display here ...
retval = g15_close_screen( screen_fd );
.SH "int g15_send (int sock, char *buf, unsigned int len)"
A simple wrapper around send() to ensure that all 'len' bytes of data is sent to the daemon. It simply uses poll() to block until the entire message is sent.
Returns 0 on success, \-1 if the send failed due to timeout or socket error.
.SH "int g15_recv (int sock, char *buf, unsigned int len)"
A simple wrapper around recv() to ensure that all 'len' bytes of data are received from the daemon. It simply uses poll() to block until the entire message is received.
Returns 0 on success, \-1 if the recv failed due to timeout or socket error.
.SH "int g15_send_cmd ( int sock, unsigned char command, unsigned char value)"
Sends a command to the daemon (possible commands are listed below). Returns 0 or the return value of the command on success, \-1 on failure.
See examples for usage.
.SH "G15Daemon Command Types"
.P
Commands and requests to the daemon are sent via OOB data packets. Changes to the backlight and mkey state will only affect the calling client. The following commands are supported as defined in g15daemon_client.h:
.IP "G15DAEMON_KEY_HANDLER"
Requests that all M and G key presses are sent to this client. All keys are packed into an unsigned int, and sent to the client inband when a key is pressed.
.IP "G15DAEMON_MKEYLEDS"
Sets the M key LED state. In order to change LED state, each LED that is to be turned on is OR'd with the command byte. See libg15.h for values. For examples see the end of this document.
.IP "G15DAEMON_BACKLIGHT"
Sets the LCD Backlight brightness. Brightness level (0|1|2) is OR'd with the command byte. For examples see the end of this document.
.IP "G15DAEMON_CONTRAST"
Sets the LCD contrast. Contrast level (0|1|2) is OR'd with the command byte. For examples see the end of this document.
.IP "G15DAEMON_GET_KEYSTATE"
Requests a packet containing the current keystate. The daemon will return an unsigned int containing any keys pressed. See libg15.h for details on key values, and lcdclient_test.c in the source distribution for an example.
.IP "G15DAEMON_SWITCH_PRIORITIES"
Toggles the client's LCD screen to/from the front. Clients can check their foreground/background state with the following:
.IP "G15DAEMON_IS_FOREGROUND"
On reciept of this command, G15Daemon will send a 1 byte packet back with the value 1 if the client is foreground, or 0 if not.
.IP "G15DAEMON_IS_USER_SELECTED"
On reciept of this command, G15daemon will return a byte indicating if the user selected the client be foreground or background.
.SH "EXAMPLES"
Below is a completely nonsensical client which (poorly) demonstrates the usage of most of the commands.
\-\-\- Cut here \-\-\-
.P
#include <stdio.h>
.br
#include <stdlib.h>
.br
#include <string.h>
.br
#include <sys/types.h>
.br
#include <sys/socket.h>
.br
#include <errno.h>
.br
#include <poll.h>
.br
#include <g15daemon_client.h>
.br
#include <libg15.h>
.br
.P
/* #define TEST_KEYHANDLER */
int main(int argc, char *argv[])
{
int g15screen_fd, retval;
char lcdbuffer[6880];
unsigned int keystate;
char msgbuf[256];
int foo = 0;
if((g15screen_fd = new_g15_screen(G15_PIXELBUF))<0){
printf("Sorry, cant connect to the G15daemon\n");
return 5;
}else
printf("Connected to g15daemon. sending image\n");
if(argc<2)
retval = g15_send(g15screen_fd,(char*)logo_data,6880);
else {
memset(lcdbuffer,0,6880);
memset(lcdbuffer,1,6880/2);
retval = g15_send(g15screen_fd,(char*)lcdbuffer,6880);
}
printf("checking key status \- press G1 to exit\n",retval);
while(1){
keystate = 0;
int foo;
keystate = g15_send_cmd (g15screen_fd, G15DAEMON_GET_KEYSTATE, foo);
if(keystate)
printf("keystate = %i\n",keystate);
if(keystate & G15_KEY_G1) //G1 key. See libg15.h for details on key values.
break;
/* G2,G3 & G4 change LCD backlight */
if(keystate & G15_KEY_G2){
retval = g15_send_cmd (g15screen_fd, G15DAEMON_BACKLIGHT, G15_BRIGHTNESS_DARK);
}
if(keystate & G15_KEY_G3){
retval = g15_send_cmd (g15screen_fd, G15DAEMON_BACKLIGHT, G15_BRIGHTNESS_MEDIUM);
}
if(keystate & G15_KEY_G4){
retval = g15_send_cmd (g15screen_fd, G15DAEMON_BACKLIGHT, G15_BRIGHTNESS_BRIGHT);
}
/* is this client in the foreground?? */
retval = g15_send_cmd (g15screen_fd, G15DAEMON_IS_FOREGROUND, foo);
if(retval)
printf("Hey, we are in the foreground, Doc\n");
else
printf("What dastardly wabbit put me in the background?\n");
retval = g15_send_cmd (g15screen_fd, G15DAEMON_IS_USER_SELECTED, foo);
if(retval)
printf("You wanted me in the foreground, right Doc?\n");
else
printf("You dastardly wabbit !\n");
if(retval){ /* we've been backgrounded! */
sleep(2); /* remain in the background for a bit */
retval = g15_send_cmd (g15screen_fd, G15DAEMON_SWITCH_PRIORITIES, foo);
sleep(2); /* switch to foreground */
retval = g15_send_cmd (g15screen_fd, G15DAEMON_SWITCH_PRIORITIES, foo);
}
usleep(500);
#ifdef TEST_KEYHANDLER
/* ok.. request that all G&M keys are passed to us.. */
retval = g15_send_cmd (g15screen_fd, G15DAEMON_KEY_HANDLER, foo);
while(1){
printf("waiting on keystate\n");
keystate=0;
retval = recv(g15screen_fd, &keystate , sizeof(keystate),0);
if(keystate)
printf("Recieved %i as keystate",keystate);
}
#endif
}
g15_close_screen(g15screen_fd);
return 0;
}
\-\- end cutting \-\-
+35
View File
@@ -0,0 +1,35 @@
This file contains some frequently asked questions and answers
regarding G15Daemon and it's installation.
Q1. G15daemon complains that it cant find libg15.so.1 !!
Answer:
By default, libg15 is installed in /usr/local/lib. Some distros
don't look there for libraries by default. There are two ways
around this - 1. add /usr/local/lib to /etc/ld.so.conf (you'll
need to be root to do this) and run ldconfig or 2. rerun the
libg15 configure script with --prefix=/usr, then make && make in-
stall. This will install libg15 into the /usr/lib directory.
Q2. G15daemon complains about not receiving a return value
and won't run!!
Answer:
G15daemon really needs to be run by the user root. If you are
already running as root, and you still see this error, please let
us know.
Q3. My 'G' keys dont work in X11 !!
Answer:
The daemon adds new scancodes for all the G & M keys. X11 doesnt
understand some of these. In order to have the keys work in X,
you'll find an xmodmaprc script and a bash script in the contrib
directory. Copy the xmodmaprc file to $HOME/.Xmodmap and set the
bash script to run every time X11 starts. KDE has an AutoStart
folder you can put it in, Gnome probably has something similar.
+119
View File
@@ -0,0 +1,119 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
Install Notes for g15daemon-1.2.1
1.About the G15Daemon.
2.Check list.
3.Installing.
4.Additional Notes
1. About the G15Daemon.
The G15Daemon was written in a effort to add functionality to the Logitech G15 keyboard under Linux.
These functions include the handling of the additional keys (or G keys) and writing
of data to the LCD display on the keyboard. The data that is written to the LCD is sent by
additional programs/scripts that are written for the g15daemon.
A clock for the LCD is loaded as default for the daemon.
The g15daemon was written by Mike Lampard, Philip Lawatsch, and others.
My thanks to them for a great program.
2. Check list.
A few things we need to check before installing the g15daemon.
For compiling you need:
libg15, libg15render, and libusb development packages.
For running the daemon you need:
linux kernel uniput module
This module used to send the new keypresses for the additional keys (or G keys).
You can check if you have the uniput module loaded by using the lsmod command.
If not you can manually the uinput module with 'modprode uinput' (as root...) .
You can load the module on boot by adding it your /etc/modules or
/etc/modules.preload (depending on your distribution.)
libg15
This library is needed by the daemon for managing the LCD on the keyboard.
You can download the libg15 library from the g15tools homepage on Sourceforge.
libg15 depends on libusb-dev so please install libusb-dev before compiling libg15.
libusb-dev can be found in your distribution's repositories... hopefully.
IMPORTANT!! When libg15 is compiled it will be copied into /usr/local/lib but the
daemon looks for it in /usr/lib. If you have not already, add /usr/local/lib to the
file /etc/ld.so.conf and run the command 'ldconfig' as root. This will allow
Linux to find the libraries installed there. Alternatively, run the libg15
configure script with --prefix=/usr as an argument, it will then be installed in /usr/lib.
And that is about it for the check list...
3.Installing.
Ok browse to the directory where you extracted the daemon to.
As a user or root type
./configure
make
Then as root type
make install
To run the g15daemon type
g15daemon
This must be done as root.
You should see the initial logo and then default clock appear.
to kill a previously running daemon
g15daemon -k
4. Additional Notes.
As of version 1.2, the MR key is used for switching between LCD clients,
and cannot be used for other purposes if the LCD is being used.
For a number of reasons, by default the keys on the G15 arent usable -
especially without g15daemon :) With g15daemon running, the kernel will
know all about the new keys, but your 'X' server won't without a bit of help.
In the contrib subfolder of the g15daemon distrobution, you'll find an xmodmaprc
script. To have all those new keys working in X11, you'll need to have
xmodmap read that file on every startup. Depending on your distro, xmodmap
may automatically load the file if it is copied to ${HOME}/.Xmodmap
otherwise you will have to load it yourself. There is an example xmodmap.sh
file in the contrib directory that will do this, if it's placed (for
instance) in kde's Autostart folder.
Patches are available for libgraphlcd, in the g15daemon patches
subdirectory. You'll need a copy of graphlcd source, which is available
from http://graphlcd.berlios.de . The patches are against the current
version, which is 1.3. [UPDATE] The g15daemon graphlcd driver is now
in the graphlcd SVN repository. If you use the SVN version of graphlcd,
you won't need to patch the library to use the LCD.
To patch the graphlcd source, extract the graphlcd-base archive, then type:
patch -p0 -i "g15daemon_src_folder"/patches/graphlcd-1.3_g15daemon_drv.patch
where 'g15daemon_src_folder' is the directory you extracted the g15daemon
sourcecode into...
+340
View File
@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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) <year> <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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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) year 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.
+37
View File
@@ -0,0 +1,37 @@
LLIBDIR=@LIBDIR@
SUBDIRS = libg15daemon_client g15daemon plugins
INCLUDES = -I$(top_srcdir)/libg15daemon_client -I$(top_srcdir)/g15daemon
EXTRA_DIST = debian contrib Documentation lang-bindings patches rpm README.usage FAQ LICENSE images
docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
doc_DATA = FAQ README.usage README ChangeLog TODO AUTHORS NEWS LICENSE
man1_MANS = $(top_srcdir)/Documentation/g15daemon.1
man3_MANS = $(top_srcdir)/Documentation/g15daemon_client_devel.3
imagedir = $(prefix)/share/g15daemon/splash
image_DATA = images/g15logo2.wbmp
install-data-hook:
if KEXT_INSTALL
cp -Rf $(top_srcdir)/contrib/libusbshield.kext @KEXT_LOCATION@
chown -R root:wheel @KEXT_LOCATION@/libusbshield.kext
endif
dist-hook:
rm -rf `find $(distdir)/debian -name .svn`
rm -rf `find $(distdir)/contrib -name .svn`
rm -rf `find $(distdir)/Documentation -name .svn`
rm -rf `find $(distdir)/lang_bindings -name .svn`
rm -rf `find $(distdir)/patches -name .svn`
rm -rf `find $(distdir)/rpm -name .svn`
rm -rf `find $(distdir)/plugins -name .svn`
rm -rf `find $(distdir)/images -name .svn`
dist-rpm: dist-bzip2
rpmbuild -ts $(distdir).tar.bz2
dist-archives:
$(MAKE) dist-bzip2
$(MAKE) dist-rpm
+2
View File
@@ -0,0 +1,2 @@
2006/07/14
First public release.
+77
View File
@@ -0,0 +1,77 @@
** README G15Daemon 1.2 **
$Revision: 214 $
$Date: 2006-12-25 03:38:09 +0100 (Mon, 25 Dec 2006) $
$Author: aneurysm9 $
G15daemon takes control of the G15 keyboard, allowing the use of
all keys through the linux kernel uinput device driver. It also
controls the use of the keyboard's LCD display, allows multiple,
simultaneous client applications to connect, and gives the user
the ability to switch between client apps at the press of a but-
ton.
Currently, patches to enable support for the daemon are available
for libgraphlcd, which in turn enables support for lcdproc, vdr,
and any other applications able to use that library. A simple
xmms spectrum analyser plugin, based on the finespectrum plugin,
is available separately.
G15daemon depends on libg15 from G15tools.
[INSTALLING]
To install, enter the directory you've extracted the archive in-
to, and type:
make make install
[RUNNING THE DAEMON] G15daemon must be run by the superuser,
root, as it writes to system logs. There is a sample init script
in the contrib directory that could be used to run the daemon on
system startup.
to run : g15daemon
to kill a previously running daemon : g15daemon -k
[USING THE EXTRA KEYS]
*** Please Note ***
As of version 1.2, the MR key is used for switching between
LCD clients, and cannot be used for other purposes if the
LCD is being used.
[EDIT] As of 30/10/06 svn, the client switch key can be altered
from MR to L1 by specifying -s on the g15daemon commandline.
***
For a number of reasons, by default the keys on the G15 arent us-
able - especially without g15daemon :) With g15daemon running,
the kernel will know all about the new keys, but your 'X' server
won't without a bit of help. In the contrib subfolder of the
g15daemon distrobution, you'll find an xmodmaprc script. To have
all those new keys working in X11, you'll need to have xmodmap
read that file on every startup. Depending on your distro,
xmodmap may automatically load the file if it is copied to
${HOME}/.Xmodmap otherwise you will have to load it yourself.
There is an example xmodmap.sh file in the contrib directory that
will do this, if it's placed (for instance) in kde's Autostart
folder.
[USING THE LCD]
Patches are available for libgraphlcd, in the g15daemon patches
subdirectory. You'll need a copy of graphlcd source, which is
available from http://graphlcd.berlios.de . The patches are
against the current version, which is 1.3.
To patch the graphlcd source, extract the graphlcd-base archive,
then type: patch -p0 -i "g15daemon_src_folder"/patch-
es/graphlcd-1.3_g15daemon_drv.patch
where 'g15daemon_src_folder' is the directory you extracted the
g15daemon sourcecode into...
+155
View File
@@ -0,0 +1,155 @@
G15Daemon(1) 1 G15Daemon(1)
NAME
g15daemon - provides access to extra keys and the LCD available on the
logitech G15 keyboard.
DESCRIPTION
G15Daemon allows users access to all extra keys by decoding them and
pushing them back into the kernel via the linux UINPUT driver. This
driver must be loaded before g15daemon can be used for keyboard access.
The G15 LCD is also supported. By default, with no other clients
active, g15daemon will display a clock. Client applications and
scripts can access the LCD via a simple API.
OPTIONS
The current version of G15Daemon understands the following options:
-v Show version info.
-s By default, g15daemon uses the MR key to switch between client
screens. Using this switch on the cmdline alters this, making
L1 (the small, round, black button below the LCD) the button to
achieve this function.
-k Stop a previously running copy of G15Daemon. For the keys and
LCD to work, you'll have to restart the daemon manually.
-h Show a brief summary of commandline options available.
BASIC USAGE
G15Daemon must be run as the root user, either from a startup script
(sample scripts are available in the contrib folder) or manually, via
the su command.
To run the daemon with default options, run:
g15daemon
or
g15daemon -s to have the L1 key as the client screen switch.
If all required libraries are installed and in locations known to your
operating system, the daemon will slip quietly into the background and
a clock will appear on the LCD. Congratulations! The linux kernel
will now output keycodes for all your extra keys.
Using the keys in X11
Current versions of the Xorg Xserver dont have support for the extra
keys that g15daemon provides. This support will be available in the
next release of Xorg (7.2).
For now, if you want access to the extra keys for hotkey support in
X11, you need to run the xmodmaprc script on each start of X. This
script is available in the contrib folder (if g15daemon is installed in
the default location, the contrib folder is in /usr/share/doc/g15dae-
mon-${VERSION}/contrib
Depending on your linux distribution, copying the xmodmaprc file (or
pasting the text below) into ~/.Xmodmap may be all that's required.
Xmodmaprc file
Copy the following into ~/.Xmodmap (depending on your distribution) for
X11 to recognise all extra G15 keys:
-- cut here --
keycode 93 = XF86Launch1
keycode 129 = XF86Launch8
keycode 130 = XF86Launch9
keycode 131 = XF86Launch2
keycode 132 = XF86Phone
keycode 133 = XF86Messenger
keycode 136 = XF86LaunchD
keycode 137 = XF86Support
keycode 138 = XF86Word
keycode 143 = XF86LaunchF
keycode 144 = XF86AudioPrev
keycode 150 = XF86LogOff
keycode 152 = XF86Launch5
keycode 153 = XF86AudioNext
keycode 160 = XF86AudioMute
keycode 161 = XF86Travel
keycode 162 = XF86AudioPlay
keycode 163 = XF86Spell
keycode 164 = XF86AudioStop
keycode 170 = XF86VendorHome
keycode 174 = XF86AudioLowerVolume
keycode 176 = XF86AudioRaiseVolume
keycode 177 = XF86Launch4
keycode 178 = XF86HomePage
keycode 182 = XF86Away
keycode 183 = XF86WebCam
keycode 184 = XF86Launch0
keycode 188 = XF86Music
keycode 190 = XF86Launch6
keycode 194 = XF86Forward
keycode 195 = XF86Send
keycode 205 = XF86Calendar
keycode 208 = XF86Launch7
keycode 209 = XF86LaunchB
keycode 210 = XF86LaunchC
keycode 215 = XF86Save
keycode 219 = XF86WWW
keycode 220 = XF86LaunchE
keycode 223 = XF86Sleep
keycode 228 = XF86Pictures
keycode 231 = XF86LaunchA
keycode 236 = XF86Mail
keycode 237 = XF86AudioMedia
keycode 246 = XF86iTouch
keycode 247 = XF86Launch3
keycode 249 = XF86ToDoList
keycode 251 = XF86Calculater
-- end cutting --
AUTHORS
The latest release of g15daemon is available at
http://g15daemon.sourceforge.net
G15daemon was written by Mike Lampard mlampard@users.sourceforge.net
and uses the libg15 library by Philip Lawatsch and Anthony J. Mirabella
of the g15tools project. (g15tools.sourceforge.net)
The Python bindings for libg15daemon_client were written by Sven Lud-
wig.
Many thanks to everyone who has assisted in reporting bugs, misfeatures
and made feature requests.
An up to date list of all authors is available in the AUTHORS file dis-
tributed in the source.
LICENSE
G15daemon, libg15daemon_client and other sourcecode in this package are
licensed under the GPL (General Public License), version 2 or later.
Details on this license are available in the LICENSE document in the
root directory of the source package, and at http://www.fsf.org
G15tools - G15Daemon 1.3 G15Daemon(1)
+34
View File
@@ -0,0 +1,34 @@
********************************************************************************
TODO list for G15daemon. Not in any particular order.
********************************************************************************
PARTIALLY DONE - Add manpage and other documentation for the client library and it's
bindings.
- Add client to record & playback macros (being worked on)
- add a few simple template client examples in various languages
- Read a configuration file. Currently there are no real user-configurable
options, but ....
DONE - Allow for clients to change LCD backlight.
DONE - enable the M-key backlights - the library supports this
- write a small client app to set configuration options on-the-fly (M-key
toggle, backlight, etc)
DONE - Allow for clients to request sole use of the 'L' keys (perhaps passing
their status back to the client via MSGs on the socket.
- Allow for clients to send text-based commands controlling the output (need
interpreter for this)
- Allow for clients to set a time-to-live for screens they create, which
will allow the client app to exit without taking the screen with them.
- Clients using the above functionality ought to be able to re-connect and
use the 'screen' they previously created, as long as they return within the
'time-to-live' period they set before exiting. This will allow for scripts
etc to periodically update.
+26
View File
@@ -0,0 +1,26 @@
This is the starting point of g15daemon 2.0. It's a work in progress,
partially functional (it already does most of the stuff the previous version
did), and incredibly untidy...
This is simply here to test and stabilise the API of what will become 2.0
FEATURES:
- True Plugins
- Synchronous Event-based architecture.
- Mostly backward-compatible with versions 1.0 & 1.2.* via the LCDServer plugin.
-
If you want to write a plugin, please see some examples in the plugin
folder. If the current plugin API doesn't do something you think it should,
let us know, it's never too late to change.
TODO:
- re-write most of it, currently it's simply the old code modified to suit
the new architecture, and the new stuff is not much better...
- tidy up the code
- write some updated documentation
- write some plugins!
- write some more documentation and plugins...
- add config options to a configuration file..
- add menu functionality to the clock for plugin/g15daemon configuration
- ???
Executable
+9
View File
@@ -0,0 +1,9 @@
#! /bin/sh
set -x
aclocal -I config
libtoolize --force --copy
autoheader
automake --add-missing --copy
autoconf
./configure $*
+82
View File
@@ -0,0 +1,82 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
# $Revision: 295 $ - $Date: 2007-09-09 06:37:50 +0200 (Sun, 09 Sep 2007) $ $Author: mlampard $
AC_PREREQ(2.59)
AC_INIT(g15daemon, [1.9pre], [mlampard@users.sf.net])
AC_PREFIX_DEFAULT(/usr)
AC_CONFIG_AUX_DIR(config)
AC_CANONICAL_TARGET()
AM_INIT_AUTOMAKE()
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_LIBTOOL
AC_PROG_RANLIB
# Checks for libraries.
AC_CHECK_LIB([g15], [initLibG15],,AC_MSG_ERROR(["libg15 (or its devel package) not found. please install it"]))
AC_CHECK_LIB([g15render], [g15r_loadWbmpSplash],,AC_MSG_ERROR([">=libg15render-1.2 (or its devel package) not found. please install it"]))
AC_CHECK_LIB([m], [sin])
AC_CHECK_LIB([pthread], [pthread_mutex_init])
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([ linux/input.h ])
AC_CHECK_HEADERS([ linux/uinput.h arpa/inet.h fcntl.h stdlib.h string.h sys/socket.h unistd.h libg15.h], [], [],
[#if HAVE_LINUX_INPUT_H
#include <linux/input.h>
#endif
])
#if HAVE_LINUX_UINPUT_H
dnl check for uinput.h version 2.4 or 2.6 ?
AC_CHECK_MEMBER([struct uinput_user_dev.id],
[AC_DEFINE(HAVE_UINPUT_USER_DEV_ID, 1,
[Define if struct uinput_user_dev has id member.])],,
[
#include <linux/input.h>
#include <linux/uinput.h>
]
)
dnl end of uinput version checks
#endif
case $host_os in
*linux*)
AC_DEFINE([OSTYPE_LINUX], [1],[Target OS is Linux])
;;
*darwin*)
AC_DEFINE([OSTYPE_DARWIN], [1],[Target OS is Darwin])
AC_SUBST(KEXT_LOCATION,["/System/Library/Extensions/"])
install_kext=true
;;
*)
AC_DEFINE([OSTYPE_OTHER], [1],[Target OS is unknown])
;;
esac
AM_CONDITIONAL([KEXT_INSTALL], [test x$install_kext = xtrue])
CPPFLAGS=$CPPFLAGS_save
CPPFLAGS="$CPPFLAGS "'-DDATADIR="\"$(datadir)\""'
AC_SUBST(G15DAEMON_PLUGIN_DIR,["$libdir/g15daemon/$PACKAGE_VERSION/plugins"])
CPPFLAGS="$CPPFLAGS "'-DPLUGINDIR=\"$(G15DAEMON_PLUGIN_DIR)\"'
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_PID_T
AC_TYPE_SIZE_T
# Checks for library functions.
AC_PROG_GCC_TRADITIONAL
AC_FUNC_SELECT_ARGTYPES
AC_FUNC_STRFTIME
AC_CHECK_FUNCS([memset select socket strerror])
AC_CONFIG_FILES([Makefile g15daemon/Makefile libg15daemon_client/Makefile plugins/Makefile])
AC_OUTPUT
+35
View File
@@ -0,0 +1,35 @@
This directory contains misc. scripts and handy stuff for the G15daemon
user.
It currently has:
xmodmaprc
- enables support for the extra G15 keys in Xorg.
xkb-xorg-7.1-g15daemon.patch
- patch against xorg 7.1 xkb datafiles, adds a new keyboard definition
enabling full native support for the g15 keys in the Xserver (via
g15daemon).
To Use:
cd /usr/share/X11/
patch -p0 <xkb-xorg-7.1-g15daemon.patch
Restart the Xserver, and a new keyboard type should be available in the
KDE/Gnome keyboard selection applet: "Logitech G15 keyboard support via G15Daemon".
Select that and apply, and all keys will be available for use as hotkeys etc.
If you use this xkb patch, the xmodmap procedure is not necessary.
If you prefer, you can also edit your Xorg configuration, adding the
Option "XkbModel" "g15daemon" line in your keyboard section.
Section "InputDevice"
Identifier "Keyboard1"
Driver "kbd"
Option "XkbModel" "g15daemon"
Option "XkbLayout" "us"
Option "XkbOptions" "compose:rwin"
EndSection
>>>> EDIT -> as of 30/10/06, xorg cvs has this patch included. If you're
>>>> using a newer version of Xorg or xkeyboard-config, you may not need to use this patch. The
>>>> keyboard model included in Xorg is called logitech_g15, not g15daemon.
+56
View File
@@ -0,0 +1,56 @@
#!/bin/sh
# Init script for the G15daemon
# for Redhat/Mandriva based systems
#
# Copyright (c)2006 Mike Lampard
#
# This script 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
# any later version.
#
# This script 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 file; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
#
. /etc/rc.d/init.d/functions
[ -f /usr/sbin/g15daemon ] || exit 0
case "$1" in
start)
echo "Starting G15daemon"
/sbin/modprobe uinput
/usr/sbin/g15daemon
echo
;;
stop)
echo "Stopping G15daemon"
/usr/sbin/g15daemon -k
echo
;;
restart)
echo "Restarting G15daemon"
/usr/sbin/g15daemon -k
/usr/sbin/g15daemon
echo
;;
status)
echo ""
/usr/sbin/g15daemon --version
echo
;;
*)
gprintf "$0 {start|stop|restart|reload|status}\n"
exit 1
;;
esac
exit ${RETVAL}
+43
View File
@@ -0,0 +1,43 @@
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key> <string>English</string>
<key>CFBundleGetInfoString</key> <string>Libusb USB device Shield</string>
<key>CFBundleIdentifier</key> <string>com.libusb.USB_Shield</string>
<key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
<key>CFBundleName</key> <string>Libusb USB device Shield</string>
<key>CFBundlePackageType</key> <string>KEXT</string>
<key>CFBundleSignature</key> <string>????</string>
<key>CFBundleVersion</key> <string>6.0</string>
<key>IOKitPersonalities</key>
<dict>
<key>Logitech G15</key>
<dict>
<key>CFBundleIdentifier</key>
<string>com.apple.kernel.iokit</string>
<key>IOClass</key>
<string>IOService</string>
<key>IOProbeScore</key>
<integer>106000</integer>
<key>IOProviderClass</key>
<string>IOUSBInterface</string>
<key>bConfigurationValue</key>
<integer>1</integer>
<key>bInterfaceNumber</key>
<integer>0</integer>
<key>bcdDevice</key>
<integer>259</integer>
<key>idProduct</key>
<integer>49698</integer>
<key>idVendor</key>
<integer>1133</integer>
</dict>
</dict>
<key>OSBundleCompatibleVersion</key> <string>1.8</string>
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.kernel.iokit</key> <string>6.0</string>
</dict>
</dict>
</plist>
+83
View File
@@ -0,0 +1,83 @@
use G15Daemon;
use GD;
use GD::Graph::lines;
#use GD::Graph::bars;
# simple demo. creates two screens (selectable via L1 button) and
# displays some text & a border on one, and a graph on the other..
@data = (
["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"],
[ 1, 2, 5, 6, 3, 1.5, 1, 3, 4],
[ sort { $a <=> $b } (1, 2, 5, 6, 3, 1.5, 1, 3, 4) ]
);
# possible screentypes are $g15pbuf (1bpp pixel buffer)
# $g15txt (text - not implemented yet)
# or $g15wbmp (WBMP pixelbuffer useful for GD)
#
# ok.. create a couple of new screens..
my $lcdintro = G15Daemon->new($g15wbmp);
my $lcdgraph = G15Daemon->new($g15wbmp);
printf "perl bindings version is %f\n",$lcdintro->VERSION;
printf "interface version is %f\n ",$lcdintro->apiversion;
my $width = $lcdintro->width();
my $height = $lcdintro->height();
# create a new GD image
$im = new GD::Image ($width, $height);
# allocate some colors - these are the only valid ones for the G15
$black = $im->colorAllocate (0, 0, 0);
$white = $im->colorAllocate (255, 255, 255);
# fill with black
$im->fill(1,1,$black);
# Draw an oval
$im->arc (80, 22, 95, 42, 0, 360, $white);
# fill it with white
$im->fill(90,32,$white);
# draw a rectangle
$im->rectangle (10, 10, 150, 33, $white);
# fill it
$im->fill(12,12,$white);
$im->fill(145,12,$white);
# draw some text onto the buffer
$im->string(gdSmallFont,30,15,"G15Daemon & GDlib",$black);
#convert the buffer to WBMP format..
my $wbmpdata = $im->wbmp ($white);
#send it to the daemon....
$lcdintro->send($wbmpdata);
# create a graph, and send it on the other connection.
my $graph = GD::Graph::lines->new(160, 44);
$graph->set(
# x_label => 'X Label',
# y_label => 'Y label',
# title => 'Some simple graph',
y_max_value => 8,
y_tick_number => 8,
y_label_skip => 5,
x_label_skip => 2,
dclrs => [ qw(dblue) ]
) or die $my_graph->error;
my $gd = $graph->plot(\@data) or die $graph->error;
# again convert to WBMP format and send it...
my $graphwbmp = $gd->wbmp ($black);
$lcdgraph->send($graphwbmp);
sleep(60);
$lcd->closescreen();
$lcdgraph->closescreen();
+100
View File
@@ -0,0 +1,100 @@
diff -x 'base*' -ur xkb-orig/rules/xorg xkb/rules/xorg
--- xkb-orig/rules/xorg 2006-08-31 23:34:45.000000000 +0930
+++ xkb/rules/xorg 2006-10-24 09:58:16.000000000 +0930
@@ -47,7 +47,8 @@
qtronix \
samsung4500 samsung4510 \
sk1300 sk2500 sk6200 sk7100 sp_inet \
- sven symplon toshiba_s3000 trust trustda yahoo
+ sven symplon toshiba_s3000 trust trustda yahoo \
+ g15daemon
// all layouts with 3rd and 4th groups
! $threelevellayouts = al az \
diff -x 'base*' -ur xkb-orig/rules/xorg.lst xkb/rules/xorg.lst
--- xkb-orig/rules/xorg.lst 2006-08-31 23:34:45.000000000 +0930
+++ xkb/rules/xorg.lst 2006-10-24 09:59:05.000000000 +0930
@@ -114,6 +114,7 @@
power_g5 Power G5
silvercrest SILVERCREST Multimedia Wireless Keyboard
emachines Laptop/notebook eMachines m68xx
+ g15daemon Logitech G15 keyboard support via G15Daemon
! layout
us U.S. English
diff -x 'base*' -ur xkb-orig/rules/xorg.xml xkb/rules/xorg.xml
--- xkb-orig/rules/xorg.xml 2006-08-31 23:34:45.000000000 +0930
+++ xkb/rules/xorg.xml 2006-10-24 10:00:06.000000000 +0930
@@ -2815,6 +2815,12 @@
</model>
<model>
<configItem>
+ <name>g15daemon</name>
+ <description>Logitech G15 keyboard support via G15Daemon</description>
+ </configItem>
+ </model>
+ <model>
+ <configItem>
<name>yahoo</name>
<description>Yahoo! Internet Keyboard</description>
<description xml:lang="af">Yahoo! Internetsleutelbord</description>
diff -x 'base*' -ur xkb-orig/symbols/inet xkb/symbols/inet
--- xkb-orig/symbols/inet 2006-08-31 23:34:55.000000000 +0930
+++ xkb/symbols/inet 2006-10-25 01:31:18.000000000 +0930
@@ -2028,3 +2028,56 @@
key <K67> { [ XF86MyComputer ] };
key <XFER> { [ XF86AudioMedia ] };
};
+
+partial alphanumeric_keys
+xkb_symbols "g15daemon" {
+
+ name[Group1]= "Logitech G15 keyboard support via G15Daemon";
+ key <MDSW> { [ XF86Launch1 ] };
+ key <XFER> { [ XF86Launch8 ] };
+ key <I02> { [ XF86Launch9 ] };
+ key <NFER> { [ XF86Launch2 ] };
+ key <I04> { [ XF86Pictures ] };
+ key <AE13> { [ XF86Messenger ] };
+ key <I08> { [ XF86LaunchD ] };
+ key <I09> { [ XF86Support ] };
+ key <I0A> { [ XF86Word ] };
+ key <I0F> { [ XF86LaunchF ] };
+ key <I10> { [ XF86AudioPrev ] };
+ key <I16> { [ XF86LogOff ] };
+ key <I18> { [ XF86Launch5 ] };
+ key <I19> { [ XF86AudioNext ] };
+ key <I20> { [ XF86AudioMute ] };
+ key <I21> { [ XF86Calculator ] };
+ key <I22> { [ XF86AudioPlay ] };
+ key <I23> { [ XF86Spell ] };
+ key <I24> { [ XF86AudioStop ] };
+ key <K5A> { [ XF86VendorHome ] };
+ key <I2E> { [ XF86AudioLowerVolume ] };
+ key <I30> { [ XF86AudioRaiseVolume ] };
+ key <I31> { [ XF86Launch4 ] };
+ key <I32> { [ XF86HomePage ] };
+ key <K5D> { [ XF86Messenger ] };
+ key <K5E> { [ XF86WebCam ] };
+ key <K5F> { [ XF86Launch0 ] };
+ key <I3C> { [ XF86Music ] };
+ key <K63> { [ XF86Launch6 ] };
+ key <I42> { [ XF86Forward ] };
+ key <I43> { [ XF86Send ] };
+ key <K6D> { [ XF86Calendar ] };
+ key <HKTG> { [ XF86Launch7 ] };
+ key <K71> { [ XF86LaunchB ] };
+ key <K72> { [ XF86LaunchC ] };
+ key <I57> { [ XF86Save ] };
+ key <K74> { [ XF86WWW ] };
+ key <K75> { [ XF86LaunchE ] };
+ key <I5F> { [ XF86Sleep ] };
+ key <I64> { [ XF86Pictures ] };
+ key <I67> { [ XF86LaunchA ] };
+ key <I6C> { [ XF86Mail ] };
+ key <I6D> { [ XF86AudioMedia ] };
+ key <I76> { [ XF86iTouch ] };
+ key <I77> { [ XF86Launch3 ] };
+ key <I79> { [ XF86ToDoList ] };
+ key <I7B> { [ XF86Calculater ] };
+};
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
xmodmap $HOME/.Xmodmap
echo Added key mods in $HOME/.Xmodmap
+47
View File
@@ -0,0 +1,47 @@
keycode 93 = XF86Launch1
keycode 129 = XF86Launch8
keycode 130 = XF86Launch9
keycode 131 = XF86Launch2
keycode 132 = XF86Phone
keycode 133 = XF86Messenger
keycode 136 = XF86LaunchD
keycode 137 = XF86Support
keycode 138 = XF86Word
keycode 143 = XF86LaunchF
keycode 144 = XF86AudioPrev
keycode 150 = XF86LogOff
keycode 152 = XF86Launch5
keycode 153 = XF86AudioNext
keycode 160 = XF86AudioMute
keycode 161 = XF86Travel
keycode 162 = XF86AudioPlay
keycode 163 = XF86Spell
keycode 164 = XF86AudioStop
keycode 170 = XF86VendorHome
keycode 174 = XF86AudioLowerVolume
keycode 176 = XF86AudioRaiseVolume
keycode 177 = XF86Launch4
keycode 178 = XF86HomePage
keycode 182 = XF86Away
keycode 183 = XF86WebCam
keycode 184 = XF86Launch0
keycode 188 = XF86Music
keycode 190 = XF86Launch6
keycode 194 = XF86Forward
keycode 195 = XF86Send
keycode 205 = XF86Calendar
keycode 208 = XF86Launch7
keycode 209 = XF86LaunchB
keycode 210 = XF86LaunchC
keycode 215 = XF86Save
keycode 219 = XF86WWW
keycode 220 = XF86LaunchE
keycode 223 = XF86Sleep
keycode 228 = XF86Pictures
keycode 231 = XF86LaunchA
keycode 236 = XF86Mail
keycode 237 = XF86AudioMedia
keycode 246 = XF86iTouch
keycode 247 = XF86Launch3
keycode 249 = XF86ToDoList
keycode 251 = XF86Calculater
+6
View File
@@ -0,0 +1,6 @@
g15daemon for Debian
--------------------
<possible notes regarding this package - if none, delete this file>
-- Anthony J. Mirabella <mirabeaj@gmail.com>, Thu, 28 Sep 2006 04:46:06 -0400
+6
View File
@@ -0,0 +1,6 @@
g15daemon (1.2.1-1) breezy; urgency=low
* Initial release
-- Anthony J. Mirabella <mirabeaj@gmail.com> Thu, 28 Sep 2006 04:46:06 -0400
+1
View File
@@ -0,0 +1 @@
4
+28
View File
@@ -0,0 +1,28 @@
Source: g15daemon
Section: utils
Priority: optional
Maintainer: Anthony J. Mirabella <mirabeaj@gmail.com>
Build-Depends: debhelper (>= 4.0.0), autotools-dev, libg15-dev, libg15render-dev
Standards-Version: 3.6.2
Package: g15daemon
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libg15daemon-client (= ${Source-Version})
Description: Screen multiplexer for Logitech G15 Keyboard
G15daemon provides multiple virtual screens for the LCD on the Logitech
G15 Keyboard
Package: libg15daemon-client
Section: libs
Architecture: any
Depends: ${shlibs:Depends}
Description: Client library for communicating with g15daemon
Provides interface functions for clients that wish to communicate with
a running instance of g15daemon
Package: libg15daemon-client-dev
Section: libdevel
Architecture: any
Depends: libg15daemon-client (= ${Source-Version})
Description: Development packages for libg15daemon-client
Includes the files needed for developing g15daemon clients
+10
View File
@@ -0,0 +1,10 @@
This package was debianized by Anthony J. Mirabella <mirabeaj@gmail.com> on
Thu, 28 Sep 2006 04:46:06 -0400.
It was downloaded from <fill in ftp site>
Copyright Holder: <put author(s) name and email here>
License:
<Put the license of the package here>
Vendored
+3
View File
@@ -0,0 +1,3 @@
NEWS
README
TODO
+1
View File
@@ -0,0 +1 @@
usr/sbin/*
+6
View File
@@ -0,0 +1,6 @@
usr/include/*
usr/lib/lib*.a
usr/lib/lib*.so
usr/lib/pkgconfig/*
usr/lib/*.la
usr/share/pkgconfig/*
+1
View File
@@ -0,0 +1 @@
usr/lib/lib*.so.*
Vendored Executable
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
CFLAGS = -Wall -g
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS += -O0
else
CFLAGS += -O2
endif
config.status: configure
dh_testdir
# Add here commands to configure the package.
CFLAGS="$(CFLAGS) -Wl,-z,defs" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
build: build-stamp
build-stamp: config.status
dh_testdir
# Add here commands to compile the package.
$(MAKE)
#docbook-to-man debian/g15daemon.sgml > g15daemon.1
touch build-stamp
clean:
dh_testdir
dh_testroot
rm -f build-stamp
# Add here commands to clean up after the build process.
-$(MAKE) distclean
ifneq "$(wildcard /usr/share/misc/config.sub)" ""
cp -f /usr/share/misc/config.sub config.sub
endif
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
cp -f /usr/share/misc/config.guess config.guess
endif
dh_clean
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# Add here commands to install the package into debian/g15daemon.
$(MAKE) install DESTDIR=$(CURDIR)/debian/tmp
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_installchangelogs ChangeLog
dh_installdocs
dh_installexamples
dh_install -a --sourcedir=debian/tmp
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_installinit
# dh_installcron
# dh_installinfo
dh_installman Documentation/g15daemon.1 Documentation/g15daemon_client_devel.3
dh_link
dh_strip
dh_compress
dh_fixperms
# dh_perl
# dh_python
# dh_makeshlibs
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install
+13
View File
@@ -0,0 +1,13 @@
METASOURCES = AUTO
AM_CFLAGS = -DG15DAEMON_BUILD -Wall
sbin_PROGRAMS = g15daemon
noinst_PROGRAMS = g15daemontest
noinst_HEADERS = g15logo.h
g15daemon_SOURCES = utility_funcs.c g15daemon.h main.c linked_lists.c g15_plugins.c
g15daemon_LDADD = -ldl
g15daemon_LDFLAGS = -rdynamic
g15daemontest_SOURCES = lcdclient_test.c
INCLUDES = -I$(top_builddir)/libg15daemon_client/
g15daemontest_LDADD = $(top_builddir)/libg15daemon_client/libg15daemon_client.la
include_HEADERS = g15daemon.h
+257
View File
@@ -0,0 +1,257 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 179 $ - $Date: 2006-11-19 09:33:12 +0100 (Sun, 19 Nov 2006) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
g15_plugin.c
simple plugin loader - loads each plugin and runs each one in it's own thread. a bit expensive probably
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <config.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <libg15.h>
#include <g15daemon.h>
#include <dlfcn.h>
#include <pwd.h>
#include <libg15render.h>
extern int leaving;
void * g15daemon_dlopen_plugin(char *name,unsigned int library) {
void * handle;
char * error;
int mode = library==1?RTLD_GLOBAL:RTLD_LOCAL;
handle = dlopen (name,RTLD_NOW | mode);
if ((error = dlerror()) != NULL) {
g15daemon_log (LOG_ERR, "%s\n", error);
return(NULL);
}
return handle;
}
int g15daemon_dlclose_plugin(void *handle) {
dlclose(handle);
return 0;
}
void run_lcd_client(plugin_t *plugin_args) {
plugin_info_t *info = plugin_args->info;
int plugin_retval = G15_PLUGIN_OK;
int (*plugin_init)(void *client_args) = (void*)info->plugin_init;
int (*plugin)(void *client_args) = (void*)info->plugin_run;
void (*plugin_close)(void *client_args) = (void*)info->plugin_exit;
lcdnode_t *display = (lcdnode_t*)plugin_args->args;
lcd_t *client_lcd = (lcd_t*)display->lcd;
if(plugin_init!=NULL) {
plugin_retval=(*plugin_init)((void*)client_lcd);
}
/* run the plugin thread every 'update_msecs' milliseconds */
while(!leaving && (plugin_retval!=G15_PLUGIN_QUIT)){
plugin_retval = (*plugin)((void*)client_lcd);
if(info->update_msecs<50)
info->update_msecs = 50;
g15daemon_msleep(info->update_msecs);
}
if(plugin_close!=NULL){
(*plugin_close)((void*)client_lcd);
}
if(!leaving)
g15daemon_lcdnode_remove(display);
}
void run_advanced_client(plugin_t *plugin_args)
{
plugin_info_t *info = plugin_args->info;
int (*plugin_init)(void *client_args) = (void*)plugin_args->info->plugin_init;
int (*plugin_run)(void *client_args) = (void*)plugin_args->info->plugin_run;
int (*plugin_close)(void *client_args) = (void*)plugin_args->info->plugin_exit;
/*initialise */
if(plugin_init){
if((*plugin_init)(plugin_args->args)!=G15_PLUGIN_OK)
return;
}
if(plugin_args->info->event_handler && plugin_args->type==G15_PLUGIN_CORE_OS_KB){
g15daemon_t *masterlist = (g15daemon_t*)plugin_args->args;
pthread_mutex_lock(&lcdlist_mutex);
(masterlist->keyboard_handler) = (void*)plugin_args->info->event_handler;
pthread_mutex_unlock(&lcdlist_mutex);
}
if(plugin_run) {
while(((*plugin_run)(plugin_args->args))==G15_PLUGIN_OK && !leaving){
if(info->update_msecs<50)
info->update_msecs = 50;
g15daemon_msleep(info->update_msecs);
}
}else{
while(1){
g15daemon_msleep(500);
}
}
if(plugin_close) {
(*plugin_close)(plugin_args->args);
}
}
void *plugin_thread(plugin_t *plugin_args) {
plugin_info_t *info = plugin_args->info;
/* int (*event)(plugin_event_t *event) = (void*)plugin_args->info->event_handler; */
void *handle = plugin_args->plugin_handle;
if(plugin_args->info->plugin_run!=NULL||plugin_args->info->event_handler!=NULL) {
g15daemon_log(LOG_ERR,"registered plugin \"%s\"",info->name);
} else {
return NULL;
}
if(plugin_args->type == G15_PLUGIN_LCD_CLIENT){
run_lcd_client(plugin_args);
}
else if(plugin_args->type == G15_PLUGIN_CORE_OS_KB||plugin_args->type == G15_PLUGIN_LCD_SERVER) {
run_advanced_client(plugin_args);
}
if(plugin_args)
free(plugin_args);
g15daemon_log(LOG_INFO,"Removed plugin %s",info->name);
g15daemon_dlclose_plugin(handle);
return NULL;
}
int g15_plugin_load (g15daemon_t *masterlist, char *filename) {
void * plugin_handle = NULL;
config_section_t *plugin_cfg = g15daemon_cfg_load_section(masterlist,"PLUGINS");
pthread_t client_connection;
pthread_attr_t attr;
lcdnode_t *clientnode;
if((plugin_handle = g15daemon_dlopen_plugin(filename,G15_PLUGIN_NONSHARED))!=NULL) {
plugin_t *plugin_args=malloc(sizeof(plugin_t));
plugin_args->info = dlsym(plugin_handle, "g15plugin_info");
dlerror();
if(!plugin_args->info) { /* if it doesnt have a valid struct, we should just load it as a library... but we dont at the moment FIXME */
g15daemon_log(LOG_ERR,"%s is not a valid g15daemon plugin\n",filename);
g15daemon_dlclose_plugin(plugin_handle);
dlerror();
return -1;
}
if(strncasecmp("Load",g15daemon_cfg_read_string(plugin_cfg, plugin_args->info->name,"Load"),5)!=0)
{
g15daemon_dlclose_plugin(plugin_handle);
return -1;
}
plugin_args->type = plugin_args->info->type;
/* assign the generic eventhandler if the plugin doesnt provide one - the generic one does nothing atm. FIXME*/
if(plugin_args->info->event_handler==NULL)
plugin_args->info->event_handler = (void*)internal_generic_eventhandler;
if(plugin_args->type == G15_PLUGIN_LCD_CLIENT) {
//g15daemon_t *foolist = (g15daemon_t*)*masterlist;
/* FIXME we should just sort out the linked list stuff instead of overriding it */
if((int)masterlist->numclients>0){
clientnode = g15daemon_lcdnode_add(&masterlist);
}else {
clientnode = masterlist->tail;
masterlist->numclients++;
}
plugin_args->plugin_handle = plugin_handle;
memcpy(clientnode->lcd->g15plugin,plugin_args,sizeof(plugin_s));
plugin_args->args = clientnode;
} else if(plugin_args->type == G15_PLUGIN_CORE_OS_KB ||
plugin_args->type == G15_PLUGIN_CORE_KB_INPUT ||
plugin_args->type == G15_PLUGIN_LCD_SERVER)
{
plugin_args->args = masterlist;
plugin_args->plugin_handle = plugin_handle;
}
memset(&attr,0,sizeof(pthread_attr_t));
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr,64*1024); /* set stack to 64k - dont need 8Mb */
if (pthread_create(&client_connection, &attr, (void*)plugin_thread, plugin_args) != 0) {
g15daemon_log(LOG_WARNING,"Unable to create client thread.");
} else {
pthread_detach(client_connection);
}
}
return 0;
}
void g15_open_all_plugins(g15daemon_t *masterlist, char *plugin_directory) {
DIR *directory;
struct dirent *ep;
char pluginname[2048];
directory = opendir (plugin_directory);
if (directory != NULL)
{
while ((ep = readdir (directory))) {
if(strstr(ep->d_name,".so")){
strcpy(pluginname, plugin_directory);
strncat(pluginname,"/",1);
strncat(pluginname,ep->d_name,200);
g15daemon_log(LOG_INFO, "Loading plugin %s",pluginname);
g15_plugin_load (masterlist, pluginname);
g15daemon_msleep(20);
}
}
(void) closedir (directory);
}
else
perror ("Couldn't open the directory");
}
+293
View File
@@ -0,0 +1,293 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 295 $ - $Date: 2007-09-09 06:37:50 +0200 (Sun, 09 Sep 2007) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
#ifndef G15DAEMON
#define G15DAEMON
#ifndef BLACKnWHITE
#define BLACK 1
#define WHITE 0
#define BLACKnWHITE
#endif
#define LCD_WIDTH 160
#define LCD_HEIGHT 43
#define LCD_BUFSIZE 1048
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <pthread.h>
#include <pwd.h>
#include <syslog.h>
#define CLIENT_CMD_GET_KEYSTATE 'k'
#define CLIENT_CMD_SWITCH_PRIORITIES 'p'
#define CLIENT_CMD_IS_FOREGROUND 'v'
#define CLIENT_CMD_IS_USER_SELECTED 'u'
#define CLIENT_CMD_BACKLIGHT 0x80
#define CLIENT_CMD_KB_BACKLIGHT 0x8
#define CLIENT_CMD_CONTRAST 0x40
#define CLIENT_CMD_MKEY_LIGHTS 0x20
/* if the following CMD is sent from a client, G15Daemon will not send any MR or G? keypresses via uinput,
* all M&G keys must be handled by the client. If the client dies or exits, normal functions resume. */
#define CLIENT_CMD_KEY_HANDLER 0x10
enum {
/* plugin types - LCD plugins are provided with a lcd_t and keystates via EVENT when visible */
/* CORE plugins source and sink events, have no screen associated, and are not able to quit.
by design they implement core functionality..CORE_LIBRARY implements graphic and other
functions for use by other plugins.
*/
G15_PLUGIN_NONE = 0,
G15_PLUGIN_LCD_CLIENT =1,
G15_PLUGIN_CORE_KB_INPUT = 2,
G15_PLUGIN_CORE_OS_KB = 3,
G15_PLUGIN_LCD_SERVER = 4
};
enum {
/* plugin RETURN values */
G15_PLUGIN_QUIT = -1,
G15_PLUGIN_OK = 0
};
enum {
/* plugin EVENT types */
G15_EVENT_KEYPRESS = 1,
G15_EVENT_VISIBILITY_CHANGED,
G15_EVENT_USER_FOREGROUND,
G15_EVENT_MLED,
G15_EVENT_BACKLIGHT,
G15_EVENT_CONTRAST,
G15_EVENT_REQ_PRIORITY,
G15_EVENT_CYCLE_PRIORITY,
G15_EVENT_EXITNOW,
/* core event types */
G15_COREVENT_KEYPRESS_IN,
G15_COREVENT_KEYPRESS_OUT
};
enum {
SCR_HIDDEN = 0,
SCR_VISIBLE
};
/* plugin global or local */
enum {
G15_PLUGIN_NONSHARED = 0,
G15_PLUGIN_SHARED
};
typedef struct lcd_s lcd_t;
typedef struct g15daemon_s g15daemon_t;
typedef struct lcdnode_s lcdnode_t;
typedef struct plugin_event_s plugin_event_t;
typedef struct plugin_info_s plugin_info_t;
typedef struct plugin_s plugin_t;
typedef struct config_items_s config_items_t;
typedef struct config_section_s config_section_t;
typedef struct configfile_s configfile_t;
typedef struct config_items_s
{
config_items_t *next;
config_items_t *prev;
config_items_t *head;
char *key;
char *value;
} config_items_s;
typedef struct config_section_s
{
config_section_t *head;
config_section_t *next;
char *sectionname;
config_items_t *items;
}config_section_s;
typedef struct configfile_s
{
config_section_t *sections;
}configfile_s;
typedef struct plugin_info_s
{
/* type - see above for valid defines*/
int type;
/* short name of the plugin - used only for logging at the moment */
char *name;
/* run thread - will be called every update_msecs milliseconds*/
int *(*plugin_run) (void *);
unsigned int update_msecs;
/* plugin process to be called on close or NULL if there isnt one*/
void *(*plugin_exit) (void *);
/* plugin process to be called on EVENT (such as keypress)*/
int *(*event_handler) (void *);
/* init func if there is one else NULL*/
int *(*plugin_init) (void *);
char *filename;
} plugin_info_s;
typedef struct plugin_s
{
g15daemon_t *masterlist;
unsigned int type;
plugin_info_t *info;
void *plugin_handle;
void *args;
} plugin_s;
typedef struct lcd_s
{
g15daemon_t *masterlist;
int lcd_type;
unsigned char buf[LCD_BUFSIZE];
int max_x;
int max_y;
int connection;
long int ident;
unsigned int backlight_state;
unsigned int mkey_state;
unsigned int contrast_state;
unsigned int state_changed;
/* set to 1 if user manually selected this screen 0 otherwise*/
unsigned int usr_foreground;
/* only used for plugins */
plugin_t *g15plugin;
} lcd_s;
typedef struct plugin_event_s
{
unsigned int event;
unsigned long value;
lcd_t *lcd;
} plugin_event_s;
struct lcdnode_s {
g15daemon_t *list;
lcdnode_t *prev;
lcdnode_t *next;
lcdnode_t *last_priority;
lcd_t *lcd;
}lcdnode_s;
struct g15daemon_s
{
lcdnode_t *head;
lcdnode_t *tail;
lcdnode_t *current;
void *(*keyboard_handler)(void*);
struct passwd *nobody;
volatile unsigned long numclients;
configfile_t *config;
unsigned int kb_backlight_state; // master state
unsigned int remote_keyhandler_sock;
}g15daemon_s;
pthread_mutex_t lcdlist_mutex;
pthread_mutex_t g15lib_mutex;
/* server hello */
#define SERV_HELO "G15 daemon HELLO"
#ifdef G15DAEMON_BUILD
/* internal g15daemon-only functions */
void uf_write_buf_to_g15(lcd_t *lcd);
/* return the pid of a running copy of g15daemon, else -1 */
int uf_return_running();
/* create a /var/run/g15daemon.pid file, returning 0 on success else -1 */
int uf_create_pidfile();
/* open & run all plugins in the given directory */
void g15_open_all_plugins(g15daemon_t *masterlist, char *plugin_directory);
/* linked lists */
g15daemon_t *ll_lcdlist_init();
void ll_lcdlist_destroy(g15daemon_t **masterlist);
/* open and parse config file */
int uf_conf_open(g15daemon_t *list, char *filename);
/* write the config file with all keys/sections */
int uf_conf_write(g15daemon_t *list,char *filename);
/* free all memory used by the config subsystem */
void uf_conf_free(g15daemon_t *list);
/* search the list for valid key called "key" in section named "section" return pointer to item or NULL */
config_items_t* uf_search_confitem(config_section_t *section, char *key);
/* generic handler for net clients */
int internal_generic_eventhandler(plugin_event_t *myevent);
#endif
/* the following functions are available for use by plugins */
/* create a new section */
config_section_t *g15daemon_cfg_load_section(g15daemon_t *masterlist,char *name);
/* return string value from key in sectionname */
char* g15daemon_cfg_read_string(config_section_t *section, char *key, char *defaultval);
/* return float from key in sectionname */
double g15daemon_cfg_read_float(config_section_t *section, char *key, double defaultval);
/* return int from key in sectionname */
int g15daemon_cfg_read_int(config_section_t *section, char *key, int defaultval);
/* return bool as int from key in sectionname */
int g15daemon_cfg_read_bool(config_section_t *section, char *key, int defaultval);
/* add a new key, or update the value of an already existing key, or return -1 if section doesnt exist */
int g15daemon_cfg_write_string(config_section_t *section, char *key, char *val);
int g15daemon_cfg_write_float(config_section_t *section, char *key, double val);
int g15daemon_cfg_write_int(config_section_t *section, char *key, int val);
/* simply write value as On or Off depending on whether val>0 */
int g15daemon_cfg_write_bool(config_section_t *section, char *key, unsigned int val);
/* remoe a key/value pair from named section */
int g15daemon_cfg_remove_key(config_section_t *section, char *key);
/* send event to foreground client's eventlistener */
int g15daemon_send_event(void *caller, unsigned int event, unsigned long value);
/* open named plugin */
void * g15daemon_dlopen_plugin(char *name,unsigned int library);
/* close plugin with handle <handle> */
int g15daemon_dlclose_plugin(void *handle) ;
/* syslog wrapper */
int g15daemon_log (int priority, const char *fmt, ...);
/* cycle from displayed screen to next on list */
void g15daemon_lcdnode_cycle(g15daemon_t *masterlist);
/* add new screen */
lcdnode_t *g15daemon_lcdnode_add(g15daemon_t **masterlist) ;
/* remove screen */
void g15daemon_lcdnode_remove (lcdnode_t *oldnode);
/* handy function from xine_utils.c */
void *g15daemon_xmalloc(size_t size) ;
/* threadsafe sleep */
void g15daemon_sleep(int seconds);
/* threadsafe millisecond sleep */
int g15daemon_msleep(int milliseconds) ;
/* return current time in milliseconds */
unsigned int g15daemon_gettime_ms();
/* convert 1byte/pixel buffer to internal g15 format */
void g15daemon_convert_buf(lcd_t *lcd, unsigned char * orig_buf);
#endif
+432
View File
@@ -0,0 +1,432 @@
static char logo_data[] = {
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,
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,
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,
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,
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,
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,
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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,0,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,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,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,0,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,
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,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,0,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,
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,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,0,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,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,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,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,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,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,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,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,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,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,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,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,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,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,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,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,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,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,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,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,
0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,
0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,
0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,
0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,
1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,0,0,0,0,0,0,1,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,0,
0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,
0,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,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,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,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,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,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,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,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,0,0,0,0,0,0,0,1,1,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,1,1,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,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,0,0,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,0,0,0,0,0,0,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
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,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,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,
1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,
0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,
0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,
0,0,0,0,0,1,1,1,1,1,1,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,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,
1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,0,
0,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,
1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,
1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,
1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,
1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,
1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,
1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,
0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,
0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,
1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,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,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,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,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,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,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,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,1,1,1,1,1,1,1,1
};
+135
View File
@@ -0,0 +1,135 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 300 $ - $Date: 2007-09-10 09:52:01 +0200 (Mon, 10 Sep 2007) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
/* quickndirty g15daemon client example. it just connects and sends a prefab image to the server
* and remains connected until the user presses enter..
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "g15daemon_client.h"
#include "g15logo.h"
#include <errno.h>
#include <poll.h>
#include <libg15.h>
/* #define TEST_KEYHANDLER */
int main(int argc, char *argv[])
{
int g15screen_fd, retval;
char lcdbuffer[6880];
unsigned int keystate;
if((g15screen_fd = new_g15_screen(G15_PIXELBUF))<0){
printf("Sorry, cant connect to the G15daemon\n");
return 5;
}else
printf("Connected to g15daemon. sending image\n");
if(argc<2)
retval = g15_send(g15screen_fd,(char*)logo_data,6880);
else {
memset(lcdbuffer,0,6880);
memset(lcdbuffer,1,6880/2);
retval = g15_send(g15screen_fd,(char*)lcdbuffer,6880);
}
printf("checking key status - press G1 to exit\n");
while(1){
keystate = 0;
int foo = 0;
// keystate = g15_send_cmd (g15screen_fd, G15DAEMON_GET_KEYSTATE, foo);
//while(1){
//recv(g15screen_fd, &keystate, 4, 0);
if(keystate)
printf("keystate = %i\n",keystate);
//}
// if(keystate & G15_KEY_G1) //G1 key. See libg15.h for details on key values.
// break;
/* G2,G3 & G4 change LCD backlight */
// if(keystate & G15_KEY_G2){
// retval = g15_send_cmd (g15screen_fd, G15DAEMON_BACKLIGHT, G15_BRIGHTNESS_DARK);
// }
// if(keystate & G15_KEY_G3){
// retval = g15_send_cmd (g15screen_fd, G15DAEMON_BACKLIGHT, G15_BRIGHTNESS_MEDIUM);
unsigned char packet[2];
packet[0] = G15DAEMON_BACKLIGHT|G15_BRIGHTNESS_MEDIUM;
printf("sent %i bytes\n",send(g15screen_fd, packet, 1, MSG_OOB ));
// }
// if(keystate & G15_KEY_G4){
// retval = g15_send_cmd (g15screen_fd, G15DAEMON_BACKLIGHT, G15_BRIGHTNESS_BRIGHT);
// }
/*
retval = g15_send_cmd (g15screen_fd, G15DAEMON_IS_FOREGROUND, foo);
if(retval)
printf("Hey, we are in the foreground, Doc\n");
else
printf("What dastardly wabbit put me in the background?\n");
retval = g15_send_cmd (g15screen_fd, G15DAEMON_IS_USER_SELECTED, foo);
if(retval)
printf("You wanted me in the foreground, right Doc?\n");
else
printf("You dastardly wabbit !\n");
// if(retval){
sleep(2);
retval = g15_send_cmd (g15screen_fd, G15DAEMON_SWITCH_PRIORITIES, foo);
sleep(2);
retval = g15_send_cmd (g15screen_fd, G15DAEMON_SWITCH_PRIORITIES, foo);
// }
*/
sleep(2);
#ifdef TEST_KEYHANDLER
/* ok.. request that all G&M keys are passed to us.. */
retval = g15_send_cmd (g15screen_fd, G15DAEMON_KEY_HANDLER, foo);
while(1){
printf("waiting on keystate\n");
keystate=0;
retval = recv(g15screen_fd, &keystate , sizeof(keystate),0);
if(keystate)
printf("Recieved %i as keystate",keystate);
}
#endif
}
g15_close_screen(g15screen_fd);
return 0;
}
+206
View File
@@ -0,0 +1,206 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 177 $ - $Date: 2006-11-18 14:46:03 +0100 (Sat, 18 Nov 2006) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <g15daemon.h>
#include <libg15.h>
extern lcd_t *keyhandler;
extern unsigned int client_handles_keys;
extern plugin_info_t *generic_info;
lcd_t static * ll_create_lcd () {
lcd_t *lcd = g15daemon_xmalloc (sizeof (lcd_t));
lcd->max_x = LCD_WIDTH;
lcd->max_y = LCD_HEIGHT;
lcd->backlight_state = G15_BRIGHTNESS_MEDIUM;
lcd->mkey_state = 0;
lcd->contrast_state = G15_CONTRAST_MEDIUM;
lcd->state_changed = 1;
lcd->usr_foreground = 0;
lcd->g15plugin = g15daemon_xmalloc(sizeof (plugin_s));
lcd->g15plugin->plugin_handle = NULL;
lcd->g15plugin->info = (void*)&generic_info;
return (lcd);
}
static void ll_quit_lcd (lcd_t * lcd) {
free (lcd->g15plugin);
free (lcd);
}
/* initialise a new masterlist, and add an initial node at the tail (used for the clock) */
g15daemon_t *ll_lcdlist_init () {
g15daemon_t *masterlist = NULL;
pthread_mutex_init(&lcdlist_mutex, NULL);
pthread_mutex_lock(&lcdlist_mutex);
masterlist = g15daemon_xmalloc(sizeof(g15daemon_t));
masterlist->head = g15daemon_xmalloc(sizeof(lcdnode_t));
masterlist->tail = masterlist->head;
masterlist->current = masterlist->head;
masterlist->head->lcd = ll_create_lcd();
masterlist->head->lcd->mkey_state = 0;
masterlist->head->lcd->masterlist = masterlist;
/* first screen is the clock/menu */
masterlist->head->lcd->g15plugin->info = NULL;
masterlist->head->prev = masterlist->head;
masterlist->head->next = masterlist->head;
masterlist->head->list = masterlist;
masterlist->keyboard_handler = NULL;
masterlist->numclients = 0;
pthread_mutex_unlock(&lcdlist_mutex);
return masterlist;
}
lcdnode_t *g15daemon_lcdnode_add(g15daemon_t **masterlist) {
lcdnode_t *new = NULL;
pthread_mutex_lock(&lcdlist_mutex);
new = g15daemon_xmalloc(sizeof(lcdnode_t));
new->prev = (*masterlist)->head;
new->next = (*masterlist)->tail;
new->lcd = ll_create_lcd();
new->lcd->masterlist = (*masterlist);
new->last_priority = NULL;
new->list = *masterlist;
(*masterlist)->head->next=new;
(*masterlist)->current = new;
(*masterlist)->head = new;
(*masterlist)->head->list = *masterlist;
(*masterlist)->numclients++;
pthread_mutex_unlock(&lcdlist_mutex);
return new;
}
/* cycle through connected client displays */
void g15daemon_lcdnode_cycle(g15daemon_t *masterlist)
{
lcdnode_t *current_screen = masterlist->current;
g15daemon_send_event(current_screen->lcd, G15_EVENT_VISIBILITY_CHANGED, SCR_HIDDEN);
do
{
pthread_mutex_lock(&lcdlist_mutex);
g15daemon_send_event(current_screen->lcd, G15_EVENT_USER_FOREGROUND, 0);
if(masterlist->tail == masterlist->current){
masterlist->current = masterlist->head;
}else{
masterlist->current = masterlist->current->prev;
}
pthread_mutex_unlock(&lcdlist_mutex);
}
while (current_screen != masterlist->current);
pthread_mutex_lock(&lcdlist_mutex);
if(masterlist->tail == masterlist->current) {
masterlist->current = masterlist->head;
} else {
masterlist->current = masterlist->current->prev;
}
pthread_mutex_unlock(&lcdlist_mutex);
g15daemon_send_event(masterlist->current->lcd, G15_EVENT_VISIBILITY_CHANGED, SCR_VISIBLE);
g15daemon_send_event(current_screen->lcd, G15_EVENT_USER_FOREGROUND, 1);
pthread_mutex_lock(&lcdlist_mutex);
masterlist->current->lcd->state_changed = 1;
masterlist->current->last_priority = masterlist->current;
pthread_mutex_unlock(&lcdlist_mutex);
}
void g15daemon_lcdnode_remove (lcdnode_t *oldnode) {
g15daemon_t **masterlist = NULL;
lcdnode_t **prev = NULL;
lcdnode_t **next = NULL;
pthread_mutex_lock(&lcdlist_mutex);
masterlist = &oldnode->list;
prev = &oldnode->prev;
next = &oldnode->next;
ll_quit_lcd(oldnode->lcd);
(*masterlist)->numclients--;
if((*masterlist)->current == oldnode) {
if((*masterlist)->current!=(*masterlist)->head){
(*masterlist)->current = oldnode->next;
} else {
(*masterlist)->current = oldnode->prev;
}
(*masterlist)->current->lcd->state_changed = 1;
}
if(&oldnode->lcd == (void*)keyhandler) {
client_handles_keys = 0;
keyhandler = NULL;
g15daemon_log(LOG_WARNING,"Client key handler quit, going back to defaults");
}
if((*masterlist)->head!=oldnode){
(*next)->prev = oldnode->prev;
(*prev)->next = oldnode->next;
}else{
(*prev)->next = (*masterlist)->tail;
(*masterlist)->head = oldnode->prev;
}
free(oldnode);
pthread_mutex_unlock(&lcdlist_mutex);
}
void ll_lcdlist_destroy(g15daemon_t **masterlist) {
int i = 0;
while ((*masterlist)->head != (*masterlist)->tail) {
i++;
g15daemon_lcdnode_remove((*masterlist)->head);
}
free((*masterlist)->tail->lcd);
free((*masterlist)->tail);
free(*masterlist);
pthread_mutex_destroy(&lcdlist_mutex);
}
+502
View File
@@ -0,0 +1,502 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 302 $ - $Date: 2007-09-10 09:57:53 +0200 (Mon, 10 Sep 2007) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#include <ctype.h>
#include <config.h>
#include <libg15.h>
#include <libg15render.h>
#include "g15daemon.h"
#ifndef LIBG15_VERSION
#define LIBG15_VERSION 1000
#endif
/* all threads will exit if leaving >0 */
int leaving = 0;
int keyboard_backlight_off_onexit = 0;
unsigned int g15daemon_debug = 0;
unsigned int cycle_key;
unsigned int client_handles_keys = 0;
struct lcd_t *keyhandler = NULL;
/* send event to foreground client's eventlistener */
int g15daemon_send_event(void *caller, unsigned int event, unsigned long value)
{
switch(event) {
case G15_EVENT_KEYPRESS: {
static unsigned long lastkeys;
if(!(value & cycle_key) && !(lastkeys & cycle_key)){
lcd_t *lcd = (lcd_t*)caller;
int *(*plugin_listener)(plugin_event_t *newevent) = (void*)lcd->g15plugin->info->event_handler;
plugin_event_t *newevent=g15daemon_xmalloc(sizeof(plugin_event_t));
newevent->event = event;
newevent->value = value;
newevent->lcd = lcd;
(*plugin_listener)((void*)newevent);
/* hack - keyboard events are always sent from the foreground even when they aren't
send keypress event to the OS keyboard_handler plugin */
if(lcd->masterlist->keyboard_handler != NULL && lcd->masterlist->remote_keyhandler_sock==0) {
int *(*keyboard_handler)(plugin_event_t *newevent) = (void*)lcd->masterlist->keyboard_handler;
(*keyboard_handler)((void*)newevent);
}
// if we have a remote keyhandler, send the key. FIXME: we should do this from the net plugin
if(lcd->masterlist->remote_keyhandler_sock!=0) {
if((send(lcd->masterlist->remote_keyhandler_sock,(void *)&newevent->value,sizeof(newevent->value),0))<0)
g15daemon_log(LOG_WARNING,"Error in send: %s\n",strerror(errno));
}
if(value & G15_KEY_LIGHT){ // the backlight key was pressed - maintain user-selected state
lcd->masterlist->kb_backlight_state++;
if(lcd->masterlist->kb_backlight_state>2)
lcd->masterlist->kb_backlight_state=0;
}
free(newevent);
}else{
/* hacky attempt to double-time the use of L1, if the key is pressed less than half a second, it cycles the screens. If held for longer, the key is sent to the application for use instead */
lcd_t *lcd = (lcd_t*)caller;
g15daemon_t* masterlist = lcd->masterlist;
static unsigned int clicktime;
if(value & cycle_key) {
clicktime=g15daemon_gettime_ms();
}else{
unsigned int unclick=g15daemon_gettime_ms();
if ((unclick-clicktime)<500) {
g15daemon_lcdnode_cycle(masterlist);
}
else
{
plugin_event_t *clickevent=g15daemon_xmalloc(sizeof(plugin_event_t));
int *(*plugin_listener)(plugin_event_t *clickevent) = (void*)lcd->g15plugin->info->event_handler;
clickevent->event = event;
clickevent->value = value|cycle_key;
clickevent->lcd = lcd;
(*plugin_listener)((void*)clickevent);
clickevent->event = event;
clickevent->value = value&~cycle_key;
clickevent->lcd = lcd;
(*plugin_listener)((void*)clickevent);
free(clickevent);
}
}
}
lastkeys = value;
break;
}
case G15_EVENT_CYCLE_PRIORITY:{
lcd_t *lcd = (lcd_t*)caller;
g15daemon_t* masterlist = lcd->masterlist;
if(value)
g15daemon_lcdnode_cycle(masterlist);
break;
}
case G15_EVENT_REQ_PRIORITY: {
lcdnode_t *lcdnode=(lcdnode_t*)caller;
/* client wants to switch priorities */
pthread_mutex_lock(&lcdlist_mutex);
if(lcdnode->list->current != lcdnode){
lcdnode->last_priority = lcdnode->list->current;
lcdnode->list->current = lcdnode;
}
else {
if(lcdnode->list->current == lcdnode->last_priority){
lcdnode->list->current = lcdnode->list->current->prev;
} else{
if(lcdnode->last_priority != NULL) {
lcdnode->list->current = lcdnode->last_priority;
lcdnode->last_priority = NULL;
}
else
lcdnode->list->current = lcdnode->list->current->prev;
}
}
pthread_mutex_unlock(&lcdlist_mutex);
break;
}
default: {
lcd_t *lcd = (lcd_t*)caller;
int *(*plugin_listener)(plugin_event_t *newevent) = (void*)lcd->g15plugin->info->event_handler;
plugin_event_t *newevent=g15daemon_xmalloc(sizeof(plugin_event_t));
newevent->event = event;
newevent->value = value;
newevent->lcd = lcd;
(*plugin_listener)((void*)newevent);
free(newevent);
}
}
return 0;
}
static void *keyboard_watch_thread(void *lcdlist){
g15daemon_t *masterlist = (g15daemon_t*)(lcdlist);
unsigned int keypresses = 0;
int retval = 0;
while (!leaving) {
pthread_mutex_lock(&g15lib_mutex);
retval = getPressedKeys(&keypresses, 40);
pthread_mutex_unlock(&g15lib_mutex);
/* every 2nd packet contains the codes we want.. immediately try again */
while (retval == G15_ERROR_TRY_AGAIN){
pthread_mutex_lock(&g15lib_mutex);
retval = getPressedKeys(&keypresses, 40);
pthread_mutex_unlock(&g15lib_mutex);
}
if(retval == G15_NO_ERROR){
g15daemon_send_event(masterlist->current->lcd,
G15_EVENT_KEYPRESS, keypresses);
}
if(retval == -ENODEV && LIBG15_VERSION>=1200) {
pthread_mutex_lock(&g15lib_mutex);
while((retval=re_initLibG15() != G15_NO_ERROR) && !leaving){
sleep(1);
}
if(!leaving) { masterlist->current->lcd->state_changed=1; masterlist->current->lcd->ident=random();}
pthread_mutex_unlock(&g15lib_mutex);
}
g15daemon_msleep(10);
}
return NULL;
}
static void *lcd_draw_thread(void *lcdlist){
g15daemon_t *masterlist = (g15daemon_t*)(lcdlist);
static long int lastlcd = 1;
static unsigned int lastscreentime;
/* unsigned int fps = 0; */
lcd_t *displaying = masterlist->tail->lcd;
char *lastdisplayed=NULL;
memset(displaying->buf,0,1024);
g15daemon_sleep(2);
while (!leaving) {
pthread_mutex_lock(&lcdlist_mutex);
displaying = masterlist->current->lcd;
if(displaying->ident != lastlcd){
/* monitor 'fps' - due to the TCP protocol, some frames will be bunched up.
discard excess to reduce load on the bus */
/* fps = 1000 / (g15daemon_gettime_ms() - lastscreentime); */
/* if the current screen is less than 20ms from the previous (equivelant to 50fps) delay it */
/* this allows a real-world fps of 40fps with no almost frame loss and reduces peak usb bus-load */
if((g15daemon_gettime_ms() - lastscreentime)>=20||(char*)displaying!=lastdisplayed){
uf_write_buf_to_g15(displaying);
lastscreentime = g15daemon_gettime_ms();
lastdisplayed = (char*)displaying;
lastlcd = displaying->ident;
}
}
if(displaying->state_changed){
pthread_mutex_lock(&g15lib_mutex);
setLCDContrast(displaying->contrast_state);
if(displaying->masterlist->remote_keyhandler_sock==0) // only allow mled control if the macro recorder isnt running
setLEDs(displaying->mkey_state);
if(masterlist->kb_backlight_state)
setLCDBrightness(displaying->backlight_state);
else
setLCDBrightness(masterlist->kb_backlight_state);
pthread_mutex_unlock(&g15lib_mutex);
displaying->state_changed = 0;
}
pthread_mutex_unlock(&lcdlist_mutex);
g15daemon_msleep(5);
}
return NULL;
}
void g15daemon_sighandler(int sig) {
switch(sig){
case SIGUSR1:
keyboard_backlight_off_onexit = 1;
case SIGINT:
case SIGQUIT:
leaving = 1;
break;
case SIGPIPE:
break;
}
}
int main (int argc, char *argv[])
{
pid_t daemonpid;
int retval;
int i;
int cycle_cmdline_override=0;
struct sigaction new_action;
cycle_key = G15_KEY_L1;
unsigned char user[256];
pthread_t keyboard_thread;
pthread_t lcd_thread;
memset(user,0,256);
for (i=0;i<argc;i++) {
char daemonargs[20];
memset(daemonargs,0,20);
strncpy(daemonargs,argv[i],19);
if (!strncmp(daemonargs, "-k",2) || !strncmp(daemonargs, "--kill",6)) {
daemonpid = uf_return_running();
if(daemonpid>0) {
kill(daemonpid,SIGINT);
} else
printf("G15Daemon not running\n");
exit(0);
}
if (!strncmp(daemonargs, "-K",2) || !strncmp(daemonargs, "--KILL",6)) {
daemonpid = uf_return_running();
if(daemonpid>0) {
kill(daemonpid,SIGUSR1);
} else
printf("G15Daemon not running\n");
exit(0);
}
if (!strncmp(daemonargs, "-v",2) || !strncmp(daemonargs, "--version",9)) {
float lg15ver = LIBG15_VERSION;
printf("G15Daemon version %s - %s\n",VERSION,uf_return_running() >= 0 ?"Loaded & Running":"Not Running");
printf("compiled with libg15 version %.3f\n\n",lg15ver/1000);
exit(0);
}
if (!strncmp(daemonargs, "-h",2) || !strncmp(daemonargs, "--help",6)) {
printf("G15Daemon version %s - %s\n",VERSION,uf_return_running() >= 0 ?"Loaded & Running":"Not Running");
printf("%s -h (--help) or -k (--kill) or -s (--switch) or -d (--debug) or -v (--version)\n\n -k will kill a previous incarnation",argv[0]);
#ifdef LIBG15_VERSION
#if LIBG15_VERSION >= 1200
printf(", if uppercase -K or -KILL turn off the keyboard backlight on the way out.");
#endif
#endif
printf("\n -h shows this help\n -s changes the screen-switch key from MR to L1\n -d debug mode - stay in foreground and output all debug messages to STDERR\n -v show version\n");
exit(0);
}
if (!strncmp(daemonargs, "-s",2) || !strncmp(daemonargs, "--switch",8)) {
cycle_key = G15_KEY_MR;
cycle_cmdline_override=1;
}
if (!strncmp(daemonargs, "-d",2) || !strncmp(daemonargs, "--debug",7)) {
g15daemon_debug = 1;
if((argv[i+1])!=NULL)
if(isdigit(argv[i+1][0])){
g15daemon_debug = atoi(argv[i+1]);
if(g15daemon_debug==0) g15daemon_debug = 1;
}
}
if (!strncmp(daemonargs, "-u",2) || !strncmp(daemonargs, "--user",7)) {
if(argv[i+1]!=NULL){
strncpy((char*)user,argv[i+1],128);
i++;
}
}
}
if(uf_return_running()>=0) {
g15daemon_log(LOG_ERR,"G15Daemon already running.. Exiting");
exit(0);
}
/* set libg15 debugging to our debug setting */
if(LIBG15_VERSION>=1200)
libg15Debug(g15daemon_debug);
#ifdef OSTYPE_DARWIN
/* OS X: load codeless kext */
retval = system("/sbin/kextload " "/System/Library/Extensions/libusbshield.kext");
if (WIFEXITED(retval)){
if (WEXITSTATUS(retval) !=0){
g15daemon_log(LOG_ERR,"Unable to load USB shield kext...exiting");
exit(1);
}
} else {
g15daemon_log(LOG_ERR,"Unable to launch kextload...exiting");
exit(1);
}
#endif
/* init stuff here.. */
if((retval=initLibG15())!=G15_NO_ERROR){
g15daemon_log(LOG_ERR,"Unable to attach to the G15 Keyboard... exiting");
exit(1);
}
if(!g15daemon_debug)
daemon(0,0);
if(uf_create_pidfile() == 0) {
g15daemon_t *lcdlist;
config_section_t *global_cfg=NULL;
pthread_attr_t attr;
struct passwd *nobody;
unsigned char location[1024];
openlog("g15daemon", LOG_PID, LOG_DAEMON);
if(strlen((char*)user)==0){
nobody = getpwnam("nobody");
}else {
nobody = getpwnam((char*)user);
}
if (nobody==NULL)
{
nobody = getpwuid(geteuid());
g15daemon_log(LOG_WARNING,"BEWARE: running as effective uid %i\n",nobody->pw_uid);
}
/* initialise the linked list */
lcdlist = ll_lcdlist_init();
lcdlist->nobody = nobody;
setLCDContrast(1);
setLEDs(0);
lcdlist->kb_backlight_state=1;
setLCDBrightness(lcdlist->kb_backlight_state);
#ifdef LIBG15_VERSION
#if LIBG15_VERSION >= 1200
setKBBrightness(lcdlist->kb_backlight_state);
#endif
#endif
uf_conf_open(lcdlist, "/etc/g15daemon.conf");
global_cfg=g15daemon_cfg_load_section(lcdlist,"Global");
if(!cycle_cmdline_override){
cycle_key = 1==g15daemon_cfg_read_bool(global_cfg,"Use MR as Cycle Key",0)?G15_KEY_MR:G15_KEY_L1;
}
/* all other processes/threads should be seteuid nobody */
if(nobody!=NULL) {
seteuid(nobody->pw_uid);
setegid(nobody->pw_gid);
}
pthread_mutex_init(&g15lib_mutex, NULL);
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr,512*1024); /* set stack to 512k - dont need 8Mb !! */
pthread_attr_setscope(&attr,PTHREAD_SCOPE_SYSTEM);
int thread_policy=SCHED_RR;
pthread_attr_setschedpolicy(&attr,thread_policy);
if (pthread_create(&keyboard_thread, &attr, keyboard_watch_thread, lcdlist) != 0) {
g15daemon_log(LOG_ERR,"Unable to create keyboard listener thread. Exiting");
goto exitnow;
}
pthread_attr_setstacksize(&attr,128*1024);
/* all other threads have a lower priority... maybe */
pthread_attr_setscope(&attr,PTHREAD_SCOPE_PROCESS);
thread_policy=SCHED_OTHER;
pthread_attr_setschedpolicy(&attr,thread_policy);
if (pthread_create(&lcd_thread, &attr, lcd_draw_thread, lcdlist) != 0) {
g15daemon_log(LOG_ERR,"Unable to create display thread. Exiting");
goto exitnow;
}
g15daemon_log(LOG_INFO,"%s loaded\n",PACKAGE_STRING);
snprintf((char*)location,1024,"%s/%s",DATADIR,"g15daemon/splash/g15logo2.wbmp");
g15canvas *canvas = (g15canvas *)g15daemon_xmalloc (sizeof (g15canvas));
memset (canvas->buffer, 0, G15_BUFFER_LEN);
canvas->mode_cache = 0;
canvas->mode_reverse = 0;
canvas->mode_xor = 0;
g15r_loadWbmpSplash(canvas,(char*)location);
memcpy (lcdlist->tail->lcd->buf, canvas->buffer, G15_BUFFER_LEN);
free (canvas);
uf_write_buf_to_g15(lcdlist->tail->lcd);
snprintf((char*)location,1024,"%s",PLUGINDIR);
g15_open_all_plugins(lcdlist,(char*)location);
new_action.sa_handler = g15daemon_sighandler;
new_action.sa_flags = 0;
sigaction(SIGINT, &new_action, NULL);
sigaction(SIGQUIT, &new_action, NULL);
sigaction(SIGUSR1, &new_action, NULL);
do {
sleep(1);
} while( leaving == 0);
g15daemon_log(LOG_INFO,"Leaving by request");
pthread_join(lcd_thread,NULL);
pthread_join(keyboard_thread,NULL);
/* switch off the lcd backlight */
setLCDBrightness(0);
#ifdef LIBG15_VERSION
#if LIBG15_VERSION >= 1200
/* if SIGUSR1 was sent to kill us, switch off the keyboard backlight as well */
if(keyboard_backlight_off_onexit==1)
setKBBrightness(0);
#endif
#endif
#ifdef LIBG15_VERSION
#if LIBG15_VERSION >= 1100
exitLibG15();
#endif
#endif
ll_lcdlist_destroy(&lcdlist);
exitnow:
/* return to root privilages for the final countdown */
seteuid(0);
setegid(0);
closelog();
uf_conf_write(lcdlist,"/etc/g15daemon.conf");
uf_conf_free(lcdlist);
unlink("/var/run/g15daemon.pid");
}
return 0;
}
+585
View File
@@ -0,0 +1,585 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 190 $ - $Date: 2006-11-21 17:31:03 +0100 (Tue, 21 Nov 2006) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <ctype.h>
#include <sys/time.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "g15daemon.h"
#include <libg15.h>
#include <stdarg.h>
extern unsigned int g15daemon_debug;
#define G15DAEMON_PIDFILE "/var/run/g15daemon.pid"
/* if no exitfunc or eventhandler, member should be NULL */
const plugin_info_t generic_info[] = {
/* TYPE, name, initfunc, updatefreq, exitfunc, eventhandler */
{G15_PLUGIN_LCD_CLIENT, "BackwardCompatible", NULL, 0, NULL, (void*)internal_generic_eventhandler},
{G15_PLUGIN_NONE, "" , NULL, 0, NULL, NULL}
};
/* handy function from xine_utils.c */
void *g15daemon_xmalloc(size_t size) {
void *ptr;
/* prevent xmalloc(0) of possibly returning NULL */
if( !size )
size++;
if((ptr = calloc(1, size)) == NULL) {
g15daemon_log(LOG_WARNING, "g15_xmalloc() failed: %s.\n", strerror(errno));
return NULL;
}
return ptr;
}
int uf_return_running(){
int fd;
char pidtxt[128];
int pid;
int l;
if ((fd = open(G15DAEMON_PIDFILE, O_RDWR, 0644)) < 0) {
return -1;
}
if((l = read(fd,pidtxt,sizeof(pidtxt)-1)) < 0) {
unlink (G15DAEMON_PIDFILE);
close(fd);
return -1;
}
if((pid = atoi(pidtxt)) <= 0) {
g15daemon_log(LOG_ERR,"pidfile corrupt");
unlink(G15DAEMON_PIDFILE);
close(fd);
return -1;
}
if((kill(pid,0) != 0) && errno != EPERM ) {
g15daemon_log(LOG_ERR,"Process died - removing pidfile");
unlink(G15DAEMON_PIDFILE);
close(fd);
return -1;
}
return pid;
}
int uf_create_pidfile() {
char pidtxt[128];
size_t l;
int fd;
if(!uf_return_running() && (fd = open(G15DAEMON_PIDFILE, O_CREAT|O_RDWR|O_EXCL, 0644)) < 0) {
g15daemon_log(LOG_ERR,"previous G15Daemon process died. removing pidfile");
unlink(G15DAEMON_PIDFILE);
}
if ((fd = open(G15DAEMON_PIDFILE, O_CREAT|O_RDWR|O_EXCL, 0644)) < 0) {
return 1;
}
snprintf(pidtxt, sizeof(pidtxt), "%lu\n", (unsigned long) getpid());
if (write(fd, pidtxt, l = strlen(pidtxt)) != l) {
g15daemon_log(LOG_WARNING, "write(): %s", strerror(errno));
unlink(G15DAEMON_PIDFILE);
}
if(fd>0) {
close(fd);
return 0;
}
return 1;
}
/* syslog wrapper */
int g15daemon_log (int priority, const char *fmt, ...) {
va_list argp;
va_start (argp, fmt);
if(g15daemon_debug == 0)
vsyslog(priority, fmt, argp);
else {
vfprintf(stderr,fmt,argp);
fprintf(stderr,"\n");
}
va_end (argp);
return 0;
}
void g15daemon_convert_buf(lcd_t *lcd, unsigned char * orig_buf)
{
unsigned int x,y,val;
for(x=0;x<160;x++)
for(y=0;y<43;y++)
{
unsigned int pixel_offset = y * LCD_WIDTH + x;
unsigned int byte_offset = pixel_offset / 8;
unsigned int bit_offset = 7-(pixel_offset % 8);
val = orig_buf[x+(y*160)];
if (val)
lcd->buf[byte_offset] = lcd->buf[byte_offset] | 1 << bit_offset;
else
lcd->buf[byte_offset] = lcd->buf[byte_offset] & ~(1 << bit_offset);
}
}
/* wrap the libg15 function */
void uf_write_buf_to_g15(lcd_t *lcd)
{
pthread_mutex_lock(&g15lib_mutex);
writePixmapToLCD(lcd->buf);
pthread_mutex_unlock(&g15lib_mutex);
return;
}
/* Sleep routine (hackish). */
void g15daemon_sleep(int seconds) {
pthread_mutex_t dummy_mutex;
static pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER;
struct timespec timeout;
/* Create a dummy mutex which doesn't unlock for sure while waiting. */
pthread_mutex_init(&dummy_mutex, NULL);
pthread_mutex_lock(&dummy_mutex);
timeout.tv_sec = time(NULL) + seconds;
timeout.tv_nsec = 0;
pthread_cond_timedwait(&dummy_cond, &dummy_mutex, &timeout);
/* pthread_cond_destroy(&dummy_cond); */
pthread_mutex_unlock(&dummy_mutex);
pthread_mutex_destroy(&dummy_mutex);
}
/* millisecond sleep routine. */
int g15daemon_msleep(int milliseconds) {
struct timespec timeout;
if(milliseconds>999)
milliseconds=999;
timeout.tv_sec = 0;
timeout.tv_nsec = milliseconds*1000000;
return nanosleep (&timeout, NULL);
}
unsigned int g15daemon_gettime_ms(){
struct timeval tv;
gettimeofday(&tv,NULL);
return (tv.tv_sec*1000+tv.tv_usec/1000);
}
/* generic event handler used unless overridden (only loading a plugin will override currently)*/
int internal_generic_eventhandler(plugin_event_t *event) {
lcd_t *lcd = (lcd_t*) event->lcd;
switch (event->event)
{
case G15_EVENT_KEYPRESS: {
if(lcd->g15plugin->plugin_handle){ /* loadable plugin */
/* plugin had null for eventhandler therefore doesnt want events.. throw them away */
}
}
break;
case G15_EVENT_VISIBILITY_CHANGED:
break;
default:
break;
}
return G15_PLUGIN_OK;
}
/* free all memory used by the config subsystem */
void uf_conf_free(g15daemon_t *list)
{
config_section_t *section=list->config->sections;
config_items_t *tmpitem=NULL;
config_section_t *tmpsection=section;
while(tmpsection!=NULL){
tmpitem=section->items;
if(section->sectionname){
free(section->sectionname);
while(section->items!=NULL){
if(tmpitem->key!=NULL)
free(tmpitem->key);
if(tmpitem->value!=NULL)
free(tmpitem->value);
tmpitem=section->items->next;
free(section->items);
section->items=tmpitem;
}
}
tmpsection=section->next;
free(section);
section=tmpsection;
}
free(section);
free(list->config);
}
/* write the config file with all keys/sections */
int uf_conf_write(g15daemon_t *list,char *filename)
{
int config_fd=-1;
config_section_t *foo=list->config->sections;
config_items_t * item=NULL;
char line[1024];
config_fd = open(filename,O_CREAT|O_RDWR|O_TRUNC);
if(config_fd){
snprintf(line,1024,"# G15Daemon Configuration File\n# any items entered before a [section] header\n# will be in the Global config space\n# comments you wish to keep should start with a semicolon';'\n");
write(config_fd,line,strlen(line));
while(foo!=NULL){
item=foo->items;
memset(line,0,1024);
if(foo->sectionname!=NULL){
snprintf(line,1024,"\n[%s]\n",foo->sectionname);
write(config_fd,line,strlen(line));
while(item!=NULL){
memset(line,0,1024);
if(item->key!=NULL){
if(item->key[0]==';') // comment
snprintf(line,1024,"%s\n",item->key);
else
snprintf(line,1024,"%s: %s\n",item->key, item->value);
write(config_fd,line,strlen(line));
}
item=item->next;
}
}
foo=foo->next;
}
close(config_fd);
return 0;
}
return -1;
}
/* search the list for valid section name return pointer to section, or NULL otherwise */
config_section_t* uf_search_confsection(g15daemon_t *list,char *sectionname){
config_section_t *section=list->config->sections;
while(section!=NULL){
if(0==strcmp((char*)section->sectionname,(char*)sectionname))
break;
section=section->next;
}
return section;
}
/* search the list for valid key called "key" in section named "section" return pointer to item or NULL */
config_items_t* uf_search_confitem(config_section_t *section, char *key){
config_items_t * item=NULL;
if(section!=NULL){
item=section->items;
while(item!=NULL){
if(0==strcmp((char*)item->key,(char*)key))
break;
item=item->next;
}
}
return item;
}
/* return pointer to section, or create a new section if it doesnt exist */
config_section_t *g15daemon_cfg_load_section(g15daemon_t *masterlist,char *name) {
config_section_t *new = NULL;
if((new=uf_search_confsection(masterlist,name))!=NULL)
return new;
new = g15daemon_xmalloc(sizeof(config_section_t));
new->head = new;
new->next = NULL;;
new->sectionname=strdup(name);
if(!masterlist->config->sections){
masterlist->config->sections=new;
masterlist->config->sections->head = new;
} else {
masterlist->config->sections->head->next=new;
masterlist->config->sections->head = new;
}
return new;
}
/* cleanup whitespace */
char * uf_remove_whitespace(char *str){
int z=0;
if(str==NULL)
str=strdup(" ");
while(isspace(str[z])&&str[z])
z++;
str+=z;
return str;
}
/* add a new key, or update the value of an already existing key, or return -1 if section doesnt exist */
int g15daemon_cfg_write_string(config_section_t *section, char *key, char *val){
config_items_t *new = NULL;
const char empty[]=" ";
if(section==NULL)
return -1;
if((uf_search_confitem(section, key))){
free(new);
new=uf_search_confitem(section, key);
new->value=strdup(val);
}else{
new=g15daemon_xmalloc(sizeof(config_items_t));
new->head=new;
new->next=NULL;
new->key=strdup(key);
new->value=strdup(val);
if(!section->items){
new->prev=NULL;
section->items=new;
section->items->head=new;
}else{
new->prev=section->items->head;
section->items->head->next=new;
section->items->head=new;
}
}
return 0;
}
/* remoe a key/value pair from named section */
int g15daemon_cfg_remove_key(config_section_t *section, char *key){
config_items_t *new = NULL;
config_items_t *next = NULL;
config_items_t *prev = NULL;
if(section==NULL)
return -1;
if((uf_search_confitem(section, key))){
new=uf_search_confitem(section, key);
prev=new->prev;
next=new->next;
if(prev){
prev->next=new->next;
}else{
if(!next) {
free(section->items);
section->items=NULL;
}
else
section->items=next;
}
if(new->head==new){
if(prev){
prev->head = prev;
section->items->head=prev;
}
if(!prev){
if(!next) {
free(section->items);
section->items=NULL;
}
}
}
if(next){
if(prev)
next->prev=prev;
else
next->prev=NULL;
}
free(new->key);
free(new->value);
free(new);
}
return 0;
}
int g15daemon_cfg_write_int(config_section_t *section, char *key, int val) {
char tmp[1024];
snprintf(tmp,1024,"%i",val);
return g15daemon_cfg_write_string(section, key, tmp);
}
int g15daemon_cfg_write_float(config_section_t *section, char *key, double val) {
char tmp[1024];
snprintf(tmp,1024,"%f",val);
return g15daemon_cfg_write_string(section, key, tmp);
}
/* simply write value as On or Off depending on whether val>0 */
int g15daemon_cfg_write_bool(config_section_t *section, char *key, unsigned int val) {
char tmp[1024];
snprintf(tmp,1024,"%s",val?"On":"Off");
return g15daemon_cfg_write_string(section, key, tmp);
}
/* the config read functions will either return a value from the config file, or the default value, which will be written to the config file if the key doesnt exist */
/* return bool as int from key in sectionname */
int g15daemon_cfg_read_bool(config_section_t *section, char *key, int defaultval) {
int retval=0;
config_items_t *item = uf_search_confitem(section, key);
if(item){
retval = 1^retval?(strncmp(item->value,"On",2)==0):1;
return retval;
}
g15daemon_cfg_write_bool(section, key, defaultval);
return defaultval;
}
/* return int from key in sectionname */
int g15daemon_cfg_read_int(config_section_t *section, char *key, int defaultval) {
config_items_t *item = uf_search_confitem(section, key);
if(item){
return atoi(item->value);
}
g15daemon_cfg_write_int(section, key, defaultval);
return defaultval;
}
/* return float from key in sectionname */
double g15daemon_cfg_read_float(config_section_t *section, char *key, double defaultval) {
config_items_t *item = uf_search_confitem(section, key);
if(item){
return atof(item->value);
}
g15daemon_cfg_write_float(section, key, defaultval);
return defaultval;
}
/* return string value from key in sectionname */
char* g15daemon_cfg_read_string(config_section_t *section, char *key, char *defaultval) {
config_items_t *item = uf_search_confitem(section, key);
if(item){
return item->value;
}
g15daemon_cfg_write_string(section, key, defaultval);
return defaultval;
}
int uf_conf_open(g15daemon_t *list, char *filename) {
char *buffer, *lines;
int config_fd=-1;
char *sect;
char *start;
char *bar;
int i;
struct stat stats;
list->config=g15daemon_xmalloc(sizeof(configfile_t));
list->config->sections=NULL;
if (lstat(filename, &stats) == -1)
return -1;
if (!(config_fd = open(filename, O_RDWR)))
return -1;
buffer = g15daemon_xmalloc(stats.st_size + 1);
if (read(config_fd, buffer, stats.st_size) != stats.st_size)
{
free(buffer);
close(config_fd);
return -1;
}
close(config_fd);
buffer[stats.st_size] = '\0';
lines=strtok_r(buffer,"\n",&bar);
config_section_t *section=NULL;
while(lines!=NULL){
sect=strdup(lines);
i=0;
while(isspace(sect[i])){
i++;
}
start=sect+i;
if(start[0]=='#'){
/* header - ignore */
/* comments start with ; and can be produced like so:
g15daemon_cfg_write_string(noload_cfg,"; Plugins in this section will not be loaded on start","");
the value parameter must not be used.
*/
} else if(strrchr(start,']')) { /* section title */
char sectiontitle[1024];
memset(sectiontitle,0,1024);
strncpy(sectiontitle,start+1,strlen(start)-2);
section = g15daemon_cfg_load_section(list,sectiontitle);
}else{
/*section keys */
if(section==NULL){
/* create an internal section "Global" which is the default for items not under a [section] header */
section=g15daemon_cfg_load_section(list,"Global");
}
char *foo=NULL;
char *key = uf_remove_whitespace( strtok_r(start,":=",&foo) );
char *val = uf_remove_whitespace( strtok_r(NULL,":=", &foo) );
g15daemon_cfg_write_string(section,key,val);
}
free(sect);
lines=strtok_r(NULL,"\n",&bar);
}
free(buffer);
return 0;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
+99
View File
@@ -0,0 +1,99 @@
package G15Daemon;
use base 'Exporter';
use warnings;
use strict;
use 5.008007;
our $VERSION = '0.2';
require Exporter;
our @EXPORT = qw( $g15wbmp $g15pbuf $g15txt );
use Inline C =>
DATA =>
LIBS => '-lg15daemon_client';
our $WIDTH = '160';
our $HEIGHT = '43';
*g15pbuf = \0;
*g15txt = \1;
*g15wbmp = \2;
sub apiversion {
my $self = shift;
return g15version();
}
sub width {
my $self = shift;
return $WIDTH;
}
sub height {
my $self = shift;
return $HEIGHT;
}
sub new
{
my ($class, $screentype) = @_;
my $sock = g15newscreen ($screentype);
my $self = {socket => $sock};
bless $self, $_[0];
}
sub DESTROY {
my $self = shift;
return g15closescreen($self->{socket});
}
sub closescreen {
my $self = shift;
return g15closescreen($self->{socket});
}
sub send {
my $self = shift;
my ($buffer) = @_;
my $len = length($buffer);
return g15send($self->{socket}, $buffer, $len);
}
sub recv{
my $self = shift;
my ($buffer, $len) = @_;
return g15recv($self->{socket}, $buffer, $len);
}
1;
__DATA__
__C__
#include <g15daemon_client.h>
SV* g15version() {
return newSVpvf("%s\n", G15DAEMON_VERSION);
}
int g15newscreen (int screentype) {
return new_g15_screen(screentype);
}
int g15closescreen(int sockfd) {
return g15_close_screen(sockfd);
}
int g15send(int sockfd, char *buf, unsigned int len) {
int retval = g15_send(sockfd, buf, len);
memset(buf,0,len);
return retval;
}
char * g15recv(int sockfd, char *buf, unsigned int len) {
g15_recv(sockfd, buf, len);
return buf;
}
__END__
+16
View File
@@ -0,0 +1,16 @@
***** Perl bindings *****
To use the perl language bindings for libg15daemon_client, copy the
G15Daemon.pm file into a perl include folder, or untar the archive and run
the makefile with:
perl Makefile.PL && make && make install
You'll need to have the
Inline:: perl module installed, which is (as usual) available on CPAN.
The bindings are pretty basic, see the contribs folder for an example of
use.
***** Python Bindings *****
The pyg15daemon bindings are available in this folder, or the latest release
of these bindings are available at http://abraumhal.de/pyg15daemon/
Binary file not shown.
Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
METASOURCES = AUTO
lib_LTLIBRARIES = libg15daemon_client.la
libg15daemon_client_la_LDFLAGS = -version-info 1:2:0
libg15daemon_client_la_SOURCES = g15daemon_client.h g15daemon_net.c
include_HEADERS= g15daemon_client.h
+76
View File
@@ -0,0 +1,76 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 301 $ - $Date: 2007-09-10 09:55:15 +0200 (Mon, 10 Sep 2007) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
#ifdef __cplusplus
extern "C"
{
#endif
#define G15_WIDTH 160
#define G15_HEIGHT 43
#define G15_BUFSIZE 6880
#define G15DAEMON_VERSION g15daemon_version()
#define G15_PIXELBUF 0
#define G15_TEXTBUF 1
#define G15_WBMPBUF 2
#define G15_G15RBUF 3
#define G15_SHMRBUF 4
/* client / server commands - see README.devel for details on use */
#define G15DAEMON_KEY_HANDLER 0x10
#define G15DAEMON_MKEYLEDS 0x20
#define G15DAEMON_CONTRAST 0x40
#define G15DAEMON_BACKLIGHT 0x80
#define G15DAEMON_KB_BACKLIGHT 0x8
#define G15DAEMON_GET_KEYSTATE 'k'
#define G15DAEMON_SWITCH_PRIORITIES 'p'
#define G15DAEMON_IS_FOREGROUND 'v'
#define G15DAEMON_IS_USER_SELECTED 'u'
const char *g15daemon_version();
/* open a new connection to the g15daemon. returns an fd to be used with g15_send & g15_recv */
/* screentype should be either 0 (graphic/pixelbuffer) or 1 (textbuffer). only Graphic buffers are
supported in this version */
int new_g15_screen(int screentype);
/* close connection - just calls close() */
int g15_close_screen(int sock);
/* these two functions operate in the same way as send & recv, except they wont return
* until _all_ len bytes are sent or received, or an error occurs */
int g15_send(int sock, char *buf, unsigned int len);
int g15_recv(int sock, char *buf, unsigned int len);
/* send a command (defined above) to the daemon. any replies from the daemon are returned */
int g15_send_cmd (int sock, unsigned char command, unsigned char value);
/* receive an oob byte from the daemon, used internally by g15_send_cmd, but useful elsewhere */
#define G15_FOREGROUND_SENT_OOB 1
int g15_recv_oob_answer(int sock);
#ifdef __cplusplus
}
#endif
+244
View File
@@ -0,0 +1,244 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 301 $ - $Date: 2007-09-10 09:55:15 +0200 (Mon, 10 Sep 2007) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <poll.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <config.h>
#include <libg15.h>
#include "g15daemon_client.h"
#ifndef SO_PRIORITY
#define SO_PRIORITY 12
#endif
#define G15SERVER_PORT 15550
#define G15SERVER_ADDR "127.0.0.1"
int leaving = 0;
const char *g15daemon_version () {
return VERSION;
}
int new_g15_screen(int screentype)
{
int g15screen_fd;
struct sockaddr_in serv_addr;
/* raise the priority of our packets */
int tos = 0x6;
char buffer[256];
g15screen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (g15screen_fd < 0)
return -1;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
inet_aton (G15SERVER_ADDR, &serv_addr.sin_addr);
serv_addr.sin_port = htons(G15SERVER_PORT);
if (connect(g15screen_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
return -1;
setsockopt(g15screen_fd, SOL_SOCKET, SO_PRIORITY, &tos, sizeof(tos));
if (fcntl(g15screen_fd, F_SETFL, O_NONBLOCK) <0 ) {
}
memset(buffer,0,256);
if(g15_recv(g15screen_fd, buffer, 16)<0)
return -1;
/* here we check that we're really talking to the g15daemon */
if(strcmp(buffer,"G15 daemon HELLO") != 0)
return -1;
if(screentype == G15_TEXTBUF) /* txt buffer - not supported yet */
g15_send(g15screen_fd,"TBUF",4);
else if(screentype == G15_WBMPBUF) /* wbmp buffer */
g15_send(g15screen_fd,"WBUF",4);
else if(screentype == G15_G15RBUF)
g15_send(g15screen_fd,"RBUF",4);
else
g15_send(g15screen_fd,"GBUF",4);
return g15screen_fd;
}
int g15_close_screen(int sock)
{
return close(sock);
}
int g15_send(int sock, char *buf, unsigned int len)
{
int total = 0;
int retval = 0;
int bytesleft = len;
struct pollfd pfd[1];
while(total < len && !leaving) {
memset(pfd,0,sizeof(pfd));
pfd[0].fd = sock;
pfd[0].events = POLLOUT|POLLERR|POLLHUP|POLLNVAL;
if(poll(pfd,1,500)>=0) {
if(pfd[0].revents & POLLOUT && !(pfd[0].revents & POLLERR || pfd[0].revents & POLLHUP || pfd[0].revents & POLLNVAL) ) {
retval = send(sock, buf+total, bytesleft, MSG_DONTWAIT);
if (retval == -1) {
break;
}
bytesleft -= retval;
total += retval;
}
if((pfd[0].revents & POLLERR|| pfd[0].revents & POLLHUP || pfd[0].revents & POLLNVAL)){
retval=-1;
break;
}
}
}
return retval==-1?-1:0;
}
int g15_recv(int sock, char *buf, unsigned int len)
{
int total = 0;
int retval = 0;
int bytesleft = len;
struct pollfd pfd[1];
while(total < len && !leaving) {
memset(pfd,0,sizeof(pfd));
pfd[0].fd = sock;
pfd[0].events = POLLIN;
if(poll(pfd,1,500)>0){
if(pfd[0].revents & POLLIN) {
retval = recv(sock, buf+total, bytesleft, 0);
if (retval < 1) {
break;
}
total += retval;
bytesleft -= retval;
}
}
}
return total;
}
/* receive a byte from a priority, out-of-band packet */
int g15_recv_oob_answer(int sock) {
int packet[2];
int msgret = 0;
struct pollfd pfd[1];
memset(pfd,0,sizeof(pfd));
memset(packet,0,2);
pfd[0].fd = sock;
pfd[0].events = POLLPRI | POLLERR | POLLHUP | POLLNVAL;
if(poll(pfd,1,100)>0){
if(pfd[0].revents & POLLPRI && !(pfd[0].revents & POLLERR || pfd[0].revents & POLLHUP || pfd[0].revents & POLLNVAL)) {
memset(packet,0,sizeof(packet));
msgret = recv(sock, packet, 10 , MSG_OOB);
if (msgret < 1) {
return -1;
}
}
}
return packet[0];
}
int g15_send_cmd (int sock, unsigned char command, unsigned char value)
{
int retval;
unsigned char packet[2];
switch (command) {
case G15DAEMON_KEY_HANDLER:
if (value > G15_LED_MR)
value = G15_LED_MR;
packet[0] = (unsigned char)command | (unsigned char)value;
retval = send( sock, packet, 1, MSG_OOB );
break;
case G15DAEMON_CONTRAST:
if (value > G15_CONTRAST_HIGH)
value = G15_CONTRAST_HIGH;
packet[0] = (unsigned char)command | (unsigned char)value;
send( sock, packet, 1, MSG_OOB );
retval = g15_recv_oob_answer(sock);
break;
case G15DAEMON_BACKLIGHT:
if (value > G15_BRIGHTNESS_BRIGHT)
value = G15_BRIGHTNESS_BRIGHT;
packet[0] = (unsigned char)command | (unsigned char)value;
send( sock, packet, 1, MSG_OOB );
retval = g15_recv_oob_answer(sock);
break;
case G15DAEMON_KB_BACKLIGHT:
if (value > G15_BRIGHTNESS_BRIGHT)
value = G15_BRIGHTNESS_BRIGHT;
packet[0] = (unsigned char)command | (unsigned char)value;
retval = send( sock, packet, 1, MSG_OOB );
break;
case G15DAEMON_MKEYLEDS:
packet[0] = (unsigned char)command|(unsigned char)value;
retval = send( sock, packet, 1, MSG_OOB );
break;
case G15DAEMON_SWITCH_PRIORITIES:
packet[0] = (unsigned char)command;
retval = send( sock, packet, 1, MSG_OOB );
break;
case G15DAEMON_GET_KEYSTATE:{
retval = 0;
packet[0] = (unsigned char)command;
send( sock, packet, 1, MSG_OOB );
g15_recv(sock, (char*)&retval, sizeof(retval));
break;
}
case G15DAEMON_IS_FOREGROUND:{
packet[0] = (unsigned char)command;
send( sock, packet, 1, MSG_OOB );
retval = g15_recv_oob_answer(sock) - 48;
break;
}
case G15DAEMON_IS_USER_SELECTED:{
packet[0] = (unsigned char)command;
send( sock, packet, 1, MSG_OOB );
retval = g15_recv_oob_answer(sock) - 48;
break;
}
default:
return -1;
}
return retval;
}
+346
View File
@@ -0,0 +1,346 @@
diff -urN graphlcd-base-0.1.3-orig/glcddrivers/drivers.c graphlcd-base-0.1.3/glcddrivers/drivers.c
--- graphlcd-base-0.1.3-orig/glcddrivers/drivers.c 2006-01-16 00:52:36.000000000 +1030
+++ graphlcd-base-0.1.3/glcddrivers/drivers.c 2006-07-08 13:18:40.000000000 +0930
@@ -26,7 +26,7 @@
#include "noritake800.h"
#include "avrctl.h"
#include "serdisp.h"
-
+#include "g15daemon.h"
namespace GLCD
{
@@ -46,6 +46,7 @@
{"noritake800", kDriverNoritake800},
{"avrctl", kDriverAvrCtl},
{"serdisp", kDriverSerDisp},
+ {"g15daemon", kDriverG15daemon},
{"", kDriverUnknown}
};
@@ -82,6 +83,7 @@
case kDriverNoritake800 : return new cDriverNoritake800(config);
case kDriverAvrCtl : return new cDriverAvrCtl(config);
case kDriverSerDisp : return new cDriverSerDisp(config);
+ case kDriverG15daemon : return new cDriverG15daemon(config);
case kDriverUnknown :
default : return NULL;
}
diff -urN graphlcd-base-0.1.3-orig/glcddrivers/drivers.h graphlcd-base-0.1.3/glcddrivers/drivers.h
--- graphlcd-base-0.1.3-orig/glcddrivers/drivers.h 2006-01-16 00:51:54.000000000 +1030
+++ graphlcd-base-0.1.3/glcddrivers/drivers.h 2006-07-08 13:04:04.000000000 +0930
@@ -37,7 +37,8 @@
kDriverImage = 11,
kDriverNoritake800 = 12,
kDriverAvrCtl = 13,
- kDriverSerDisp = 100
+ kDriverSerDisp = 100,
+ kDriverG15daemon = 200
};
struct tDriver
diff -urN graphlcd-base-0.1.3-orig/glcddrivers/g15daemon.c graphlcd-base-0.1.3/glcddrivers/g15daemon.c
--- graphlcd-base-0.1.3-orig/glcddrivers/g15daemon.c 1970-01-01 09:30:00.000000000 +0930
+++ graphlcd-base-0.1.3/glcddrivers/g15daemon.c 2006-07-13 11:44:00.000000000 +0930
@@ -0,0 +1,218 @@
+/*
+* GraphLCD driver library
+*
+* g15daemon.c - pseudo device for the g15daemon meta driver
+* Output goes to the g15daemon which then displays it
+*
+* This file is released under the GNU General Public License. Refer
+* to the COPYING file distributed with this package.
+*
+*/
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "config.h"
+
+#include "g15daemon.h"
+
+#define G15SERVER_PORT 15550
+#define G15SERVER_ADDR "127.0.0.1"
+
+#define G15_WIDTH 160
+#define G15_HEIGHT 43
+
+
+static int g15_send(int sock, char *buf, int len)
+{
+ int total = 0;
+ int retval = 0;
+ int bytesleft = len;
+
+ while(total < len) {
+ retval = send(sock, buf+total, bytesleft, 0);
+ if (retval == -1) {
+ break;
+ }
+ bytesleft -= retval;
+ total += retval;
+ }
+ return retval==-1?-1:0;
+}
+
+static int g15_recv(int sock, char *buf, int len)
+{
+ int total = 0;
+ int retval = 0;
+ int bytesleft = len;
+
+ while(total < len) {
+ retval = recv(sock, buf+total, bytesleft, 0);
+ if (retval < 1) {
+ break;
+ }
+ total += retval;
+ bytesleft -= retval;
+ }
+ return total;
+}
+
+static int open_g15_daemon()
+{
+ int g15screen_fd;
+ struct sockaddr_in serv_addr;
+
+ char buffer[256];
+
+ g15screen_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (g15screen_fd < 0)
+ return -1;
+
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ inet_aton (G15SERVER_ADDR, &serv_addr.sin_addr);
+ serv_addr.sin_port = htons(G15SERVER_PORT);
+
+ if (connect(g15screen_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
+ return -1;
+
+ memset(buffer,0,256);
+ if(g15_recv(g15screen_fd, buffer, 16)<0)
+ return -1;
+
+ /* here we check that we're really talking to the g15daemon */
+ if(strcmp(buffer,"G15 daemon HELLO") != 0)
+ return -1;
+
+ /* we want to use a pixelbuffer */
+ g15_send(g15screen_fd,"GBUF",4);
+
+ return g15screen_fd;
+}
+
+
+namespace GLCD
+{
+
+ cDriverG15daemon::cDriverG15daemon(cDriverConfig * config)
+ : config(config),
+ offbuff(0),
+ sockfd(-1)
+ {
+ oldConfig = new cDriverConfig(*config);
+ }
+
+ cDriverG15daemon::~cDriverG15daemon()
+ {
+ delete oldConfig;
+ }
+
+ int cDriverG15daemon::Init()
+ {
+ // default values
+ width = config->width;
+ if (width !=G15_WIDTH)
+ width = G15_WIDTH;
+ height = config->height;
+ if (height !=G15_HEIGHT)
+ height = G15_HEIGHT;
+
+ for (unsigned int i = 0; i < config->options.size(); i++) {
+ if (config->options[i].name == "") {
+ }
+ }
+
+ screensize = 6880;
+
+ if((sockfd = open_g15_daemon())<0)
+ return -1;
+ // reserve memory to draw into
+ offbuff = new char[6880];
+
+ *oldConfig = *config;
+
+ // clear display
+ Refresh(true);
+
+ syslog(LOG_INFO, "%s: g15daemon initialized.\n", config->name.c_str());
+ return 0;
+ }
+
+ int cDriverG15daemon::DeInit()
+ {
+ if (offbuff);
+ delete[] offbuff;
+ if (-1 != sockfd)
+ close(sockfd);
+
+ return 0;
+ }
+
+ int cDriverG15daemon::CheckSetup()
+ {
+ if (config->device != oldConfig->device ||
+ config->port != oldConfig->port ||
+ config->width != oldConfig->width ||
+ config->height != oldConfig->height)
+ {
+ DeInit();
+ Init();
+ return 0;
+ }
+
+ if (config->upsideDown != oldConfig->upsideDown ||
+ config->invert != oldConfig->invert)
+ {
+ oldConfig->upsideDown = config->upsideDown;
+ oldConfig->invert = config->invert;
+ return 1;
+ }
+ return 0;
+ }
+
+ void cDriverG15daemon::SetPixel(int x, int y)
+ {
+ if (x >= width || y >= height)
+ return;
+
+ if (config->upsideDown)
+ {
+ x = width - 1 - x;
+ y = height - 1 - y;
+ }
+
+ offbuff[x + (width * y)] = 1;
+ }
+
+ void cDriverG15daemon::Clear()
+ {
+ memset(offbuff, 0, screensize);
+ }
+
+ void cDriverG15daemon::Set8Pixels(int x, int y, unsigned char data)
+ {
+ int n;
+
+ x &= 0xFFF8;
+
+ for (n = 0; n < 8; ++n)
+ {
+ if (data & (0x80 >> n)) // if bit is set
+ SetPixel(x + n, y);
+ }
+ }
+
+ void cDriverG15daemon::Refresh(bool refreshAll)
+ {
+ g15_send(sockfd, offbuff, screensize);
+ }
+
+} // end of namespace
diff -urN graphlcd-base-0.1.3-orig/glcddrivers/g15daemon.h graphlcd-base-0.1.3/glcddrivers/g15daemon.h
--- graphlcd-base-0.1.3-orig/glcddrivers/g15daemon.h 1970-01-01 09:30:00.000000000 +0930
+++ graphlcd-base-0.1.3/glcddrivers/g15daemon.h 2006-07-08 16:49:46.000000000 +0930
@@ -0,0 +1,49 @@
+/*
+ * GraphLCD driver library
+ *
+ * g15daemon.h - pseudo device for the g15daemon
+ * Output goes to the g15daemon which then displays it
+ *
+ */
+
+#ifndef _GLCDDRIVERS_G15DAEMON_H_
+#define _GLCDDRIVERS_G15DAEMON_H_
+
+#include "driver.h"
+
+
+namespace GLCD
+{
+
+class cDriverConfig;
+
+class cDriverG15daemon : public cDriver
+{
+private:
+ unsigned char ** LCD;
+ cDriverConfig * config;
+ cDriverConfig * oldConfig;
+ char *offbuff;
+ int sockfd;
+ long int screensize;
+ char *fbp;
+ int zoom;
+
+ int CheckSetup();
+ void SetPixel(int x, int y);
+
+public:
+ cDriverG15daemon(cDriverConfig * config);
+ virtual ~cDriverG15daemon();
+
+ virtual int Init();
+ virtual int DeInit();
+
+ virtual void Clear();
+ virtual void Set8Pixels(int x, int y, unsigned char data);
+ virtual void Refresh(bool refreshAll = false);
+};
+
+} // end of namespace
+
+#endif
diff -urN graphlcd-base-0.1.3-orig/glcddrivers/Makefile graphlcd-base-0.1.3/glcddrivers/Makefile
--- graphlcd-base-0.1.3-orig/glcddrivers/Makefile 2006-01-16 00:47:01.000000000 +1030
+++ graphlcd-base-0.1.3/glcddrivers/Makefile 2006-07-08 14:29:03.000000000 +0930
@@ -12,9 +12,9 @@
LIBNAME = $(BASENAME).$(VERMAJOR).$(VERMINOR).$(VERMICRO)
-OBJS = common.o config.o driver.o drivers.o port.o simlcd.o framebuffer.o gu140x32f.o gu256x64-372.o gu256x64-3900.o hd61830.o ks0108.o image.o sed1330.o sed1520.o t6963c.o noritake800.o serdisp.o avrctl.o
+OBJS = common.o config.o driver.o drivers.o port.o g15daemon.o simlcd.o framebuffer.o gu140x32f.o gu256x64-372.o gu256x64-3900.o hd61830.o ks0108.o image.o sed1330.o sed1520.o t6963c.o noritake800.o serdisp.o avrctl.o
-HEADERS = config.h driver.h drivers.h port.h simlcd.h framebuffer.h gu140x32f.h gu256x64-372.h gu256x64-3900.h hd61830.h ks0108.h image.h sed1330.h sed1520.h t6963c.h noritake800.h serdisp.h avrctl.h
+HEADERS = config.h driver.h drivers.h port.h g15daemon.h simlcd.h framebuffer.h gu140x32f.h gu256x64-372.h gu256x64-3900.h hd61830.h ks0108.h image.h sed1330.h sed1520.h t6963c.h noritake800.h serdisp.h avrctl.h
### Implicit rules:
diff -urN graphlcd-base-0.1.3-orig/graphlcd.conf graphlcd-base-0.1.3/graphlcd.conf
--- graphlcd-base-0.1.3-orig/graphlcd.conf 2006-01-16 03:41:20.000000000 +1030
+++ graphlcd-base-0.1.3/graphlcd.conf 2006-07-08 14:08:00.000000000 +0930
@@ -116,6 +116,11 @@
########################################################################
+[g15daemon]
+Driver=g15daemon
+Width=160
+Height=43
+
[framebuffer]
# framebuffer driver
# Output goes to a framebuffer device
+98
View File
@@ -0,0 +1,98 @@
Index: g15.c
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/g15.c,v
retrieving revision 1.1
diff -a -u -r1.1 g15.c
--- g15.c 13 Aug 2006 15:55:47 -0000 1.1
+++ g15.c 12 Nov 2006 02:05:36 -0000
@@ -30,6 +30,7 @@
#include <errno.h>
#include <syslog.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <libg15.h>
#include <g15daemon_client.h>
#include <libg15render.h>
@@ -70,6 +71,7 @@
p->cellheight = G15_CELL_HEIGHT;
p->backlight_state = BACKLIGHT_ON;
p->g15screen_fd = 0;
+ p->g15d_ver = g15daemon_version();
if((p->g15screen_fd = new_g15_screen(G15_G15RBUF)) < 0)
{
@@ -109,15 +111,8 @@
g15_close_screen(p->g15screen_fd);
- if (p != NULL) {
- if (p->canvas)
- free(p->canvas);
-
- if (p->backingstore)
- free(p->backingstore);
-
- free(p);
- }
+ if (p != NULL)
+ free(p);
drvthis->store_private_ptr(drvthis, NULL);
}
@@ -372,14 +367,35 @@
MODULE_EXPORT const char * g15_get_key (Driver *drvthis)
{
PrivateData *p = drvthis->private_data;
-
+ int toread = 0;
unsigned int key_state = 0;
-
- if(send(p->g15screen_fd, "k", 1, MSG_OOB)<1) /* request key status */
- report(RPT_INFO, "%s: Error in send to g15daemon", drvthis->name);
- recv(p->g15screen_fd, &key_state , sizeof(key_state),0);
+ if ((strncmp("1.2", p->g15d_ver, 3)))
+ { /* other than g15daemon-1.2 (should be >=1.9) */
+ fd_set fds;
+ struct timeval tv;
+ memset (&tv, 0, sizeof(struct timeval));
+
+ FD_ZERO(&fds);
+ FD_SET(p->g15screen_fd, &fds);
+
+ toread = select(FD_SETSIZE, &fds, NULL, NULL, &tv);
+ }
+ else
+ { /* g15daemon-1.2 */
+ if(send(p->g15screen_fd, "k", 1, MSG_OOB)<1) /* request key status */
+ {
+ report(RPT_INFO, "%s: Error in send to g15daemon", drvthis->name);
+ return NULL;
+ }
+ toread = 1;
+ }
+ if (toread >= 1)
+ read(p->g15screen_fd, &key_state, sizeof(key_state));
+ else
+ return NULL;
+
if (key_state & G15_KEY_G1)
return "Escape";
else if (key_state & G15_KEY_L1)
Index: g15.h
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/g15.h,v
retrieving revision 1.1
diff -a -u -r1.1 g15.h
--- g15.h 13 Aug 2006 15:55:47 -0000 1.1
+++ g15.h 12 Nov 2006 02:05:36 -0000
@@ -32,6 +32,8 @@
int cellwidth, cellheight;
/* file descriptor for g15daemon socket */
int g15screen_fd;
+ /* g15daemon version for compatibility checks */
+ const char *g15d_ver;
/* canvas for LCD contents */
g15canvas *canvas;
g15canvas *backingstore;
+17
View File
@@ -0,0 +1,17 @@
METASOURCES = AUTO
libdir = @G15DAEMON_PLUGIN_DIR@
AM_CFLAGS = -Wall
lib_LTLIBRARIES =g15plugin_uinput.la g15plugin_tcpserver.la g15plugin_clock.la
INCLUDES = -I$(top_builddir)/libg15daemon_client/ -I$(top_builddir)/g15daemon
g15plugin_uinput_la_SOURCES = g15_plugin_uinput.c
g15plugin_uinput_la_LDFLAGS = -avoid-version -module
g15plugin_tcpserver_la_SOURCES = g15_plugin_net.c
g15plugin_tcpserver_la_LDFLAGS = -avoid-version -module
g15plugin_clock_la_SOURCES = g15_plugin_clock.c
g15plugin_clock_la_LDFLAGS = -avoid-version -module
+352
View File
@@ -0,0 +1,352 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 290 $ - $Date: 2007-09-08 08:50:33 +0200 (Sat, 08 Sep 2007) $ $Author: mlampard $
simple Clock plugin, replace the various functions with your own, and change the g15plugin_info struct below to suit,
edit Makefile.am and compile. Add salt and pepper to taste. For a more advanced plugin that creates it's own lcd screens on-the-fly,
see the tcpserver plugin in this directory.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <libg15.h>
#include <config.h>
#include <g15daemon.h>
#include <libg15render.h>
extern double round(double);
// clock specs:
#define CLOCK_CENTERX 25
#define CLOCK_CENTERY 21
#define CLOCK_RADIUS 20
// useful shortcuts (g15r_drawCircle() is a bit egg-shaped, or my math is :)
#define CLOCK_STARTX (CLOCK_CENTERX-CLOCK_RADIUS-1)
#define CLOCK_STARTY (CLOCK_CENTERY-CLOCK_RADIUS)
#define CLOCK_ENDX (CLOCK_CENTERX+CLOCK_RADIUS+1)
#define CLOCK_ENDY (CLOCK_CENTERY+CLOCK_RADIUS)
static int mode=1;
static int showdate=0;
static int digital=1;
g15canvas *static_canvas = NULL;
//----------------------------------------------------------------------------
// calc x,y for given minute/hour/sec (pos), cut_off is for radius variations
// ( ie. shorter/longer clock-hands, line parts....)
void get_clock_pos(int pos, int *x, int *y, int cut_off)
{
// pos = [0-60]
// make sure it's in range:
pos %= 60;
// angles go contra-clockwise, but clock goes clockwise :), so invert clock orientation
pos = 60 - pos;
// this math is patent-copy-trademark-protected by <Rasta Freak> :)
double ang = 270.0 - 6.0*(double)pos;
ang = (ang * 2.0 * M_PI) / 360.0;
// simple pre-school math for naturaly dumb:
double _x = (double)CLOCK_CENTERX + (cos(ang)*(double)(CLOCK_RADIUS+1-cut_off));
double _y = (double)CLOCK_CENTERY + (sin(ang)*(double)(CLOCK_RADIUS-cut_off));
*x = (int)(round(_x));
*y = (int)(round(_y));
}
//----------------------------------------------------------------------------
// draw clock frame (only once, as it is stored in static_canvas)
// NOTE - coords here are hardcoded !
void draw_static_canvas(void)
{
g15canvas *c = static_canvas;
int i;
g15r_clearScreen (c, G15_COLOR_WHITE);
g15r_drawCircle(c, CLOCK_CENTERX, CLOCK_CENTERY, CLOCK_RADIUS, 0, G15_COLOR_BLACK);
g15r_drawCircle(c, CLOCK_CENTERX, CLOCK_CENTERY, 2, 1, G15_COLOR_BLACK);
for (i=0; i<60; i+=5)
{
if ((i%15)==0)
{
// draw number (12/3/6/9):
switch (i)
{
case 0:
g15r_renderString(c, (unsigned char*)"12", 0, G15_TEXT_SMALL, 22, 3);
break;
case 15:
g15r_renderString(c, (unsigned char*)"3", 3, G15_TEXT_SMALL, 42, 1);
break;
case 30:
g15r_renderString(c, (unsigned char*)"6", 6, G15_TEXT_SMALL, 24, -1);
break;
case 45:
g15r_renderString(c, (unsigned char*)"9", 3, G15_TEXT_SMALL, 6, 1);
break;
}
}
else
{
// draw 4-pixel square dot for other hours:
int x1,y1,dir;
if (i>15 && i<45) dir=-1; else dir=1;
get_clock_pos(i, &x1, &y1, 3);
g15r_setPixel(c, x1, y1, G15_COLOR_BLACK);
g15r_setPixel(c, x1+dir, y1, G15_COLOR_BLACK);
g15r_setPixel(c, x1, y1+dir, G15_COLOR_BLACK);
g15r_setPixel(c, x1+dir, y1+dir, G15_COLOR_BLACK);
}
}
}
static int draw_digital(g15canvas *canvas)
{
unsigned int col = 0;
unsigned int len=0;
int narrows=0;
int totalwidth=0;
char buf[10];
char ampm[3];
int height = G15_LCD_HEIGHT - 1;
time_t currtime = time(NULL);
memset(buf,0,10);
memset(ampm,0,3);
if(showdate) {
char buf2[40];
strftime(buf2,40,"%A %e %B %Y",localtime(&currtime));
g15r_renderString (canvas,(unsigned char *)buf2 , 0, G15_TEXT_MED, 80-((strlen(buf2)*5)/2), height-6);
height-=10;
}
if(mode) {
strftime(buf,6,"%H:%M",localtime(&currtime));
} else {
strftime(buf,6,"%l:%M",localtime(&currtime));
strftime(ampm,3,"%p",localtime(&currtime));
}
if(buf[0]==49)
narrows=1;
len = strlen(buf);
if(buf[0]==' ')
len++;
if(narrows)
totalwidth=(len*20)+(15);
else
totalwidth=len*20;
for (col=0;col<len;col++)
{
int num = -1;
if ((buf[col] > 47) && (buf[col] < 59))
num = buf[col] - 48;
else if (buf[col] == 45)
num = 11;
else if (buf[col] == 46)
num = 12;
if (num >= 0)
g15r_drawBigNum (canvas, (80-(totalwidth)/2)+col*20, 1,(80-(totalwidth)/2)+(col+1)*20, height, G15_COLOR_BLACK, num);
}
if(ampm[0]!=0)
g15r_renderString (canvas,(unsigned char *)ampm,0,G15_TEXT_LARGE,totalwidth+15,height-6);
return G15_PLUGIN_OK;
}
static int draw_analog(g15canvas *c)
{
int xh, yh;
int xm, ym;
int xs, ys;
time_t now = time(NULL);
struct tm *t = localtime(&now);
int h;
h = t->tm_hour;
h %= 12;
h *= 5;
h += t->tm_min * 5 / 60;
get_clock_pos(h, &xh, &yh, 9);
get_clock_pos(t->tm_min, &xm, &ym, 6);
get_clock_pos(t->tm_sec, &xs, &ys, 3);
// put background:
memcpy(c, static_canvas, sizeof(g15canvas));
// hour
g15r_drawLine(c, CLOCK_CENTERX-2, CLOCK_CENTERY, xh, yh, G15_COLOR_BLACK);
g15r_drawLine(c, CLOCK_CENTERX-1, CLOCK_CENTERY, xh, yh, G15_COLOR_BLACK);
g15r_drawLine(c, CLOCK_CENTERX, CLOCK_CENTERY, xh, yh+1, G15_COLOR_BLACK);
g15r_drawLine(c, CLOCK_CENTERX+1, CLOCK_CENTERY, xh, yh, G15_COLOR_BLACK);
g15r_drawLine(c, CLOCK_CENTERX+2, CLOCK_CENTERY, xh, yh, G15_COLOR_BLACK);
// minute
g15r_drawLine(c, CLOCK_CENTERX-1, CLOCK_CENTERY, xm, ym, G15_COLOR_BLACK);
g15r_drawLine(c, CLOCK_CENTERX, CLOCK_CENTERY, xm, ym+1, G15_COLOR_BLACK);
g15r_drawLine(c, CLOCK_CENTERX+1, CLOCK_CENTERY, xm, ym, G15_COLOR_BLACK);
// second:
g15r_drawLine(c, CLOCK_CENTERX, CLOCK_CENTERY, xs, ys, G15_COLOR_BLACK);
//
// draw texts:
//
char day[32]; // Tuesday
char mon[32]; // March
char year[32]; // 1234 AD
char time[32]; // 22:33:44
char date[32]; // 21.April
strftime(day, sizeof(day), "%A", t);
strftime(mon, sizeof(mon), "%B", t);
sprintf(date, "%d.%s", t->tm_mday, mon);
sprintf(year, "%4d AD", t->tm_year+1900);
if(mode)
strftime(time,sizeof(time),"%H:%M:%S",t);
else
strftime(time,sizeof(time),"%r",t);
if(showdate) {
g15r_renderString(c, (unsigned char*)time, 0, G15_TEXT_LARGE, 60, 4);
g15r_renderString(c, (unsigned char*)day, 1, G15_TEXT_LARGE, 60, 5);
g15r_renderString(c, (unsigned char*)date, 2, G15_TEXT_LARGE, 60, 6);
g15r_renderString(c, (unsigned char*)year, 3, G15_TEXT_LARGE, 60, 7);
} else
g15r_renderString(c, (unsigned char*)time, 0, G15_TEXT_LARGE, 60, 18);
return G15_PLUGIN_OK;
}
static int lcdclock(lcd_t *lcd)
{
int ret = 0;
g15canvas *canvas = (g15canvas *) malloc (sizeof (g15canvas));
if (canvas == NULL) {
g15daemon_log(LOG_ERR, "Unable to allocate canvas");
return G15_PLUGIN_QUIT;
}
memset(canvas->buffer, 0, G15_BUFFER_LEN);
canvas->mode_cache = 0;
canvas->mode_reverse = 0;
canvas->mode_xor = 0;
memset(lcd->buf,0,G15_BUFFER_LEN);
if(digital)
ret = draw_digital(canvas);
else
ret = draw_analog(canvas);
memcpy (lcd->buf, canvas->buffer, G15_BUFFER_LEN);
lcd->ident = random();
free(canvas);
return G15_PLUGIN_OK;
}
static int myeventhandler(plugin_event_t *myevent) {
lcd_t *lcd = (lcd_t*) myevent->lcd;
config_section_t *clockcfg =NULL;
switch (myevent->event)
{
case G15_EVENT_KEYPRESS:
clockcfg = g15daemon_cfg_load_section(lcd->masterlist,"Clock");
if(myevent->value & G15_KEY_L2){
mode = 1^mode;
g15daemon_cfg_write_bool(clockcfg, "24hrFormat", mode);
}
if(myevent->value & G15_KEY_L3) {
showdate = 1^showdate;
g15daemon_cfg_write_bool(clockcfg, "ShowDate", showdate);
}
if(myevent->value & G15_KEY_L4) {
digital = 1^digital;
g15daemon_cfg_write_bool(clockcfg, "Digital", digital);
}
// printf("Clock plugin received keypress event : %i\n",myevent->value);
break;
case G15_EVENT_VISIBILITY_CHANGED:
// printf("Clock received new visibility status (%i)\n",myevent->value);
break;
default:
break;
}
return G15_PLUGIN_OK;
}
/* completely uncessary function called when plugin is exiting */
static void callmewhenimdone(lcd_t *lcd){
if(static_canvas != NULL) free(static_canvas);
return;
}
/* completely unnecessary initialisation function which could just as easily have been set to NULL in the g15plugin_info struct */
static int myinithandler(lcd_t *lcd){
config_section_t *clockcfg = g15daemon_cfg_load_section(lcd->masterlist,"Clock");
mode=g15daemon_cfg_read_bool(clockcfg, "24hrFormat",1);
showdate=g15daemon_cfg_read_bool(clockcfg, "ShowDate",0);
digital=g15daemon_cfg_read_bool(clockcfg, "Digital",1);
static_canvas = (g15canvas*)malloc(sizeof(g15canvas));
if (static_canvas != NULL)
{
memset(static_canvas->buffer, 0, G15_BUFFER_LEN);
static_canvas->mode_cache = 0;
static_canvas->mode_reverse = 0;
static_canvas->mode_xor = 0;
draw_static_canvas();
}
return static_canvas == NULL ? G15_PLUGIN_QUIT : G15_PLUGIN_OK;
}
/* if no exitfunc or eventhandler, member should be NULL */
plugin_info_t g15plugin_info[] = {
/* TYPE, name, initfunc, updatefreq, exitfunc, eventhandler, initfunc */
{G15_PLUGIN_LCD_CLIENT, "Clock", (void*)lcdclock, 500, (void*)callmewhenimdone, (void*)myeventhandler, (void*)myinithandler},
{G15_PLUGIN_NONE, "" , NULL, 0, NULL, NULL, NULL}
};
+435
View File
@@ -0,0 +1,435 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 299 $ - $Date: 2007-09-09 19:19:52 +0200 (Sun, 09 Sep 2007) $ $Author: mlampard $
This daemon listens on localhost port 15550 for client connections,
and arbitrates LCD display. Allows for multiple simultaneous clients.
Client screens can be cycled through by pressing the 'L1' key.
*/
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <poll.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <libg15.h>
#include <g15daemon.h>
static int leaving;
int server_events(plugin_event_t *myevent);
#ifndef SO_PRIORITY
#define SO_PRIORITY 12
#endif
/* tcp server defines */
#define LISTEN_PORT 15550
#define LISTEN_ADDR "127.0.0.1"
/* any more than this number of simultaneous clients will be rejected. */
#define MAX_CLIENTS 10
/* custom plugininfo for clients... */
plugin_info_t lcdclient_info[] = {
/* TYPE, name, initfunc, updatefreq, exitfunc, eventhandler, initfunc */
{G15_PLUGIN_LCD_SERVER, "LCDclient" , NULL, 500, NULL, (void*)server_events, NULL},
{G15_PLUGIN_NONE, "" , NULL, 0, NULL, NULL, NULL}
};
static void process_client_cmds(lcdnode_t *lcdnode, int sock, unsigned int *msgbuf, unsigned int len)
{
switch(msgbuf[0]){
case CLIENT_CMD_SWITCH_PRIORITIES: {
g15daemon_send_event(lcdnode,G15_EVENT_REQ_PRIORITY,1);
break;
}
case CLIENT_CMD_IS_FOREGROUND: { /* client wants to know if it's currently viewable */
pthread_mutex_lock(&lcdlist_mutex);
memset(msgbuf,0,2);
if(lcdnode->list->current == lcdnode){
msgbuf[0] = '1';
}else{
msgbuf[0] = '0';
}
pthread_mutex_unlock(&lcdlist_mutex);
send(sock,msgbuf,1,MSG_OOB);
break;
}
case CLIENT_CMD_IS_USER_SELECTED: { /* client wants to know if it was set to foreground by the user */
pthread_mutex_lock(&lcdlist_mutex);
if(lcdnode->lcd->usr_foreground) /* user manually selected this lcd */
msgbuf[0] = '1';
else
msgbuf[0] = '0';
pthread_mutex_unlock(&lcdlist_mutex);
send(sock,msgbuf,1,0);
break;
}
default:
if(msgbuf[0] & CLIENT_CMD_MKEY_LIGHTS)
{ /* client wants to change the M-key backlights */
lcdnode->lcd->mkey_state = msgbuf[0]-0x20;
lcdnode->lcd->state_changed = 1;
//if the client is the keyhandler, allow full, direct control over the mled status
if(lcdnode->lcd->masterlist->remote_keyhandler_sock==lcdnode->lcd->connection)
setLEDs(msgbuf[0]-0x20);
} else if (msgbuf[0] & CLIENT_CMD_KEY_HANDLER)
{
g15daemon_log(LOG_WARNING, "Client is taking over keystate");
lcdnode->list->remote_keyhandler_sock = sock;
g15daemon_log(LOG_WARNING, "Client has taken over keystate");
}
else if (msgbuf[0] & CLIENT_CMD_BACKLIGHT)
{
send(sock,&lcdnode->lcd->backlight_state,1,MSG_OOB);
lcdnode->lcd->backlight_state = msgbuf[0]-0x80;
lcdnode->lcd->state_changed = 1;
}
else if (msgbuf[0] & CLIENT_CMD_KB_BACKLIGHT)
{
setKBBrightness((unsigned int)msgbuf[0]-0x8);
}
else if (msgbuf[0] & CLIENT_CMD_CONTRAST)
{
send(sock,&lcdnode->lcd->contrast_state,1,MSG_OOB);
lcdnode->lcd->contrast_state = msgbuf[0]-0x40;
lcdnode->lcd->state_changed = 1;
}
}
}
/* create and open a socket for listening */
int init_sockserver(){
int listening_socket;
int yes=1;
int tos = 0x18;
struct sockaddr_in servaddr;
if ((listening_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
g15daemon_log(LOG_WARNING, "Unable to create socket.\n");
return -1;
}
setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
setsockopt(listening_socket, SOL_SOCKET, SO_PRIORITY, &tos, sizeof(tos));
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_aton (LISTEN_ADDR, &servaddr.sin_addr);
servaddr.sin_port = htons(LISTEN_PORT);
if (bind(listening_socket, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
g15daemon_log(LOG_WARNING, "error calling bind()\n");
return -1;
}
if (listen(listening_socket, MAX_CLIENTS) < 0 ) {
g15daemon_log(LOG_WARNING, "error calling listen()\n");
return -1;
}
return listening_socket;
}
int g15_send(int sock, char *buf, unsigned int len)
{
int total = 0;
int retval = 0;
int bytesleft = len;
struct pollfd pfd[1];
while(total < len && !leaving) {
memset(pfd,0,sizeof(pfd));
pfd[0].fd = sock;
pfd[0].events = POLLOUT | POLLERR | POLLHUP | POLLNVAL;
if(poll(pfd,1,500)>0) {
if(pfd[0].revents & POLLOUT && !(pfd[0].revents & POLLERR || pfd[0].revents & POLLHUP || pfd[0].revents & POLLNVAL)) {
retval = send(sock, buf+total, bytesleft, 0);
if (retval == -1) {
break;
}
bytesleft -= retval;
total += retval;
}
if((pfd[0].revents & POLLERR || pfd[0].revents & POLLHUP || pfd[0].revents & POLLNVAL)){
retval=-1;
break;
}
}
}
return retval==-1?-1:0;
}
int g15_recv(lcdnode_t *lcdnode, int sock, char *buf, unsigned int len)
{
int total = 0;
int retval = 0;
int msgret = 0;
int bytesleft = len;
struct pollfd pfd[1];
unsigned int msgbuf[20];
while(total < len && !leaving) {
memset(pfd,0,sizeof(pfd));
pfd[0].fd = sock;
pfd[0].events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
if(poll(pfd,1,500)>0){
if(pfd[0].revents & POLLPRI && !(pfd[0].revents & POLLERR || pfd[0].revents & POLLHUP || pfd[0].revents & POLLNVAL)) { /* receive out-of-band request from client and deal with it */
memset(msgbuf,0,20);
msgret = recv(sock, msgbuf, 10 , MSG_OOB);
if (msgret < 1) {
break;
}
process_client_cmds(lcdnode, sock, msgbuf,len);
}
else if(pfd[0].revents & POLLIN && !(pfd[0].revents & POLLERR || pfd[0].revents & POLLHUP || pfd[0].revents & POLLNVAL)) {
retval = recv(sock, buf+total, bytesleft, 0);
if (retval < 1) {
break;
}
total += retval;
bytesleft -= retval;
}
if((pfd[0].revents & POLLERR || pfd[0].revents & POLLHUP || pfd[0].revents & POLLNVAL)){
retval=-1;
break;
}
}
}
return total;
}
/* the client must send 6880 bytes for each lcd screen. This thread will continue to copy data
* into the clients LCD buffer for as long as the connection remains open.
* so, the client should open a socket, check to ensure that the server is a g15daemon,
* and send multiple 6880 byte packets (1 for each screen update)
* once the client disconnects by closing the socket, the LCD buffer is
* removed and will no longer be displayed.
*/
void *lcd_client_thread(void *display) {
lcdnode_t *g15node = display;
lcd_t *client_lcd = g15node->lcd;
int retval;
unsigned int width, height, buflen,header=4;
int client_sock = client_lcd->connection;
char helo[]=SERV_HELO;
unsigned char *tmpbuf=g15daemon_xmalloc(6880);
if(g15_send(client_sock, (char*)helo, strlen(SERV_HELO))<0){
goto exitthread;
}
/* check for requested buffer type.. we only handle pixel buffers atm */
if(g15_recv(g15node, client_sock,(char*)tmpbuf,4)<4)
goto exitthread;
/* we will in the future handle txt buffers gracefully but for now we just hangup */
if(tmpbuf[0]=='G') {
while(!leaving) {
retval = g15_recv(g15node, client_sock,(char *)tmpbuf,6880);
if(retval!=6880){
break;
}
pthread_mutex_lock(&lcdlist_mutex);
memset(client_lcd->buf,0,1024);
g15daemon_convert_buf(client_lcd,tmpbuf);
client_lcd->ident = random();
pthread_mutex_unlock(&lcdlist_mutex);
}
}
else if (tmpbuf[0]=='R') { /* libg15render buffer */
while(!leaving) {
retval = g15_recv(g15node, client_sock, (char *)tmpbuf, 1048);
if(retval != 1048) {
break;
}
pthread_mutex_lock(&lcdlist_mutex);
memcpy(client_lcd->buf,tmpbuf,sizeof(client_lcd->buf));
client_lcd->ident = random();
pthread_mutex_unlock(&lcdlist_mutex);
}
}
else if (tmpbuf[0]=='W'){ /* wbmp buffer - we assume (stupidly) that it's 160 pixels wide */
while(!leaving) {
retval = g15_recv(g15node, client_sock,(char*)tmpbuf, 865);
if(!retval)
break;
if (tmpbuf[2] & 1) {
width = ((unsigned char)tmpbuf[2] ^ 1) | (unsigned char)tmpbuf[3];
height = tmpbuf[4];
header = 5;
} else {
width = tmpbuf[2];
height = tmpbuf[3];
header = 4;
}
buflen = (width/8)*height;
if(buflen>860){ /* grab the remainder of the image and discard excess bytes */
/* retval=g15_recv(client_sock,(char*)tmpbuf+865,buflen-860); */
retval=g15_recv(g15node, client_sock,NULL,buflen-860);
buflen = 860;
}
if(width!=160) /* FIXME - we ought to scale images I suppose */
goto exitthread;
pthread_mutex_lock(&lcdlist_mutex);
memcpy(client_lcd->buf,tmpbuf+header,buflen+header);
client_lcd->ident = random();
pthread_mutex_unlock(&lcdlist_mutex);
}
}
exitthread:
if(client_lcd->masterlist->remote_keyhandler_sock==client_sock)
client_lcd->masterlist->remote_keyhandler_sock=0;
close(client_sock);
free(tmpbuf);
g15daemon_lcdnode_remove(display);
pthread_exit(NULL);
}
/* poll the listening socket for connections, spawning new threads as needed to handle clients */
int g15_clientconnect (g15daemon_t **g15daemon, int listening_socket) {
int conn_s;
struct pollfd pfd[1];
pthread_t client_connection;
pthread_attr_t attr;
lcdnode_t *clientnode;
memset(pfd,0,sizeof(pfd));
pfd[0].fd = listening_socket;
pfd[0].events = POLLIN;
if (poll(pfd,1,500)>0){
if (!(pfd[0].revents & POLLIN)){
return 0;
}
if ( (conn_s = accept(listening_socket, NULL, NULL) ) < 0 ) {
if(errno==EWOULDBLOCK || errno==EAGAIN){
}else{
g15daemon_log(LOG_WARNING, "error calling accept()\n");
return -1;
}
}
clientnode = g15daemon_lcdnode_add(g15daemon);
clientnode->lcd->connection = conn_s;
/* override the default (generic handler and use our own for our clients */
clientnode->lcd->g15plugin->info=(void*)(&lcdclient_info);
memset(&attr,0,sizeof(pthread_attr_t));
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr,256*1024); /* set stack to 768k - dont need 8Mb - this is probably rather excessive also */
if (pthread_create(&client_connection, &attr, lcd_client_thread, clientnode) != 0) {
g15daemon_log(LOG_WARNING,"Unable to create client thread.");
if (close(conn_s) < 0 ) {
g15daemon_log(LOG_WARNING, "error calling close()\n");
return -1;
}
}
pthread_detach(client_connection);
}
return 0;
}
/* this thread only listens for new connections.
* sockserver_accept will spawn a new thread for each connected client
*/
static void lcdserver_thread(void *lcdlist){
g15daemon_t *masterlist = (g15daemon_t*) lcdlist ;
int g15_socket=-1;
if((g15_socket = init_sockserver())<0){
g15daemon_log(LOG_ERR,"Unable to initialise the server at port %i",LISTEN_PORT);
return;
}
if (fcntl(g15_socket, F_SETFL, O_NONBLOCK) <0 ) {
g15daemon_log(LOG_ERR,"Unable to set socket to nonblocking");
}
while ( !leaving ) {
g15_clientconnect(&masterlist,g15_socket);
}
close(g15_socket);
return;
}
/* incoming events */
int server_events(plugin_event_t *event) {
lcd_t *lcd = (lcd_t*) event->lcd;
switch (event->event)
{
case G15_EVENT_KEYPRESS:{
if(lcd->connection && lcd->masterlist->remote_keyhandler_sock!=lcd->connection) { /* server client */
if((send(lcd->connection,(void *)&event->value,sizeof(event->value),0))<0)
g15daemon_log(LOG_WARNING,"Error in send: %s\n",strerror(errno));
}
break;
}
case G15_EVENT_VISIBILITY_CHANGED:
break;
case G15_EVENT_USER_FOREGROUND:
lcd->usr_foreground = event->value;
break;
case G15_EVENT_MLED:
case G15_EVENT_BACKLIGHT:
case G15_EVENT_CONTRAST:
/* should never receive these */
default:
break;
}
return G15_PLUGIN_OK;
}
/* if no exitfunc or eventhandler, member should be NULL */
plugin_info_t g15plugin_info[] = {
/* TYPE, name, initfunc, updatefreq, exitfunc, eventhandler, initfunc */
{G15_PLUGIN_LCD_SERVER, "LCDServer" , (void*)lcdserver_thread, 500, NULL, (void*)server_events, NULL},
{G15_PLUGIN_NONE, "" , NULL, 0, NULL, NULL, NULL}
};
+105
View File
@@ -0,0 +1,105 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 129 $ - $Date: 2006-11-13 03:02:49 +0100 (Mon, 13 Nov 2006) $ $Author: mlampard $
simple template plugin, replace the various functions with your own, and change the g15plugin_info struct below to suit,
edit Makefile.am and compile. Add salt and pepper to taste. For a more advanced plugin that creates it's own lcd screens on-the-fly,
see the tcpserver plugin in this directory.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <config.h>
#include <g15daemon.h>
static int *lcdclock(lcd_t *lcd)
{
unsigned int col = 0;
unsigned int len=0;
int narrows=0;
int totalwidth=0;
char buf[10];
time_t currtime = time(NULL);
memset(lcd->buf,0,1024);
memset(buf,0,10);
strftime(buf,6,"%H:%M",localtime(&currtime));
if(buf[0]==49)
narrows=1;
len = strlen(buf);
if(narrows)
totalwidth=(len*20)+(15);
else
totalwidth=len*20;
for (col=0;col<len;col++)
{
draw_bignum (lcd, (80-(totalwidth)/2)+col*20, 1,(80-(totalwidth)/2)+(col+1)*20, LCD_HEIGHT, BLACK, buf[col]);
}
lcd->ident = currtime+100;
return G15_PLUGIN_OK;
}
static int myeventhandler(plugin_event_t *myevent) {
// lcd_t *lcd = (lcd_t*) myevent->lcd;
switch (myevent->event)
{
case G15_EVENT_KEYPRESS:
printf("template plugin received keypress event : %i\n",myevent->value);
break;
case G15_EVENT_VISIBILITY_CHANGED:
printf("template received new visibility status (%i)\n",myevent->value);
break;
default:
break;
}
return G15_PLUGIN_OK;
}
/* completely uncessary function called when plugin is exiting */
static void *callmewhenimdone(lcd_t *lcd){
}
/* completely unnecessary initialisation function which could just as easily have been set to NULL in the g15plugin_info struct */
static void *myinithandler(lcd_t *lcd){
}
/* if no exitfunc or eventhandler, member should be NULL */
plugin_info_t g15plugin_info[] = {
/* TYPE, name, initfunc, updatefreq, exitfunc, eventhandler, initfunc */
{G15_PLUGIN_LCD_CLIENT, "template plugin clock", (void*)lcdclock, 500, (void*)callmewhenimdone, (void*)myeventhandler, (void*)myinithandler},
{G15_PLUGIN_NONE, "" , NULL, 0, NULL, NULL, NULL}
};
+324
View File
@@ -0,0 +1,324 @@
/*
This file is part of g15daemon.
g15daemon 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.
g15daemon 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 g15daemon; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(c) 2006 Mike Lampard, Philip Lawatsch, and others
$Revision: 177 $ - $Date: 2006-11-18 14:46:03 +0100 (Sat, 18 Nov 2006) $ $Author: mlampard $
UINPUT key processing plugin. receives events and sends keycodes to the linux kernel.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <config.h>
#include <g15daemon.h>
#include <pwd.h>
#ifdef HAVE_CONFIG_H
#ifdef HAVE_LINUX_UINPUT_H
#include <linux/input.h>
#include <linux/uinput.h>
#include <libg15.h>
static int uinp_fd = -1;
static config_section_t *uinput_cfg=NULL;
static int map_Lkeys = 0;
#define GKEY_OFFSET 167
#define MKEY_OFFSET 185
#define LKEY_OFFSET 189
#define G15KEY_DOWN 1
#define G15KEY_UP 0
int g15_init_uinput(void *plugin_args) {
int i=0;
char *custom_filename;
g15daemon_t *masterlist = (g15daemon_t*) plugin_args;
struct uinput_user_dev uinp;
static const char *uinput_device_fn[] = { "/dev/uinput", "/dev/input/uinput","/dev/misc/uinput",0};
uinput_cfg = g15daemon_cfg_load_section(masterlist,"Keyboard OS Mapping (uinput)");
custom_filename = g15daemon_cfg_read_string(uinput_cfg, "device",(char*)uinput_device_fn[1]);
map_Lkeys=g15daemon_cfg_read_int(uinput_cfg, "Lkeys.mapped",0);
seteuid(0);
setegid(0);
while (uinput_device_fn[i] && (uinp_fd = open(uinput_device_fn[i],O_RDWR))<0){
++i;
}
if(uinp_fd<0) { /* try reading the users preference in the config */
uinp_fd = open(custom_filename,O_RDWR);
}
if(uinp_fd<0){
g15daemon_log(LOG_ERR,"Unable to open UINPUT device. Please ensure the uinput driver is loaded into the kernel and that you have permission to open the device.");
return -1;
}
/* all other processes/threads should be seteuid nobody */
seteuid(masterlist->nobody->pw_uid);
setegid(masterlist->nobody->pw_gid);
memset(&uinp,0,sizeof(uinp));
strncpy(uinp.name, "G15 Extra Keys", UINPUT_MAX_NAME_SIZE);
#ifdef HAVE_UINPUT_USER_DEV_ID
uinp.id.version = 4;
uinp.id.bustype = BUS_USB;
#else
uinp.idversion = 4;
uinp.idbus = BUS_USB;
#endif
ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY);
for (i=0; i<256; ++i)
ioctl(uinp_fd, UI_SET_KEYBIT, i);
write(uinp_fd, &uinp, sizeof(uinp));
if (ioctl(uinp_fd, UI_DEV_CREATE))
{
g15daemon_log(LOG_ERR,"Unable to create UINPUT device.");
return -1;
}
return 0;
}
void g15_exit_uinput(void *plugin_args){
ioctl(uinp_fd, UI_DEV_DESTROY);
close(uinp_fd);
}
void g15_uinput_keydown(unsigned char code)
{
struct input_event event;
memset(&event, 0, sizeof(event));
event.type = EV_KEY;
event.code = code;
event.value = G15KEY_DOWN;
write (uinp_fd, &event, sizeof(event));
}
void g15_uinput_keyup(unsigned char code)
{
struct input_event event;
memset(&event, 0, sizeof(event));
event.type = EV_KEY;
event.code = code;
event.value = G15KEY_UP;
write (uinp_fd, &event, sizeof(event));
}
void (*keyup)(unsigned char code) = &g15_uinput_keyup;
void (*keydown)(unsigned char code) = &g15_uinput_keydown;
#else
void keyup(unsigned char code) { printf("Extra Keys not supported due to missing Uinput.h\n"); }
void keydown(unsigned char code) { printf("Extra Keys not supported due to missing Uinput.h\n"); }
#endif
#endif
void g15_process_keys(g15daemon_t *masterlist, unsigned int currentkeys, unsigned int lastkeys)
{
/* 'G' keys */
if((currentkeys & G15_KEY_G1) && !(lastkeys & G15_KEY_G1))
keydown(GKEY_OFFSET);
else if(!(currentkeys & G15_KEY_G1) && (lastkeys & G15_KEY_G1))
keyup(GKEY_OFFSET);
if((currentkeys & G15_KEY_G2) && !(lastkeys & G15_KEY_G2))
keydown(GKEY_OFFSET+1);
else if(!(currentkeys & G15_KEY_G2) && (lastkeys & G15_KEY_G2))
keyup(GKEY_OFFSET+1);
if((currentkeys & G15_KEY_G3) && !(lastkeys & G15_KEY_G3))
keydown(GKEY_OFFSET+2);
else if(!(currentkeys & G15_KEY_G3) && (lastkeys & G15_KEY_G3))
keyup(GKEY_OFFSET+2);
if((currentkeys & G15_KEY_G4) && !(lastkeys & G15_KEY_G4))
keydown(GKEY_OFFSET+3);
else if(!(currentkeys & G15_KEY_G4) && (lastkeys & G15_KEY_G4))
keyup(GKEY_OFFSET+3);
if((currentkeys & G15_KEY_G5) && !(lastkeys & G15_KEY_G5))
keydown(GKEY_OFFSET+4);
else if(!(currentkeys & G15_KEY_G5) && (lastkeys & G15_KEY_G5))
keyup(GKEY_OFFSET+4);
if((currentkeys & G15_KEY_G6) && !(lastkeys & G15_KEY_G6))
keydown(GKEY_OFFSET+5);
else if(!(currentkeys & G15_KEY_G6) && (lastkeys & G15_KEY_G6))
keyup(GKEY_OFFSET+5);
if((currentkeys & G15_KEY_G7) && !(lastkeys & G15_KEY_G7))
keydown(GKEY_OFFSET+6);
else if(!(currentkeys & G15_KEY_G7) && (lastkeys & G15_KEY_G7))
keyup(GKEY_OFFSET+6);
if((currentkeys & G15_KEY_G8) && !(lastkeys & G15_KEY_G8))
keydown(GKEY_OFFSET+7);
else if(!(currentkeys & G15_KEY_G8) && (lastkeys & G15_KEY_G8))
keyup(GKEY_OFFSET+7);
if((currentkeys & G15_KEY_G9) && !(lastkeys & G15_KEY_G9))
keydown(GKEY_OFFSET+8);
else if(!(currentkeys & G15_KEY_G9) && (lastkeys & G15_KEY_G9))
keyup(GKEY_OFFSET+8);
if((currentkeys & G15_KEY_G10) && !(lastkeys & G15_KEY_G10))
keydown(GKEY_OFFSET+9);
else if(!(currentkeys & G15_KEY_G10) && (lastkeys & G15_KEY_G10))
keyup(GKEY_OFFSET+9);
if((currentkeys & G15_KEY_G11) && !(lastkeys & G15_KEY_G11))
keydown(GKEY_OFFSET+10);
else if(!(currentkeys & G15_KEY_G11) && (lastkeys & G15_KEY_G11))
keyup(GKEY_OFFSET+10);
if((currentkeys & G15_KEY_G12) && !(lastkeys & G15_KEY_G12))
keydown(GKEY_OFFSET+11);
else if(!(currentkeys & G15_KEY_G12) && (lastkeys & G15_KEY_G12))
keyup(GKEY_OFFSET+11);
if((currentkeys & G15_KEY_G13) && !(lastkeys & G15_KEY_G13))
keydown(GKEY_OFFSET+12);
else if(!(currentkeys & G15_KEY_G13) && (lastkeys & G15_KEY_G13))
keyup(GKEY_OFFSET+12);
if((currentkeys & G15_KEY_G14) && !(lastkeys & G15_KEY_G14))
keydown(GKEY_OFFSET+13);
else if(!(currentkeys & G15_KEY_G14) && (lastkeys & G15_KEY_G14))
keyup(GKEY_OFFSET+13);
if((currentkeys & G15_KEY_G15) && !(lastkeys & G15_KEY_G15))
keydown(GKEY_OFFSET+14);
else if(!(currentkeys & G15_KEY_G15) && (lastkeys & G15_KEY_G15))
keyup(GKEY_OFFSET+14);
if((currentkeys & G15_KEY_G16) && !(lastkeys & G15_KEY_G16))
keydown(GKEY_OFFSET+15);
else if(!(currentkeys & G15_KEY_G16) && (lastkeys & G15_KEY_G16))
keyup(GKEY_OFFSET+15);
if((currentkeys & G15_KEY_G17) && !(lastkeys & G15_KEY_G17))
keydown(GKEY_OFFSET+16);
else if(!(currentkeys & G15_KEY_G17) && (lastkeys & G15_KEY_G17))
keyup(GKEY_OFFSET+16);
if((currentkeys & G15_KEY_G18) && !(lastkeys & G15_KEY_G18))
keydown(GKEY_OFFSET+17);
else if(!(currentkeys & G15_KEY_G18) && (lastkeys & G15_KEY_G18))
keyup(GKEY_OFFSET+17);
/* 'M' keys */
if((currentkeys & G15_KEY_M1) && !(lastkeys & G15_KEY_M1))
keydown(MKEY_OFFSET);
else if(!(currentkeys & G15_KEY_M1) && (lastkeys & G15_KEY_M1))
keyup(MKEY_OFFSET);
if((currentkeys & G15_KEY_M2) && !(lastkeys & G15_KEY_M2))
keydown(MKEY_OFFSET+1);
else if(!(currentkeys & G15_KEY_M2) && (lastkeys & G15_KEY_M2))
keyup(MKEY_OFFSET+1);
if((currentkeys & G15_KEY_M3) && !(lastkeys & G15_KEY_M3))
keydown(MKEY_OFFSET+2);
else if(!(currentkeys & G15_KEY_M3) && (lastkeys & G15_KEY_M3))
keyup(MKEY_OFFSET+2);
if((currentkeys & G15_KEY_MR) && !(lastkeys & G15_KEY_MR))
keydown(MKEY_OFFSET+3);
else if(!(currentkeys & G15_KEY_MR) && (lastkeys & G15_KEY_MR))
keyup(MKEY_OFFSET+3);
if(map_Lkeys){
/* 'L' keys... */
if((currentkeys & G15_KEY_L1) && !(lastkeys & G15_KEY_L1))
keydown(LKEY_OFFSET);
else if(!(currentkeys & G15_KEY_L1) && (lastkeys & G15_KEY_L1))
keyup(LKEY_OFFSET);
if((currentkeys & G15_KEY_L2) && !(lastkeys & G15_KEY_L2))
keydown(LKEY_OFFSET+1);
else if(!(currentkeys & G15_KEY_L2) && (lastkeys & G15_KEY_L2))
keyup(LKEY_OFFSET+1);
if((currentkeys & G15_KEY_L3) && !(lastkeys & G15_KEY_L3))
keydown(LKEY_OFFSET+2);
else if(!(currentkeys & G15_KEY_L3) && (lastkeys & G15_KEY_L3))
keyup(LKEY_OFFSET+2);
if((currentkeys & G15_KEY_L4) && !(lastkeys & G15_KEY_L4))
keydown(LKEY_OFFSET+3);
else if(!(currentkeys & G15_KEY_L4) && (lastkeys & G15_KEY_L4))
keyup(LKEY_OFFSET+3);
if((currentkeys & G15_KEY_L5) && !(lastkeys & G15_KEY_L5))
keydown(LKEY_OFFSET+4);
else if(!(currentkeys & G15_KEY_L5) && (lastkeys & G15_KEY_L5))
keyup(LKEY_OFFSET+4);
}
}
int keyevents(plugin_event_t *myevent) {
lcd_t *lcd = (lcd_t*) myevent->lcd;
static int lastkeys;
switch (myevent->event)
{
case G15_EVENT_KEYPRESS:{
g15_process_keys(lcd->masterlist, myevent->value,lastkeys);
lastkeys = myevent->value;
break;
}
case G15_EVENT_VISIBILITY_CHANGED:
case G15_EVENT_USER_FOREGROUND:
case G15_EVENT_MLED:
case G15_EVENT_BACKLIGHT:
case G15_EVENT_CONTRAST:
case G15_EVENT_REQ_PRIORITY:
case G15_EVENT_CYCLE_PRIORITY:
default:
break;
}
return G15_PLUGIN_OK;
}
/* if no exitfunc or eventhandler, member should be NULL */
plugin_info_t g15plugin_info[] = {
/* TYPE, name, initfunc, updatefreq, exitfunc, eventhandler, initfunc */
{G15_PLUGIN_CORE_OS_KB, "Linux UINPUT Keyboard Output" , NULL, 500, (void*)g15_exit_uinput, (void*)keyevents, (void*)g15_init_uinput},
{G15_PLUGIN_NONE, "" , NULL, 0, NULL, NULL, NULL}
};
+76
View File
@@ -0,0 +1,76 @@
# G15daemon rpm spec file
#
%define prefix /usr
Summary: Daemon to control logitech G15 keyboards
Name: g15daemon
Version: 1.2.5
Release: 1
Copyright: GPL
Group: Applications/System
Source: ftp://prdownloads.sf.net/g15daemon-1.2.5.tar.bz2
URL: http://g15daemon.sf.net
Distribution: Linux
Vendor: NONE
Packager: Mike Lampard <mlampard@users.sourceforge.net>
Buildroot: /var/tmp/g15daemon-%{PACKAGE_VERSION}-root
BuildRequires: daemon-devel
Requires: daemon
Requires: libg15
Provides: g15daemon
%description
G15daemon controls the G15 keyboard, allowing the use of
all keys through the linux kernel uinput device driver.
It also controls the use of the keyboard's LCD display,
allows multiple, simultaneous client applications to connect,
and gives the user the ability to switch between client
apps at the press of a button.
%package devel
Summary: G15daemon controls the G15 keyboard and LCD.
Group: System Environment/Libraries
BuildRequires: libg15-devel
Requires: g15daemon
Provides: g15daemon-devel
%description devel
G15daemon controls the G15 keyboard, allowing the use of
all keys through the linux kernel uinput device driver.
It also controls the use of the keyboard's LCD display,
allows multiple, simultaneous client applications to connect,
and gives the user the ability to switch between client
apps at the press of a button.
%prep
%setup
%build
CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{prefix}
make
%install
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
%clean
rm -rf $RPM_BUILD_ROOT
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%files
%defattr(-, root, root)
%doc AUTHORS COPYING LICENSE NEWS README README.usage contrib lang-bindings
%doc %{_mandir}/man*/*.*
%{prefix}/lib/*.so
%{prefix}/lib/*.so.*
%{prefix}/sbin/*
%files devel
%defattr(-, root, root)
%doc AUTHORS COPYING LICENSE NEWS README README.usage contrib lang-bindings Documentation/README.client_devel
%doc %{_mandir}/man*/*.*
%{prefix}/lib/libg15daemon_client.*
%{prefix}/include/*