summaryrefslogtreecommitdiff
path: root/src/irdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/irdev.c')
-rw-r--r--src/irdev.c290
1 files changed, 290 insertions, 0 deletions
diff --git a/src/irdev.c b/src/irdev.c
new file mode 100644
index 0000000..88f5a2c
--- /dev/null
+++ b/src/irdev.c
@@ -0,0 +1,290 @@
+/*
+ *
+ * IRBOX, an Ivy driver for infra-red remote controls
+ *
+ * Copyright 1998-1999
+ * Centre d'Etudes de la Navigation Aerienne
+ *
+ * Device driver
+ *
+ * Authors: Francois-Regis Colin <fcolin@cenatoulouse.dgac.fr>
+ * Yann Malichecq
+ * Stephane Chatty <chatty@cenatoulouse.dgac.fr>
+ *
+ *
+ * $Id$
+ *
+ * Please refer to file version.h for the
+ * copyright notice regarding this software
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <termio.h>
+#include <sys/ioctl.h>
+
+#include "irdev.h"
+
+
+#define CHECKEDWRITE(fd , buff , len ) \
+ if (write( fd, buff, len) != len) { perror("IR write"); return -1; }
+
+#define NBITS 8
+#define SET(n, p) ((p)[(n)/NBITS] |= ((unsigned)1 << ((n) % NBITS)))
+#define CLR(n, p) ((p)[(n)/NBITS] &= ~((unsigned)1 << ((n) % NBITS)))
+#define ISSET(n, p) ((p)[(n)/NBITS] & ((unsigned)1 << ((n) % NBITS)))
+
+struct ir_state {
+ int fd;
+ IrEvtCallback callback;
+ IrFailCallback fail_callback;
+ IrTimerSetter set_timeout;
+ IrTimerCanceller cancel_timeout;
+
+ /* state machine stuff */
+ char state;
+ unsigned char value[6];
+
+ void *checkinit_id;
+
+ /* misc. std. driver stuff */
+ unsigned char initialized;/* true if data structures are set */
+ /* and init sequence has been sent to */
+ /* device */
+ unsigned char ready; /* true if we've received confirmation */
+ /* of the init sequence from the device */
+ unsigned char errorCount;/* count of bad messages for recovery */
+};
+
+
+static int IrInitDevice (IrState*);
+
+
+int
+IrInit (IrState *ir, IrEvtCallback cb, IrFailCallback f, IrTimerSetter st, IrTimerCanceller ct)
+{
+ ir->callback = cb;
+ ir->fail_callback = f;
+ ir->set_timeout = st;
+ ir->cancel_timeout = ct;
+ return IrInitDevice (ir);
+}
+
+
+
+static void
+IrCheckInit (void * id, IrState *ir, int delta)
+{
+ if ((!ir->ready) && (ir->checkinit_id)) {
+ if (ir->errorCount++<5) {
+ IrInitDevice (ir);
+ return;
+ } else {
+ /* pas de reponse, on abandonne */
+ if (ir->fail_callback)
+ (*ir->fail_callback)(ir);
+ }
+ }
+ ir->checkinit_id= 0;
+ return;
+}
+
+
+#define SPEED B9600
+
+/* ARGSUSED */
+static int
+IrInitDevice (IrState *ir)
+{
+ unsigned char dcmd[2];
+ struct termios terms;
+
+ /*initialisation du port serie */
+ if (tcgetattr (ir->fd, &terms) == -1) {
+ perror ( "Cant get device configuration for IR box");
+ return 0;
+ }
+
+ /* change the modes */
+ cfmakeraw (&terms);
+ terms.c_lflag = 0;
+
+ if (cfsetospeed (&terms, SPEED) < 0 ) {
+ perror ("Can't set ouput speed for IR box");
+ return 0;
+ }
+
+ if (cfsetispeed (&terms, SPEED) < 0 ) {
+ perror ("Can't set input speed for IR box");
+ return 0;
+ }
+
+ if (tcsetattr (ir->fd, TCSANOW, &terms) < 0)
+ {
+ perror ("Can't change device configuration for IR box");
+ return 0;
+ }
+
+ /* discard all unread or unwritten data */
+ tcflush (ir->fd, TCIOFLUSH );
+
+#ifdef DEBUG
+ fprintf (stderr, "IR box initialization in progress.....\n");
+#endif
+ dcmd[0] = 'I';
+ dcmd[1] = 'R';
+ CHECKEDWRITE(ir->fd, dcmd, sizeof(dcmd));
+
+ ir->initialized= 1;
+ if (ir->set_timeout)
+ ir->checkinit_id = (*ir->set_timeout)(IrCheckInit, 1000, ir);
+ return 1;
+}
+
+
+
+
+static void
+IrSetup (IrState *ir)
+{
+ ir->ready=1;
+ if (ir->cancel_timeout)
+ (*ir->cancel_timeout)(ir->checkinit_id);
+
+ ir->errorCount= 0;
+ return;
+}
+
+
+static void
+IrDecodeInit (IrState *ir, char ch)
+{
+ /* on doit attendre les caracteres "OK" */
+ switch (ir->state) {
+ case 0:
+ if ( ch == 'O' )
+ ir->state++;
+ break;
+ case 1:
+ if ( ch == 'K' ) {
+ ir->state = 0;
+#ifdef DEBUG
+ fprintf (stderr,"IR box initialized OK.\n");
+#endif
+ IrSetup (ir);
+ ir->errorCount = 0;
+ } else {
+ fprintf (stderr, "unexpected char %d from IR box\n", ch);
+ if (ir->errorCount++ > 5) {
+ /* try to reinitialize */
+ fprintf (stderr,"Reinitializing IR box\n");
+
+ IrInitDevice (ir);
+ }
+ }
+ break;
+ default:
+ fprintf (stderr,"Impossible state %d in ir_intr.\n", ir->state);
+ ir->state = 0;
+ break;
+ }
+}
+
+
+static void
+IrDecodeFrame (IrState *ir, char ch)
+{
+ ir->value[(int)(ir->state++)] = ch;
+
+ /* fin de trame de 6 caracteres */
+ if (ir->state == 6) {
+#ifdef DEBUG
+ fprintf (stdout, "%.3d %.3d %.3d %.3d %.3d %.3d\n", ir->value[0], ir->value[1],ir->value[2],ir->value[3],ir->value[4],ir->value[5]);
+#endif
+ if (ir->callback)
+ (*ir->callback)(ir, ir->value );
+ ir->state = 0;
+ }
+}
+
+void
+IrIntr (IrState *ir)
+{
+ unsigned char buf[128];
+ unsigned char *str;
+ int len;
+ register unsigned char ch;
+#ifdef DEBUG_RECEIVE
+ int i;
+#endif
+ if ((len = read(ir->fd, buf, sizeof(buf))) < 0)
+ return;
+#ifdef DEBUG_RECEIVE
+ fprintf (stderr, "received %d bytes from device \n",len);
+ for ( i = 0; i < len ; i ++ )
+ fprintf(stderr, "0x%02x ",buf[i]);
+ fprintf(stderr, "\n");
+#endif
+ str = buf;
+ while (len > 0) {
+ ch = *str++;
+ if (!ir->ready) /* on doit attendre les caracteres OK */
+ IrDecodeInit (ir,ch);
+ else /* on doit attendre la fin de la trame ( 6 car ) */
+ IrDecodeFrame (ir, ch);
+ len--;
+ }
+ return;
+}
+
+/* ARGSUSED */
+IrState*
+IrOpen (const char *name )
+{
+ register IrState *ir;
+
+ if ( !(ir = (IrState *)malloc(sizeof *ir)))
+ return NULL;
+ /* Set defaults -- totally arbitrary, my choice */
+ memset( ir, 0, sizeof *ir ) ;
+
+ if ((ir->fd = open(name, O_RDWR/*|O_NONBLOCK*/)) < 0) {
+ fprintf(stderr, "Couldn't open %s\n", name);
+ free( ir );
+ return NULL;
+
+ }
+
+
+ ir->initialized = 1;
+ ir->errorCount = 0;
+ ir->state = 0;
+
+
+ return ir;
+}
+
+/* ARGSUSED */
+void
+IrClose (IrState *ir)
+{
+ if (ir->checkinit_id) {
+ if (ir->cancel_timeout )
+ (*ir->cancel_timeout)( ir->checkinit_id );
+ ir->checkinit_id= 0;
+ }
+ free (ir);
+}
+
+int
+IrGetFd (IrState *ir)
+{
+ return ir->fd;
+}