======== Newsgroups: alt.hackers Subject: Caller-Id -- Followup From: davef@@mindspring.com (Dave Frascone) Date: 6 Dec 1995 03:09:29 GMT Due to overwhelming demand, here is more info: You can get the schematic I used for all my detection from http://www.semicon.mitel.com/toc_tele.htmll Just look up the MT8843 I used a 7805 and a 9v battery for power. (Available from your nearest radio shack). Just connect the +9v to the left pin, and the - to the middle. Then, the right pin will have a nice 5v ttl output for you! You can also use this device with an AC/DC adapter outputing up to around 6-12 volts. Well, you can probably tell this from the C-program's header, but here goes anyway... You connect the parallel port pins of your computer to the device as follows: Pin 11 -> TRIGout Pin 10 -> INT Pin 12 -> DCLK Pin 13 -> DR Pin 15 -> DATA Pin 2 -> POWDN Pin 25 -> System Ground (The middle pin on the 7805) What the program does is keep POWDN asserted until it gets an INT. It should probably check to make sure a ring event has occured (TRIGout), but it doesn't. Then, it negates POWDN, allowing the chip to run fully. The Mitel 8843 is a power hog. I would not run it continuously in full power mode. (It got my 9v battery really hot!) Anyway, that's about it. What follows is the code I used. It runs under DOS and Linux. For linux, compile it with UNIX defined. Later! Dave /* ** Filename: callerid.c ** Author: Dave Frascone ** Purpose: This will run my neat caller-id toy. It will setup all the ** signaling, and keep it in low-power state until it receives ** the first ring. ** ** The parallel port pin-out is: ** ** Input only pins: Get from status_addr ** bit 7: (Pin 11) -> TRIGout This is 0 when Ring ** bit 6: (Pin 10) -> INT This is 0 when Ring, or data ** bit 5: (Pin 12) -> DCLK This is our output clock ** bit 4: (Pin 13) -> DR This is 0 when Data Ready ** bit 3: (Pin 15) -> DATA This is our data bit ** ** Output pins: ** bit 0: (Pin 2) -> POWDN Give the board power on TRIGout ** ** */ #include #include #include #ifdef UNIX #include #include #include #else #include #include #endif #include #include #include /* Define our port operators... */ #ifdef UNIX static inline int port_in( int port ) { unsigned char value; __asm__ volatile ("inb %1,%0" : "=a" (value) : "d" ((unsigned short)port)); return value; } static inline void port_out( unsigned short int port, unsigned char val ) { __asm__ volatile ( "outb %0,%1\n" : : "a" (val), "d" (port) ); } #else #define port_in(A) inportb(A) #define port_out(A,B) outport(A,B) #endif /* Some bit defines */ #define UNSHIFTED_MASK 0x38 /* This is the mask of the bits we need */ /* Our bit masks (Once shifted) */ #define BIT_TRIGOUT (0x10) #define BIT_INT (0x08) #define BIT_DCLK (0x04) #define BIT_DR (0x02) #define BIT_DATA (0x01) /* The port bit settings (PWDN) */ #define ASSERT_PWDN 0x01 #define NEGATE_PWDN 0x00 /* Some of our pauses */ #define MAX_SLEEP_TIME 250 /* usecs to sleep between polls */ #define MAX_WAIT_TIME 4 /* Max secs to wait for end of carrier */ /* Some brain-dead compilers don't define these for you. */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define STATUS_ADDRESS (port_address+1) /* Some globals! */ unsigned int port_address = 0x378; /* address of port to write to */ unsigned char Buffer[4096]; unsigned char RawBuffer[256]; int MaxWaitTime=MAX_WAIT_TIME; int QuietOutput=FALSE; int LogToFile=FALSE; FILE *LogHandle=0; char LogFilename[100]; #ifdef UNIX int Daemonize=FALSE; #endif /* And our prototypes */ int InitalizePort( void ); int CheckForInterrupt(unsigned char *DataByte); void GetCall( char *DataByte ); char *GetData( char *DataByte ); unsigned char GetPortByte( void ); char *DumpByte(unsigned char Byte); char *ParseBuffer(char *Buffer,int BufferIndex); void DumpOutput(char *Month, char *Day, char *Hour, char *Minute, char *AC, char *Prefix, char *Number, char *Name); void StartLog( void ); void ParseArguments(int argc,char *argv[]); #ifdef UNIX void daemonize( void ); #endif #ifdef UNIX #define USAGE(A) printf("\nUSAGE: %s [options]\nOptions:\n\t-p port\t\t\ default 0x378\n\t-w time\t\tTime to wait for data\n\t-f file\t\t\ File to log into\n\t-q\t\tQuiet Output (Don't print to stdout)\n\t-d\t\t\ daemonize (implies -q)\n\n",A) #else #define USAGE(A) printf("\nUSAGE: %s [options]\nOptions:\n\t-p port\n\ \t-w time\t\tTime to wait for data\n\t-f file\t\tFile to log into\n\ \t-q\t\tQuiet Output (Don't print to stdout)\n\n",A) #endif /* Start doing work!*/ void main( int argc, char *argv[] ) { unsigned char DataByte; ParseArguments(argc,argv); if (QuietOutput&&(!LogToFile)) { printf("Must print output somewhere.\n"); exit(1); } #ifdef UNIX /* Damonize first, so our permissions don't get reset on the port */ if (Daemonize) daemonize(); /* ** Become root so we can read from the port... */ setuid(0); /* ** Check to see if we can clear the led. */ /* set access permissions on the port (Grab two bytes, data and status)*/ if ((ioperm(port_address, 2, 1)) == -1) { fprintf(stderr, "Error: <%s> setting permissions on port 0x%x\n", strerror(errno),port_address); exit(1); } #endif if (LogToFile) { StartLog(); } if (InitalizePort()) { exit (1); /* We got some kind of error... */ } if (!QuietOutput) printf("Callerid port=0x%x WaitTime=%d LogFile=%s\n",port_address, MaxWaitTime,LogToFile?LogFilename:"(none)"); /* If we are getting data, don't sleep as long as when we are idle */ while (1) { #ifdef UNIX usleep(MAX_SLEEP_TIME); #else /* Give DOS a nice way out. */ if (kbhit()) exit(0); #endif if (CheckForInterrupt(&DataByte)) { GetCall(&DataByte); } } } /* ** This function will check the status of the interrupt bit. If it is ** set, it will return 1 */ int CheckForInterrupt(unsigned char *DataByte) { /* ** For now, just get the data byte */ *DataByte=GetPortByte(); /* ** printf("Received: <0x%x:%s>\n",*DataByte,DumpByte(*DataByte)); ** return 0; */ #ifndef UNIX if (kbhit()) exit(0); #endif return (!((*DataByte)&BIT_INT)); } /* ** This function will get a raw byte from the port. (Using the status ** address!) */ unsigned char GetPortByte() { return (port_in(STATUS_ADDRESS)>>3); } /* ** This function will get the call data from the toy. It has to wait for ** DCLK to make a transition from 0 to 1, then use the bit in DATA */ void GetCall(char *DataByte) { char *String; char Month[3]; char Day[3]; char Hour[3]; char Minute[3]; char AC[4]; char Prefix[4]; char Number[5]; char Name[14]; port_out (port_address,NEGATE_PWDN); /* Turn on device */ String=GetData(DataByte); if (!String) return; strncpy(Month,&String[0],2); Month[2]=0; strncpy(Day,&String[2],2); Day[2]=0; strncpy(Hour,&String[4],2); Hour[2]=0; strncpy(Minute,&String[6],2); Minute[2]=0; strncpy(AC,&String[8],3); AC[3]=0; strncpy(Prefix,&String[11],3); Prefix[3]=0; strncpy(Number,&String[14],4); Number[4]=0; strncpy(Name,&String[18],13); Name[13]=0; DumpOutput(Month, Day, Hour, Minute, AC, Prefix, Number, Name); } /* Print the output, and log it. */ void DumpOutput(char *Month, char *Day, char *Hour, char *Minute, char *AC, char *Prefix, char *Number, char *Name) { char TempBuffer[200]; /* Print our lines to a buffer, then write it out */ sprintf(TempBuffer,"%s/%s %s:%s %s (%s)%s-%s\n",Month, Day,Hour,Minute, Name, AC, Prefix, Number); if (!QuietOutput) { fprintf(stdout,TempBuffer); fflush(stdout); } if (LogToFile) { fprintf(LogHandle, TempBuffer); fflush(LogHandle); } } /* ** This function will spin, waiting on data for at most a second. */ char *GetData(char *StartByte) { unsigned char DataByte,OldByte=*StartByte; register int i=0,Loop=0; time_t StartTime; int Finished=0; /* Just ignore it. */ *StartByte=0; /* Keep saving the bytes so we can parse them later. */ StartTime=time(NULL); while (!Finished) { Loop++; if (!(Loop%10000)) { /* Check elapsed time */ if (difftime(time(NULL),StartTime)>MaxWaitTime) Finished=TRUE; } DataByte=port_in(STATUS_ADDRESS)&UNSHIFTED_MASK; if (DataByte==OldByte) continue; OldByte=DataByte; Buffer[i++]=DataByte; } port_out (port_address,ASSERT_PWDN); /* Turn it back off! */ return ParseBuffer(Buffer,i); } #define STATE_DR_WAIT 1 #define STATE_CK_HIGH 2 #define STATE_CK_LOW 3 char *ParseBuffer(char *Buffer,int BufferIndex) { int PercentFound=FALSE; unsigned char Letter=0; unsigned char DataByte; int i,j,r; int LettersFound=0; int State; static char OutputString[80]; i=0;j=0;r=0; State=STATE_CK_HIGH; while (i>3; switch(State) { case STATE_DR_WAIT: /* Wait for DR to drop */ if (!(DataByte&BIT_DR)) State=STATE_CK_HIGH; break; case STATE_CK_HIGH: /* Wait for CK to drop (or DR) */ if (!(DataByte&BIT_DR)) { /* Our word is done. output the letter */ if (isprint(Letter)) { if (!PercentFound) { if (Letter=='%') PercentFound=TRUE; } else OutputString[j++]=Letter; RawBuffer[r++]=Letter; Letter=0; LettersFound++; } break; } if (!(DataByte&BIT_DCLK)) State=STATE_CK_LOW; break; case STATE_CK_LOW: /* If we go high, get a bit */ if (DataByte&BIT_DCLK) { DataByte=DataByte&BIT_DATA; Letter=(Letter>>1) + (DataByte<<7); State=STATE_CK_HIGH; } break; } i++; } if (!PercentFound) return NULL; OutputString[j]=0;RawBuffer[r]=0; return OutputString; } /* ** This function will initalize the paralell port, and put our toy ** to sleep. */ int InitalizePort() { /* Put our board into sleep mode */ port_out (port_address,ASSERT_PWDN); /* Bit 1 is powerdown ... We want it high */ return 0; } char *DumpByte(unsigned char DataByte) { static char BitData[9]; int i; for (i=0;i<8;i++) { if (DataByte&(1< opening logfile: <%s>\n",strerror(errno),LogFilename); if (QuietOutput) exit(1); /* exit if we can't print */ LogToFile=FALSE; } } #ifdef UNIX void daemonize ( void ) { switch (fork()) { case 0: /* We are the child */ break; case -1: printf("Error <%s> forking child.\n",strerror(errno)); exit(1); default: /* We are the parent */ exit(0); } } #endif /* ** Catch DOS's brain deadedness */ void ParseArguments(int argc, char *argv[]) { #ifdef UNIX extern char *optarg; extern int optind, opterr; int c; /* Turn off default error handling */ opterr=0; while ((c=getopt(argc,argv,"p:w:f:dq"))!=-1) switch (c) { case 'p': sscanf(optarg,"%x",&port_address); break; case 'w': MaxWaitTime=atoi(optarg); break; case 'f': LogToFile=TRUE; strcpy(LogFilename,optarg); break; case 'q': QuietOutput=TRUE; break; case 'd': Daemonize=TRUE; QuietOutput=TRUE; break; default: USAGE(argv[0]); exit(1); } #else /* DOS is SOOOOO brain dead. I can't believe it doesn't have getopt. */ int i; for (i=1;i