#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <time.h>
#include <string.h>
#include <graphics.h>

#include "uart.h" /* UART.ASM driver's definitions */

#include "svga256.h"

#define FFTbins 32

int DisplayRowStartX=0;
int DisplayRowStartY=2;
int DisplayRowLength=320;
int DisplayRowSepar=FFTbins+1;
int DisplayRows=6;

int DisplayCurrRow=0;
int DisplayCurrPos=0;

#define ColorLevels 4
int ColourPalette[ColorLevels] = { BLACK, DARKGRAY, LIGHTGRAY, WHITE };
/*
#define ColorLevels 8
int ColourPalette[ColorLevels] = { BLACK, BLUE, CYAN, GREEN, LIGHTCYAN, LIGHTRED, YELLOW, WHITE };
*/

void PlotFFTbatch(unsigned char *batch)
{ int chan,x,y,color;
  x=DisplayRowStartX+DisplayCurrPos;
  y=DisplayRowStartY+DisplayRowSepar*DisplayCurrRow;
  for(chan=FFTbins-1; chan>=0; chan--)
  { /* color=batch[chan]>>6; */ /* if(color>=ColorLevels) color=ColorLevels-1; */
    /* color=ColourPalette[color]; */
    color=batch[chan]; putpixel(x,y++,color); }
  DisplayCurrPos=x-DisplayRowStartX+1;
  if(DisplayCurrPos>=DisplayRowLength)
    { DisplayCurrPos=0; DisplayCurrRow+=1;
      if(DisplayCurrRow>=DisplayRows) DisplayCurrRow=0; }

  x=DisplayRowStartX+DisplayCurrPos;
  y=DisplayRowStartY+DisplayRowSepar*DisplayCurrRow;
  setcolor(255); line(x,y,x,y+FFTbins-1);
}

/* this routine will be executed in case of Ctrl-Break */
int CtrlBreakHandler(void)
{
  closegraph();	/* we close graphics so the screens comes back to the text mode */
  UartClose(); /* we close the serial port, so the IRQ is disabled and unchained */
  printf("\nYou pressed Ctrl-C or Ctrl-Break\nbut have you tried other keys ?\n");
  return(0);
}

unsigned char BatchData[FFTbins+1];

int RxBatch(void)
{ int len;
  len=UartRxSeekTerm('\0');
  if(len)
  { if(len==(FFTbins+1)) { UartRxBlock(BatchData,len,1); return 0; }
    if(len<(FFTbins+1)) { UartRxBlock(BatchData,len,1); return 2; }
    len-=(FFTbins+1);
  } else
  { len=UartRxReady()-FFTbins; }
  if(len>0)
    { if(len>FFTbins) len=FFTbins; UartRxBlock(BatchData,len,1); return 2; }
  return 1;
}

unsigned int UartSpeed=19200;
int UartBase=0x3f8;
int UartIrq=4;

main(int argc, char *argv[])
{ int err; int driver,mode; int key,color; clock_t Start;

printf("\n\
Display program for the FFT-CW noise filter\n\
(c) 1996 Pawel Jalocha\n\n\
");

if(argc==2)
{ if(stricmp(argv[1],"com1")==0) { UartBase=0x3f8; UartIrq=4; }
  else if(stricmp(argv[1],"com2")==0) { UartBase=0x2f8; UartIrq=3; }
  else if(stricmp(argv[1],"com3")==0) { UartBase=0x3e8; UartIrq=4; }
  else if(stricmp(argv[1],"com4")==0) { UartBase=0x2e8; UartIrq=3; }
  else { printf("Invalid COM port specified: %s\n",argv[1]); return(1); }
}
else if(argc==3)
{
  if(sscanf(argv[1],"%x",&UartBase)!=1) { printf("Invalid UART base address\n"); return 1; }
  if(sscanf(argv[2],"%d",&UartIrq)!=1) { printf("Invalid UART IRQ\n"); return 1; }
}
else
{ printf("\
Usage: fft-cw <com1|com2|com3|com4>  like: fft-cw com1\n\
   or: fft-cw <base>[hex] <irq>[dec]  like: fft-cw 2f8 3\n");
  return(1);
}

err=UartOpen(UartDivisor(UartSpeed),UartBase,UartIrq);
if(err) { printf("UART base address [%3x] or IRQ [%d] are out of the allowed range\n",UartBase,UartIrq); return 1; }

/* driver=VGA; mode=VGAHI; */
driver=installuserdriver("SVGA256",NULL);
mode=SVGA320x200x256;
initgraph(&driver,&mode,"");
if(graphresult())
{ closegraph();
  printf("\
Something went wrong with graphics: this program needs a VGA graphics card\n\
and the SVGA256.BGI driver being present in the current directory\n");
UartClose(); return 1;
}

for(color=0; color<256; color++)
  setrgbpalette(color,color>>2,color>>2,color>>2);

ctrlbrk(CtrlBreakHandler);

Start=clock();
while(!kbhit())
{ int chan;

err=RxBatch();
if(err==0) PlotFFTbatch(BatchData);

/* delay(40);
for(chan=0; chan<FFTbins; chan++) BatchData[chan]=(char)rand();
for(chan=0; chan<FFTbins; chan++) BatchData[chan]=(chan*(FFTbins-chan))/5;
PlotFFTbatch(BatchData);
*/

}
key=getch();

closegraph(); UartClose();
return 0;
}
