/*
 * *************************************************************************
 *
 * Trimble Navigation, Ltd.
 * OEM Products Development Group
 * P.O. Box 3642
 * 645 North Mary Avenue
 * Sunnyvale, California 94088-3642
 *
 * Corporate Headquarter:
 *    Telephone:  (408) 481-8000
 *    Fax:        (408) 481-6005
 *
 * Technical Support Center:
 *    Telephone:  (800) 767-4822	(U.S. and Canada)
 *                (408) 481-6940    (outside U.S. and Canada)
 *    Fax:        (408) 481-6020
 *    BBS:        (408) 481-7800
 *    e-mail:     trimble_support@trimble.com
 *
 * *************************************************************************
 *
 * Vers	Date		   Changes									   Author
 * ----	---------   ----------------------------------------	   ----------
 * 1.12	10 Feb 94	Intial version								  pvwl
 * 1.13  17 Jul 95   Revisions                                    ahl
 * 1.40  14 Jul 97   Revisions                                    pvwl
 *
 * *************************************************************************
 *
 * TCHAT.C contains the main() function for the TCHAT program. The
 * main()function is a good model for programs that interface with a TSIP-
 * based receiver.  The functions in TSIP_IFC.C can be used as is, or with
 * minimal modifications.  The following modules are required for TCHAT:
 *
 *    TSIP_IFC.H: prototypes
 *    TSIP_IFC.C: standard command/report interface for TSIP
 *
 *    TSIPINCL.H: prototypes
 *    TCHAT.C: main program
 *    TSIP_RPT.C: report interpreter
 *    T_SERIAL.C: serial buffering routines
 *
 * Binary Output Storage:  If a filename for binary output is specified on
 * the command line, all reports will be saved into a binary file, which
 * may be printed in ASCII using the TSIPPRNT program.
 *
 *
 * *************************************************************************
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include "tsip_ifc.h"
#include "tsipincl.h"

#define TCHATVNUM "5a10 Release"

FILE *tsipstream;

/* Generate Control-letter character */
#define cntrl(x) ((x)-'A'+ 0x01)
static short iPort ;

/**/
/*********************************************************************/
/* Dummy routines routines for calls in TSIP_RPT.C   */
/*********************************************************************/
void GPS_time_to_PC (double rtime)
{
	rtime = 1.0-rtime;	/* dummy statement to avoid compiler warnings */
}
void show_crlf (void)
{
	printf("\n");
}

/******************************************************************/
void print_pause_message(void)
{
	printf ("\n           SCREEN IS PAUSED; PRESS ANY KEY TO CONTINUE");
}

void print_failure_message (void)
{
	printf ("\nTCHAT Syntax = \n   TCHAT -c(comport) -f<binary log file name>");
	printf ("\n    Comport must be declared.  Binary log file is optional.");
	exit(0);
}

void print_header(void)
{
	printf (
		"       TCHAT -- GPS Sensor Packet Data Monitor -- %s(%s)\n",
		TCHAT_VERNUM, TSIP_VERNUM);
	printf (
"                        Use 'c' command to switch COMPORT                   \n");
	printf (
"                         Press '?' for list of commands                     \n\n");
	printf (
"         For DEMO MODE:   Press <SPACE> to cycle through the commands       \n");
	print_pause_message();
}

void ParseCommandLine (short argc, char *argv[])
{
	char
		filename[80], *argvi;
	short
		iarg;

	iPort = -1 ;
	for (iarg =0; iarg < argc; iarg++)
	{
		argvi = argv[iarg];
		if (argvi[0] != '-' && argvi[0] != '/')
		{
			/* only accept command line arguments starting with '-' or '/' */
			continue;
		}
		switch (argvi[1])
		{
		case 'c': case 'C':
			switch (argvi[2])
			{
			case '1':
				iPort = 1;
				break;
			case '2':
				iPort = 2;
				break;
			}
			/* set COM port to 9600 8-1-odd */
			initsio (iPort, 9600, 8, 1, 0x08) ;
			/*  send end-of-packet to clear out serial  */
			sendb (DLE);
			sendb (ETX);

			break;
		case 'f': case 'F':
			strcpy (filename, &argvi[2]);
			tsipstream = fopen (filename, "wb");
			if (tsipstream == NULL) {
				printf ("\nFile %s could not be opened", filename);
				closeserial();
				print_failure_message ();
			}
			break;
		}
	}

	if (iPort == -1)
	{
		printf ("Comport not specified correctly.");
		print_failure_message ();
	}
}

