#include <stdio.h>
#include <dos.h>
#include <ctype.h>
#include <time.h>
#include <malloc.h>
#include <string.h>
#include <conio.h>
#include <process.h>
#include <graph.h>

/* kiss tnc routines for various  - HEP/RWM  */

int getbyte(),port,instat();
 
#define	FEND		0300	/* Frame End */
#define	FESC		0333	/* Frame Escape */
#define	TFEND		0334	/* Transposed frame end */
#define	TFESC		0335	/* Transposed frame escape */
 

#define SSIDMD	0x60
#define SSIDMS	0x61
 
unsigned char pkt[300],echo=0;
unsigned long time_out,now;
unsigned char line[336],dump=0;
unsigned char *in_buf;
FILE *dumpr,*dumpa;
union REGS inreg,outreg;
struct tm *gmt;
unsigned char satellite=4,com_str[]="COM1:9600,N,8,1",*satname[]={"PACSAT",
"DOVE","WEBER","LUSAT"},newsat=0,rawdmp[40],ascdmp[40];

struct eqn {
	unsigned char channel,name[16],units[9],ok,value;
	float a0,a1,a2;
} tlmval[80];

void asc_enab(),asc_disab();	
main(argc,argv)
int argc;
char *argv[];
{
   int ch,frame_l,i;
   long timeit,addr;
   unsigned char *buf,*bufc;
   void tlm(),status(),check_call(); 

   i=1;


   while (argv[i] != NULL) {
   	*argv[i] = toupper(*argv[i]);
   	switch(*argv[i]) {
		case 'C':{
			strcpy(com_str,argv[i]);
			break;
		}
		default : break;
	}
	i++;
    }	

   /* Set up serial port */

   setcom(com_str);
   _clearscreen(_GCLEARSCREEN);
   main_men();
   while(1) {
	if (kbhit() != 0) {
	    ch = getch();
	    ch = toupper(ch);
	    switch(ch) {
	    	case 'F':{
	    		if(dump) {
	    			dump = 0;
	    			fcloseall();
	    		}
	    		_settextwindow(1,1,25,80);
			_clearscreen(_GCLEARSCREEN);
	    		_outtext("Input raw data file to read: ");
	    		scanf("%s",rawdmp);
	    		if ((dumpr = fopen(rawdmp,"rb")) == NULL) {
	    			_outtext("\nFile Not found. Strike a key");
	    			getch();
				main_men();
	    			break;
	    		}
			_clearscreen(_GCLEARSCREEN);
			_settextposition(1,70);
			if (satellite != 4) _outtext(satname[satellite]);
			else _outtext("      ");
			_settextposition(25,55);
			_outtext("Q=Quit,space to continue");
			frame_l = 0;
 			while (frame_l != -1) {
				frame_l=dsk_frame(pkt,dumpr);
				if (frame_l < 0 ) {
					fclose(dumpr);
					_settextposition(25,55);
					while(kbhit() != 0) getch();
					_outtext("File end, strike a key  ");
					getch();
					break;
				}
				ax25r(pkt,frame_l);
				if (strstr(line,">TLM") != NULL) {
				    check_call();
				    tlm();
				} else if ((buf=strstr(line,"uptime")) != NULL) {
					_settextposition(1,1);
					_outtext(buf);
				}
				else if (strstr(line,">STATUS") != NULL) {
				    	check_call();
				    	status();
				    	frame_l = getch();
				    	if (toupper(frame_l) == 'Q') break;
				}
				if(newsat) {
					_settextposition(1,70);
			   		_outtext("       ");
					_settextposition(1,70);
			   		_outtext(satname[satellite]);
			   		newsat = 0;
				}
			}
			_clearscreen(_GCLEARSCREEN);
			main_men();
	    		break;
	    	}
	    	case 'D': {
	    		if (dump == 0) {
	    			_settextwindow(1,1,25,80);
				_clearscreen(_GCLEARSCREEN);
	    			_outtext("Input raw data dump file: ");
	    			scanf("%s",rawdmp);
	    			_outtext("\nInput ascii dump file: ");
	    			scanf("%s",ascdmp);
	    			if (((dumpr = fopen(rawdmp,"ab")) == NULL) ||
	    			   ((dumpa = fopen(ascdmp,"at")) == NULL)) {
	    			   	perror("Error opening files");
	    			   	dump = 0;
	    			} else 	dump = 1;
    			   	main_men();
			} else {
				dump = 0;
				fcloseall();
			}
			break;
		}
		case 'Q': {
			_clearscreen(_GCLEARSCREEN);
			asc_disab(port);
			fcloseall();
			exit(0);
		}
		case 'U':{
			_clearscreen(_GCLEARSCREEN);
			system("command");
			main_men();
			break;
		}
		case 'T': {
			_settextwindow(1,1,25,80);
			_clearscreen(_GCLEARSCREEN);
			_settextposition(1,70);
			if (satellite != 4) _outtext(satname[satellite]);
			else _outtext("       ");
			_settextposition(25,60);
			_outtext("Keystroke to Quit");
			do {
				if (instat(port)){
				frame_l=rec_frame(pkt);
				if (frame_l != -1) {
				  ax25r(pkt,frame_l);
				  if (dump) {
					fputs(line,dumpa);
				  }
				  if (strstr(line,">TLM") != NULL) {
				    check_call();
				    tlm();
				  } else  if (strstr(line,">STATUS") != NULL) {
				    check_call();
				    status();
				  } else if ((in_buf=strstr(line,"uptime")) != NULL) {
				    _settextposition(1,1);
				    _outtext(in_buf);
				  }
				}}
				if(newsat) {
					_settextposition(1,70);
			   		_outtext("       ");
					_settextposition(1,70);
			   		_outtext(satname[satellite]);
			   		newsat = 0;
				}
			} while (kbhit() == 0);
			if (getch() == 0) getch();
			_clearscreen(_GCLEARSCREEN);
			main_men();
			break;
		}
	     }
	}
	_settextwindow(1,1,24,80);
	do {
	   if(newsat) {
	   	_settextwindow(25,1,25,80);
	   	_settextposition(1,1);
   	        _outtext("       ");
	   	_settextposition(1,1);
   	        _outtext(satname[satellite]);
   	        _settextwindow(1,1,24,80);
   	        newsat = 0;
   	   }
	   if (instat(port) != 0) {
		_settextposition(24,1);
		frame_l=rec_frame(pkt);
		if (frame_l != -1) {
			ax25r(pkt,frame_l);
			check_call();
			_outtext(line);
			if (dump) fputs(line,dumpa);
		}
	    }
	}  while (kbhit() == 0);
    }
}

