#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