/*
RS232:
2	TXDATA	uit
3	RXDATA	in
4	RTS	uit
5	CTS	in
6	DSR	in
7	GND
8	DCD	in
20	DTR	uit
22	RI	in
*/

/*             
'De eerste keer status bit TSA5511 lezen na POR: MSB is altijd=1??
'Waarom is niet in Philips doc te vinden

'-IIC<--> LPT1 Base=378,
'        PC-lezen: Base+1 bit7&3 Bit3=SCL Bit3=SDA
'        PC-schrijven: Base bit7 Geinverteerd! =SDA
'                      Base+2 bit3 NIET geinverteerd! =SCL
' na PC-POR en boot staat er op I/O &H379  47 decimaal
' Op iic hardware na boot:SCL=1,SDA=0
'bij "call i2csetscl" direct gevolgd door "call i2cclearscl" wordt
'op 486-dx50/2 een puls van 20us breed geleverd.

*/

/*                
     byte2: 64   32   16   8    4    2   1
 deeltal: 16384+8192+4096+2048+1024+512+256+128+64+32+16+8+4+2+1
     byte3:                                 128 64 32 16 8 4 2 1
*/

#define M_DS 0x2A    /* masker set data   (was:  42=2A=0010 1010) */
#define M_DC 0xAA    /* masker clear data (was: 170=AA=1010 1010 */
#define M_CS 0xEC    /* masker set clock   (was: 236=EC=1110 1100) */
#define M_CC 0xE4    /* masker clear clock (was: 228=E4=1110 0100) */
#define M_DR 0x80    /* masker data read */
#define M_CR 0x08    /* masker clock read */

/* Basisroutines serieel lezen/schrijven */
i2csetscl(port)   { delay(1); outportb(port+2,M_CS); delay(1); }
i2cclearscl(port) { delay(1); outportb(port+2,M_CC); delay(1); }
i2csetsda(port)   { delay(1); outportb(port,M_DS);   delay(1); }
i2cclearsda(port) { delay(1); outportb(port,M_DC);   delay(1); }

/* start en stop */
i2cstart(int port)
{
  i2csetsda(port);       /* definieer begintoestand */
  i2csetscl(port);       /* definieer begintoestand */
  i2cclearsda(port);     /* Genereer start conditie */
  i2cclearscl(port);     /* klok laag */
}

/* einde */
i2cstop(int port)
{
  i2cclearsda(port);        /* maak SDA laag */
  i2csetscl(port);
  i2csetsda(port);          /* =stop conditie */
}

/* lees byte van port */
int i2cgetbyte(int port)
{
  int n;
  int i,byte = 0;        /* initialize */
  for (i=7; i>=0; i--)    /* 'msb first! */
  {
    i2csetscl(port);
    n=inportb(port+1);
    if (n & M_DR) byte+=(1<<i);
    i2cclearscl(port);
  }
  return byte;
}

/* zend byte en ontvang bevestiging */
int i2csendbyte(int port,int trbyte)
{
  int ack,i;
  for (i=7; i>=0; i--)                   /* MSB's first */
  {
    if (!(trbyte & (1<<i))) 
      i2cclearsda(port);
    else
      i2csetsda(port);                   /* data bit staat nu op output */
    i2csetscl(port);                     /* genereer klokpuls */
    i2cclearscl(port);
  }

/* data transfer compleet, nu acknowledge ontvangen: */
  i2csetsda(port);          /* SDA=1 : High-Z */
  i2csetscl(port);          /* slave moet nu antwoorden met acknowledge */
  ack = inportb(port+1);
  delay(1);
  i2cclearscl(port);        /* einde klokpuls */
  if (ack & M_DR) return 1; /* error; no acknowledge */
  return 0;
}

int write_freq(int port,int deeltal,int tunertype)
{
  int b2,b3;
  int sel_ttype;
  if (tunertype==5510) sel_ttype=0x60;
  else                 sel_ttype=0xe0;
  b2=(deeltal>>8);
  b3=(deeltal&0xff);
  if (i2csendbyte(port,b2)) return 2;
  if (i2csendbyte(port,b3)) return 3;
  if (i2csendbyte(port,0x8e)) return 4;      /* control info byte4 */
  if (i2csendbyte(port,sel_ttype)) return 5; /* control byte5: LOW-BAND op TSA5510/11 */
  i2cstop(port);
  return 0;
}

int lees_status(int port)
{
  int status;
  i2cstart(port);
  if (i2csendbyte(port,195)) return 1;        /* dit is LEESadres TSA5510 (schrijfadres +1) */
  status=i2cgetbyte(port);
  i2csetsda(port);              /* SDA:1 = no acknowledge */
  i2csetscl(port);              /* generate transmit klokpuls */
  i2cclearscl(port);            /* 0->1->0 flank */
  i2cstop(port);
  return status;
}