/* Decode the raw KISS frames which have been stored on DISK*/

int dsk_frame(ubuf,dat_file)
unsigned char *ubuf;
FILE *dat_file;
{
 
	int c,frame_size;
	unsigned char *buf;
 
	while((c=fgetc(dat_file)) != FEND) 
	  if (c == EOF) 
	    if (feof(dat_file)) return -1;

kludge_garb:
 
	buf=ubuf;
	
	while( (c = fgetc(dat_file)) == FEND) 
	  if (c == EOF) 
	    if (feof(dat_file)) return -1;

	c = fgetc(dat_file);  /* ignore KISS type code */
	if (c == EOF) 
	  if(feof(dat_file)) return -1;
	frame_size = 0;
	do{
		if(c == FESC){
			c = fgetc(dat_file);
			switch(c){
				case TFEND:
					*buf++ = FEND;
					frame_size++;
					break;
 
				case TFESC:
					*buf++ = FESC;
					frame_size++;
					break;
 
				default:
					break;
			}
		}
		else{
			if (c == EOF) 
			  if(feof(dat_file)) return -1;
			*buf++ = c;
			frame_size++;
		}
		c = fgetc(dat_file);
	} while( c != FEND);
 
		/* If we get a short frame becuase the main loop doesn't read
		   except after it sends a command, go and restart this frame,
		   i.e., assume that the "end" is the start of a new frame. */
 
	if (frame_size<14) goto kludge_garb;
	return frame_size;
}


/* Telemetry format routine */

static unsigned char *t;

void tlm()
{
	int a,b;
	unsigned char *print_tlm();
	if ((t=strchr(in_buf,':')) != NULL){
		t=in_buf;
	}
	else return;
	while (sscanf(t," %x:%x",&a,&b)==2) {
		_settextposition(3+(a/3),(a%3)*26+1);
		printf("%-25.25s   ",print_tlm(a,b));
		t= t+6;
	}
}

/* Decode the telemetry from the tlm table values */

static unsigned char printit[40];
unsigned char *print_tlm(chan,value)
unsigned char chan,value;
{
	float fvalue;
	struct eqn *ptr;
	
	ptr = &tlmval[chan];
	if (ptr->ok == 1) {
		ptr->value = value;
		fvalue = value;
		fvalue = fvalue * (fvalue * ptr->a2 + ptr->a1) + ptr->a0;
		sprintf(printit,"%-14.14s %7.3f %c ",ptr->name,fvalue,ptr->units[0]);
	} else *printit=0;
	return printit;
}


