#include #include #include #include #include /************************************************************************/ /* GLOBAL VARIABLE DECLARATIONS */ /************************************************************************/ int lc=0; char ob[1000]; /* output buffer for packet before being sent to screen */ int obp=0; /* pointer to current position in array ob */ double dtt, odtt,ul,ll; /* variables used in clock tracking routine */ FILE *out; /* pointer to output file */ /* configuration parameter declaration to the defaults for RAM network */ static int verbose = 0; /* verbose mode parameter */ static int cfs = 1; /* system specific frame sync checking status */ static int frsync=0xB433; /* system specific frame sync */ static int btsync=0xCCCC; /* bit sync */ static double brate = 8000.0; /* Mobitex system baud rate */ static int bitscr = 1; /* bit scrambling in use ? */ static int clocka = 1; /* fine tune receive clock */ static int bitinv = 0; /* bit inversion */ static int ramnet = 1; /* ramnet flag - 1 means it's ram */ static int outfil = 1; /* file output toggle */ static int comport = 0x3f8; /* serial port base address; set in main*/ static int tempo=0; /* maybe I should get a new compiler */ /* data buffer for raw data coming in over serial port */ static unsigned int buflen= 15000; /* length of data buffer */ static volatile unsigned int cpstn = 0; /* current position in buffer */ static unsigned int fdata[15001] ; /* frequency data array */ void interrupt (*oldfuncc) (); /* vector to old com port interrupt */ /************************************************************************/ /* SERIAL PORT INTERRUPT HANDLER */ /************************************************************************/ /* this is serial com port interrupt */ /* we assume here that it only gets called when one of the status */ /* lines on the serial port changes (that's all you have hooked up). */ /* All this handler does is read the system timer (which increments */ /* every 840 nanoseconds) and stores it in the fdata array. The MSB */ /* is set to indicate whether the status line is zero. In this way */ /* the fdata array is continuously updated with the length and the */ /* length and polarity of each data pulse for further processing by */ /* the main program. */ void interrupt com1int() { static unsigned int d1,d2,ltick,tick,dtick; /* the system timer is a 16 bit counter whose value counts down */ /* from 65535 to zero and repeats ad nauseum. For those who really */ /* care, every time the count reaches zero the system timer */ /* interrupt is called (remember that thing that gets called every */ /* 55 milliseconds and does housekeeping such as checking the */ /* keyboard). */ outportb (0x43, 0x00); /* latch counter until we read it */ d1 = inportb (0x40); /* get low count */ d2 = inportb (0x40); /* get high count */ /* get difference between current, last counter reading */ tick = (d2 << 8) + d1; dtick = ltick - tick; ltick = tick; /* set MSB to reflect state of input line */ if ((inportb(comport + 6) & 0xF0) > 0) dtick = dtick | 0x8000; else dtick = dtick & 0x3fff; fdata[cpstn] = dtick; /* put freq in fdata array */ cpstn ++; /* increment data buffer pointer */ if (cpstn>buflen) cpstn=0; /* make sure cpstn doesnt leave array */ d1 = inportb (comport + 2); /* clear IIR */ d1 = inportb (comport + 5); /* clear LSR */ d1 = inportb (comport + 6); /* clear MSR */ d1 = inportb (comport); /* clear RX */ outportb (0x20, 0x20); /* this is the END OF INTERRUPT SIGNAL */ /* "... that's all folks!!!!" */ } /************************************************************************/ /* SERIAL PORT INITIALIZATION */ /************************************************************************/ /* basic purpose: enable modem status interrupt and set serial port */ /* output lines to supply power to interface */ void set8250 () /* sets up the 8250 UART */ { static unsigned int t; outportb (comport+3, 0x00); /* set IER on 0x03f9 */ outportb (comport+1, 0x08); /* enable MODEM STATUS INTERRUPT */ outportb (comport+4, 0x0a); /* push up RTS, DOWN DTR */ t = inportb(comport + 5); /* clear LSR */ t = inportb(comport); /* clear RX */ t = inportb(comport + 6); /* clear MSR */ t = inportb(comport + 2); /* clear IID */ t = inportb(comport + 2); /* clear IID - again to make sure */ } /************************************************************************/ /* TIMER CHIP INITIALIZATION */ /************************************************************************/ /* purpose: make sure computer timekeeper is set up properly. This */ /* routine probably isn't necessary - it's just an insurance */ /* policy. */ void set8253() /* set up the 8253 timer chip */ { /* NOTE: ctr zero, the one we are using*/ /* is incremented every 840nSec, is */ /* main system time keeper for dos */ outportb (0x43, 0x34); /* set ctr 0 to mode 2, binary */ outportb (0x40, 0x00); /* this gives us the max count */ outportb (0x40, 0x00); } /************************************************************************/ /* minor forward error correcting stuff stuff... */ /************************************************************************/ /* do error correcting stuff */ /* matrix for block encoding */ int h3 = 0xEC, h2 = 0xD3, h1 = 0xBA, h0 = 0x75; /* returns the number of ones in the byte passed to routine */ int ones(int h) { static int i,nb; nb = 0; for (i=0; i<8; i++) { if ((h & 0x01) == 1) nb++; h = h >> 1; } return(nb); } /* returns number of ones in the integer passed to routine */ int ones_int(int h) { return(ones(h) + ones(h >> 8)); } /************************************************************************/ /* RUN THROUGH BLOCK FORWARD ERROR CORRECTION CODE */ /************************************************************************/ /* PURPOSE: */ /* does FEC on the 8 data bits and 4 FEC bits passed to it in goi */ /* blert tries to check and correct errors... If the errors are */ /* uncorrectable blert returns a 1 ; otherwise 0 */ /* but don't read too much into this - two thirds of the time */ /* random crap going into this routine will not generate the */ /* uncorrectable error signal... Please Rely on the CRC check */ int blert(int *goi) { static int dab,nb,bb,uce=0; uce = 0; /* flag that indicates an uncorrectable error */ /* calculate ecc bits from our current info bits */ dab = *goi >> 4; nb = (ones(dab & h3) & 0x01) << 3; nb += (ones(dab & h2) & 0x01) << 2; nb += (ones(dab & h1) & 0x01) << 1; nb += (ones(dab & h0) & 0x01); /* get syndrome */ nb = nb ^ (*goi & 0x0f); if (ones(nb) > 0) uce = 1; else uce = 0; /* if syndrome is not equal to zero try to correct the bad bit */ if (ones(nb) > 1) { if ((nb & 0x08) > 0) bb = h3; else bb = h3 ^ 0xff; if ((nb & 0x04) > 0) bb &= h2; else bb &= h2 ^ 0xff; if ((nb & 0x02) > 0) bb &= h1; else bb &= h1 ^ 0xff; if ((nb & 0x01) > 0) bb &= h0; else bb &= h0 ^ 0xff; /* are we pointing to a single bit? if so we nailed the bastard */ if ( ones(bb) == 1) *goi = *goi ^ (bb<<4); else uce ++; } else *goi = *goi ^ nb; /* single wrong bit in syndrome => error occured in FEC bits */ return(uce); } /************************************************************************/ /* BIT SCRAMBLING SEQUENCE GENERATOR */ /************************************************************************/ /* following is the pseudo-random bit scrambling generator. */ /* It's the output of a 9 stage linear-feedback shift register with taps */ /* at position 5 and 9 XORed and fed back into the first stage. */ /* An input of less than zero resets the scrambler. */ /* Otherwise it returns one bit at a time each time it is called */ int bs(int st) { static int rs,ud; /* leave if system isn't supposed to use bit scrambling */ if (bitscr == 0) return(0); if (st < 0) rs = 0x1E; /* inputs <0 reset scrambler */ else { if ( (rs & 0x01) > 0) ud=1; else ud = 0; if ( (rs & 0x10) > 0) ud = ud ^ 0x01; rs = rs >> 1; if (ud > 0) rs = rs ^ 0x100; } return(ud); } /************************************************************************/ /* CRC GENERATING ROUTINE */ /************************************************************************/ /* CRC generator - passing a -1 to this routine resets it, otherwise */ /* pass all 144 data bits in the mobitex data block to it (starting */ /* with byte 0, LSB bit). The returned value will then be the */ /* CRC value. Passing any other negative value just returns CRC. */ unsigned int crc(signed int gin) { static unsigned int sr = 0x00,cr; if (gin >= 0) { if (gin == 1) cr = cr ^ sr; if ((sr & 0x8000) != 0) sr = (sr << 1) ^ 0x0811; else sr = sr << 1; } else if (gin == -1) /* -1 resets the crc state */ { sr = 0xF8E7; cr = 0x2A5D; } return(cr); } /**********************************************************************/ /* PROCESS RECEIVED 240 BIT MOBITEX DATA BLOCK */ /**********************************************************************/ /* process MOBITEX data block */ int barfrog() { static int i,j,k,b,nerr,cb; static unsigned int crcc=0x0000; static int blob[30]; nerr = 0; /* process data block into 20 byte chunk stored in array blob */ crc(-1); /* reset crc routine */ crcc = 0x0000; for (i=0; i<20; i++) { /* uninterleave the data into b (holds 8 data bits + 4 FEC bits) */ b = 0; for (j = 0; j<12; j++) { b = b << 1; k = (j*20) + i; if (ob[k] == 49) b ^= 0x01; } /* run through error correction routine */ nerr+=blert(&b); /* spit out data bits to CRC routine - LSB data bit first... */ cb = b >> 4; if (i < 18) { for (j=0; j<8; j++) { if ( (cb & 0x01) == 1) crc(1); else crc(0); cb = cb >> 1; } } else { crcc = (crcc << 8) ^ (cb & 0xff) ; } /* store the byte in our wonderful wonderful array */ b = b >> 4; blob[i] = b; } /* at this point array BLOB holds the data; nerr gives the number */ /* of errors detected by the FEC code ('corrected' errors count as */ /* one, uncorrectable count as 2); and crcc gives the received */ /* CRC code. We use this info to decide if we got a good block */ /* if CRC is correct or nerr <15 we'll say it's a good block */ if ( (crc(-2) == crcc) | (nerr < 15) ) { for (i=0; i<20; i++) { printf("%02X",blob[i]); if (outfil) fprintf(out,"%02X",blob[i]); } if ( crc(-2) == crcc) { printf (" "); if (outfil) fprintf (out," "); } else { printf(" BAD CRC "); if (outfil) fprintf(out," BAD CRC "); } for (i=0; i<20; i++) if (blob[i] > 31) { printf ("%c",blob[i]); if (outfil) fprintf (out,"%c",blob[i]); } else { printf ("."); if (outfil) fprintf(out,"."); } printf("\n"); if (outfil) fprintf(out,"\n"); } return(nerr); } /************************************************************************/ /* FRAME SYNCHRONIZATION OF RAW BIT STREAM */ /************************************************************************/ /* this routine tries to achieve frame sync up in the raw bit stream */ int frame_sync(char gin) { static int s1=0x0000,s2=0x0000; static int cb1,cb2,bc=0,nbc=0,og,nu,bcb,fss = 0,fsb; fss = 0; /* nbc is a bit counter for # of bits left to form into a data block */ if (nbc == 0) { /* nbc = 0 so we aren't trying to process a data block; instead try */ /* to sync up with incoming bit stream */ /* keep sliding buffers up to date */ s1 = s1 << 1; if ( (s2 & 0x8000) != 0) s1++; s2 = s2 << 1; if (gin == 49) s2++; /* check for sync */ fsb = ones_int(s1^btsync); if (cfs) fsb += ones_int(s2^frsync); /* if first two integers match up within a bit or two then */ /* we've gotten frame sync */ if ( (fsb < (1+cfs)) && (bc == 0) ) { if (verbose) { printf("SYSTEM FRAME SYNC %04X ;",s2); if (outfil) fprintf(out,"SYSTEM FRAME SYNC %04X ;",s2); } bc = 25; } /* bc is a bit counter used to pick off the two status bytes and */ /* the FEC byte in the header. */ if (bc > 0) { bc--; if (bc == 0) { /* strip off control bytes, run them through FEC routine */ cb1 = (s1 & 0xff) << 4; cb1 += (s2 >> 4) & 0xf; cb2 = (s2 >> 4) & 0xff0; cb2 += (s2 & 0xf); bcb = blert(&cb1) + blert(&cb2); if (bcb == 0) fss = 1; if (verbose) { printf ("Control Bytes #1=%02X, #2=%02X",cb1>>4,cb2>>4); if (outfil) fprintf (out,"Control Bytes #1=%02X, #2=%02X", cb1>>4,cb2>>4); if (bcb != 0) { printf (" BAD Control Byte FEC"); if (outfil) fprintf (out," BAD Control Byte FEC"); } printf("\n"); if (outfil) fprintf(out,"\n"); } /* for RAM network - */ /* control byte2 : bits 1 and 2 both 0 -> data block(s) follow */ /* otherwise just be adventurous and see if we get a valid block */ if (ramnet) { if ( (cb2 & 0x60) == 0) nbc = 1440; } else nbc = 1440; nu = 0; bs(-1); } } } else { if (bs(1) == 1) og = gin ^ 0x01; else og = gin; ob[nu] = og; nu ++; if (nu == 240) { nu = 0 ; if (barfrog() < 15) nbc = 241; else nbc = 1; } nbc --; if (nbc == 0) { printf ("\n"); if (outfil) fprintf(out,"\n"); } } return (fss); } /************************************************************************/ /* RECEIVE CLOCK TWEAKING ROUTINE */ /************************************************************************/ void check_clk(int i, int nbs) { static int nt,ii,ndt,na=0; static double a=0.0,avg,cvg; if (clocka) { ii = i-1; if (ii < 0) ii = buflen; nt = 0; ndt = 0; while (ndt < (54-nbs) ) { nt += fdata[ii]; ndt = 0.5 + (nt/odtt); ii--; if (ii < 0) ii = buflen; } cvg = (double) nt / ndt; /* update average if in roughly the right range */ if ( (cvg < ul) && (cvg > ll)) { a = a + cvg; na ++; avg = a / (double) na; dtt = avg; } } } /************************************************************************/ /* DISPLAY HELP SCREEN */ /************************************************************************/ void help() { printf("\n MOBITEX RECEIVING PROGRAM - Command line arguement summary\n"); printf(" (Defaults are set up for RAM Mobile Data's system.)\n\n"); printf(" /V:1 - print received system frame sync and control blocks\n"); printf(" /V:0 - don't show the above (DEFAULT)\n"); printf(" /CFS:1 - check system specific frame sync field (DEFAULT).\n"); printf(" /CFS:0 - Don't check it - useful for unknown systems.\n"); printf(" /FS:XXXX - set system specific frame sync to HEX XXXX (DEFAULT B433)\n"); printf(" /SY:YYYY - set bit sync to HEX YYYY (Default for base stations CCCC)\n"); printf(" /BR:Z - Z is the Mobitex system's baud rate (Default = 8000).\n"); printf(" /BS:1 - System uses bit scrambling (DEFAULT)\n"); printf(" /BS:0 - system does not use bit scrambling\n"); printf(" /CA:1 - program attempts to fine tune receive clock (DEFAULT)\n"); printf(" /CA:0 - program does not attemp to fine tune receive clock.\n"); printf(" /BI:1 - Inverts incoming raw data.\n"); printf(" /BI:0 - don't invert incoming raw data (DEFAULT).\n"); printf(" /RN:1 - RAM only: control bytes determine if data blocks follow sync.\n"); printf(" /RN:0 - always try to decode data blocks regardless of control bytes.\n"); printf(" /OF:1 - Write data to output file (DEFAULT).\n"); printf(" /OF:0 - Don't write output data file.\n"); printf(" /COM:z - set z = 1,2,3,4 to set com port you want to use.\n"); printf("\nSee text file for further details..."); printf(" press any key to continue...\n"); getch(); } /************************************************************************/ /* MAIN ROUTINE */ /************************************************************************/ void main (int argc,char *argv[],char *env[]) { unsigned int n,i=0,j=0,k,l,nbs,imax=0; int sport=1,irqv=0x0c; char s=48,temp[20],yon[2][5]= {"OFF","ON"}; double pl,dt,exc=0.0,clk=0.0,xct; /* process command line arguements */ for (n=1; n= xct ) { /* if frame_sync returns a 1 it means the last 56 bits were the sync */ /* frame_sync(s); */ nbs ++; if (frame_sync(s) == 1) check_clk(i,nbs); clk = clk - dtt; } /* clk now holds new boundary position. update exc slowly... */ /* 0.005 sucks; 0.02 better; 0.06 mayber even better; 0.05 seems pretty good */ exc = exc + 0.050*(clk - exc); i++; if( i >buflen) i = 0; if ( ((cpstn - i) > imax) && (cpstn > i)) imax = cpstn - i; } } /* shutdown */ outportb (0x21, n); /* disable IRQ4 interrupt */ setvect (irqv, oldfuncc); /* restore old COM1 Vector */ printf (" %i\n",imax); if (outfil) fclose(out); } /* end of post */