/* Hoofdroutine freq. instellen.
   ret=0 ==> ok
   ret=1 ==> Fout
*/
int set_freq(int port,int deeltal,int tunertype)
{
  int cnt=0;
  int status;
  if (status=write_freq(port,deeltal,tunertype)) return status;
/* wacht op lock */
  do
  {
/* Status byte van TSA5510 lezen */
    status=lees_status(port);
    if (status == 72) return 0;   /* ok */
    cnt++;
  } while (cnt<25);
  return 1;                       /* niet ok */
}
/* ================================================= */


/* subroutines */
#include <stdio.h>
#include <string.h>
#include <math.h>

#define FSTAP 62.5      /* 62.5 Khz bij 4 MHz Xtal, 50 KHz bij 3.2 MHz Xtal */

usage(char *prog,int p,char s,float fr,float fs,int t)
{
  fprintf(stderr,"%s options\n",prog);
  fprintf(stderr,"   options:\n");
  fprintf(stderr,"     -port  <portnr>   (1, 2, 3)        default: %d\n",p);
  fprintf(stderr,"     -sat   <sat_type> (p=pdus, h=hrpt) default: %c\n",s);
  fprintf(stderr,"     -freq  <freq>     (in MHz)         default: %f\n",fr);
  fprintf(stderr,"     -fstap <stap>     (in kHz)         default: %f\n",fs);
  fprintf(stderr,"     -type  <type_TSA> (5510 or 11/12)  default: %d\n",t);
  fprintf(stderr,"     -c                check only\n");
  fprintf(stderr,"E.g. \n   %s -port 1 -sat p -freq 137.5 -fstap 62.5 -type 5510\n",prog);
  fprintf(stderr,"Check-only:\n   %s -port 1 -sat p -freq 137.5 -fstap 62.5 -type 5510 -c\n",prog);
  exit(0);
}


main(int argc,char **argv)
{
  int i;
  int port=1;
  int deeltal;
  int Fosc;
  int check=0;
  float mf;

  int bp=1;
  char ph='h';
  float freq=137.5;
  float fstap=FSTAP;
  int tunertype=5512;

  if ((argc>1) && (!strcmp(argv[1],"-h")))
    usage("zetfr",bp,ph,freq,fstap,tunertype);

  for (i=1; i<argc; i++)
  {
    if (!strcmp(argv[i],"-h"))
      usage("zetfr",bp,ph,freq,fstap,tunertype);
    if (!strcmp(argv[i-1],"-port")) bp=atoi(argv[i]);
    if (!strcmp(argv[i-1],"-sat"))  ph=tolower(argv[i][0]);
    if (!strcmp(argv[i-1],"-freq")) freq=atof(argv[i]);
    if (!strcmp(argv[i-1],"-fstap")) fstap=atof(argv[i]);
    if (!strcmp(argv[i-1],"-type")) tunertype=atoi(argv[i]);
    if (!strcmp(argv[i],"-c")) check=1;
  }

  switch(tunertype)
  {
    case 5510: break;
    case 5511: break;
    case 5512: break;
    default: fprintf(stderr,"ERROR: tunertype=%d\n",tunertype); return 1;
  }

  port=(bp==1? 0x378: bp==2? 0x278: bp==3? 0x3bc: bp<0x100? 0x378 : bp);

  switch(ph)
  {
    case 'p': mf=38.9; break;
    case 'h': mf=36.7; break;
    default:  fprintf(stderr,"ERROR: sattype=%c\n",ph); return 1;
  }
  Fosc = 10 * (freq + mf);
  deeltal = Fosc / fstap * 100;

  clrscr();
  fprintf(stderr,"Port: %x\n",port);
  fprintf(stderr,"%s, mf=%4.1f\n",(ph=='p'? "PDUS" : "HRPT"),mf);
  fprintf(stderr,"Freq=%f\n",freq);
  fprintf(stderr,"  Foscil.=%d\n",Fosc/10);
  fprintf(stderr,"  Fstep  =%f kHz\n",fstap);
  fprintf(stderr,"  (Xtal  =%f MHz\n",.064*fstap);
  fprintf(stderr,"Divide=%d\n",deeltal);
  fprintf(stderr,"Tunertype: TSA%d\n",tunertype);

  if (check)
  {
    printf("Check only:\n");
    i=lees_status(port);
    if (i==72) printf("OK: status=%d\n",i);
    else       printf("ERROR: status=%d (should be 72)\n",i);
    return 0;
  }

/* init */
  i2cstart(port);
  i2csendbyte(port,194);

  if (i=set_freq(port,deeltal,tunertype))
  {
    if (i>=2)
      fprintf(stderr,"No acknowledge: %d!\n",i);
    else
      fprintf(stderr,"Not locked!\n");
    return 1;
  }
  else
    fprintf(stderr,"In lock!");
  return 0;
}