/* Menu routine */
main_men()
{
	_settextwindow(25,1,25,80);
	_clearscreen(_GCLEARSCREEN);
	if (satellite != 4) {
		_settextposition(25,1);
		_outtext(satname[satellite]);
	}
	_settextposition(1,10);
	_outtext("D = Toggle Dump, T = Tlm Decode, F = Decode File, Q = Quit");
	_settextwindow(1,1,24,80);
}

/* Decode the status line from the telemetry */

void status()
{
	int tx,txp,bcr,sb;
	_settextposition(25,1);
	switch (satellite) {
		case 0: {
			sscanf(&in_buf[9]," %2X",&bcr);
			sscanf(&in_buf[18]," %2X",&txp);
			sscanf(&in_buf[21]," %2X",&tx);
			sscanf(&in_buf[27]," %2X",&sb);
			sprintf(line,"TXA:%1u TXB:%1u TX Pwr:%1X SbT:%1X BCR:%2X",
					1^(tx&1),1^((tx&2)>>1),txp&0xF,(sb>>7)^1,bcr);
			_outtext(line);
			break;
		}
		case 1 :{
			sscanf(&in_buf[9]," %2X",&bcr);
			sscanf(&in_buf[18]," %2X",&txp);
			sscanf(&in_buf[21]," %2X",&tx);
			sscanf(&in_buf[27]," %2X",&sb);
			sprintf(line,"TXA:%1u TXB:%1u TX Pwr:%1X SbT:%1X BCR:%2X",
				(tx&1),((tx&2)>>1),txp&0xF,(sb>>7)^1,bcr);
			_outtext(line);
			break;
		}
		case 2: {
			sscanf(&in_buf[9]," %2X",&bcr);
			sscanf(&in_buf[18]," %2X",&txp);
			sscanf(&in_buf[21]," %2X",&tx);
			sprintf(line,"TXA:%1u TXB:%1u TX Pwr:%1X, BCR:%2X",
				1^(tx&1),1^((tx&2)>>1),txp&0xF,bcr);
			_outtext(line);
			break;
		}
		case 3: {
			sscanf(&in_buf[9]," %2X",&bcr);
			sscanf(&in_buf[18]," %2X",&txp);
			sscanf(&in_buf[21]," %2X",&tx);
			sprintf(line,"TXA:%1u TXB:%1u TX Pwr:%1X, BCR:%2X",
				1^(tx&1),1^((tx&2)>>1),txp&0xF,bcr);
			_outtext(line);
			break;
		}
	}
}

/* Make sure we are decoding with the correct equations, if not, then
   read in the appropriate file */
   
void check_call()
{
	FILE *tlm_dat;
	unsigned char tmpsat,tlmline[81];
	struct eqn *ptr;
	for(tmpsat=0;tmpsat<4;tmpsat++) {
	  if(strstr(line,satname[tmpsat]) != NULL) {
	    if (tmpsat != satellite) {
		satellite = tmpsat;
		newsat = 1;
		if((tlm_dat=fopen(satname[tmpsat],"rt")) == NULL) {
			puts("OOPS, you forgot to leave those files around!");
			fcloseall();
			exit(0);
		}
		tmpsat = 0;
		memset(tlmval,0,80*sizeof(tlmval[0]));
		while (fgets(tlmline,80,tlm_dat) != NULL) {
			ptr = &tlmval[tmpsat++];
			sscanf(tlmline," %X",&ptr->channel);
			strncpy(ptr->name,&tlmline[6],15);
			*(strchr(ptr->name,':')) = 0;
			ptr->name[15]=0;
			sscanf(&tlmline[21]," %f",&ptr->a0);
			sscanf(&tlmline[34]," %f",&ptr->a1);
			sscanf(&tlmline[46]," %f",&ptr->a2);
			sscanf(&tlmline[59],"%7s",ptr->units);
			ptr->units[8]=0;
			ptr->ok=1;
		}
		fclose(tlm_dat);
	     }
	     return;
	  }
	}
}


/* Horrible AX.25 handler, receive only */

ax25r(frame,framel)
unsigned char *frame;
int framel;
{
  unsigned char *buf,*bufc,lineptr=0;
  int i,j,k,endadr=0;

  buf = bufc = frame;
  buf[framel]=0;
  /* Find the end of the address field */
  do {

  /* Fix up addresses and SSID's into readable form */

    /* Pick off the ssid from the shit in byte 7 of each address */
    
    k = bufc[6]&1;
    bufc[6] = ((bufc[6] >> 1) & 0x0F);
    if (bufc[6] < 10) bufc[6] += '0';
    else bufc[6] += 'A'-10;

    /* Shift the bits where they belong in each character of the
       address */

    for(i=0;i<6;i++) {
      bufc[i] >>= 1;
    }
    bufc += 7;
    endadr++;
  }  while ( k == 0);

  /* Output header line */

  /* For each callsign field */

    /* Output a dash, SSID, and arrow pointing to direction, screw
       the heard/digipeated bit */

    bufc = &buf[7];
    for(j=0;j<6;j++) line[lineptr++] = bufc[j];
    line[lineptr++] ='-';
    line[lineptr++] = buf[13];
    line[lineptr++] ='>';
    for(j=0;j<6;j++) line[lineptr++] = buf[j];
    line[lineptr++] ='-';
    line[lineptr++] = buf[6];
    line[lineptr++]=' ';
/*    line[lineptr++]='V';
    line[lineptr++]=' ';*/
    /* Output the call and SSID of repeaters */
/*    for(i=endadr-1,bufc=buf+(endadr-1)*7;i>=2;i--,bufc -= 7) {
	for(j=0;j<6;j++) line[lineptr++] =bufc[j];
    	line[lineptr++] = '-';
    	line[lineptr++] = bufc[6];
    	line[lineptr++] = ' ';
    }
  line[lineptr++] = ' ';*/
  /* Is it a U frame, I frame, or S frame ? */
  buf = frame + 7*endadr;
  switch((*buf) & 0x1) {
  case 0 : { /* It is an I frame */
    while ((bufc=strchr(&buf[2],'\r')) != NULL) *bufc = '\n';
    sprintf(&line[lineptr],"NR=%1u P/F=%1u NS=%1u PID=%2X\n%s",
    	     (unsigned) (((*buf)&0xE0)>>5),
	     (unsigned) (((*buf)&0x10)>>4),
	     (unsigned)(((*buf)&0xF)>>1),
	     (unsigned) buf[1],&buf[2]);
	     bufc = &line[strlen(line)-1];
	     if (*bufc != '\n') {
	     	*(bufc+1) = '\n';
		*(bufc+2) = 0;
	     }
    break;
  }
  case 1: {
    switch( (*buf) & 0x2) {
    case 0: {
      switch ((*buf) & 0xC) {
      case 0: {
	sprintf(&line[lineptr],"RR NR=%1u P/F=%1u\n",(unsigned) (((*buf) & 0xE0)>>5),
	       (unsigned) ((*buf) & 0x10)>>4);
	break;
      }
      case 4: {
	sprintf(&line[lineptr],"RNR NR=%1u P/F=%1u\n",(unsigned) (((*buf) & 0xE0)>>5),
	       (unsigned) ((*buf) & 0x10)>>4);
	break;
      }
      case 8: {
	sprintf(&line[lineptr],"REJ NR=%1u P/F=%1u\n",(unsigned) (((*buf) & 0xE0)>>5),
	       (unsigned) ((*buf) & 0x10)>>4);
	break;
      }
      }
      break;
    }
    case 2:{
      switch(((*buf) & 0xE0)>>5) {
      case 0 :{
	if ((*buf & 0x0C) != 0) sprintf(&line[lineptr]," DM\n");
	else {
	  while ((bufc=strchr(&buf[2],'\r')) != NULL) *bufc = '\n';
	  in_buf = &buf[2];
	  time(&now);
	  gmt = gmtime(&now);
	  sprintf(&line[lineptr],"%s%s",asctime(gmt),in_buf);
	  bufc = &line[strlen(line)-1];
	  if (*bufc != '\n') {
	  	*(bufc+1) = '\n';
		*(bufc+2) = 0;
	  }
	}
	break;
      }
      case 1: {
	sprintf(&line[lineptr]," SABM\n");
	break;
      }
      case 2: {
	sprintf(&line[lineptr]," DISC\n");
	break;
      }
      case 3: {
	sprintf(&line[lineptr]," UA\n");
	break;
      }
      case 4: {
	sprintf(&line[lineptr]," FRMR");
	break;
      }
      }
      break;
    }
    }
    break;
  }
  }
}

 
int rec_frame(ubuf)
unsigned char *ubuf;
{
 
	unsigned char c;
	int frame_size;
	unsigned char *buf;
	time(&time_out);
	time_out+=3;
 
	while(getbyte() != FEND) {
		time(&now);
		if (now>time_out) return -1;
 
	}
kludge_garb:
 
	buf=ubuf;
	/* wait for start of frame */
	while( (c = getbyte()) == FEND) {
		time(&now);
		if (now>time_out) return -1;
	}
					/* ignore any extra FENDS */
	c = getbyte();  /* ignore KISS type code */
	frame_size = 0;
	do{
		time(&now);
		if (now>time_out) return -1;
 
		if(c == FESC){
			c = getbyte();
			switch(c){
				case TFEND:
					*buf++ = FEND;
					frame_size++;
					break;
 
				case TFESC:
					*buf++ = FESC;
					frame_size++;
					break;
 
				default:
					break;
			}
		}
		else{
			*buf++ = c;
			frame_size++;
		}
		c = getbyte();
	} while( c != FEND);
 
		/* If we get a short frame because the main loop doesn't read
		   except after it sends a command, go and restart this frame,
		   i.e., assume that the "end" is the start of a new frame. */
 
	if (frame_size<14) goto kludge_garb;
	return frame_size;
 
}

 

/* Following serial io routines are taken from Quiktrak */

    
static unsigned char b1[8] = { '1', '1', '3', '6', '1', '2', '4', '9' };
static unsigned char b2[8] = { '1', '5', '0', '0', '2', '4', '8', '6' };
static unsigned char pars[4] = { 'N', 'O', 'N', 'E' };
static unsigned char stops[2] = { '1', '2' };
static unsigned char wlens[4] = { '?', '?', '7', '8' };

/*setcom, sets up the COM port*/ 
setcom(setstr)
unsigned char *setstr;
{
  unsigned char *p;
  int  baud, par, stop, wlen;
  short ok;
  union REGS inreg, outreg;
 
 
/*
 *  Command line to upper case.
 */
 
  for (p = setstr; *p; p++) if (islower(*p)) *p = toupper(*p);
/*
 *  Find port number.
 */
 
  for (p = setstr; *p && (*p != ':'); p++);
  if (*p != ':') { 
  	error("No colon after COMn");
  	return;
  }
  port = (int) (*(p - 1) - '0') - 1;
  if ((port < 0) || (port > 7)) {
  	error("Port number out of range");
  	return;
  }
  p++;
  if (!*p) {
  	error("Parameters missing");
  	return;
  }
 
/*
 *  Find baud rate.
 */
 
  ok = 0;
  for (baud = 0; !ok && (baud < 8); baud++)
  {
    ok = (*p == b1[baud]) && (*(p + 1) == b2[baud]);
  }
  baud--;
  if (!ok) {
  	error("Baud rate not correct");
  	return;
  }
  for (; *p && (*p != ','); p++);
  if (!*p++) {
  	error("Missing parameter");
  	return;
  }
  if (!*p) {
  	error("Missing parameter");
  	return;
  }
 
/*
 *  Find parity.
 */
  ok = 0;
  for (par = 0; !ok && (par < 4); par++)
  {
    ok = (pars[par] == *p);
  }
  par--;
  if (!ok) {
  	error("Parity not N, E, or O");
  	return;
  }
  for (; *p && (*p != ','); p++);
  if (!*p++) {
  	error("Missing parameter");
  	return;
  }
  if (!*p) {
  	error("Missing parameter");
  	return;
  }
 
/*
 *  Find word length.
 */
 
  ok = 0;
  for (wlen = 0; !ok && (wlen < 4); wlen++)
  {
    ok = (wlens[wlen] == *p);
  }
  wlen--;
  if (!ok) {
  	error("Word length is not 7 or 8");
  	return;
  }
  for (; *p && (*p != ','); p++);
  if (!*p++) {
  	error("Missing parameter");
  	return;
  }
  if (!*p) {
  	error("Missing parameter");
  	return;
  }
/*
 *  Find number of stop bits.
 */
 
  ok = 0;
  for (stop = 0; !ok && (stop < 2); stop++)
  {
    ok = (stops[stop] == *p);
  }
  stop--;
  if (!ok) {
  	error("Number of stop bits not 1 or 2");
  	return;
  }

/* Compute control byte */
  inreg.h.al = 32 * baud + 8 * par + 4 * stop + wlen;
 
  printf("     COM%d:%c%c,%c,%c,%c = %x\n", port + 1,
    b1[baud], b2[baud], pars[par], wlens[wlen], stops[stop], inreg.h.al);
 
  inreg.x.dx = port;
  inreg.h.ah = 0;
  int86 (0x14, &inreg, &outreg);   /* Set the speed,etc using the BIOS */
  asc_enab(port);		   /* Turn on interrupt handler */
}
 
int getbyte()
{
	int x;
 
	do{
		time(&now);
		if (now>time_out) return -1;
 
		else{
			x = rcvbyte(port);
		}
	} while(x == -1);
	x &= 0xff;
	if (dump) fputc(x,dumpr);
 
	return x;
 
}

 
error(str)
char *str;
{
	perror(str);
	exit(0);
}

