#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <dos.h>
#include <stdlib.h>
#include <math.h>
int pork(int l);
void set8250 ();
void set8253();
void shob();
void frame_sync(char gin);

/* This copy of MDTWIDR is modified to use Com1 thru COM4.            */
/* Only Com1, Com2 and Com3 are tested and working.                   */
/* Com4 has not been tested, but should work just the same.           */
/* Output of intercepted data is now supported using the same         */
/* Com port as the incoming data slicer bitstream.                    */
/*                                                                    */
/* Much of this code has been lifted directly from the Trunker        */
/* source code that is floating around the net.  Why reinvent the     */
/* wheel?  Many thanks to the authors of Trunker for all the code     */
/* I ripped off.                                                      */
/*                                                                    */
/*                                                                    */
/* This program supports command line switches as follows:            */
/*                                                                    */
/*        /OUT   - enables output of intercepts on the Com port       */
/*        /COM:1 - selects Com1 for input from data slicer (default)  */
/*        /COM:2 - selects Com2 for input from data slicer            */
/*        /COM:3 - selects Com3 for input from data slicer            */
/*        /COM:4 - selects Com4 for input from data slicer            */
/*        /RE    - reverses input polarity                            */
/*        /WS    - selects wide-screen (Non-Hex) output to screen     */
/*                 (default is Hex-Narrow output)                     */
/*        /WF    - selects wide-file (Non-Hex) output to data file    */
/*                 (default is Hex-Narrow output)                     */
/*        /H     - display help screen                                */
/*        /?     - display help screen                                */
/*                                                                    */
/*  - Bonzo -                                                         */
/*                                                                    */

/*                                                                    */
/* Purpose of program: receive messages using the Motorola MDC4800    */
/* protocol and show them on the screen                               */
/*                                                                    */
/* WARNING TO ALL : This program is free. Please distribute and modify*/
/* this program. I only request that you always include the source    */
/* code so that others may also learn and add improvements. The       */
/* status of this program at the time of the original release is :    */
/* it doesn't have much in the way of a user interface or options but */
/* it should work if you follow the procedure in the text file. Don't */
/* expect any sort of support (you get what you pay for - nothing in  */
/* this case). Finally, here's a special message to all of you who    */
/* might have the urge to try to make money with this information:    */
/* I know where you live. I will shave your pets and pour rubbing     */
/* alcohol all over them (unless said pet happens to be a Rottweiler).*/
/* I will have sex with your wife while you off at work; on the rare  */
/* occasions when you have sex with your wife she will in the throes  */
/* of passion cry not your name but mine. I will sell drugs to the    */
/* demented spawn you refer to as your children. And if that's not    */
/* enough for you let a thousand lawyers from motorola descend on you */
/* and pound your fat rear end so far into the ground that it finally */
/* sees daylight again somewhere in Australia.                        */
/*                                                                    */
/*                                                                    */
/* General tidbits (a few of those "Why were things done this way     */
/* questions).                                                        */
/* 1. Why is captured data kept in an array and only written to a     */
/* disk file at the very end? Because disk access seems unreliable    */
/* when so much time is taken up by the background interrupt service  */
/* routine.                                                           */
/* 2. Why is the array storing this so small? Because yours truly was */
/* too damn lazy to use a pointer and allocate a huge chunk of memory.*/
/* (Hint for those of you who would like to improve this.             */
/*--------------------------------------------------------------------*/

/* global variables */

static double baudrate=9600.0;/* baud rate of data link output        */
static int lassie=0;          /* bring help indicator                 */

int nuline=1;
int lc=0;
char fob[30000];/* output buffer for captured data to be sent to disk */
int foblen=29900;
int fobp=0;	/* pointer to current position in array fob	      */
char ob[1000];  /* output buffer for packet before being sent to screen */
int obp=0;	/* pointer to current position in array ob		*/

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    */

  static char temp[100];
  static int sport;
  static int irqv = 0x0c;
  static int wscreen = 0;
  static int wfile   = 0;
  static int comout  = 0;
  static int comport;
  static int comport8;
  static int comport9;
  static int comporta;
  static int comportb;
  static int comportc;
  static int comportd;
  static int comporte;


