
/*                      Filename: tw523.c
               ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
               º     TW523 Control Program      º
               º      for an IBM PC Clone       º
               º        driver software         º
               º      Jonathan M. Chattin       º
               ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
*/
#include <dos.h>

int pindx = 0;                          /* port index */
int pbase = 0;                          /* base of port */
int zero = 0;                           /* zero crossing flag */
int rdtmr = 0;                          /* read timer address */

/* transmit translation table */
int tbltx[] =   {0x6,0x7,0x4,0x5,0x8,0x9,0xa,0xb,
                0xe,0xf,0xc,0xd,0x0,0x1,0x2,0x3};

/* receive translation table */
int tblrx[] =   {0xc,0xd,0xe,0xf,0x2,0x3,0x0,0x1,
                0x4,0x5,0x6,0x7,0xa,0xb,0x8,0x9};

int tw523ok(int index)
{
  int i, zcnt;
  int far *ptable;


  if((index < 0)||(index > 6))          /* ensure valid index */
    return(-1);
  pindx = index;                        /* assign global */
  if(atorxt() != 0)                     /* must find read timer */
    return(-2);
  ptable =  MK_FP(0, 0x400);            /* get port table pointer */
  pbase = ptable[pindx];                /* get base */
  if(pbase == 0)                        /* invalid port */
    return(-3);

  if(pindx < 4)
    outportb(pbase + 4, 1);             /* init RS232 signals */
  else
  {
    outportb(pbase, 0);                 /* init parallel signals */
    outportb(pbase + 2, 0);
  }

  for(i = 0; i < 250; i++)              /* delay for power-up */
    dly1000();

  testz();                              /* clear status */
  for(zcnt = 0, i = 0; i < 20; i++)     /* in 20 ms */
  {
    dly1000();
    if(testz())                         /* should be 2 or 3 zero xings */
      zcnt++;
  }

  if((zcnt != 2) && (zcnt != 3))        /* 2 or 3 zero xings ? */
    return(-4);                         /* oops no tw523 there */

  testz();                              /* clear status */
  disable();
  while(testz() == 0);                  /* wait for zero xing */
  for(i = 0; i < 7; i++)                /* check duty cycle */
    dly1000();                          /* wait 7ms */
  if(testz())                           /* better not be zero xing */
  {
    enable();
    return(-5);                         /* oops bad tw523 there */
  }
  dly1000();                            /* delay 2.6 more ms */
  dly1000();
  dly0600();
  if(!testz())                          /* better be zero xing */
  {
    enable();
    return(-6);                         /* oops bad tw523 there */
  }
  enable();

  return(0);                            /* yes, all is fine */
}

sendx10(int house, int unfu)
{
  int i;

  for(i = 0; i < 2; i++)                /* send transmissions 2x */
  {
    send1();
    send1();
    send1();
    send0();

    sendb(house & 0x1);
    sendb(house & 0x2);
    sendb(house & 0x4);
    sendb(house & 0x8);

    sendb(unfu  & 0x1);
    sendb(unfu  & 0x2);
    sendb(unfu  & 0x4);
    sendb(unfu  & 0x8);
    sendb(unfu  & 0x10);
  }
  waitz();                              /* always wait a bit */
  waitz();
  waitz();
  waitz();
  waitz();
  waitz();

}

int recvx10(int *house, int *unfu)      /* receive a code if available */
{
  int i;

  if(!recvh())                          /* check for sync */
    return(1);                          /* no, quit */
  if(!recvh())                          /* check for sync */
    return(-1);                         /* no, quit */
  for(i = 0; i < 3; i++)                /* prevent endless loop */
  {
    if(recvh() == 0)                    /* wait for sync done */
      break;
  }
  if(i == 3)                            /* if in loop too long */
    return(-2);

  *house = 0;                           /* init return values */
  *unfu  = 0;
  *house |= recvb() ? 0x1 : 0 ;
  *house |= recvb() ? 0x2 : 0 ;
  *house |= recvb() ? 0x4 : 0 ;
  *house |= recvb() ? 0x8 : 0 ;
  *unfu |= recvb() ? 0x1 : 0 ;
  *unfu |= recvb() ? 0x2 : 0 ;
  *unfu |= recvb() ? 0x4 : 0 ;
  *unfu |= recvb() ? 0x8 : 0 ;
  *unfu |= recvb() ? 0x10: 0 ;
  return(0);                            /* mark valid reception */
}

