/* * SRCFILE: rap-isd.c * NAME: RAP-ISD (Rec And Play ISD1420 Memory) * VERSION: 0.2 * DESC: Graba y reproduce mensages en una memoria de audio ISD1420 a traves * del puerto paralelo de la PC. * OS: Linux 2.x.x * * Autor: Estudiez, Boris * Nick : slice * Fecha: 28/09/2003 * Update: xx/xx/xx * Web : http://stk.freeshell.org * Mails: slicetek@hotpop.com, 43824@electronica.frc.utn.edu.ar * * Compilacion: gcc -O rap-isd.c -o rap * Ejecucion: ./rap [OPCION] [ARGUMENTOS] * * Nota(0): Este programa es funcional pero esta en estado de desarrollo. * Los errores por su mal uso no estan contemplados. whocare? Enjoyit! * * Nota(1): Usted debe ser root para ejecutar este programa. Si quiere * ejecutarlo como usuario, como root teclee: chmod +s rap-isd * y luego puede usar el programa como usuario. * * Nota(2): El programa no verifica si los mensages a grabar exeden * el espacio en la memoria ISD1420. * * Nota(3): Lea el fichero README.TXT que se adjunta para un corrrecto * uso del programa, se recomienda LEER la hoja de datos de la memoria * ISD1420 (www.isd.com) antes de usar el programa!. * La interfaz de hardware tambien se adjunta para un correcto conexionado * del puerto paralelo a la memoria ISD1420. * */ #include <signal.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <asm/io.h> #include <string.h> #include <stdio.h> #include <stdlib.h> /* Modificar si es necesario: lp0 = 0x378, lp1 = 0x278 y lp2 = 0x3BC */ #define PORT 0x378 /* Direccion del puerto paralelo a usar lp0 (LPT1) */ /* Definiciones usadas por el programa */ #define VERSION "0.2" #define NAMEPRG "rap-isd" #define FALSE 0 #define TRUE 1 #define ERROR 0 #define OK 1 #define ERRPAR "Error, Parametros incorrectos o insuficientes." /* Retardos introducidos por el ISD1420 - Expresados en microsegundos. Para mayor referencia lea la hoja tecnica del ISD1420. TYP=TYPICAL. Valores probados en una PIII @ 500 MHz. Si su PC es mas rapida y el programa no funciona correctamente al grabar, incremente el valor de TRPUD. */ #define TSET 1 /* ADDRESS SETUP TIME - TYP = 300 ns */ #define TRPUD 32000 /* RECORD POWERUP DELAY TIME - TYP = 32 ms */ #define TRPDD 32500 /* RECORD POWERDOWN DELAY TIME - TYP = 32 ms */ #define TPPUD 32000 /* PLAYBACK POWERUP DELAY TIME - TYP = 32 ms */ #define TPPDD 8200 /* PLAYBACK POWERDOWN DELAY TIME - TYP = 8.1 ms */ #define THOLD 1 /* ADDRESS HOLD TIME - TYP = 0s */ /* Comando de la ISD1420 asociado Control Port del puerto paralelo. Pines usados: Pin 1 (strobe) conectado a Pin 27 (/rec) de ISD1420. Pin 14 (Auto Feed XT) conectado a pin 24 (/playe) de ISD1420. */ #define PLAYEON 0x02 /* /PLAYE = 0 -> Activa ISD para Reproducir */ #define PLAYEOFF 0 #define RECON 0x01 /* /REC = 0 -> Activa ISD para Grabar */ #define RECOFF 0 #define STATIC 0 /* ISD1420 en modo estatico -> /PLAYE=1 y /REC=1 */ /* Seleccion de Modos de operacion y Direccionamiento Interno de memoria de la ISD1420 asociado al Data Port del Puerto Paralelo. */ /* Modo de Operacion */ #define OPMODE 0xC0 /* ISD1420 en Modo de Operacion -> A6=1 y A7=1 */ #define OP0 0x01 /* Modo de Operacion - Message Cueing -> A0=1 */ #define OP4 0x10 /* Modo de Operacion - Consecutive Addressing -> A4=1 */ /* Direccionamiento de Memoria */ #define RESET_ADDRESS 0 /* Direccion 0 de memoria interna de ISD1420 */ char player[BUFSIZ]; /* Almacena nombre del Reproductor de audio */ int rec_isd1420(int isd_address, char *msg_path); int reclst_isd1420(char *msg_path_lst); int play_isd1420(int isd_address); int playn_isd1420(int N); void inicialize_isd_hard(void); int iline(register char *line, char c); void help(void); /* Lee bit 5 del byte (PORT+1) - STATUS PORT / bit PE / pin 12, conectado a pin 25 (/recled) de ISD1420. Devuelve 0 cuando encontramos un EOM al reproducir un mensage y 1 cuando no hay EOM presente. */ int getEOM(void) { return (inb(PORT+1) & 0x20); } int main(int argc, char *argv[], char *envp[]) { int c, error=FALSE; /* Dar Permisos a PORT, PORT+1 y PORT+2 */ if(ioperm(PORT, 3, 1)) { perror("rap-isd, error en funcion ioperm"); exit(EXIT_FAILURE); } if(argc >= 2 && *argv[1] == '-') { c = argv[1][1]; switch(c) { case 'r': if(argc==5) { strcpy(player, argv[4]); rec_isd1420(atoi(argv[2]), argv[3]); } else { fprintf(stderr, "%s: %s\n", NAMEPRG, ERRPAR); error=TRUE; } break; case 'l': if(argc==4) { strcpy(player, argv[3]); reclst_isd1420(argv[2]); } else { fprintf(stderr, "%s: %s\n", NAMEPRG, ERRPAR); error=TRUE; } break; case 'p': if(argc==3) play_isd1420(atoi(argv[2])); else { fprintf(stderr, "%s: %s\n", NAMEPRG, ERRPAR); error=TRUE; } break; case 's': if(argc==3) playn_isd1420(atoi(argv[2])); else { fprintf(stderr, "%s: %s\n", NAMEPRG, ERRPAR); error=TRUE; } break; case 'i': if(argc==2) inicialize_isd_hard(); else { fprintf(stderr, "%s: %s\n", NAMEPRG, ERRPAR); error=TRUE; } break; case 'm': if(argc==2) { printf("\nDireccion del Puerto Paralelo: 0x%x\n", PORT); printf("\nUd. Puede cambiar este valor, desde la variable\n"); printf("PORT, ubicada en primeras lineas del codigo fuente, \n"); printf("luego compile el programa nuevamente.\n\n"); printf("Para ejemplos lea el archivo: README.TXT incluido.\n\n"); } else { fprintf(stderr, "%s: %s\n", NAMEPRG, ERRPAR); error=TRUE; } break; case 'h': help(); break; default: help(); break; } } else { help(); error=TRUE; } if(ioperm(PORT, 3, 0)) /* Quitando Permisos a la direccion PORT */ { exit(EXIT_FAILURE); } if(error==FALSE) exit(EXIT_SUCCESS); else exit(EXIT_FAILURE); } /* rec_isd1420: graba el mensage msg_path en la direccion isd_address de la memoria ISD1420. Donde : 0 <= isd_address <= 159, y msg_path es el path donde se encuentra el archivo de sonido a grabar. Devuelve: OK -> Todo bien y ERROR -> Todo mal... */ int rec_isd1420(int isd_address, char *msg_path) { char command[4096]; outb(STATIC, PORT+2); /* /PLAYE=1 y /REC=1 */ if(isd_address >= 0 && isd_address <= 159) outb(isd_address, PORT); /* Direccion de memoria de ISD1420 */ else { printf("Direccion %d no valida, rango valido: 0-159\n", isd_address); return ERROR; /* direccion no valida */ } usleep(TSET); printf("ISD1420: Grabando mensage.\n"); printf("Direccion de Memoria: %d \n", isd_address); printf("Archivo: %s\n", msg_path); sprintf(command, "%s %s > /dev/null ", player, msg_path); outb(RECON, PORT+2); /* /REC=0 - Grabamos */ /* usleep(TRPUD) ; // descomentar si hace falta */ system(command); /* Reproducir sonido en la PC */ outb(RECOFF, PORT+2); /* /REC=1 - Grabacion terminada */ printf("\n"); usleep(TRPDD); /* Esperamos tiempo de apagado */ return OK; } /* reclst_isd1420: Graba los mensages indicados del archivo msg_path_lst en la memoria ISD1420. La lista contiene el path de cada archivo de audio a grabar. Los mensages son grabados consecutivamente desde la direccion 0 de la memoria y son terminandos con un /EOM (END OF MESSAGE) dentro de la memoria ISD. Devuelve: OK -> Todo bien y ERROR -> Todo mal... Nota: Es conveniente grabar silencio como primer mensage de una duracion de 0.5 segundos (primeras 4 posiciones de memoria) para que si el ISD se dispara por ruido, no reprodusca ningun mensage. Quizas mas seguro seria grabar 2 mensages de 250 ms. */ int reclst_isd1420(char *msg_path_lst) { FILE *msg_filelst; char command[4096], line[4096]; int stat=OK, msg_recorded=0; outb(STATIC, PORT+2); /* /PLAYE=1 y /REC=1 */ outb(RESET_ADDRESS, PORT); /* Ponemos 0 direccion de mem ISD. Resetea Puntero A4 =0 */ usleep(TSET); outb(OPMODE+OP4, PORT); /* 11010000 - Consecutive Addresing A4=1 ello es para que en cada /REC=0 el dispositivo no resetee el puntero de direcciones interno. */ usleep(TSET); if((msg_filelst = fopen(msg_path_lst, "r")) != NULL) { while(fgets(line, 4096, msg_filelst)) { if(!iline(line, '#')) /*ignora lineas en blanco o antecedidas con #*/ continue; line[strlen(line)-1] = '\0'; sprintf(command, "%s %s > /dev/null", player, line); printf("\nISD1420: Grabando mensage.\n"); printf("Numero de mensage: %d \n", ++msg_recorded); printf("Archivo: %s\n", line); usleep(TSET); outb(RECON, PORT+2); /* /REC=0 - Grabamos */ /* usleep(TRPUD) ; // descomentar si hace falta */ system(command); /* Reproducir Sonido del PC*/ outb(RECOFF, PORT+2); /* /REC=1 -> poner EOM (terminar grabar)*/ printf("\n"); usleep(TRPDD); /* Esperamos tiempo de apagado */ sleep(1); /* Esperamos tensiones en el pin /REC se estabilize y se ponga a 1 . Nos aceguramos una correcta grabacion.*/ } printf("\nTotal de Mensages Grabados: %d\n\n", msg_recorded); fclose(msg_filelst); } else { fprintf(stderr, "rap-isd: %s archivo inexistente.\n", msg_path_lst); stat=ERROR; } outb(RESET_ADDRESS, PORT); /* Resetemos puntero interno de direcciones y quitamos modo de operacion conse- cutive addressing. */ return stat; } /* play_isd1420: Reproduce mensage de la ISD1420 ubicado en la direccion isd_address de la memoria. Espera hasta que termina de reproducirse el mensage determinado por su EOM. Donde : 0 <= isd_address <= 159 Devuelve: OK -> Todo bien y ERROR -> Todo mal... */ int play_isd1420(int isd_address) { outb(STATIC, PORT+2); /* /PLAYE=1 y /REC=1 */ if(isd_address >= 0 && isd_address <= 159) outb(isd_address, PORT); /* Direccion de memoria de ISD1420 */ else { printf("Direccion %d no valida, rango valido: 0-159\n", isd_address); return ERROR; /* direccion no valida */ } usleep(TSET); printf("ISD1420: Reproduciendo mensage.\n"); printf("Direccion de Memoria: %d \n", isd_address); printf("Esperando fin de mensage (EOM) ...\n"); outb(PLAYEON, PORT+2); /* /PLAYE=0 */ usleep(TPPUD); /* Esperamos Tiempo de encendido */ outb(PLAYEOFF, PORT+2); /* /PLAYE=1 */ while(getEOM()); /* Esperamos fin de mensage /EOM */ usleep(TPPDD); outb(RESET_ADDRESS, PORT); /* En modo estatico esto resetea el puntero de direcciones interno de la memoria. */ return OK; } /* playn_isd1420: Saltea N-1 mensages determinados por un /EOM y luego reproduce el mensage que le sigue. Espera hasta que termina de reproducirse el mensage determinado por su EOM. Equivale a decir que reproduce el mensage N de la memoria ISD. Decimos que el mensage N=1 es el primero de todos. Donde : 1 <= N <= 160 como maximo. Devuelve: OK -> Todo bien y ERROR -> Todo mal... */ int playn_isd1420(int N) { int i; outb(STATIC, PORT+2); /* /PLAYE=1 y /REC=1 */ outb(RESET_ADDRESS, PORT); /* Puntero de direcciones interno reseteado */ usleep(TSET); if(N < 1 || N > 160) { printf("Numero %d de mensage invalido, rango valido: 1-160\n", N); return ERROR; /* direccion no valida */ } /* Modo de operacion: A0 -> MESSAGE CUEING y A4 -> CONSECUTIVE ADDRESSING */ outb(OPMODE+OP0+OP4, PORT); /* 11010001 -> A7=1,A6=1 + A0=1,A4=1 */ usleep(TSET); for(i=1; i < N; i++) /* Tiempo aprox de ciclo for: (N-1)*2(TSET) */ { usleep(TSET); outb(PLAYEON, PORT+2); /* /PLAYE=0 -> saltear 1 mensage */ usleep(TSET); /* Tiempo minimo para /PLAYE=0 */ outb(PLAYEOFF, PORT+2); /* /PLAYE=1 */ } /* Sacamos Modo Message Cueing pero dejamos Consecutive addressing, ello es para que no se resetee el puntero de direccciones interno de la ISD1420. Ademas el proximo /PLAYE=0 No saltea mensage. Sino que reproduce.*/ outb(OPMODE+OP4, PORT); /* 11010000 -> A7=1,A6=1 + A0=0,A4=1 */ usleep(TSET); printf("ISD1420: Reproduciendo mensage.\n"); printf("Mensage Numero: %d \n", N); printf("Esperando fin de mensage (EOM) ...\n"); outb(PLAYEON, PORT+2); /* /PLAYE=0 -> Reproducimos mensage N.*/ usleep(TPPUD); /* Esperamos tiempo de encendido */ outb(PLAYEOFF, PORT+2); /* /PLAYE=1 */ while(getEOM()); /* Esperamos fin de mensage /EOM */ usleep(TPPDD); /* Esperamos tiempo de apagado. Para /PLAYE este tiempo no tiene mucho sentido, pero es util si vamos a ejecutar muchas veces esta funcion.*/ outb(RESET_ADDRESS, PORT); /* Sacamos modo de operacion y reseteamos puntero de direcciones interno de la ISD1420. A4=0*/ return OK; } /* inicialize_isd_hard: inicializa el hardware para grabar la memoria ISD1420 conectado al puerto paralelo. Es decir pone a la ISD1420 en modo estatico (sin hacer nada) y la linea de direcciones A0...A7 es puesta a Cero. En otras palabras PORT y PORT+2 del puero son puestos a CERO, los niveles que presentara a la salida el puerto sera de 0 Volts. */ void inicialize_isd_hard(void) { printf("Inicializando Puerto Paralelo...\n"); outb(STATIC, PORT+2); outb(RESET_ADDRESS, PORT); usleep(TSET); printf("Listo, conecte la ISD1420 a la interfaz de hardware.\n"); } void help(void) { fprintf(stderr, "\nRAP-ISD %s (Rec And Play ISD1420 Memory)\n", VERSION); fprintf(stderr, "Sintaxis: rap-isd [OPCION] [argumento/s]\n"); fprintf(stderr, "OPCIONES:\n"); fprintf(stderr, "\t -r isd_address file.wav wav_player (Graba mensage en direccion\n"); fprintf(stderr, "\t isd_address de la memoria ISD1420)\n"); fprintf(stderr, "\t -p isd_address (Reproduce mensage ubicado en la direccion isd_address)\n"); fprintf(stderr, "\t -l wav-list.txt wav_player (Graba mensages listados en wav-list.txt,\n"); fprintf(stderr, "\t delimitandolos con EOM en la memoria ISD1420)\n"); fprintf(stderr, "\t -s msg_number (Reproduce mensage N de la ISD1420, cada mensage debe\n"); fprintf(stderr, "\t estar limitado con un EOM dentro de la ISD1420)\n"); fprintf(stderr, "\t -i Inicializa Puerto paralelo, use esta opcion antes de conectar el\n"); fprintf(stderr, "\t Puerto Paralelo a la memoria ISD1420. Tambien puede usarse para\n"); fprintf(stderr, "\t para poner a la ISD1420 en modo estatico (no graba ni reproduce).\n"); fprintf(stderr, "\t -m Informacion adicional del programa y ejemplos.\n\n"); fprintf(stderr, "\nAutor: Boris Estudiez\n"); fprintf(stderr, "Mail(1): stk@freeshell.org\n"); fprintf(stderr, "Mail(2): 43824@electronica.frc.utn.edu.ar\n"); fprintf(stderr, "Web: http://stk.freeshell.org\n\n"); } /* iline: toma una cadena y regresa 0 si solamente contiene espacios en blanco o si su primera letra es igual a la contenida en C. */ int iline(register char *line, char c) { while(isspace(*line)) *++line; if(*line == c) return 0; else if(*line == '\0') return 0; else return 1; }