/*********************************************************************
 * PROGRAM NAME:  AROEN.C
 *--------------------------------------------------------------------
 * 		This program provides an all mode amateur radio operating
 *	environment.  It is designed to work spegetchfically with an AEA
 *	PK232 'PAKRATT' node controller and the Kenwood TS440S tranceiver.
 *	Complete control of both the PK232 and the 440S is available from
 *	the PC keyboard.
 *--------------------------------------------------------------------
 *	MODIFICATIONS:
 *		04/18/87	Original Source
 *      03/23/88    Ported to Turbo C
 ********************************************************************/

#include <stdio.h>
#include <dos.h>
#include <litecomm.h>
#include <time.h>
#include <conio.h>
#include "aroen.h"

#define VIDEO 0x10

FILE *log_file;
FILE *init_file;
FILE *send_file;
FILE *save_file;
FILE *printer;

/* TS440 Information string received on IF or AI1 CMD */
struct ts440_if {
	char if_type[2];
	char p0[3];			/* P00	*/
	char freq[8];		/* P01	*/
	char p2[5];			/* P02	*/
	char rit_freq[5];	/* P03	*/
	char rit_on;		/* P04	*/
	char xit_on;		/* P05	*/
	char p6;			/* P06	*/
	char mem_chan[2];	/* P07	*/
	char tx_rx_flag;	/* P08	*/
	char mode;			/* P09	*/
	char function;		/* P10	*/
	char scan_on;		/* P11	*/
	char split_on;		/* P12	*/
	char p13[6];		/* P13	*/
	};

int ts440_mode;
char *ts440_mode_str[] = {"   ","LSB", "USB", "CW ", "FM ", "AM ", "FSK"};

int pk232_mode;
char *pk232_mode_str[] = {"ARQ", "VOICE", "VOICE", "MORSE", "VOICE",
						  "VOICE", "ASCII", "BAUDOT", "AMTOR", "PACKET",
						  "ALIST", "FEC", };
char *tx_mode[] = {"RCVE", "XMIT"};

char cq_str[80];
char qrz_str[80];
char ga_str[] = "K K PSE";
char ry_str[] = "RYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYRYR";
char my_call[15];
char my_name[20];
char my_qth[25];
char my_equip[80];
char save_fn[80];
char my_log[80];

int tx_flag = FALSE;
int tx_col = 0;
int save = FALSE;
int print = FALSE;

char ts_440_freq[10];

int ts440_port = 2;
int pk232_port = 1;

struct ts440_if ts440_info;
char *ts440_buf;

int index_440 = 0;

char his_selcal[5];