void help_screen (void)
{
	printf ("\n SAMPLE COMMANDS AVAILABLE IN THIS TCHAT VERSION:");
	printf ("\n ' c': switch between COM1 and COM2");
	printf ("\n ' v': request SW version");
	printf ("\n ' t': show time");
	printf ("\n '^N': set Nav mode to auto 2-D/3-D");
	printf ("\n ' n': set nav mode to manual 2-D");
	printf ("\n ' N': set nav mode to manual 3-D");
	printf ("\n ' M': show nav mode");
	printf ("\n '^R': reset receiver to default");
	printf ("\n ' h': show receiver health");
	printf ("\n ' s': show satellite signal levels");
	printf ("\n ' S': toggle output to/from 8F-20 ");
	printf ("\n ' O': show I/O options");
	printf ("\n ' /': toggle raw measmt output on/off");
	printf ("\n ' >': output tracking status");
	printf ("\n ' p': pause the scrolling of the screen");
	printf ("\n Esc : quit program");
}

/* keystroke command processing; a simplified form of TSIP_CMD.C
* returns TRUE if a command is to be sent to the receiver, FALSE otherwise
* For the meanings of these commands, consult the TSIP_IFC.C and the
* TSIP Appendix in the Manual.  The source code TSIP_CMD.C may also help.
* Commands may be added or customized by the user.
*/
#define NUM_KBCMDS 22
short proc_keystroke (unsigned char kbch)
{
	static unsigned char
		aux_code = 0,
		superpackets_on = 1,
		icycle;
	unsigned char
		command_cycle[NUM_KBCMDS] =
		{'v','h','s','O','S','O','t','S',0x0E,'M','n','M','N','M','/','>','>',0x0D};
		/* last element = 0x0D */


	if (kbch == ' ')
	{
		/* DEMO MODE: space bar cycles through commands */
		kbch = command_cycle[icycle];
		if (kbch == 0x0D)	/* last element */
		{
			icycle = 0;
			kbch = command_cycle[0];
		}
		icycle++;
	}
	switch (kbch) {

	case 'c':				/* switch between COM1 and COM2 */
		printf ("\n???? switch COMPORT from COM%d to COM%d", iPort, 3-iPort);
		if (iPort == 1)
		{
			iPort = 2;
		}
		else
		{
			iPort = 1;
		}
		initsio (iPort, 9600, 8, 1, 0x08);
		printf ("\nSwitching to COM%d", iPort);
		return TRUE;

	case 'v':            /* request_SW_version (); */
		printf ("\n???? request version number ");
		cmd_0x1F ();
		return TRUE;

	case 't':				/* query time */
		printf ("\n???? request time ");
		cmd_0x21 ();
		return TRUE;

	case cntrl('N'):		/* set nav mode to auto 2-D/3-D */
		printf ("\n???? set nav mode to auto 3D/2D/2D-clock hold");
		cmd_0x22 (6);
		cmd_0x24 ();	/* query/display new nav mode */
		return TRUE;

	case 'n':				/* set nav mode to manual 2-D */
		printf ("\n???? set nav mode to manual 2D");
		cmd_0x22 (3);
		cmd_0x24 ();	/* query/display new nav mode */
		return TRUE;

	case 'N':				/* set nav mode to manual 3-D */
		printf ("\n???? set nav mode to manual 3D");
		cmd_0x22 (4);
		cmd_0x24 ();	/* query/display new nav mode */
		return TRUE;

	case 'M':				/* request_nav_mode (); */
		printf ("\n???? request nav mode");
		cmd_0x24 ();
		return TRUE;

	case cntrl('R'):		/* reset receiver */
		printf ("\n???? hot-start receiver (soft reset)");
		cmd_0x25 ();
		return TRUE;

	case 'h':				/* request_rx_health ();*/
		printf ("\n???? request receiver health");
		cmd_0x26 ();
		return TRUE;

	case 's':				/* request_SNRs ();*/
		printf ("\n???? request satellite signal strengths");
		cmd_0x27 ();
		return TRUE;

	case 'S':				/* toggle Superpackets output on/off */
		printf ("\n???? toggle superpacket output on/off");
		if (superpackets_on)
		{
			cmd_0x35s (0x12, 2, 0, aux_code);
			superpackets_on = 0;
		}
		else
		{
			cmd_0x35s (0x20, 0, 0, aux_code);
			superpackets_on = 1;
		}
		return TRUE;

	case 'O':				/* query IO options */
		printf ("\n???? request I/O options");
		cmd_0x35q ();
		return TRUE;

	case '/':		      /* toggle measurement output on/off */
		printf ("\n???? toggle raw measurement output on/off");
		aux_code = aux_code ? 0 : 3;
		cmd_0x35s (0x12, 0, 0, aux_code);
		return TRUE;

	case '>':		      /* output tracking status */
		printf ("\n???? request satellite tracking status");
		cmd_0x3C (0);
		return TRUE;

	case '?':
		help_screen ();
		return FALSE;
	}
	return FALSE;
}