/**********************************************************************/
/*                                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 appropriate the   */
/* length and polarity of each data pulse for further processing by   */
/* the main program.						      */
void interrupt comint()
{
  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;

    /* Corrected per arron5@geocities.com 02/08/97 */

  if ((inportb(comporte) & 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 (comporta);       /* clear IIR                           */
  d1 = inportb (comportd);       /* clear LSR                           */
  d1 = inportb (comporte);       /* clear MSR                           */
  d1 = inportb (comport8);       /* clear RX                            */
  outportb (0x20, 0x20);         /* this is the END OF INTERRUPT SIGNAL */
                                 /* "... that's all folks!!!!"          */
}

void set8250 (double bps)        /* sets up the 8250 UART               */
{
  static unsigned int t,dv,tp;

  dv = (int) 1843200.0/(16.0*bps);
  /* how to configure your serial port setup:          */
  /* do you want two stop bits? then make sure you set bit 2 in tp */
  /* do you want a parity bit generated? then set bit bit 3 in tp  */
  /* do you want even parity? then set bit 4 in tp                 */
  /* do you want an 8 bit word length? set bits 0 and 1 in tp      */
  /* do you want an 7 bit word length? set bit  1 in tp            */
  tp = 0x80 + 0x02 + 0x01;
  outportb (comport+3, tp);  /* set line control register  */
  outport  (comport  , dv);  /* output brg divisor latch   */
  tp = tp & 0x7f;            /* switch out brg divisor reg */
  outportb (comport+3, tp);

  outportb (comport9, 0x08);     /*  enable MODEM STATUS INTERRUPT      */
  outportb (comportc, 0x0a);     /*  push up RTS, DOWN DTR              */
  t = inportb(comportd);         /*  clear LSR                          */
  t = inportb(comport8);         /*  clear RX                           */
  t = inportb(comporte);         /*  clear MSR                          */
  t = inportb(comporta);         /*  clear IID                          */
  t = inportb(comporta);         /*  clear IID - again to make sure     */
}

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);
}

/************************************************************************/
/*                         send_char                                    */
/*                                                                      */
/* This routine sends a character out on the serial port TxD line.      */
/* It makes sure the previous character has been completely sent and    */
/* then sends puts the current character into the transmit register.    */
/************************************************************************/
void send_char(int c)
{
  /* wait for transmit reg to empty */
  while ( (inportb(comport+0x05) & 0x20) == 0x00);

  /* send character */
  outportb(comport,c);
}


int pork(int l)
{
  static int s=0,sl=0x0000,t1,asp=0,ll,k,v,b,tap,synd=0,nsy;
  static char line[200]; /* array used to format 112 bit data chunks */
  static int lc=0;	 /* pointer to position in array line	     */
  if (l == -1)
  {
/**********************************************************************/
/*  Wide Screen Output?                                               */
/**********************************************************************/
    if (wscreen == 0)
    {
/*    printf ("  %2i\n",asp); */
    }

    sl = 0x0000;
    s = 0;
    synd = 0;
    if ((asp <12) && (lc > 50))
    {
      ll = 12 - asp;
      for (ll=0; ll<6; ll++)
      {
	v = 0;
	for (k=7; k>=0; k--)
	{
	  b = line[ (ll<<3) +k ];
	  v = v << 1;
	  if ( b == 49) v++;
	}
	ob[obp] = (char) v;
	if (obp < 999) obp++;
      }
    }
    lc = 0;
    tap = asp;
    asp = 0;
    return(tap);
  }
  else
  {
    s++;
    if (s==1)
    {
      line[lc] = (char) l;
      lc++;
    }

    /* update sliding buffer */
    sl = sl << 1;
    sl = sl & 0x7fff;
    if (l == 49) sl++;

    if (s >1)
    {
      s = 0;

      if ((sl & 0x2000) > 0) t1 = 1; else t1 = 0;
      if ((sl & 0x0800) > 0) t1^=1;
      if ((sl & 0x0020) > 0) t1^=1;
      if ((sl & 0x0002) > 0) t1^=1;
      if ((sl & 0x0001) > 0) t1^=1;

      /* attempt to identify, correct certain erroneous bits */

      synd = synd << 1;
      if (t1 == 0)
      {
	asp++;
	synd++;
      }
      nsy = 0;

    /* Corrected per arron5@geocities.com 02/08/97 */
      if ( (synd & 0x0001) > 0) nsy++;
      if ( (synd & 0x0002) > 0) nsy++;
      if ( (synd & 0x0010) > 0) nsy++;
      if ( (synd & 0x0040) > 0) nsy++;
      /* assume bit is correctable */
      if ( nsy >= 3)
      {
	printf ("*");
	nuline=1;
	synd = synd ^ 0x53;
	line[lc - 7] ^= 0x01;
      }


    }

  }
  return(0);
}

