#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <math.h>
#include <string.h>
/************************************************************************/
/* 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<argc; n++)
{
strcpy(temp,argv[n]);
strupr(temp);
j+=sscanf(temp,"/FS:%X",&frsync);
j+=sscanf(temp,"/SY:%X",&btsync);
j+=sscanf(temp,"/V:%i",&verbose);
j+=sscanf(temp,"/CFS:%i",&cfs);
j+=sscanf(temp,"/BR:%g",&brate);
j+=sscanf(temp,"/BS:%i",&bitscr);
j+=sscanf(temp,"/CA:%i",&clocka);
j+=sscanf(temp,"/BI:%i",&bitinv);
j+=sscanf(temp,"/RN:%i",&ramnet);
j+=sscanf(temp,"/OF:%i",&outfil);
j+=sscanf(temp,"/COM:%i",&sport);
if (temp[1] == 'H') j=30;
}
if ( (j+1) != argc) help();
printf ("\n\nProgram Options set as follows: \n");
printf ("Baud Rate : %g baud\n",brate);
printf ("Frame sync : %04X\n",frsync);
printf ("Bit sync : %04X\n",btsync);
cfs &= 0x01; printf ("Check frame sync : %s\n",yon[cfs]);
verbose&= 0x01; printf ("Verbose mode : %s\n",yon[verbose]);
bitscr &= 0x01; printf ("Bit scrambling : %s\n",yon[bitscr]);
clocka &= 0x01; printf ("Fine tune clock : %s\n",yon[clocka]);
bitinv &= 0x01; printf ("Bit Inversion : %s\n",yon[bitinv]);
ramnet &= 0x01; printf ("RAM network mode : %s\n",yon[ramnet]);
outfil &= 0x01; printf ("Output file echo : %s\n",yon[outfil]);
sport &= 0x03; printf ("Running on COM%i\n\n",sport);
if (outfil)
{
strcpy (temp,"MOBYDAXXXXXX");
mktemp(temp);
printf("\nfilename where screen display will be echoed : %s\n\n",temp);
out = fopen(temp,"wt");
}
printf ("Press any key to stop program...\n\n");
/* dtt is the number of expected clock ticks per bit */
dtt = 1.0/(brate*839.22e-9); /* this will be the updated clock */
odtt = dtt; /* this oddt is not updated */
/* following give the range over which the the clock can be adjusted */
ul = odtt + 1.0;
ll = odtt - 1.0;
/* set up serial port and related parameters */
n = inportb (0x21);
if ( (sport == 1) | (sport == 3))
{
irqv = 0x0c;
oldfuncc = getvect(irqv); /* save COM Vector */
setvect (irqv, com1int); /* Capture COM vector */
outportb(0x21, n & 0xef);
if (sport == 1) comport = 0x3f8; else comport = 0x3e8;
}
else
{
irqv = 0x0b;
oldfuncc = getvect(irqv); /* save COM Vector */
setvect (irqv, com1int); /* Capture COM vector */
outportb(0x21, n & 0xf7);
if (sport == 2) comport = 0x2f8; else comport = 0x2e8;
}
set8253(); /* set up 8253 timer chip */
set8250(); /* set up 8250 UART */
while ( (cpstn < 3) & (kbhit() == 0) );
if (cpstn < 3)
printf("HEY - no data seems to be coming in over your interface.\n\n");
else
printf("Interface seems to work properly...\n\n");
/* main process routine - keeps on going until any key was hit */
while (kbhit() == 0)
{
if (i != cpstn)
{
if ( ( fdata[i] & 0x8000) != 0) s = 48; else s = 49;
s = s ^ bitinv;
/* add in new number of cycles to clock */
clk += (fdata[i] & 0x7fff);
xct = exc + 0.5 * dtt; /* exc is current boundary */
nbs = 0;
while ( clk >= 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 */
syntax highlighted by Code2HTML, v. 0.9.1