/* * * 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 * Yann Malichecq * Stephane Chatty * * * $Id$ * * Please refer to file version.h for the * copyright notice regarding this software */ #include #include #include #include #include #include #include #include #include #include #include #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; }