/******************************************************************/
/*            serial port input routine, used in main()           */
/******************************************************************/
short getb (void)
{
	/*  get byte, if available  */
	short this_byte;

	this_byte = get_char (iPort) ;
	if (this_byte != -1)
	{
		/* store in raw binary output file */
		if (tsipstream) fputc (this_byte, tsipstream);
	}
	return this_byte;
}

/******************************************************************/
/* serial port output routine, used in send_cmd() of TSIP_IFC.C   */
/******************************************************************/
short sendb (unsigned char db)
{
	/*  send a byte, if able  */
	return (put_char (iPort, db)) ;
}

/* ************************************************************** */
/* ****************  main routine for TCHAT ****************** */
/* ************************************************************** */
void main (short argc, char *argv[])
{
	unsigned char
		kbch,
		pause = TRUE,
		report_printed;
	static TSIPPKT
		rpt;
	short
		thisbyte;
	/*
	 * parse command line.
	 * In this routine, initsio() is called, which
	 * allocates serial buffers in T_SERIAL.C
	 */
	ParseCommandLine (argc, argv);

	print_header();

	/* set up the receiver outputs for TCHAT */
	/* enable 8f20 Superpackets for automatic output */
	/* Note: this is default for v5.10 and later */
	cmd_0x8E20e();
	/* Set I/O options to output 8f20 superpackets only */
	cmd_0x35s (0x20, 0, 0, 0);

	/*
	 * Explicitly initialize rpt.status data field.
	 * Not necessary if rpt.status is set to 0 at initialization.
	 * If rpt.status is not initialized, the parser recovers immediately.
	 */
	rpt.status = TSIP_PARSED_EMPTY;
	report_printed = FALSE;

	do {

		/* get new incoming byte from serial port; -1 if serial port is empty */
		thisbyte = getb();

		/*
		 * tsip_input_proc() is a standard TSIP routine that strips
		 * control characters and accumulates incoming bytes into rpt.buf[].
		 * rpt.status indicates when the mesage has been completely received.
		 * It has value TSIP_PARSED_FULL when a complete message has been
		 * collected in rpt.buf[].
		 */
		tsip_input_proc (&rpt, thisbyte);

		if (rpt.status == TSIP_PARSED_FULL)
		{
			/* complete report collected */
			if (!report_printed)
			{
				/* not printed yet */
				if (!pause) rpt_packet (&rpt);
				/* prevent this report from printing again */
				report_printed = TRUE;
			}
		}
		else
		{
			/* new report coming in */
			report_printed = FALSE;
		}

		/* service keyboard commands */
		kbch = 0;
		if (kbhit ()) {
			if (!pause)
			{
				kbch = getch ();
				proc_keystroke (kbch);
				if (kbch == 'p' || kbch == '?') {
					pause = TRUE;
					print_pause_message();
				}
			}
			else pause = FALSE;
		}
	} while (kbch != 0x1B);	/* ESC */

	/*
	 * Free serial buffers in T_SERIAL.C.
	 * This subroutine MUST be called if initsio() has been called.
	 * If this is not done, computer will hang!
	 */
	closeserial();
}