void shob()
{
  int i1,i2,j1,j2,k1;

  if (nuline==1)
  {
    printf("\n");
    nuline=0;
  }
  /* update file output buffer */
  i1 = obp / 18;
  if ( (obp-(i1*18)) > 0) i1++;
  fob[fobp] = (char) (i1 & 0xff);
  if (fobp < 29999) fobp++;
  for (i2 = obp; i2<=(obp+20); i2++) ob[i2] = 0;
  for (j1 = 0; j1 < i1; j1++)
  {
    for (j2 = 0; j2 < 18; j2++)
    {
      k1 = j2 + (j1*18);

/**********************************************************************/
/*  Wide Screen Output?                                               */
/**********************************************************************/
      if (wscreen == 0)
      {
        printf("%02X ", ob[k1] & 0xff);
      }

      fob[fobp] = (char) (ob[k1] & 0xff);
      if (fobp < 29999) fobp++;
    }

/**********************************************************************/
/*  Wide Screen Output?                                               */
/**********************************************************************/
      if (wscreen == 0)
      {
        printf ("    ");
      }

    for (j2 = 0; j2 < 18; j2++)
    {
      k1 = j2 + (j1*18);
      if (ob[k1] >=32) printf("%c",ob[k1]); else printf(".");

/**********************************************************************/
/*  Copy each byte to the comport if requested                        */
/*  but only if its decimal ascii equivalent is within the following  */
/*  printable ranges:                                                 */
/*                                                                    */
/*    010 - 010                                                       */
/*    013 - 013                                                       */
/*    032 - 122                                                       */
/*                                                                    */
/*  Otherwise, send a period.                                         */
/*                                                                    */
/**********************************************************************/

      if (comout == 1)
      {
        if (ob[k1] == 10)
        {
          send_char(ob[k1]);
        }
        else
	{
	  if (ob[k1] == 13)
	  {
	    send_char(ob[k1]);
	  }
	  else
	  {
	    if ((ob[k1] >= 32) && (ob[k1] <= 122)) send_char(ob[k1]);else send_char( (char) 46 );
       	  }
	}
      }
    }
/**********************************************************************/
/*  Wide Screen Output?                                               */
/**********************************************************************/
    if (wscreen == 0)
    {
      printf("\n");
    }

  }

  obp=0;
  printf("\n");
  printf("BUFFER: %3i percent full\n",(int)(fobp/299.0));

/**********************************************************************/
/* After sending data for this burst, send a carriage return/linefeed */
/* and then reset the com port for receiving the next data burst.     */
/**********************************************************************/

  if (comout == 1)
  {
     send_char( (char) 10 );
     send_char( (char) 13 );
     set8250(baudrate);
  }
}

/**********************************************************************/
/*                      frame_sync                                    */
/**********************************************************************/
/* this routine recieves the raw bit stream and tries to decode it    */
/* the first step is frame synchronization - a particular 40 bit      */
/* long sequence indicates the start of each data frame. Data frames  */
/* are always 112 bits long. After each 112 bit chunk this routine    */
/* tries to see if the message is finished (assumption - it's finished*/
/* if the 40 bit frame sync sequence is detected right after the end  */
/* of the 112 bit data chunk). This routine also goes back to hunting */
/* for the frame sync when the routine processing the 112 bit data    */
/* chunk decides there are too many errors (transmitter stopped or    */
/* bit detection routine skipped or gained an extra bit).	      */
/*                                                                    */
/* inputs are fed to this routine one bit at a time                   */
/* input : 48 - bit is a zero                                         */
/*         49 - bit is a 1                                            */

void frame_sync(char gin)
{
  static unsigned int s1=0,s2=0,s3=0,nm,j,t1,t2,t3,ns=0,st=0,n,m,l,chu=0,eef=0;
  static char ta[200];

  if (st == 1)
  {
    ta[ns] = gin;
    ns++;
    if (ns >= 112)   /* process 112 bit chunk */
    {
      chu++;
      ns = 0;
      for (n= 0; n<16; n++)
      {
	for (m=0; m<7; m++)
	{
	  l = n + (m<<4);
	  pork(ta[l]);
	}
      }
      if (pork(-1) > 20) eef++; else eef=0;
      if (eef > 1)  /* if two consecutive excess error chunks - bye  */
      {
	st = 0;
	shob();
	eef = 0;
      }
/*      else eef = 0; */
    }
  }

    /* s1,s2,s3 represent a 40 bit long buffer */
    s1 = (s1 << 1) & 0xff;
    if ((s2 & 0x8000) > 0) s1++;
    s2 = (s2 << 1);
    if ((s3 & 0x8000) > 0) s2++;
    s3 = (s3 << 1);
    if (gin == 49) s3++;

    /* xor with 40 bit long sync word */
    t1 = s1 ^ 0x0007;
    t2 = s2 ^ 0x092A;
    t3 = s3 ^ 0x446F;

    /* find how many bits match up */
    /* currently : the frame sync indicates system id / idling / whatever */
    /*        inverted frame sync indicates message follows             */
    nm = 0;
    for (j=0; j<16; j++)
    {
      if (t1 & 1) nm++;
      if (t2 & 1) nm++;
      if (t3 & 1) nm++;
      t1 = t1 >> 1;
      t2 = t2 >> 1;
      t3 = t3 >> 1;
    }

    if (nm <  5)
    {
      st = 1;
      ns = 0;
    }
    else if (nm > 35)
    {
      if (st==1)
      {
	shob();
      }
      st = 0;
      ns = 0;
    }
}

/************************************************************************/
/*                         DISPLAY HELP SCREEN
*/
/************************************************************************/
void help()
{
  printf("\n  MDTW1234 Revision B MDC4800 monitoring program\n");
  printf("     Command line argument summary\n\n");
  printf("  /COM:y      - set y = 1,2,3,4 to set com port you want to use.\n");
  printf("  /RE         - reverse input polarity of incoming data.\n");
  printf("  /WS         - remove hex display from screen output and use\n");
  printf("                the additional room for more character output.\n");
  printf("  /WF         - remove hex display and newline characters from the output\n");
  printf("                file making it more suitable for keyword searches.\n");
  printf("  /H          - produces this help screen.\n");
  printf("  /?          - ditto.\n");

  printf("\nExample: MDTW1234 /COM:2 /WS /RE\n");
  printf("         will use reversed input from COM2 and produce wide screen output.\n");
  printf("\n Interface requirements: Hamcomm type data slicer circuit.\n");
  printf("\n See README file for further details...\n\n");
  printf(" press any key to continue...\n");
  getch();
}

void main (int argc, char **argv)
{
  unsigned int n,i=0,j,k,l,cw1=49,cw0=48;

  FILE *out;
  char s=48;
  double pl,dt,exc=0.0,clk=0.0,xct;

  for (n=1; n<argc; n++)
  {
    strcpy(temp,argv[n]);
    strupr(temp);
    j+=sscanf(temp,"/COM:%i",&sport);

    if (temp[1] == 'O' && temp[2] == 'U' && temp[3] == 'T')
    {
      printf ("Intercept Output Enabled.\n");
      comout = 1;
    }

    if (temp[1] == 'W' && temp[2] == 'S')
    {
      printf ("Wide Screen Output Selected.\n");
      wscreen = 1;
    }

    if (temp[1] == 'W' && temp[2] == 'F')
    {
      printf ("Wide File Output Selected.\n");
      wfile   = 1;
    }

    if (temp[1] == 'R' && temp[2] == 'E')
    {
      printf ("Reverse Polarity.\n");
      cw1 = 48;
      cw0 = 49;
    }

    if (temp[1] == 'H') lassie=1;

    if (temp[1] == '?') lassie=1;

  }


  if ( lassie == 1) help();

  if (sport > 4) { sport = 4;  }
  if (sport < 1) { sport = 1;  }

  printf("Checking for data coming in on COM%i... \n",sport);

    /* dt is the number of expected clock ticks per bit */
  dt =  1.0/(4800.0*838.8e-9);

     /* set up items related to serial port                                */
  n = inportb (0x21);
  if ( (sport == 1) | (sport == 3))
  {
    irqv = 0x0c;
    oldfuncc = getvect(irqv);    /* save COM  Vector                    */
    setvect (irqv, comint);     /* 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, comint);     /* Capture COM  vector                 */
    outportb(0x21, n & 0xf7);
    if (sport == 2) comport = 0x2f8; else comport = 0x2e8;
  }

  /* set up comport offsets for other code */
  comport8 = comport + 0x00;
  comport9 = comport + 0x01;
  comporta = comport + 0x02;
  comportb = comport + 0x03;
  comportc = comport + 0x04;
  comportd = comport + 0x05;
  comporte = comport + 0x06;


  set8253();                   /* set up 8253 timer chip              */

  set8250(baudrate);           /* set up 8250 UART                    */

  while ((kbhit() == 0) && (fobp<29900))
  {
   if (i != cpstn)
   {
    if  ( ( fdata[i] & 0x8000) != 0) s = cw1; else s = cw0;

    /* add in new number of cycles to clock  */
    clk += (fdata[i] & 0x7fff);
    xct = exc + 0.5 * dt;  /* exc is current boundary */
    while ( clk >= xct )
    {
      frame_sync(s);
      clk = clk - dt;
    }
    /* 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.020*(clk - exc);

    i++;
    if( i >buflen) i = 0;
   }

  }

  outportb (0x21, n);          /* disable IRQ interrupt              */
  setvect (irqv, oldfuncc);    /* restore old COM Vector             */


  /* save captured data to disk file	*/
  i = 0;
  out = fopen("data.dat","wt");
  if (out == NULL)
  {
    printf ("couldn't open output file.\n");
    exit(1);
  }

  i = 0;
  while ( (i < fobp) && (i < 29800))
  {
    j = ((int)fob[i] & 0xff);
    i++;
    for (k=0; k<j; k++)
    {
/************************************************************************/
/*  This produces Narrow File Output                                    */
/************************************************************************/
      if (wfile == 0)
      {
        for (l=0; l<18; l++)
        {
          fprintf(out,"%02X ",((int) fob[i + l]&0xff));
        }
        fprintf(out,"    ");
        for (l=0; l<18; l++)
        {
          	n = ((int)fob[i]&0xff);
          	i++;
          	if (n >=32) fprintf(out,"%c",n); else fprintf(out,".");
        }
        fprintf(out,"\n");
      }

/************************************************************************/
/*  This produces Wide File Output                                      */
/************************************************************************/
      if (wfile == 1)
      {
        for (l=0; l<18; l++)
        {
          	n = ((int)fob[i]&0xff);
          	i++;
          	if (n >=32) fprintf(out,"%c",n); else fprintf(out,".");
        }
      }

    }

/************************************************************************/
/*  Extra linefeed here for narrow file output                          */
/************************************************************************/
    if (wfile == 0)
    {
      fprintf(out,"\n");
    }
  }
  fclose(out);
}


syntax highlighted by Code2HTML, v. 0.9.1