/* * test-aac.c * * Programa que implementa una comunicación de prueba contra el * aire acondicionado usando solaris-io. * * La manera de inicializar el puerto y los valores de las constantes se * han cogido del ejemplo del libro "El Universo Digital del IBM PC" (de * Ciriaco García de Celis), http://atc.ugr.es/docencia/udigital/1209.html * * Historia: * 5/09/03 Creación. Dejo hecha la parte de transmisión * 8/09/03 Hago la parte de recepción (también usando el puerto * directamente). NOTA: Para el timeout leo directamente * del RTC de la CMOS sin hacer un cli/sti (!), si alguien * toca el rtc mientras puede saltar el timeout sin que * haya pasado realmente un segundo. Pongo una comprobación * de que no estçé desactivado el puerto (si no hay nada, * todas las lecturas devuelven 0xFF (error)); * 17/09/03 ¡¡Por fin comunica!! (he hecho muchos cambios estos últimos * días, pero no los he ido poniendo aqui O:-). Básicamente * le faltaba el esperar TSRE antes de mandar cada caracter * (en vez de esperar THRE, que es lo normal). * * Autor: Dario Rodriguez dario@softhome.net * (C) 2003 SICO software */ /* Ficheros de cabecera */ #include #include #include #include #include #include #include #include /* Constantes */ #define IOPREAD 1 #define IOPWRITE 2 #define LCR(base) (base+3) /* registro de control de línea */ #define IER(base) (base+1) /* registro de activación de interrupciones */ #define DLL(base) (base+0) /* parte baja del divisor */ #define DLM(base) (base+1) /* parte alta del divisor */ #define MCR(base) (base+4) /* registro de control del modem */ #define LSR(base) (base+5) /* registro de estado de línea */ #define RBR(base) (base+0) /* registro buffer de recepción */ #define THR(base) (base+0) /* registro de retención de transmisión */ #define DR 1 /* bit dato disponible del LSR */ #define OE 2 /* bit de error de overrun del LSR */ #define PE 4 /* bit de error de paridad del LSR */ #define FE 8 /* bit de error en bits de stop del LSR */ #define BI 0x10 /* bit de error de break en el LSR */ #define THRE 0x20 /* bit de THR vacío */ #define TSRE 0x40 /* bit de TSR vacío */ /* Para depurado... */ long UltimoTiempo=0,NuevoTiempo=0; struct timeval OrigenTiempo; #define TIEMPOINIT() TimevalInit(&OrigenTiempo) #define TIEMPO(Cad) NuevoTiempo=gettimediffus(&OrigenTiempo),UltimoTiempo=((UltimoTiempo>NuevoTiempo)?0:UltimoTiempo),printf("%08li %08li %s\n",NuevoTiempo,NuevoTiempo-UltimoTiempo,Cad),fflush(stdout),UltimoTiempo=NuevoTiempo #define TIEMPORELHASTA(Tiempo) while((gettimediffus(&OrigenTiempo)-UltimoTiempo)>8); } IopWrite(Iop,LCR(Base),0x1B); /* DLAB=0, 8 bits, 1 stop, paridad par */ IopWrite(Iop,MCR(Base),9); /* sin interrupciones, DTR en nivel bajo */ /* Activamos SIGINT */ printf("Pulse ctrl-c para salir.\n"),fflush(stdout); InstalaSenial(SIGINT,sigint); /* Bucle principal */ while(BanderaSigInt==0) { char Cadena0[]={"\xFF"}; char Cadena1[]={"\x82"}; /* NOTA: Es posible que haya que poner aquí el primer byte de par. impar (depende de cómo coja la paridad la UART, si al transmitirla o al leer el byte del THR */ char Cadena2[]={"\xD0\x30\x01\x00\xFE\x7C"}; int Leido; int i; printf("Polling...\n"),fflush(stdout); TIEMPOINIT(); /* Ponemos en nivel alto el DTR */ IopWrite(Iop,MCR(Base),0x8); TIEMPO("DTR alto"); /* Escribimos la parte de paridad par */ ultimo=0; IopWrite(Iop,LCR(Base),0x0B); /* DLAB=0, 8 bits, 1 stop, paridad odd */ Escribe(Iop,Base,Cadena0,sizeof(Cadena0)-1); EsperaLSR(Iop,Base,THRE); TIEMPO("Cadena0 escrita"); IopWrite(Iop,LCR(Base),0x0B); /* DLAB=0, 8 bits, 1 stop, paridad odd */ Escribe(Iop,Base,Cadena1,sizeof(Cadena1)-1); /* Escribimos la parte de paridad impar */ /* cambiamos la paridad */ EsperaLSR(Iop,Base,THRE); TIEMPO("Cadena1 escrita"); IopWrite(Iop,LCR(Base),0x1B); /* 0x1b: DLAB=0, 8 bits, 1 stop, paridad even */ /* inyectamos el resto */ Escribe(Iop,Base,Cadena2,sizeof(Cadena2)-1); EsperaLSR(Iop,Base,THRE); TIEMPO("Cadena2 escrita"); EsperaLSR(Iop,Base,TSRE); TIEMPO("Transmision terminada"); /* Ponemos en nivel bajo el DTR */ IopWrite(Iop,MCR(Base),0x9); TIEMPO("DTR bajo"); /* Esperamos datos durante un "momento" */ while((LeeByte(Iop,Base,&Leido))==0) { printf("---> Recibido: 0x%02X\n",(int)Leido),fflush(stdout); } /* Hacemos una pausa de 1s para no dejar frito al PC */ SleepConSelect(1,0); } /* Ponemos los registros en un estado "sano" para el driver del S.O. */ IopWrite(Iop,IER(Base),0x0F); /* Volvemos a activar las interrupciones del puerto serie */ IopWrite(Iop,MCR(Base),0x08); /* Limpiamos y salimos */ IopLibera(Iop); return(0); } /* Implementación de las funciones de acceso a los puertos E/S */ sIoport * IopInit(void) { sIoport *Iop; if((Iop=malloc(sizeof(sIoport)))==NULL) { perror("IopInit(): Insufficient memory"); return(NULL); } if((Iop->fd=open("/devices/pseudo/iop@0:iop",O_RDONLY))<0) { perror("IopInit(): Open Failed"); free(Iop); return(NULL); } return(Iop); } void IopLibera(sIoport *Iop) { if(Iop==NULL) return; if(Iop->fd>=0) close(Iop->fd),Iop->fd=-1; free(Iop); } int IopRead(sIoport *Iop, int PortNum) { iopbuf tmpbuf; tmpbuf.port=PortNum; tmpbuf.port_value=0; if(ioctl(Iop->fd,IOPREAD,&tmpbuf)) { perror("IopRead(): IOCTL failed"); return(0); } return(tmpbuf.port_value); } int IopWrite(sIoport *Iop, int PortNum, int Value) { iopbuf tmpbuf; tmpbuf.port=PortNum; tmpbuf.port_value=Value; if(ioctl(Iop->fd,IOPWRITE,&tmpbuf)) { perror("IopWrite(): IOCTL failed"); return(-1); } return(0); } /*Cuerpo de las funciones auxiliares */ int InstalaSenial(int Num,void (*f)(int)) { struct sigaction sact; sact.sa_handler=f; sigemptyset(&sact.sa_mask); sact.sa_flags=0; return(sigaction(Num,&sact,0)); } static void sigint(int Num) { BanderaSigInt=1; } int SleepConSelect(long sec, long usec) { struct timeval Espera; Espera.tv_sec=sec; Espera.tv_usec=usec; select(1,NULL,NULL,NULL,&Espera); } /* Cuerpo de las funciones locales */ int EsperaLSR(sIoport *Iop, int Base, int Bits) { int lsr; do { lsr=IopRead(Iop,LSR(Base)); /* Si hay algún carácter esperando, lo descartamos (cosas del protocolo con el aac)*/ /* NOTA: si se le pasase una función y un void * a EsperTHRE(), se podrían procesar (p.ej. metiéndolos en un búffer o imprimiéndilos) */ if(lsr&1) { int letra; letra=IopRead(Iop,RBR(Base)); printf("Recibido: 0x%02X (ignorado)\n",(int)(letra&0xFF)),fflush(stdout); ultimo=letra&0xff; } /* Si hay un error de algún tipo, paramos la transmisión */ if(lsr&(OE|PE|FE|BI)) return(-1); /* ERROR DE TRANSMISION */ } while(!(lsr&Bits)); return(0); } void Escribe(sIoport *Iop, int Base, char *Cadena, int TamCadena) { int i; char CadenaTraza[]={"Escrito 0xxx"}; for(i=0;i>4)&0x0f)>=10)?((Cadena[i]>>4)&0x0f)-10+'A':((Cadena[i]>>4)&0x0f)+'0'; CadenaTraza[11]=(((Cadena[i])&0x0f)>=10)?((Cadena[i])&0x0f)-10+'A':((Cadena[i])&0x0f)+'0'; TIEMPO(CadenaTraza); ultimo=-1; } } void TimevalInit(struct timeval *ini) { struct timezone dummy; memset((char *)&dummy,0,sizeof(struct timezone)); gettimeofday(ini,&dummy); } long gettimediffms(struct timeval *ini) { struct timeval now; long dif; TimevalInit(&now); dif=(now.tv_sec-ini->tv_sec)*1000+(now.tv_usec-ini->tv_usec)/1000; return(dif); } long gettimediffus(struct timeval *ini) { struct timeval now; long dif; TimevalInit(&now); dif=(now.tv_sec-ini->tv_sec)*1000000+(now.tv_usec-ini->tv_usec); return(dif); } int LeeByte(sIoport *Iop, int Base, int *Leido) { int lsr; struct timeval ini; /* Hacemos reintentos de lectura hasta que pase 1 segundo */ for(TimevalInit(&ini);gettimediffms(&ini)<1000L;) { lsr=IopRead(Iop,LSR(Base)); /* Si hay algún carácter esperando, lo devolvemos */ if(lsr&1) { *Leido=(IopRead(Iop,RBR(Base))&0xFF); printf("Recibido: 0x%02X\n",(int)((*Leido)&0xFF)),fflush(stdout); ultimo=((*Leido)&0xff); return(0); } } return(-1); } void InitLoop(long min, long max, long *Contador) { struct timeval tvini,tvfin; struct timezone dummy; long elapsed; long i,inc; int retry; for(i=1,inc=1,retry=0;retry<300;retry++,i+=inc) { gettimeofday(&tvini,&dummy); HazLoop(i); gettimeofday(&tvfin,&dummy); elapsed=(tvfin.tv_sec-tvini.tv_sec)*1000000L-tvini.tv_usec+tvfin.tv_usec; if(elapsed>=min && elapsed<=max) break; if(elapsed>max) i=i-inc,inc=1; else inc*=2; } *Contador=i; printf("Loop: %li, elapsed: %li, retry=%li\n",(long)i,(long)elapsed,(long)retry),fflush(stdout); } long HazLoop(long Contador) { long lim; long i,k,l; for(l=0;l<16;l++) { for(i=0,lim=Contador,k=0;i