sendb(int bit)                          /* send a full bit */
{
  if(bit)
  {
    send1();
    send0();
  }
  else
  {
    send0();
    send1();
  }
}

send1()                                 /* send a half bit 1 */
{
  if(pindx < 4)                         /* if serial */
  {
    disable();
    waitz();
    outportb(pbase + 4, 3);
    dly1000();
    outportb(pbase + 4, 1);
    dly1778();
    outportb(pbase + 4, 3);
    dly1000();
    outportb(pbase + 4, 1);
    dly1778();
    outportb(pbase + 4, 3);
    dly1000();
    outportb(pbase + 4, 1);
    enable();
  }
  else                                  /* if parallel */
  {
    disable();
    waitz();
    outportb(pbase, 0xff);
    dly1000();
    outportb(pbase, 0x00);
    dly1778();
    outportb(pbase, 0xff);
    dly1000();
    outportb(pbase, 0x00);
    dly1778();
    outportb(pbase, 0xff);
    dly1000();
    outportb(pbase, 0x00);
    enable();
  }
}

send0()                                 /* send a half bit 0 */
{
  waitz();
}

int recvb()                             /* receive full bit */
{
  int   retc;

  retc = recvh();                       /* get bit value */
  waitz();                              /* discard next half bit */
  return(retc);
}

int recvh()                             /* get the half bit on the line */
{
  int retc;

  disable();
  waitz();
  dly0600();
  retc = samprcv();
  enable();
  return(retc);
}

int samprcv()                           /* sample the half bit on the line */
{
  if(pindx < 4)
  {
    if(inportb(pbase + 6) & 0x10)
      return(1);
    else
      return(0);
  }
  else
  {
    if(inportb(pbase + 2) & 0x02)
      return(1);
    else
      return(0);
  }
}

waitz()                                 /* wait for zero xing */
{
  while(!testz());
}

int testz()                             /* test for zero xing */
{
  int temp;

  if(pindx < 4)
    return((inportb(pbase + 6) & 2) ? 1 : 0);
  else
  {
    temp = zero;                        /* remember previous zero */
    zero = inportb(pbase + 2) & 0x08;   /* get new zero */
    return((zero ^ temp) ? 1 : 0);
  }
}

int atorxt()                            /* find terminal count bit */
{
  int x, i, j;

  x = inportb(0x61);
  x = (x & 0xfc) | 0x01;
  outportb(0x61, x);                    /* enable gate disable speaker */
  outportb(0x43, 0xb6);                 /* set mode */
  outportb(0x42, 0x00);                 /* set time constant */
  outportb(0x42, 0x01);

  for(rdtmr = 0x61; rdtmr <= 0x62; rdtmr++)
  {
    x = inportb(rdtmr) & 0x20;
    for(j = 0, i = 0; i < 1000; i++)
    {
      if(x == (inportb(rdtmr) & 0x20))
        continue;                       /* no change in bit */
      x ^= 0x20;
      j++;
    }
    if(j >= 4)                          /* if 4+ transitions */
      return(0);                        /* found correct bit */
  }
  return(-1);                           /* timer read not found */
}

dly0600()                               /* delay 0.600ms        */
{
  int x;

  x = inportb(0x61);
  x = (x & 0xfc) | 0x01;
  outportb(0x61, x);                    /* enable gate disable speaker */
  outportb(0x43, 0xb0);                 /* set mode */
  outportb(0x42, 0xac);                 /* set time constant */
  outportb(0x42, 0x02);
  while((inportb(rdtmr) & 0x20) == 0);
}

dly1000()                               /* delay 1ms    */
{
  int x;

  x = inportb(0x61);
  x = (x & 0xfc) | 0x01;
  outportb(0x61, x);                    /* enable gate disable speaker */
  outportb(0x43, 0xb0);                 /* set mode */
  outportb(0x42, 0x89);                 /* set time constant */
  outportb(0x42, 0x04);
  while((inportb(rdtmr) & 0x20) == 0);
}

dly1778()                               /* delay 1.778ms        */
{
  int x;

  x = inportb(0x61);
  x = (x & 0xfc) | 0x01;
  outportb(0x61, x);                    /* enable gate disable speaker */
  outportb(0x43, 0xb0);                 /* set mode */
  outportb(0x42, 0x29);                 /* set time constant */
  outportb(0x42, 0x08);
  while((inportb(rdtmr) & 0x20) == 0);
}



