📄 technical.html
字号:
indicating the result of processing the command. In case of an error the following data is a message explaining the problem. This message can be used to create an error message for the user.<BR> If the command was successful, data is only sent for the commands that return some information. Note that a packet containing 0 lines of data can be a valid reply. </P> <!-- Writing LIRC Applications +++++++++++++++++++++++++++++++++++++++ --> <A NAME="library"></A><HR> <H2 ALIGN="CENTER">The lirc_client library</H2> <HR WIDTH="70%"> <P> If you only want to make your application receive IR commands and if you don't want to mess with all the protocol stuff you can use the <em>lirc_client</em> library that comes with LIRC since version 0.6.0. With the help of this library your program can look as simple as this: </P> <PRE>/* $Id: irexec.c,v 5.2 2000/02/02 20:28:42 columbus Exp $ *//**************************************************************************** ** irexec.c **************************************************************** **************************************************************************** * * irexec - execute programs according to the pressed remote control buttons * * Copyright (C) 1998 Trent Piepho <xyzzy@u.washington.edu> * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de> * */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <errno.h>#include <unistd.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "lirc_client.h"char *progname;int main(int argc, char *argv[]){ struct lirc_config *config; progname=argv[0]; if(argc>2) { fprintf(stderr,"Usage: %s <config file>\n",progname); exit(EXIT_FAILURE); } if(lirc_init("irexec",1)==-1) exit(EXIT_FAILURE); if(lirc_readconfig(argc==2 ? argv[1]:NULL,&config,NULL)==0) { char *code; char *c; int ret; while(lirc_nextcode(&code)==0) { if(code==NULL) continue; while((ret=lirc_code2char(config,code,&c))==0 && c!=NULL) {#ifdef DEBUG printf("Execing command \"%s\"\n",c);#endif system(c); } free(code); if(ret==-1) break; } lirc_freeconfig(config); } lirc_deinit(); exit(EXIT_SUCCESS);}</PRE> <P> Before anything else you have to include the header file for the lirc_client library. This is done with </P> <PRE>#include <lirc/lirc_client.h></PRE> <P> Note that our example differs in this point because it was taken directly from the lirc-0.6.0 source that comes with its own <em>lirc_client.h</em> but we have to use the one that is already installed on the system. </P> <P> The next step is to initialize the library code with <em>lirc_init()</em>. This function connects to lircd and does some internal init stuff. </P> <PRE>int lirc_init(char *prog,int verbose);</PRE> <P> The first argument to this function is the string users will have to provide as <em>prog</em> token in their .lircrc config files. If the second argument is non-zero error messages will be printed to <em>stderr</em>. Otherwise no error messages will ever be displayed. This function returns the file descriptor of the socket that is connected to lircd or -1 if an error occurred. </P> <P> The example continues by reading a config file. This is done by the <em>lirc_readconfig()</em> function: </P> <PRE>int lirc_readconfig(char *file,struct lirc_config **config, int (check)(char *s));</PRE> <P> If you want to load the default config file you should pass NULL as first argument. If you want to load some other config file the <em>file</em> argument should contain the complete path to the file. Your program should give the user the possibility to use an other than the default config file. You should also be able to load multiple config files by calling this function several times.<BR> The <em>config</em> argument is used to pass the pointer to the config file data structures back to your application. You will need it for calls to the <em>lirc_code2char()</em> function. The last argument is a call-back function that can be used to do syntax checks with the config strings. The library code will call the call-back function for all config strings where the <em>prog</em> token in the config file matches the prog string you provided with the <em>lirc_init()</em> function. If there is an error in the config string the call-back function should return -1, otherwise 0. If you don't need to do any syntax checks you can pass NULL here. The function returns -1 if an error occurred, 0 otherwise. </P> <P> The <em>lirc_nextcode()</em> function blocks until there is something available on the lircd socket. This way it can be used in the main loop of your program like in our example. </P> <PRE>int lirc_nextcode(char **code);</PRE> <P> If an error occurs (usually this means that the socket has been closed by the daemon) this function returns -1. Otherwise it returns 0 and <em>code</em> points to the next string available in the data stream. This string has to be freed by your application using the <em>free(3)</em> function. If no complete string is available <em>code</em> will be NULL.<BR> If you use some GUI-toolkit for your program then you probably won't be able to use this function in your program's main loop because this is already handled by the GUI-toolkit. In this situation you should use the call-back abilities of the toolkit that will notify you whenever there is some input available from a file descriptor (you get the file descriptor from the <em>lirc_init()</em> function). E.g. you can use the <em>gdk_input_add()</em>/<em>gdk_input_remove</em>() functions with gtk or the <em>QSocketNotifier</em> class with Qt. If you don't have such functionality in your toolkit or can't use it for some reason you can still use SIGIO signals for this purpose. Check the documentation for your GUI-toolkit and signal(2) for further information.<BR> Please note that using call-backs you still have to use some kind of while loop to read strings from the socket because several strings may be available in the data stream and you will only get a notification for the first one. This poses a problem for us because <em>lirc_nextcode()</em> blocks until there is something available from the socket which is not what we need here. You can solve this problem by setting the <b>O_NONBLOCK</b> flag for the socket using the <em>fcntl(2)</em> function. Have a look at the current xirw code that is available from the LIRC homepage for an implementation example. </P> <P> To get the config string that the user has provided in the config file in response to a button press you use the following function: </P> <PRE>int lirc_code2char(struct lirc_config *config,char *code,char **string);</PRE> <P> <em>config</em> is a pointer to the config file data structure that you can get with <em>lirc_readconfig()</em> and <em>code</em> is the code transmitted to your application on the lircd socket. If an action should be taken <em>string</em> will point to the config string the user has provided in the config file. The user might want to take several actions on a button press so you have to execute this function until <em>string</em> is NULL, which means that no more actions shall be taken, or an error occurs. The function returns -1 if an error occurred, 0 otherwise. </P> <P> In our example there are only two clean-up functions to be explained. </P> <PRE>void lirc_freeconfig(struct lirc_config *config);</PRE> <P> This functions frees the data structures associated with <em>config</em>. </P> <PRE>int lirc_deinit();</PRE> <P> <em>lirc_deinit()</em> closes the connection to lircd and does some internal clean-up stuff. </P> <P> I encourage you to use autoconf and automake for your projects. To check for the lirc_client library all you have to insert to your <em>configure.in</em> file is the following: </P> <PRE>dnl Check for LIRC client supportdnl This really is not worth making a separate file for it.have_lirc=yesAC_REQUIRE_CPPAC_CHECK_LIB(lirc_client,lirc_init, AC_CHECK_HEADER(lirc/lirc_client.h,true,have_lirc=no),have_lirc=no)if test "$have_lirc" = "yes"; thendnl AC_DEFINE(HAVE_LIRC); true;else AC_MSG_ERROR([*** LIRC client support not available ***]);fi</PRE> <P> There is also a more complex m4 macro in the contrib directory of the current LIRC distribution if you plan to add LIRC support to your application without using the lirc_client library. </P> <P> While developing LIRC applications you might find a <A HREF="http://www.fi.muni.cz/~xkutale1/en/lircemu/">emulator</A> for lircd useful. With this emulator you don't need a remote control to generate LIRC events. That way you can develop LIRC applications even if you don't have a LIRC compatible device yourself. </P> <A NAME="bugs"></A><HR> <H1 ALIGN="CENTER">Known bugs</H1> <HR WIDTH="70%"> <UL> <LI> <P> If you use the <em>lirc_serial</em> or <em>lirc_parallel</em> driver regularly to transmit infra-red signals you might notice that your system clock will slow down. During transmit the driver turns off interrupts and hence some clock interrupts might get lost causing system clock inaccuracy. Unfortunately in order to ensure a good signal timing interrupts have to be disabled. Currently no work-around is known for this problem except using a program like <em>netdate</em> to synchronize your system clock regularly. </P> </LI> <LI> <P> The <em>lirc_serial</em> and <em>lirc_parallel</em> drivers measure the time between interrupts on the serial resp. parallel port to get a pulse and space representation of the incoming infra-red signal. If interrupts are disabled by the CPU for a rather long time (>100 µs, which happens often e.g. during heavy IDE disk activity) some interrupts might get lost and the incoming data stream becomes disturbed. In this case decoding of the infra-red signal will fail. This is the downside of the really simple receiver circuits and can't be addressed in software except keeping the time where interrupts are disabled to a minimum. </P> </LI> </UL> <!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <BR><BR> <CENTER>[<A HREF="http://www.lirc.org/">LIRC homepage</A>]<BR> <I>The LIRC Manual, last update: 12-Sep-2002</I></CENTER> <BR><BR> </TD> <TD WIDTH="15%"> <BR></TD> </TR> </TABLE> </TD> </TR> <TR> <TD CLASS="menu" WIDTH="100%"> <BR> </TD> </TR> </TABLE> </BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -