// GRMN/GRMN protocol display program
//
// This works under MSC v7.0.  good luck with anything else
// Written by Tim Hogard  9/20/95
// This program is in the public domain.
// Find a new version at http://www.inmind.com/~thogard or www.abnormal.com
// Ver: Wed Sep 20 21:41:25 EDT 1995
// Bugs:  The Transmit needs to check to see if its ok to transmit before
//	blindly transmitting.
// To exit program, type Alt-F (Windows style for Alt-F,x)
//
// Intended API:  Subject to change since they aren't useful for this project.
// x=ser_open("com2:",9600,SER_NONE,7,1);// com2: 9600 no_parity, 7 bits, 1st
// ser_read(x,buf,count);	// count==1?
// ser_write(x,buf,sizeof buf); //
// ser_do_io();	// to be done in a while(1) { ser_do_io();} state
// ser_close(x);
// set_stty();  change params unix style;  set blocking/non blocking.
// 
#include <stdio.h>
#include <dos.h>

// code below works on a standard com2 only.  Use dos
// mode com2: 9600 to set baud rate.
// INT is the dos interrupt vector number
#define INT	0xb

char *months[]={"no0","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug",
"Sep","Oct", "Nov","Dec"};

void (cdecl interrupt far *old_int)();
int count=0;
char buf[100],*ptr;
void interrupt far test() {
	int s,c;
	s=inp(0x2fa);
		*ptr++=inp(0x2f8);
	outp(0x20,0x20);	// Any clue what this does?  reset int ctrl
	count++;
	if(ptr>buf+sizeof(buf)-1)
		ptr=buf;
	//_chain_intr(old_int);
}

// codes hiding in the arrays:
// -1 end of message
// -2 put check sum here
// -3 start checksum here
// -4 argv[1]  16 wont work...
int send_init[]={0x10,-3,0xfe,0,-2,0x10,3,-1};
int send_init_spare[]={-3,0x10,0xfe,0,2,0x10,3,-1};
int send_alminac[]={0x10,-3,0xa,2,1,0,-2,0x10,3,-1};
int send_begin_ack[]={0x10,-3,0x6,2,0xfe,0,-2,0x10,3,-1};
int send_clock[]={0x10,-3,0xa,2,5,0,-2,0x10,3,-1};// clock
int send_position[]={0x10,-3,0xa,2,2,0,-2,0x10,3,-1};// clock
//int send_bad_position[]={0x10,-3,0x11,0x20,0,0,0,0,0,0,0xf8,0x3f,
//	0,0,0,0,0,0,0xf8,0x3f, -2,0x10,3,-1};// faked position
int send_request[]={0x10,-3,0xa,2,-4,0,-2,0x10,3,-1};// clock
char rxbuf[256]; int rxcount;
int *out;
#define debug 1

ser_open(int x)	{	// x will be 2 for com 2; for now ignore
	union REGS reg;
	_disable();
	old_int=_dos_getvect(INT);
	_dos_setvect(INT,test);
	reg.h.al=0xe3;
	reg.h.ah=0;
	reg.x.dx=1;
//int86(0x14, &reg, &reg);	// use dos mode com2: baud=2400 to set baud
	outp(0x2fb,0x3);	// 8 bits, 1 st, np
	outp(0x2f9,0x1);
	outp(0x21,inp(0x21)&0xf7);	// turn on 8259A irq
	outp(0x2fc,inp(0x2fc)|0x9);
	inp(0x2f8);
	inp(0x2f8);
	_enable();
}

bail() {
	outp(0x2f9,0x0);	// turn off interrupts
	outp(0x21,inp(0x21)|~0xf7);	// turn off 8259A irq
	_dos_setvect(INT,old_int);
	exit(0);
}

main(int argc, char **argv) {
	int c;
	int last=0;
	int chksum=0;
	int rxcount=0;
	char *rptr;
	rptr=ptr=buf;

	ser_open(2);	// init com2:
	//out=send_init;
	//out=send_alminac;
//	out=send_clock;
//	out=send_position;
	out=send_request;
	while(1) {
		if(*out!=-1) {
			if(inp(0x2fd)&0x20) {
			//***** need check here to see if last Tx is done
			// Check bit 0x20 of port 0x2fd before Tx
			if(*out==-4) {	// atoi number...
				if(debug) printf("argv(%x)\n",atoi(argv[1]));
				chksum+=atoi(argv[1]);
				outp(0x2f8,atoi(argv[1]));
			} else if(*out==-2) {
				if(debug) printf("chk(%d)\n",256-(chksum&0xff));
				outp(0x2f8,256-(chksum&0xff));
			} else if(*out==-3) {
				chksum=0;
			} else {
				chksum+=*out;
				outp(0x2f8,*out);
				if(debug) printf("%02x ",*out);
			}
			out++;
			}
		}
		while(kbhit()) {
			c=getch();
			if(c==0) {
				c=getch();
				if(c==33)	// alt-F (File menu)
					bail();
			} else
				outp(0x2f8,c);
		}
		while(rptr!=ptr) {
			c=*rptr++;
			if(rptr>buf+sizeof(buf)-1)
				rptr=buf;
			if (debug) printf("%02x %c ",c,c>=' '?c:'?',count);
			//printf("%c",c);
			if(last==0x10) {
				if(c==0x3) {	//done
					done(rxbuf,rxcount);
					rxcount=255;
				} else if(c==0x10) {
					;//rxbuf[255&rxcount++]=0x10;
				} else {
					rxbuf[255&rxcount++]=0x10;
					//rxbuf[255&rxcount++]=c;
				}
				last=0;
			}
			if(c!=0x10)
				rxbuf[255&rxcount++]=c;
			else
				last=0x10;
		}
	}
}

// code to do real stuff goes here.  

// done gets called when the above crud finds what appears to be a complete
// grmn protocol sentence.
// below you can get at the data:
//	 r[0] is a 0x10,
//	 r[1] is the code,
//	 r[2] is the length,
//	 r[3] is the 1st data byte,
// use casting macros to get other stuff   short(r[5]) will make a 16 bit
// 	number out of r[5] and r[6];  its a shortcut for (*(int *)&r[5])
//
#define short(x) (*(int *)&x)
#define long(x) (*(long *)&x)
#define float(x) (*(float *)&x)
#define double(x) (*(double *)&x)
done(unsigned char *r,int rxcount) {
if(debug) printf("\n:%x c(%x) len(%x)\n",r[0],r[1],r[2]);
	switch(r[1]) {
	case 0x0:
		if(r[2]!=4) printf("len=%d ",r[2]);
		printf("Signal %04x %04x\n", short(r[3]),short(r[5]));
		break;
	case 0x3: printf("done\n");
		break;
	case 0x6:
		if(debug) printf("ack\n");
		break;
	case 0xd:
		if(r[2]!=4) printf("len=%d ",r[2]);
		printf("Event %02x %02x %02x %02x\n", r[3],r[4],r[5],r[6]);
		break;
	case 0xe:
		if(r[2]!=4) printf("len=%d ",r[2]);
		printf("Clock %s %02d %04d ", months[r[3]],r[4],short(r[5]));
		printf("%02d:%02d:%02d (+%d) ", r[7],r[9],r[10],r[8]);// guess about 8
		//printf(" %02d %02d %02d %02d\n", r[11],r[12],r[13],r[14]);
		printf(" %08lx (%20ld)\n", long(r[11]),long(r[11]));
		out=send_clock; // try it again...
		break;
	case 0x11:
		if(r[2]!=4) printf("len=%d ",r[2]);
		printf("Position %g %g \n", double(r[3]),double(r[11]));
		break;
	case 0x15:
		printf("nack %02x\n",r[3]);
		break;
	case 0x1f:	// Almanac Data
		if(r[2]!=4) printf("len=%d ",r[2]);
		printf("Almanac week:%02x %g %g %g %g %g %g %g %g %g %g\n",
		short(r[3]),
		float(r[5]),float(r[5+4]),	// time, Af0
		float(r[5+8]),float(r[5+12]),	// Af1,Eccentricity,
		float(r[5+12+4]),float(r[5+12+8]), // sqrt(a) m^1/2 mean anon
		float(r[5+12+12]),float(r[5+12+16]), //perigee, RA at TOA
		float(r[5+16+16]),float(r[5+32+4]));  // Rate of RA // Orbital Inclination
		out=send_begin_ack;	// generic ack
		break;
	case 0x1b:
		printf("Beginxfer %d\n",short(r[3]));
		out=send_begin_ack;	// should ack the request but it
			// isn't going to build the ack array yet.
		break;
	case 0x27:	// in test mode 
		if(r[2]!=22) printf("len=%d ",r[2]);
		printf("Unknonw 27 %04x %04x\n", short(r[3]),short(r[5]));
		break;
	case 0x28:	// in test mode
		if(r[2]!=4) printf("len=%d ",r[2]);
		printf("Unknown 28 %08x %08x %08x %08x\n", long(r[3]),long(r[7]),
long(r[7+4]),long(r[7+8]));
		break;
	case 0xff:
		if(r[2]!=14) printf("len=%d ",r[2]);
		printf("version %02x %02x %d \"%18.18s\"\n",// 14.14 for GPS75
//			r[3],r[4],*(int *)&r[5],&r[7]);
			r[3],r[4],short(r[5]),&r[7]);
		break;
	}
}