int  year, month, day, hour, sec;
int min = 99;
char date[] = "27 JUN 87";
char time_of_day[] = "00:00Z";
char *mon_name[] = {" ", "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
							"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
struct {
	char frequency[10];
	char mode[6];
	char power[5];
	char date[10];
	char start[7];
	char stop[7];
	char call_sign[16];
	char rst_sent[4];
	char rst_rcvd[4];
	char name[21];
	char qth[31];
	char comments[56];
	char contest[21];
	char qsl_send[2];
	char qsl_rcvd[2];
	} qso;

struct {
	int frow;
	int fcol;
	int tcol;
	int trow;
	char buf[512];
	} cur_window;
int ch_k, ch_pk, ch_440;
int gmt_offset = 6;
int v_attribute = YELLOW;

void main()
{
	int cmd;

	init_sys();
	do {
		get_time(0);
		if (kbhit()) {
			ch_k = getch();
			if (ch_k == 0) {
				ch_k = getch() + 128;
				cmd = exec_cmd(ch_k);
				if (cmd == EXIT) {
					if (qso.call_sign[0] != 0)
						log_call();
					comm_close(1);
					comm_close(2);
					if (save)
						close(save_file);
					if (print) close(printer);
					exit(0);
					}
				}
			else if (tx_flag) {
				lc_put(pk232_port, ch_k);
				if (ch_k == 4)
					co_tx_str("<CTL-D>");
				if (ch_k > 31)
					if (++tx_col > 60)
						chr_out(BELL);
				if (tx_col > 68) {
					lc_put(pk232_port, CR);
					co_tx(CR);
					tx_col = 0;
					}
				co_tx(ch_k);
				if (ch_k == CR)
					tx_col = 0;
				}
			}
		if (lc_icnt(pk232_port) > 0)
			co_rx((ch_pk = lc_get(pk232_port)) & 0x7f);
		if (lc_icnt(ts440_port) > 0) {
			ts440_buf[index_440++] =
				(ch_440 = lc_get(ts440_port));
			if (ch_440 == ';') {
				disp_440_info();
				index_440 = 0;
				}
			if (index_440 > 38)
				index_440 = 0;
			}
		}
	while (FOREVER);
	}   /*  END MAIN */

/*******************************************************************
 * SUBROUTINE NAME:  init_sys
 *------------------------------------------------------------------
 *		This routine initializes the system by performing the
 *	following tasks;
 *		o	Clear Screen, set up split screen for xmit and rceive.
 *		o	Initialize printer
 *		o	Initialize ASYNC1 and ASYNC2 serial I/O drivers
 *		o	Open Log file
 *		o	Open initialization files
 *		o	Initialize system tables
 *		o	Initialize PK-232
 *		o	Initialize status line
 ******************************************************************/

 init_sys()
 {
 	static char ts440_init[] = ";AI1;";
 	int i;
 	char tempstr[20], ch, *err;

	ts440_buf = &ts440_info;
 	init_file = fopen("AROEN.MSG", "r");
	if (init_file == 0) {
		co_str("UNABLE TO OPEN 'AROEN.MSG'\n");
		co_str("Use your favorite text editor to create it as follows:\n");
		co_str("    PK232 COMM PORT\n");
		co_str("    TS440 COMM PORT\n");
		co_str("    Call Sign\n");
		co_str("    Name\n");
		co_str("    QTH\n");
		co_str("	Log file path and file name\n");
		co_str("	CQ Message\n");
		co_str("	QRZ Message\n");
		co_str("    Equipment file path and file name\n");
		co_str("    Save file path and file name\n");
		exit(1);
		}
	else {
		err = fgets(tempstr, 20, init_file);
		if (err == NULL) {
			printf("Error reading AROEN.MSG\n");
			exit(1);
			}
		for (i = 0; i < 20; i++)
			if ((tempstr[i] >= '1') && (tempstr[i] <= '4'))
				break;
		if (i < 20)
           pk232_port = tempstr[i] - '0';
		err = fgets(tempstr, 20, init_file);
		if (err == NULL) {
			printf("Error reading AROEN.MSG\n");
			exit(1);
			}
		for (i = 0; i < 20; i++)
			if ((tempstr[i] >= '1') && (tempstr[i] <= '4'))
				break;
		if (i < 20)
           ts440_port = tempstr[i] - '0';
		if (ts440_port == pk232_port) {
			printf("ERROR in PORT ASSIGNMENTS...Aborting\n");
			exit(1);
			}

		init_str(my_call, 15);
		init_str(my_name, 15);
		init_str(my_qth, 25);
		init_str(my_log, 80);
		init_str(cq_str, 80);
		init_str(qrz_str, 80);
		init_str(my_equip, 80);
		init_str(save_fn, 80);
		}
	close(init_file);
	printer = fopen("PRN:", "w");
	if (comm_opn(pk232_port, B1200, NPARITY, BIT8, STOP1, 4096, 256) == -1)
	{
		co_str("Error Opening COM1 (PK232).\n");
		exit(1);
	}
    lc_gotxoff(pk232_port);
	if (comm_opn(ts440_port, B4800, NPARITY, BIT8, STOP1, 128, 128) == -1)
	{
		co_str("Error Opening COM2 (TS440).\n");
		exit(1);
	}
	lc_gotxoff(ts440_port);
	send_str(TS440, ts440_init);
 	init_screen();
	get_time(1);
	get_time(0);
	send_cmd(PK232, "\003ECHO OFF\015");
	send_cmd(PK232, "USOS ON\015");  /* unshift on space */
	send_cmd(PK232, "EAS ON\015");   /* echo as sent */
	sprintf(tempstr, "DAYTIME %02d%02d%02d%02d%02d\015",
						year, month, day, hour, min);
	build_window(5,11,7,61);
	gotoxy(14, 6);
	co_str("Press any key to initialize PK232");
	getch();
	rstr_scr();
	send_cmd(PK232, tempstr);
	send_cmd(PK232, "AMTOR\015");
	send_cmd(PK232, "BAUDOT\015");
	pk232_mode = BAUDOT;
	gotoxy(33, 2);
	co_str(pk232_mode_str[pk232_mode]);
	send_str(TS440, "MD6;");
 	}

int init_str(char *str, int len)
{
	char *err;

	err = fgets(str, len, init_file);
	if (err == NULL) {
		printf("Error reading AROEN.MSG\n");
		exit(1);
		}
	str[strlen(str) - 1] = 0;
    }


init_screen()
{
	int i, j;

	clrscr();
	for (j = 1; j <= 24; j++)
		for (i = 1; i <= 80; i++)
		   chr_out(32);
	v_attribute = GREEN;  /* dark green on black */
	gotoxy(1,1);
	chr_out(ULC);
	for (i = 2; i < 80; i++) {
		gotoxy(i, 1);
		chr_out(HB);
		}
	gotoxy(i, 1);
	chr_out(URC);
	gotoxy(2, 3);
	for (i = 2; i < 80; i++) {
		gotoxy(i, 3);
		chr_out(HB);
		}
	for (i = 2; i < 80; i++) {
		gotoxy(i, 19);
		chr_out(HB);
		}
	gotoxy(1, 25);
	chr_out(LLC);
	for (i = 2; i < 80; i++) {
		gotoxy(i, 25);
		chr_out(HB);
		}
	gotoxy(i, 25);
	chr_out(LRC);
	for (i = 2; i < 25; i++) {
		gotoxy(1, i);
		chr_out(VB);
		gotoxy(80, i);
		chr_out(VB);
		}
	prnt_t(20);
	prnt_t(30);
	prnt_t(46);
	prnt_t(39);
	prnt_t(54);
	prnt_t(62);
	prnt_t(72);
	gotoxy(1, 3);
	chr_out(LRA);
	gotoxy(80, 3);
	chr_out(RRA);
	gotoxy(1, 19);
	chr_out(LRA);
	gotoxy(80, 19);
	chr_out(RRA);
	v_attribute = MAGENTA;
	gotoxy(6, 1);
	co_str("FREQ");
	gotoxy(25, 1);
	co_str("QSO");
	gotoxy(34, 1);
	co_str("MODE");
	gotoxy(42, 1);
	co_str("SAVE");
	gotoxy(50, 1);
	co_str("PTT");
	gotoxy(57, 1);
	co_str("PRINT");
	gotoxy(66, 1);
	co_str("DATE");
	gotoxy(75, 1);
	co_str("TIME");
	gotoxy(37, 3);
	co_str("TEXT IN");
	gotoxy(37, 19);
	co_str("TEXT OUT");
	gotoxy(34, 25);
	co_str("AROEN by K5WNV");
	v_attribute = YELLOW;
	gotoxy(42, 2);
	co_str("OFF");
	gotoxy(58, 2);
	co_str("OFF");
	}

prnt_t(col)   /* print vertical bar with T at top and bottom */
int col;
{
	col++;
	gotoxy(col, 1);
	chr_out(DN_T);
	gotoxy(col, 2);
	chr_out(VB);
	gotoxy(col, 3);
	chr_out(UP_T);
	}

chr_out(ch)
int ch;
{
    union REGS regs;

	regs.h.ah = 9;
	regs.h.al = ch;
	regs.h.bl = v_attribute;
	regs.h.bh = 0;
	regs.x.cx = 1;
    int86(VIDEO, &regs, &regs);
	}

disp_440_info()
{
	int i;
    char buf[20];
	if (strncmp(ts440_info.if_type, "IF", 2))
		return(0);
	for (i = 0; i < 5; i++)
		ts_440_freq[i] = ts440_info.freq[i];
	if (ts_440_freq[0] == '0')
		ts_440_freq[0] = ' ';
	ts_440_freq[i++] = '.';
	for (;i < 9; i++)
		ts_440_freq[i] = ts440_info.freq[i-1];
	ts_440_freq[9] = 0;
	gotoxy(3, 2);
	ts440_mode = ts440_info.mode - 0x30;
	sprintf(buf, "%s KHZ/%3s", ts_440_freq, ts440_mode_str[ts440_mode]);
	co_str(buf);
	i = ts440_info.tx_rx_flag - 0x30;
	if ((i == 0) || (i == 1)) {
		gotoxy(49, 2);
		co_str(tx_mode[i]);
		}
	}

int exec_cmd(ch)
int ch;
{
	static char up440_str[] ="UP;";
	static char dn440_str[] ="DN;";
	int i, j;

	switch (ch) {
		case DN	 : send_str(TS440, dn440_str);
				   break;
		case PGDN : for (i = 0; i < 100; i++)
						send_str(TS440, dn440_str);
					break;
		case UP	 : send_str(TS440, up440_str);
				   break;
		case PGUP : for (i = 0; i < 100; i++)
						send_str(TS440, up440_str);
					break;
	    case F1  : help();
	    		   break;
		case F2  : chg_mode();
				   break;
		case F3  : call_cq();
				   break;
		case F4  : call_qrz();
				   break;
		case F5  : log_call();
				   break;
		case F6  : call();
				   break;
		case F7  : chg_freq();
				   break;
		case F8  : rcve();
				   break;
		case F9  : cmd();
				   break;
		case F10 : xmit();
				   break;
		case CTL_F2  : 	lc_gotxoff(pk232_port);
						lc_gotxoff(ts440_port);
						break;
		case ALT_F1  :  fill_receive_window();
						break;
		case ALT_F2  : 	build_window(4,10, 8, 70);
						gotoxy(12, 5);
						send_data();
						rstr_scr();
					    break;
		case ALT_F4  : 	xmit_eqp();
						break;
		case ALT_F6  :  save = !save;
						gotoxy(42, 2);
						if (save) {
							save_file = fopen(save_fn, "a");
							co_str("ON ");
							}
						else {
							close(save_file);
							co_str("OFF");
							}
						break;
		case ALT_F8  : 	print = !print;
						gotoxy(58, 2);
						if (print)
							co_str("ON ");
						else
							co_str("OFF");
						break;
		case ALT_F10 : clrscr();
					  return(EXIT);
		case SHF_F1  : send_cmd(PK232, "\003TC\015");
					   break;
		case SHF_F2  : send_cmd(PK232, "\003L\015");
					   break;
		case SHF_F3  : send_cmd(PK232, "\003RXREV ON\015");
					   break;
		case SHF_F4  : send_cmd(PK232, "\003RXREV OFF\015");
					   break;
		case SHF_F5  : send_cmd(PK232, "\003RBAUD 75\015");
					   break;
		case SHF_F6  : send_cmd(PK232, "\003RBAUD 45\015");
					   break;
		case SHF_F8  : send_cmd(PK232, "\003R\015");
					   tx_flag = FALSE;
					   break;
		case SHF_F10 : send_cmd(PK232, "\003X\015");
					   tx_flag = TRUE;
					   break;
		default  : break;
		}
	return(0);
	}

help()
{
	int ch;

	ch = '1';
	build_window(5,5, 16, 39);
	while ((ch >= '1') && (ch <= '4'))
		switch (ch) {
			case '1' : ch = disp_help0();
					   break;
			case '2' : ch = disp_help1();
					   break;
			case '3' : ch = disp_help2();
					   break;
			case '4' : ch = disp_help3();
					   break;
			}
	rstr_scr();

	}

disp_help0()
{
	int ch;

	/* clear window */
	scr_scrup(0,cur_window.frow, cur_window.fcol,
				cur_window.trow-2, cur_window.tcol-2);
	gotoxy(13, 6);
	co_str("     HELP FK");
	gotoxy(13, 7);
	co_str("HELP -F1  F2- MODE");
	gotoxy(13, 8);
	co_str("  CQ -F3  F4- QRZ ");
	gotoxy(13, 9);
	co_str(" LOG -F5  F6- CALL");
	gotoxy(13, 10);
	co_str("FREQ -F7  F8- RCVE");
	gotoxy(13, 11);
	co_str(" CMD -F9 F10- XMIT");
	gotoxy(13, 13);
	co_str(" Press Any Fn Key");
	gotoxy(13, 14);
	co_str(" for Help, ESC to");
	gotoxy(13, 15);
	co_str("     to Exit");
	ch = getch();
	return(ch);
	}

disp_help1()
{
	int ch;

	/* clear window */
	scr_scrup(0,cur_window.frow, cur_window.fcol,
				cur_window.trow-2, cur_window.tcol-2);
	gotoxy(13, 6);
	co_str("  HELP CTL_FK");
	gotoxy(13, 7);
	co_str("     -F1  F2-CLEAR XOFF");
	gotoxy(13, 8);
	co_str("     -F3  F4-     ");
	gotoxy(13, 9);
	co_str("     -F5  F6-     ");
	gotoxy(13, 10);
	co_str("     -F7  F8-     ");
	gotoxy(13, 11);
	co_str("     -F9 F10-     ");
	gotoxy(13, 13);
	co_str(" Press Any Fn Key");
	gotoxy(13, 14);
	co_str(" for Help, ESC to");
	gotoxy(13, 15);
	co_str("     to Exit");
	ch = getch();
	return(ch);
	}

disp_help2()
{
	int ch;

	/* clear window */
	scr_scrup(0,cur_window.frow, cur_window.fcol,
				cur_window.trow-2, cur_window.tcol-2);
	gotoxy(13, 6);
	co_str("      HELP SHIFT_FK");
	gotoxy(13, 7);
	co_str("  CLEAR -F1  F2- LETTERS");
	gotoxy(13, 8);
	co_str(" NORMAL -F3  F4- REVERSE");
	gotoxy(13, 9);
	co_str("BAUD 75 -F5  F6- BAUD 45");
	gotoxy(13, 10);
	co_str("        -F7  F8- RCVE");
	gotoxy(13, 11);
	co_str("        -F9 F10- XMIT");
	gotoxy(13, 12);
	co_str(" Press Any Fn Key");
	gotoxy(13, 14);
	co_str(" for Help, ESC to");
	gotoxy(13, 15);
	co_str("     to Exit");
	ch = getch();
	return(ch);
	}

disp_help3()
{
	int ch;

	/* clear window */
	scr_scrup(0,cur_window.frow, cur_window.fcol,
				cur_window.trow-2, cur_window.tcol-2);
	gotoxy(13, 6);
	co_str("   HELP ALT_FK");
	gotoxy(13, 7);
	co_str("     -F1  F2- DATA");
	gotoxy(13, 8);
	co_str("     -F3  F4- EQUIP");
	gotoxy(13, 9);
	co_str("     -F5  F6- SAVE");
	gotoxy(13, 10);
	co_str("     -F7  F8- PRINT");
	gotoxy(13, 11);
	co_str("     -F9 F10- EXIT");
	gotoxy(13, 13);
	co_str(" Press Any Fn Key");
	gotoxy(13, 14);
	co_str(" for Help, ESC to");
	gotoxy(13, 15);
	co_str("     to Exit");
	ch = getch();
	return(ch);
	}

chg_mode()
{
	int ch, i;

	build_window(5,11, 15, 36);
	gotoxy(14, 7);
	co_str("0. ARQ       1. LSB");
	gotoxy(14, 8);
	co_str("2. USB       3. MORSE");
	gotoxy(14, 9);
	co_str("4. FM        5. AM");
	gotoxy(14, 10);
	co_str("6. ASCII     7. BAUDOT");
	gotoxy(14, 11);
	co_str("8. AMTOR     9. PACKET");
	gotoxy(14, 13);
	co_str("SELECT: ");
	while (((ch = getch() - 0x30) < 0) || (ch > 9)) {
		if ((ch + 0x30) == ESC)
			break;
		else
			chr_out(BELL);
		}
	if (ch != ESC) {
		send_cmd(PK232, "\003TC\015");
		pk232_mode = ch;
		if ((pk232_mode == ALIST) ||
			(pk232_mode == ARQ)) {
			send_cmd(PK232, "\003AMTOR\015");
			tx_flag = FALSE;
			}
		switch(ch) {
			case 0 : send_str(TS440, "MD6;");
					 send_cmd(PK232, "\003AMTOR\015");
					 rstr_scr();
					 build_window(5,11, 8, 36);
					 gotoxy(15, 6);
					 co_str("Xmit Mode? (Y/N): ");
					 ch = toupper(getch());
					 if (ch == 'Y') {
					 	gotoxy(13, 7);
 	  			 	 	tx_flag = TRUE;
						xmit_arq();
						}
					 else {
					 	send_cmd(PK232, "\003ALIST\015");
						pk232_mode = ALIST;
				 		}
					 break;
			case 1 : send_str(TS440, "MD1;");
					 break;
			case 2 : send_str(TS440, "MD2;");
					 break;
			case 3 : send_str(TS440, "MD3;");
					 send_cmd(PK232, "\003AMTOR\015");
					 send_cmd(PK232, "\003MORSE\015");
					 break;
			case 4 : send_str(TS440, "MD4;");
					 break;
			case 5 : send_str(TS440, "MD5;");
					 break;
			case 6 : send_str(TS440, "MD6;");
					 send_cmd(PK232, "\003AMTOR\015");
					 send_cmd(PK232, "\003ASCII\015");
					 break;
			case 7 : send_str(TS440, "MD6;");
					 send_cmd(PK232, "\003AMTOR\015");
					 send_cmd(PK232, "\003BAUDOT\015");
					 break;
			case 8 : send_str(TS440, "MD6;");
					 send_cmd(PK232, "\003AMTOR\015");
					 break;
			case 9 : send_str(TS440, "MD6;");
					 send_cmd(PK232, "\003AMTOR\015");
					 gotoxy(13,13);
					 co_str("HF/VHF? (H/V): ");
					 while (((ch = toupper(getch())) != 'V') &&
					 		 (ch != 'H'));
					 send_cmd(PK232, "PACKET\015");
					 if (ch == 'H') {
					 	send_cmd(PK232, "HBAUD 300\015");
					 	send_cmd(PK232, "VHF OFF\015");
					 	}
					 else {
					 	send_cmd(PK232, "HBAUD 1200\015");
					 	send_cmd(PK232, "VHF ON\015");
					 	}

					 break;
			default : break;
			}
		}
	rstr_scr();
	disp_mode();
	}
	
chg_freq()
{
	char cmd_str[20];
	char ch;
	int err;

	build_window(5,11, 8, 62);
	gotoxy(13, 6);
	co_str("VFO A or B, Memory (A,B,M): ");
	while (((ch = toupper(getch())) != 'A') && (ch != 'B')
			&& (ch != 'M')) {
		if (ch == ESC) {
			rstr_scr();
			return(0);
			}
		}
	chr_out(ch);
	gotoxy(13, 7);
	if (ch == 'M') {
		co_str("Memory Channel: ");
		err = enter_mem_channel(cmd_str);
		if (!err) {
			send_str(TS440, cmd_str);
			send_str(TS440, "FN2;");
			}
		}
	else {
		err = enter_freq(cmd_str, ch);
		if (!err) {
			send_str(TS440, cmd_str);
			if (ch == 'A')
				send_str(TS440, "FN0;");
			else
				send_str(TS440, "FN1;");
			}
	}
	rstr_scr();
	}

	
rcve()
{
	if (tx_flag == FALSE)
		return(0);
	switch (pk232_mode) {
	    case MORSE  :
		case LSB :
		case USB :
		case FM  :
		case AM  : send_str(TS440, "RX;");
				   break;
		case ARQ : send_cmd(PK232, "\003R\015");
				   pk232_mode = AMTOR;
				   disp_mode();
				   break;
	    case ASCII  :
	    case BAUDOT : send_stop();
	    			  break;
	    case AMTOR  : send_stop();
	    			  pk232_mode = AMTOR;
	    			  disp_mode();
	    			  break;
	    case PACKET : send_cmd(PK232, "\003D\015");
	    			  break;
	    default : break;
	    }
	tx_flag = FALSE;
	}

xmit()
{
	if (tx_flag == TRUE)	/* not allowed in xmit mode */
		return(0);
	tx_flag = TRUE;
	switch (pk232_mode) {
		case 1 :
		case 2 :
		case 4 :
		case 5 : send_str(TS440, "TX;");
				 break;
	    case 3 :
	    case 6 :
	    case 7 : send_cmd(PK232, "\003X\015");
	    		 send_start();
	    		 break;
	    case 10 : send_cmd(PK232, "\003AMTOR\015");
	    case 8  :
	    case 11 : send_cmd(PK232, "\003FEC\015");
	    		  pk232_mode = FEC;
	    		  disp_mode();
	    		  send_start();
	    		  break;
		case 9 : xmit_packet();
				 break;
	    default : break;
	    }
	}

cmd()
{
	int ch, index, i;
	char tempstr[81];

	build_window(5,11, 7, 72);
	gotoxy(13, 6);
	co_str("CMD:");
	tempstr[0] = 3;
	index = enter_str(tempstr, 80, 1);
	if (index != -1) {
		tempstr[index] = CR;
		if (index > 2)
		send_cmd(PK232, tempstr);
		}
	rstr_scr();
	}

co_rx(ch)
int ch;
{
	static row = 18;
	static col = 2;

	if (save)
		fputc(ch, save_file);
	if (print)
		fputc(ch, printer);
	if (ch < 32) {
		switch (ch) {
			case LF : scr_scrup(1,3,1,17,78);
					  col = 2;
					  break;
			case BS : if (col > 2) {
						 gotoxy(--col, row);
						 co_str(" \008");
						 }
					  break;
			case BELL  : chr_out(ch);
					  break;
			default : break;
			}
		}
	else {
		gotoxy(col++, row);
			chr_out(ch);
		if (col > 79) {
			col = 2;
			if (++row > 18) {
				scr_scrup(1,3,1,17,78);
				row = 18;
				}
			}
		}
	}

co_tx(ch)
int ch;
{
	static row = 24;
	static col = 2;

    v_attribute = CYAN;
	if (ch < 32) {
		switch (ch) {
			case CR : scr_scrup(1,19,1,23,78);
					  col = 2;
					  break;
			case BS  : if (col > 2) {
						 gotoxy(--col, row);
						 co_str(" \008");
						 }
					  break;
			case BELL  : chr_out(ch);
					  break;
			default : break;
			}
		}
	else {
		gotoxy(col++, row);
			chr_out(ch);
		if (col > 79) {
			col = 2;
			if (++row > 24) {
				scr_scrup(1,19,1,23,78);
				row = 24;
				}
			}
		}
	v_attribute = YELLOW;
	}

/* write a character string to the TEXT OUT window */
co_tx_str(str)
char *str;
{
	int i;

	i = 0;
	while (str[i])
		co_tx(str[i++]);
	}

/* write a character string to the TEXT IN window */
co_rx_str(str)
char *str;
{
	int i;

	i = 0;
	while (str[i])
		co_rx(str[i++]);
	}

build_window(frow, fcol, trow, tcol)
int frow, fcol, trow, tcol;
{
	int i, j, index;

	/* save window contents */
	index = 0;
	for (i = frow; i <= trow; i++)
		for (j = fcol; j <= tcol; j++) {
			gotoxy(j, i);
			cur_window.buf[index++] = scr_sinp();
			}
	cur_window.frow = frow;
	cur_window.trow = trow;
	cur_window.fcol = fcol;
	cur_window.tcol = tcol;

	/* clear window */
	scr_scrup(0,frow - 1, fcol - 1, trow - 1, tcol - 1);
	/* build border */
	v_attribute = GREEN;
	gotoxy(fcol, frow);
	chr_out(ULC);
	for (i = fcol+1; i <= tcol; i++) {
		gotoxy(i, frow);
		chr_out(HB);
		}
	chr_out(URC);
	gotoxy(fcol, trow);
	chr_out(LLC);
	for (i = fcol+1; i <= tcol; i++) {
		gotoxy(i, trow);
		chr_out(HB);
		}
	chr_out(LRC);
	for (i = frow+1; i < trow; i++) {
		gotoxy(fcol, i);
		chr_out(VB);
		gotoxy(tcol, i);
		chr_out(VB);
		}
    v_attribute = MAGENTA;
	}

rstr_scr()
{
	int i, j, index;

	index = 0;
	v_attribute = YELLOW;
	for (i = cur_window.frow; i <= cur_window.trow; i++)
		for (j = cur_window.fcol; j <= cur_window.tcol; j++) {
			gotoxy(j, i);
			chr_out(cur_window.buf[index++]);
			}
	}

get_time(int date_flag)
{
    struct tm *tm_now;
	long secs_now;
	char *str_now;

	time(&secs_now);
	tm_now = gmtime(&secs_now);
    if ((min == tm_now->tm_min) && (date_flag == 0))
			return(0);
	min = tm_now->tm_min;
	if (date_flag || (hour != tm_now->tm_hour)) {
		hour = tm_now->tm_hour;
		sprintf(date, "%2d %3s %02d", tm_now->tm_mday,
			 mon_name[tm_now->tm_mon], tm_now->tm_year % 100);
		gotoxy(64, 2);
		co_str(date);
		}
	gotoxy(74, 2);
	sprintf(time_of_day, "%02d:%02dZ", hour, min);
	co_str(time_of_day);
	}

int enter_mem_channel(str)
char *str;
{
	int i, err;

	err = enter_str(str, 2, 0);
	if ((err == 0) || (err == -1))
		return(err);
	i = atoi(str);
	sprintf(str, "MC %02d;", i);
	return(0);
	}

int enter_str(str, len, offset)
char *str;
int len, offset;
{
	int i;
	char ch;

	for (i = offset; i < len; i++)
		str[i] = 0;
	i = offset;
	do {
		ch = toupper(getch());
		if ((ch == CR) || (ch == ESC))
			break;
		if ((i > 0) && (ch == BS)) {
			co_str("\008 \008");
			str[--i] = 0;
			}
		else if (ch > 31) {
			chr_out(ch);
			str[i++] = ch;
			}
		}
	while (i < len);
	if (ch == ESC) {
		str[0] = 0;
		return(-1);
		}
	else 
		return(i);
	}

int enter_freq(str, ch)
char *str;
char ch;
{
	char tempstr[80];
	int i, j, k, err;

	str[0] = 'F';
	str[1] = ch;
	for (i = 2; i < 13; i++)
		str[i] = '0';
	str[13] = ';';			
	str[14] = 0;
	co_str("Frequency: ");
	err = enter_str(tempstr, 13, 0);
	if ((err == 0) || (err == -1))
		return(err);
	for (i = 0; i < err; i++)
		if (tempstr[i] == '.')
			break;
	if (i > 5) 
		return(err);
	j = i;
	k = 9;
	while (i)
		str[k--] = tempstr[--i];
	k = 10;
	while (++j < err)
		str[k++] = tempstr[j];
	return(0);
	}

int xmit_arq()
{
	int i, err;

 	co_str("SELCAL? ");
 	err = enter_str(his_selcal, 4, 0);
 	if (err == -1)
 		return(err);
 	send_cmd(PK232, "\003ARQ ");
 	send_cmd(PK232, his_selcal);
 	lc_put(pk232_port, CR);
 	return(0);
 	}

int xmit_packet()
{
	int i, err;
	char cmd_str[80];
	char ch;

	if (qso.call_sign[0] != 0) 
		log_call();
	build_window(5,11, 7, 76);
	gotoxy(13, 6);
	co_str("CALL SIGN? ");
 	err = enter_str(qso.call_sign, 15, 0);
 	if (err == -1)
 		return(err);
    sprintf(cmd_str, "\003C %s\015", qso.call_sign);
 	send_cmd(PK232, cmd_str);
 	rstr_scr();
 	}

disp_mode()
{
	int i;

	gotoxy(32, 2);
	co_str("        ");
	i = (7 - strlen(pk232_mode_str[pk232_mode]))/2;
	gotoxy(33 + i, 2);
	co_str(pk232_mode_str[pk232_mode]);
	}

call_cq()
{
	int i;

	/* Don't Call CQ if in TRANSMIT mode */
	if (tx_flag)
		return(0);
	xmit();
	co_tx(CR);
	lc_put(pk232_port, CR);
	for (i = 0; i < 3; i++) {
		send_str(PK232, cq_str);
		co_tx(CR);
		lc_put(pk232_port, CR);
		}
	send_str(PK232, ga_str);
	co_tx(CR);
	lc_put(pk232_port, CR);
	lc_put(pk232_port, 4);
	tx_flag = FALSE;
	}

call_qrz()
{
	int i;

	/* Don't QRZ if in TRANSMIT mode */
	if (tx_flag)
		return(0);
	xmit();
	co_tx(CR);
	lc_put(pk232_port, CR);
	send_str(PK232, ry_str);
	co_tx(CR);
	lc_put(pk232_port, CR);
	send_str(PK232, qrz_str);
	co_tx(CR);
	lc_put(pk232_port, CR);
	send_str(PK232, ga_str);
	co_tx(CR);
	lc_put(pk232_port, CR);
	lc_put(pk232_port, 4);
	tx_flag = FALSE;
	}

send_start()
{
	char tempstr[80];

	get_time(0);
	sprintf(tempstr, "\015%s - %s", date, time_of_day);
	send_str(PK232, tempstr);
	if (qso.call_sign[0] != 0)
		sprintf(tempstr, "\015 %s DE %s\015", qso.call_sign, my_call);
	else
		sprintf(tempstr, " %s\015", my_call);
	send_str(PK232, tempstr);
	}

send_stop()
{
	char tempstr[80];

	get_time(0);
	sprintf(tempstr, "\015%s - %s", date, time_of_day);
	send_str(PK232, tempstr);
	if (qso.call_sign[0] != 0) 
		sprintf(tempstr, "\015 %s DE %s\015K K K\015\004",
						qso.call_sign, my_call);
	else 
		sprintf(tempstr, " DE %s\015K K K\015\004", my_call);
	send_str(PK232, tempstr);
	tx_flag = FALSE;
	}

call()
{
	char tempstr[80];

	/* Don't Call if in TRANSMIT mode */
	if ((tx_flag) || (pk232_mode > 8) || (pk232_mode == 0))
		return(0);
	if (pk232_mode != 8) 
		send_cmd(PK232, "\003X\015");
	else
		send_cmd(PK232, "\003FEC\015");
	co_tx(CR);
	lc_put(pk232_port, CR);
	send_str(PK232, ry_str);
	co_tx(CR);
	lc_put(pk232_port, CR);
	sprintf(tempstr, "%s %s %s DE %s %s +%s+ IN %s",
				qso.call_sign, qso.call_sign, qso.call_sign,
					my_call, my_call, my_name, my_qth);
	send_str(PK232, tempstr);
	co_tx(CR);
	lc_put(pk232_port, CR);
	send_str(PK232, ga_str);
	lc_put(pk232_port, 4);
	tx_flag = FALSE;
	}


log_call()
{
	int i, ch, err;
	
	build_window(5,11, 7, 41);
	gotoxy(13, 6);
	if (qso.call_sign[0] == 0) {
		setmem(&qso, sizeof(qso), 0);
		strcpy(qso.date, date);
		strcpy(qso.start, time_of_day);
		strcpy(qso.frequency, ts_440_freq);
		if ((ts440_mode > 0) && (ts440_mode < 6))
			strcpy(qso.mode, ts440_mode_str[ts440_mode]);
		else
			strcpy(qso.mode, pk232_mode_str[pk232_mode]);
		co_str("CALL SIGN: ");
		err = enter_str(qso.call_sign, 15, 0);
		gotoxy(23, 2);
		if (err == -1)
			co_str("        ");
		else {
			co_str(qso.call_sign);
			}
		rstr_scr();
		}
	else {
		strcpy(qso.stop, time_of_day);
		co_str("END/ABORT QSO? ");
		while (((ch = toupper(getch())) != 'E') && (ch != 'A'));
		if (ch == 'A') {
			qso.call_sign[0] = 0;
			rstr_scr();
			gotoxy(23, 2);
			co_str("        ");
			}
		else {
			rstr_scr();
			build_window(5,11,15,73);
			do {
				err = complete_log_call();
				if (err == -1) {
					gotoxy(13, 14);
					co_str("REDO/ABORT LOG ENTRY? ");
					while (((ch = toupper(getch())) != 'R') && (ch != 'A'));
					}
				else
					ch = 'C';
				}
			while (ch == 'R');
			if (ch == 'C') {
				log_file = fopen(my_log, "a");
				fwrite(&qso, sizeof(qso), 1, log_file);
							close(log_file);
				}
			rstr_scr();
			}
		qso.call_sign[0] = 0;
		gotoxy(23, 2);
		co_str("        ");
		}
	}

int send_data()
{
	int err;
	char tempstr[80];

	/* Don't attemp to transmit file directly from RECEIVE mode */
	if (tx_flag == FALSE)
		return(0);
	co_str("FILE NAME: ");
	err = enter_str(tempstr, 50, 0);
	if ((err == -1) || (err == 0))
		return(0);
	send_file = fopen(tempstr, "r");
	if (send_file == 0) {
		gotoxy(13, 7);
		co_str("Unable to Open File: Press any key to continue");
		err = getch();
		return(0);
		}
	xmit_file(send_file);
	return(0);
	}

int xmit_file(fp)
FILE *fp;
{
	char str[80];
	char *err;

	err = fgets(str, 80, fp);
	co_tx(CR);
	lc_put(pk232_port, CR);
	while (err != NULL) {
		send_str(PK232, str);
		co_tx(CR);
		lc_put(pk232_port, CR);
		err = fgets(str, 80, fp);
		}
	co_tx(CR);
	lc_put(pk232_port, CR);
	close(fp);
	}

int xmit_eqp()
{
	int ch;
	
	/* Don't attemp to transmit file directly from RECEIVE mode */
	if (tx_flag == FALSE)
		return(0);
	send_file = fopen(my_equip, "r");
	if (send_file == 0) {
		build_window(5,11, 7, 73);
		gotoxy(13, 6);
		co_str("Unable to Open Equipment File: press any key to continue");
		getch();
		rstr_scr();
		return(0);
		}
	xmit_file(send_file);
	return(0);
	}

send_cmd(io_dev, str)
int io_dev;
char *str;
{
	co_tx(CR);
	co_tx_str("CMD: ");
	send_str(io_dev, str);
	}

/* send a character string to serial port (PK232 or TS440) */
send_str(io_dev, str)
int io_dev;
char *str;
{
	int i;

	i = 0;
	while (str[i]) {
		if (io_dev == PK232) {
			co_tx(str[i]);
			lc_put(pk232_port, str[i++]);
			}
		else
			lc_put(ts440_port, str[i++]);
		}
	}

int complete_log_call()
{
	int err;

	scr_scrup(0,cur_window.frow+1, cur_window.fcol+1,
				cur_window.trow-1, cur_window.tcol-1);
/*  Name */
	gotoxy(13, 6);
	co_str("NAME: ");
	err = enter_str(qso.name, 20, 0);
	if (err == -1)
		return(err);
/*  QTH  */
	gotoxy(13, 7);
	co_str("QTH: ");
	err = enter_str(qso.qth, 30, 0);
	if (err == -1)
		return(err);
/*  POWER */
	gotoxy(13, 8);
	co_str("POWER: ");
	err = enter_str(qso.power, 4, 0);
	if (err == -1)
		return(err);
/*  His RST  */
	gotoxy(13, 9);
	co_str("RST Sent: ");
	err = enter_str(qso.rst_sent, 3, 0);
	if (err == -1)
		return(err);
/*  My RST  */
	gotoxy(31, 9);
	co_str("RST Received: ");
	err = enter_str(qso.rst_rcvd, 3, 0);
	if (err == -1)
		return(err);
/*  Comments */
	gotoxy(13,10);
	co_str("COMMENTS: ");
	err = enter_str(qso.comments, 55, 0);
	if (err == -1)
		return(err);
/*  Contest Exchange */
	gotoxy(13, 11);
	co_str("CONTEST: ");
	err = enter_str(qso.contest, 20, 0);
	if (err == -1)
		return(err);
	return(0);
	}

/*
 scr_scrup(0,cur_window.frow+1, cur_window.fcol+1,
				cur_window.trow-1, cur_window.tcol-1);
*/

scr_scrup(int lines, int frow, int fcol, int trow, int tcol)
{
	union REGS regs;

	regs.h.ah = 6;
	regs.h.al = lines;
	regs.h.bh = 7;       /* normal video attribute  */
	regs.h.ch = frow;
	regs.h.cl = fcol;
	regs.h.dh = trow;
	regs.h.dl = tcol;

	int86(VIDEO, &regs, &regs);
	}

int scr_sinp()
{
	union REGS regs;

	regs.h.ah = 8;  /* read attribute and character at cursor */
	regs.h.bh = 0;
	int86(VIDEO, &regs, &regs);
	return (regs.h.al);
	}

fill_receive_window()
{
	int i;

	for (i = 0; i < 700; i++)
		co_rx('X');
}

co_str(str)
char *str;
{
	int i, x, y;

	i = getxy();
	y = 1 + (i >> 8);
	x = 1 + (i & 0xff);
	i = 0;
	while ((str[i] != 0) && (i < 80)) {
		chr_out(str[i++]);
		gotoxy(++x, y);
		}
   }

int getxy()
{
	union REGS regs;

	regs.h.ah = 3;  /* read cursor position into DH, DL */
	regs.h.bh = 0;
    int86(VIDEO, &regs, &regs);
    return (regs.x.dx);
    }
