/*

	ICOM Radio Control Program
	    (generalized ICOM)

	written in TURBO C V1.5

	by John Lundy - N5MHZ


			**  NOTE  **

	If you make modifications to this program and compile and link it, be
	sure and convert the .EXE file to .COM!  Although this program may
	work in some .EXE configurations, it cannot be guaranteed.  So, be safe
	and use EXE2BIN to convert it...

*/
#include <bios.h>
#include <conio.h>
#include <ctype.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define REV  "2.0"

#define BUF_SZ 4096
#define TMR_VEC 0x1c
#define COM_VEC 0x0c
#define KBD_VEC 0x09

#undef pokeb
#undef peekb
#undef poke
#undef peek
#define pokeb(s,o,b) (*((unsigned char far *)(((long)(s)<<16)+(o)))) = (b)
#define peekb(s,o) (*((unsigned char far *)(((long)(s)<<16)+(o))))
#define poke(s,o,w) (*((unsigned int far *)(((long)(s)<<16)+(o)))) = (w)
#define peek(s,o) (*((unsigned int far *)(((long)(s)<<16)+(o))))

struct	text_info	dos_info;

char	auth[]="John Lundy - N5MHZ";

unsigned char	ch, cn, first[BUF_SZ];
unsigned char	*get, *put, *last = &first[BUF_SZ-1];
unsigned char	dscr[25][160];
unsigned char	tx[81], cmd[17], dat[33], fn[81], drv[3], dir[65];
char	hex[17]={"0123456789ABCDEF"};
char	bds[64][73];
unsigned int	ticks=0, tacks=0;
unsigned int	d_ss, d_sp, sss, ssp, ssn, ssv[64];
int		i, j, k, x, y, dx, dy, vx, vy, tvx, tvy;
int		addr, com;
int		com_base, thr, rbr, llsb, lmsb, ier, iir, lcr, mcr, lsr, msr;
int		bits, baud, paron, parity, stops, intrpt;
int		bdiv, blsb, bmsb, cctl;
int		ptx, active=1, slct=0, rq, rqf;
int		dds, fgd, bgd;
int		m, v, c, bp=-1, tp, ud, bm, bms=0, bf=0, tv=0, td=4, flh=0;
long	l, r;
long	f, fb, ft, fi=250;
long	fl[32], fh[32];
long	bdf[64];
int		bdm[64];
int		*parm[]={	&addr,&com,&bits,&baud,&stops,
					&paron,&parity,&intrpt,&fgd,&bgd,
					NULL};

char	*ptxt[]={   "ICOM address (decimal) %2d\r\n",
					"Com port                %1d\r\n",
					"Data bits               %1d\r\n",
					"Baud rate           %05d\r\n",
					"Stop bit(s)             %1d\r\n",
					"Parity on=1/off=0       %1d\r\n",
					"Parity odd=1/even=0     %1d\r\n",
					"Interrupt               %1d\r\n",
					"Foreground color       %02d\r\n",
					"Background color        %1d\r\n",NULL};

int		aptr[]={4,4,4,4,4,4,2,2,4,2,2,4};

char	*prgm[]={	"03E000FEFE",	/* Freq */
					"04E000FEFE",	/* Mode */
					"09E000FEFE",	/* Mem  */
					"0AE000FEFE",	/* Mem->VFO */
					"07E000FEFE",	/* VFO  */
					"08E000FEFE",	/* Chan */
					"000000FEFE",	/* Freq */
					"0300E0FEFE",
					"05E000FEFE",
					"010000FEFE",	/* Mode */
					"0400E0FEFE",
					"06E000FEFE",
					NULL};

/*
			**  NOTE  **

	Use extreme care if you compile this program using
	any other version of C.  The following reference to
	to _atexittbl is to determine the highest address used
	by our program.  In TURBO C this location in memory is
	the address of a 64 byte block of data storage that is
	always the highest referenced address of a TURBO C pro-
	gram.
*/
void _atexittbl (void);

void interrupt (*oldtmr)();
void interrupt (*oldcom)();
FILE	*stream;

/*************************/
/*  Sound Initializaton  */
/*************************/
void bgnsd(long snd)
{
	snd = 1193280 / snd;
	outportb(0x43,0xb6);
	outportb(0x42,(char) (snd & 0xff));
	outportb(0x42,(char) ((snd >> 8) & 0xff));
	outportb(0x61,inportb(0x61) | 3);
	return;
}

/***********************/
/*  Sound Termination  */
/***********************/
void endsd(void)
{
	outportb(0x61,inportb(0x61) & 0xfc);
	return;
}

/*********************/
/*  Com Int Handler  */
/*********************/
void interrupt newcom()
{
	if (active)
	{
		outportb(0x20,0x60 + intrpt);	/*	EOI	*/
		switch (inportb(iir))
		{
		case 6:
			break;
		case 4:
			*put++ = inportb(rbr);
			if (put == last) put = first;
			break;
		case 2:
			break;
		case 0:
			break;
		default:
			break;
	    }
	}
	else
	{
		(*oldcom)();
	}
	return;
}

/***********************/
/*  Timer Int Handler  */
/***********************/
void interrupt newtmr()
{
	(*oldtmr)();
	if (slct == 0) if ((peekb(0x40, 0x17) & 0xf) == 5) slct = 1;
	if (active)
	{
		if (ticks == 2) bgnsd(400); else if (ticks == 1) endsd();
		if (ticks) ticks--; if (tacks) tacks--;
	}
	else
	{
		if (slct) if ((peekb(0x40, 0x17) & 0xf) == 0)
		{
			disable(); outportb(0x20,0x60); active = 1; slct = 0;
			d_ss = _SS; d_sp = _SP; _SS = sss; _SP = ssp;
			ssn = 0x8000 - (d_sp / 2);
			if (ssn > 64) ssn = 64;
			for (i=0 ; i < ssn ; i++) ssv[i] = peek(d_ss, d_sp + i * 2);
			enable(); prog(); disable();
			for (i=0 ; i < ssn ; i++) poke(d_ss, d_sp + i * 2, ssv[i]);
			_SS = d_ss; _SP = d_sp; active = slct = 0;
		}
	}
	return;
}

/***********************/
/*  Transmit Character */
/***********************/
void xmtch(unsigned char ch)
{
	while ((inportb(lsr) & 0x20) == 0);
	outportb(thr,ch);
	return;
}

/*********************/
/*  Transmit String  */
/*********************/
void xmts(char *strg)
{
	while (*strg) xmtch(*strg++);
	return;
}

/*******************/
/*  Setup Com Port */
/*******************/
void set_com(void)
{
	com_base = peek(0x40,(com - 1) * 2);
	thr = com_base;
	rbr = com_base;
	llsb = com_base;
	lmsb = com_base + 1;
	ier = com_base + 1;
	iir = com_base + 2;
	lcr = com_base + 3;
	mcr = com_base + 4;
	lsr = com_base + 5;
	msr = com_base + 6;

	/*
		Establish baud rate divisor
	*/
	bdiv = 115200 / baud;
	blsb = bdiv & 0xff;
	bmsb = (bdiv >> 8) & 0xff;

	/*
		Establish character attributes
	*/
	cctl = (bits - 5) + ((stops - 1) << 2) + (paron << 3) + ((1 - parity) << 5);

	/*
		Initialize COM port
	*/
	outportb(ier,0x00);		/* Disable Interrupts         */
	outportb(lcr,0x80|cctl);/* Attributes & Set Baud      */
	outportb(llsb,blsb);	/* LSB of Divisor for Baud    */
	outportb(lmsb,bmsb);	/* MSB of Divisor for Baud    */
	outportb(lcr,cctl);		/* Attributes & Xmt Regs Enab */
	outportb(mcr,0x0b);		/* DTR/RTS & Enable Int       */
	outportb(ier,0x01);		/* Enable Int on Rcv Data     */
	inportb(lsr);			/* Clr Line Status Reg        */
	inportb(msr);			/* Clr Modem Status Reg       */
	inportb(rbr);			/* Clr Receive Buffer Reg     */
	inportb(iir);			/* Clr Int Ident Reg          */
	outportb(0x21,inportb(0x21) & (~(1 << intrpt)));
	return;
}

/*****************************/
/*  Reset Interrupt Vectors  */
/*****************************/
void rst_vect(void)
{
	/*
		Deassign interrupt vectors
	*/
	outportb(0x21,inportb(0x21) | (1 << intrpt));
	setvect(COM_VEC - (1 - (com & 1)), oldcom);
	setvect(TMR_VEC, oldtmr);
	return;
}

/********************/
/*  Write to Radio  */
/********************/
void wrt(void)
{
	ticks = 9 * rq;
	xmtch(0xfe); xmtch(0xfe);
	xmtch(addr); xmtch(0xe0);
	xmtch(cn);
	for (i=0 ; i < dat[0] ; xmtch(dat[++i]));
	xmtch(0xfd);
	return;
}

/********************/
/*  Read Frequency  */
/********************/
void rd_freq(void)
{
	cn = 3; rq = 2;
	dat[0] = 0;
	wrt();
	return;
}

/***************/
/*  Read Mode  */
/***************/
void rd_mode(void)
{
	cn = 4; rq = 2;
	dat[0] = 0;
	wrt();
	return;
}

/*********************/
/*  Write Frequency  */
/*********************/
void wr_freq(void)
{
	cn = 5; rq = 2;
	sprintf(tx,"%010ld",f);
	dat[0] = fb / 2;
	for (i=10-fb, j=fb/2 ; i < 10 ; i+=2, j--)
		dat[j] = ((tx[i] - '0') << 4) + (tx[i+1] - '0');
	wrt();
	return;
}

/****************/
/*  Write Mode  */
/****************/
void wr_mode(void)
{
	cn = 6; rq = 2;
	dat[1] = m;
	dat[0] = 1;
	wrt();
	return;
}

/***************/
/*  Write VFO  */
/***************/
void wr_vfo(void)
{
	cn = 7; rq = 2;
	dat[1] = v;
	dat[0] = 1;
	wrt();
	return;
}

/*******************/
/*  Write Channel  */
/*******************/
void wr_ch(void)
{
	cn = 8; rq = 2;
	if (c < 10)
		dat[1] = c;
	else
		dat[1] = ((c / 10) << 4) + (c - ((c / 10) * 10));
	dat[0] = 1;
	wrt();
	return;
}

/******************/
/*  Write Memory  */
/*****************/
void wr_tmem(void)
{
	cn = 9; rq = 2;
	dat[0] = 0;
	wrt();
	return;
}

/***************/
/*  Write VFO  */
/***************/
void wr_tvfo(void)
{
	cn = 10; rq = 2;
	dat[0] = 0;
	wrt();
	return;
}

/*********************/
/*  Print Frequency  */
/*********************/
void pfreq(void)
{
	gotoxy(1,23);
	l = f / 1000l;
	r = (f - (l * 1000l)) / 10l;
    cprintf("%7ld.%02ld KHz in",l,r);
	gotoxy(1,1);
	if (bp >= 0)
		if ((f >= fl[bp]) && (f <= fh[bp])) return;
	for (bp=0 ; bp < flh ; bp++) if ((f >= fl[bp]) && (f <= fh[bp])) return;
	bp = -1;
	return;
}

/****************/
/*  Print Mode  */
/****************/
void pmode(void)
{
	gotoxy(19,23);
	switch (m)
	{
	case 0:	strcpy(tx,"LSB "); break;
	case 1:	strcpy(tx,"USB "); break;
	case 2:	strcpy(tx," AM "); break;
	case 3:	strcpy(tx," CW "); break;
	case 4: strcpy(tx,"RTTY"); break;
	case 5:	strcpy(tx," FM "); break;
	default:	strcpy(tx,"UNKN"); break;
	}
	cprintf("%4s mode",tx);
	gotoxy(1,1);
	return;
}

/***************/
/*  Print VFO  */
/***************/
void pvfo(void)
{
	gotoxy(29,23);
	switch (v)
	{
	case 0:	strcpy(tx,"Vfo A"); break;
	case 1:	strcpy(tx,"Vfo B"); break;
	default:	strcpy(tx,"Vfo ?"); break;
	}
	cprintf("%s",tx);
   	rd_freq();
	rqf = 1;
	return;
}

/****************/
/*  Print Chan  */
/****************/
void pchn(void)
{
	gotoxy(35,23);
	cprintf("Chan %2d",c);
	gotoxy(1,1);
	return;
}

/********************/
/*  Refresh Screen  */
/********************/
void ref_scrn(void)
{
	textcolor(fgd); textbackground(bgd);
	clrscr(); gotoxy(2,1);
	cprintf("ICOM Programmer  Version %s  %s  %s\r\n\r\n",REV,__DATE__,__TIME__);
	gotoxy(1,4);
	cprintf("B/T-Band Bot/Top    F-Frequency         (Band/Mode Entries) \r\n");
	cprintf("P/N-Band Prv/Nxt    .-Round Freq        Ins-Store           \r\n");
	cprintf("                                        Del-Clear           \r\n");
	cprintf("D/U-Scan Down/Up    C-Memory Channel    -> -Next            \r\n");
	cprintf("I-Scan Increment    V-Memory->Vfo       <- -Prev            \r\n");
	cprintf("                    M-Vfo->Memory       R-Recall Last Entry \r\n");
	cprintf("                                        L-Load List Disk    \r\n");
	cprintf("Ctrl/RShift-Exit                        S-Save List Disk    \r\n");
	cprintf("                                        Z-Clear List        \r\n");
	cprintf("                    (Key Pad)                               \r\n");
	cprintf("Home +Scan Incr     Up   +.1 KHz        PgUp +1 KHz         \r\n");
	cprintf("Left -.5 KHz                            Rght +.5 KHz        \r\n");
	cprintf("End  -Scan Incr     Down -.1 KHz        PgDn -1 KHz         \r\n");
	gotoxy(2,25);
	textcolor(bgd); textbackground(fgd);
	cprintf(" F1-LSB  F2-USB  F3-AM  F4-CW  F5-RTTY  F6-FM  F7-VfoA  F8-VfoB               ");
	textcolor(fgd); textbackground(bgd);
	set_com();
   	rd_freq();
	rqf = 1;
	return;
}

/**************************/
/*  Convert Text to Long  */
/**************************/
long cnv_txt(char *tx)
{
	for (i=0 ; (tx[i] == ' ') || (tx[i] == 0x9) ; i++);
	if ((tx[i] == '-') || (tx[i] == '+')) j = i + 1; else j = i;
	for (l=0 ; isdigit(tx[j]) ; j++)
		l = l * 10 + (tx[j] - '0');
	if (tx[j] == '.') j++;
	for (k=0, r=0 ; isdigit(tx[j]) && (k < 2) ; j++, k++)
		r = r * 10 + (tx[j] - '0');
	for ( ; k < 3 ; k++) r *= 10;
	ft = l * 1000l + r;
	return(ft);
}

/*********************/
/*  Load Parameters  */
/*********************/
int ld_parm(void)
{
	stream = fopen(fn,"rb");
	if (stream != NULL)
	{
		do
		{
			if (fgets(tx,81,stream) == NULL) break;
			for(j=strlen(tx) ; (j > 0) && (isdigit(tx[j]) == 0) ; j--);
			for( ; (j > 0) && (isspace(tx[j]) == 0) ; j--);
   	        addr = atoi(&tx[j]);
			break;
		}
		while (-1);
		flh = 0;
		do
		{
			if (fgets(tx,81,stream) == NULL) break;
			if (tx[0] != '*') break;
			if (flh < 32)
			{
				for(j=strlen(tx) ; (j > 0) && (isdigit(tx[j]) == 0) ; j--);
				for( ; (j > 0) && (isspace(tx[j]) == 0) ; j--);
    	        fh[flh] = atol(&tx[j]);
				for( ; (j > 0) && isspace(tx[j]) ; j--);
				tx[j+1] = 0;
				for( ; (j > 0) && (isspace(tx[j]) == 0) ; j--);
				if (tx[j] != '*')
	    	        fl[flh] = atol(&tx[j]);
				else
					fl[flh] = atol(&tx[j+1]);
				flh++;
			}
		}
		while (-1);
		for (i=1 ; parm[i] != NULL ; i++)
		{
			if (feof(stream)) break;
			for(j=strlen(tx) ; (j > 0) && (isdigit(tx[j]) == 0) ; j--);
			for( ; (j > 0) && (isspace(tx[j]) == 0) ; j--);
   	        *parm[i] = atoi(&tx[j]);
			fgets(tx,81,stream);
		}
		bms = 0;
		do
		{
			if (feof(stream)) break;
			if (bms < 64)
			{
				for(j=strlen(tx) ; (j > 0) && (isdigit(tx[j]) == 0) ; j--);
				for( ; (j > 0) && (isspace(tx[j]) == 0) ; j--);
				bdm[bms] = atoi(&tx[j]);
				for( ; (j > 0) && isspace(tx[j]) ; j--);
				tx[j+1] = 0;
				for( ; (j > 0) && (isspace(tx[j]) == 0) ; j--);
				bdf[bms] = atol(&tx[j]);
				if (fgets(bds[bms],73,stream) == NULL) break;
				bds[bms][strlen(bds[bms])-2] = 0;
				bms++;
			}
			fgets(tx,81,stream);
		}
		while (-1);
		bm = bms;
		fclose(stream);
		if(((com >= 1)      && (com <= 4))
		&& ((bits >= 5)     || (bits <= 8))
		&& ((baud == 300)   || (baud == 600)
		||  (baud == 1200)  || (baud == 2400)
		||  (baud == 4800)  || (baud == 9600)
		||  (baud == 19200))
		&& ((stops == 1)    || (stops == 2))
		&& ((paron == 0)    || (paron == 1))
		&& ((parity == 0)   || (parity == 1))
		&& ((intrpt == 3)   || (intrpt == 4)))
		{}
		else
		{
			printf("COM data error in ICOM.INI\a");
			return(1);
		}
		if(((fgd >= 0) && (fgd <= 15))
		&& ((bgd >= 0) && (bgd <= 7)))
		{}
		else
		{
			printf("Display data error in ICOM.INI\a");
			return(1);
		}
	}
	else
	{
		addr = 4;		/* ICOM IC735         */
		com = 1;		/* COM1               */
		bits = 8;		/* 8 data bits        */
		baud = 1200;	/* 1200 baud          */
		stops = 1;		/* stop bits = 1      */
		paron = 0;		/* parity enable = Off*/
		parity = 0;		/* parity = Even      */
		intrpt = 4;		/* interrupt 4        */
		fgd = 7;		/* foreground color   */
		bgd = 0;		/* background color   */
	}
	if (addr == 4) fb = 8; else fb = 10;
	for (i=0 ; prgm[i] != NULL ; i++)
	{
		prgm[i][aptr[i]] = hex[(addr >> 4) & 0xf];
		prgm[i][aptr[i]+1] = hex[addr & 0xf];
	}

	/*
		Check COM port
	*/
	if (peek(0x40,(com - 1) * 2) == 0)
	{
		printf("COM%d Not Available\a",com);
		return(1);
	}

	/*
		Initialize COM port
	*/
	oldcom = getvect(COM_VEC - (1 - (com & 1)));
	setvect(COM_VEC - (1 - (com & 1)), newcom);

	/*
		Reassign interrupt vectors
	*/
	oldtmr = getvect(TMR_VEC);
	setvect(TMR_VEC, newtmr);
	return(0);
}

/*********************/
/*  Execute Program  */
/*********************/
prog(void)
{

	/*
		Initialize Display
	*/
	gettextinfo(&dos_info);
	if ((dos_info.currmode == BW40) || (dos_info.currmode == BW80))
	{
		dds = 0xb000;
		textmode(BW80);
		fgd = 7;
		bgd = 0;
	}
	else
	{
		dds = 0xb800;
		textmode(C80);
	}

    /*
		Save DOS Screen
	*/
	for (i=0 ; i < 25 ; i++)
		for (j=0 ; j < 160 ; j++)
			dscr[i][j] = peekb(dds, i * 160 + j);

	/*
		Setup Variables
	*/
	get = put = first;
	ptx = 0; cmd[10] = 0;

	/*
		Setup Our Screen and COM Port
	*/
	ref_scrn();

	do
	{

		/*
			Exit
		*/
		if (slct)
		if ((peekb(0x40, 0x17) & 0xf) == 0)
		{
			/*
				Restore DOS Screen
			*/
			textmode(dos_info.currmode);
			textattr(dos_info.attribute);
			gotoxy(dos_info.curx,dos_info.cury);
			for (i=0 ; i < 25 ; i++)
				for (j=0 ; j < 160 ; j++)
					pokeb(dds, i * 160 + j, dscr[i][j]);
			return;
		}

		/*
			Check for I/O time out
		*/
		if (rq && (ticks == 0))
		{
        	ptx = rq = 0;
			gotoxy(1,21);
			cprintf("No response from radio...");
		}

		/*
			Do Up/Down
		*/
		if (ud && (rq == 0) && (kbhit() == 0) && (tacks == 0))
		{
			f += (fi * ud);
			if (bp >= 0)
			{
				if (ud > 0)
				{
					if (f > fh[bp]) f = fl[bp];
				}
				else
				{
					if (f < fl[bp]) f = fh[bp];
				}
			}
			wr_freq();
			tacks = td;
		}

		/*
			Do Memory to Vfo
	    */
		if (tv && (rq == 0) && (kbhit() == 0))
		{
			rd_freq();
			rqf = 1;
			tv = 0;
		}

		/*
			New Band/Mode
		*/
		if (bf && (rq == 0))
		{
			bf = 0;
			wr_mode();
		}

		/*
			Check for input
		*/
		if (kbhit() && (rq == 0))
		{
			ud = 0;
			gotoxy(1,21); cprintf("%80.80s",""); gotoxy(1,1);
			ch = toupper(getch());
			switch (ch)
			{
			case 0:				/* Special Key */
				ch = getch();
				switch (ch)
				{
				case 15:		/* Back Tab */
					if (bms == 0) break;
					bm--;
					if (bm < 0) bm = bms - 1;
					f = bdf[bm]; m = bdm[bm];
					wr_freq(); bf = 1;
					gotoxy(1,21);
					cprintf(" %2d: %s",bm+1,bds[bm]);
					break;
				case 59:		/* F1 */
				case 60:        /* F2 */
				case 61:        /* F3 */
				case 62:        /* F4 */
				case 63:        /* F5 */
				case 64:        /* F6 */
					m = ch - 59;
					wr_mode();
					break;
				case 65:		/* F7 */
				case 66:        /* F8 */
					v = ch - 65;
					wr_vfo();
					break;
				case 67:        /* F9 */
					break;
				case 68:        /* F10 */
					break;
				case 72:		/* Up Arrow */
					f += 100;
					wr_freq();
					break;
				case 80:		/* Down Arrow */
					f -= 100;
					wr_freq();
					break;
				case 77:		/* Right Arrow */
					f += 500;
					wr_freq();
					break;
				case 75:		/* Left Arrow */
					f -= 500;
					wr_freq();
					break;
				case 73:		/* Page Up */
					f += 1000;
					wr_freq();
					break;
				case 81:		/* Page Down */
					f -= 1000;
					wr_freq();
					break;
				case 71:		/* Home */
					f += fi;
					wr_freq();
					break;
				case 79:		/* End */
					f -= fi;
					wr_freq();
					break;
				case 82:		/* Ins */
					gotoxy(1,21);
					if (bms == 64)
					{
						cprintf("**  No Room for Band/Mode  **");
						break;
					}
					for (bm=0 ; bm < bms ; bm++)
						if (bdf[bm] == f)
						{
							cprintf(" %2d: %s",bm+1,bds[bm]);
							gotoxy(1,1);
							break;
						}
					if (bm < bms) break;
					bdf[bms] = f; bdm[bms] = m;
					cprintf(" %2d? ",bms+1);
					gets(bds[bms]);
					if (bds[bms][0] == 0)
					{
						gotoxy(1,21);
						cprintf("**  Nothing Saved  **");
						break;
					}
					bds[bms++][72] = 0;
					gotoxy(1,1);
					break;
				case 83:		/* Del */
					if (bms == 0) break;;
					gotoxy(1,21);
					cprintf("Clear this Band/Mode? ");
					if (toupper(getch()) == 'Y')
					{
						for (bms-- ; bm < bms ; bm++)
						{
							bdf[bm] = bdf[bm+1];
							bdm[bm] = bdm[bm+1];
							strcpy(bds[bm],bds[bm+1]);
						}
						gotoxy(1,21);
						cprintf("**  Band/Mode is Clear  **");
					}
					else
					{
						gotoxy(1,21);
						cprintf("%80.80s","");
						gotoxy(1,1);
					}
					break;
				default:
					break;
				}
				break;
			case 9:				/* Tab */
				if (bms == 0) break;
				bm++;
				if (bm >= bms) bm = 0;
				f = bdf[bm]; m = bdm[bm];
				wr_freq(); bf = 1;
				gotoxy(1,21);
				cprintf(" %2d: %s",bm+1,bds[bm]);
				break;
			case 13:			/* Return */
				ref_scrn();
				break;
			case 27:			/* ESCape */
				break;
			case '.':
				ft = f - (f / 1000l) * 1000l;
				if (ft >= 500l) ft = 1000l; else ft = 0l;
				f = (f / 1000l) * 1000l + ft;
				wr_freq();
				break;
			case 'B':
				if ((bp < 0) || (flh == 0)) break;
				f = fl[bp];
				wr_freq();
				break;
			case 'C':
				gotoxy(1,19);
				cprintf("Enter Memory Channel (1-99): ");
				gets(tx);
				gotoxy(1,19); cprintf("%80.80s",""); gotoxy(1,1);
				c = atoi(tx);
				if ((c < 1) || (c > 99)) break;
				wr_ch();
				break;
			case 'D':
				ud = -1;
				break;
			case 'F':
				gotoxy(1,19);
				cprintf("Enter Frequency (KHz): ");
				gets(tx);
				gotoxy(1,19); cprintf("%80.80s",""); gotoxy(1,1);
				ft = cnv_txt(tx);
				if (ft == 0) break;
				if (tx[i] == '+')
					ft = f + ft;
				else
				if (tx[i] == '-')
					ft = f - ft;
				f = ft;
				wr_freq();
				break;
			case 'I':
				gotoxy(1,19);
				cprintf("Scan Increment (KHz)");
				l = fi / 1000l;
				r = (fi - (l * 1000l)) / 10l;
			    cprintf("[%ld.%02ld]: ",l,r);
				gets(tx);
				gotoxy(1,19); cprintf("%80.80s",""); gotoxy(1,1);
				ft = cnv_txt(tx);
				if ((ft == 0) || (tx[i] == '-')) break;
				fi = ft; td = fi / 55;	/* aprx 1KHz/sec */
				if (td > 18) td = 18;	/* 1 sec/inc max */
				break;
			case 'L':
				rst_vect();
				gotoxy(1,21);
				if (ld_parm() == 0)
				{
					set_com();
					cprintf("**  List Loaded from Disk  **");
				}
				break;
			case 'M':
				wr_tmem();
				gotoxy(1,21);
				cprintf("**  Wrote Vfo to Memory  **");
				break;
			case 'N':
				if (flh == 0) break;
				tp = bp;
				for (bp=flh-1 ; (bp > 0) && (fl[bp] >= f) ; bp--);
				bp += 1;
				if (bp > (flh-1)) bp = 0;
				if (tp == bp) bp += 1;
				if (bp > (flh-1)) bp = 0;
				f = fl[bp]; bf = 1;
				wr_freq();
				break;
			case 'P':
				if (flh == 0) break;
				tp = bp;
				for (bp=0 ; (bp < flh) && (fh[bp] <= f) ; bp++);
				bp -= 1;
				if (bp < 0) bp = flh-1;
				if (tp == bp) bp -= 1;
				if (bp < 0) bp = flh-1;
				f = fl[bp]; bf = 1;
				wr_freq();
				break;
			case 'R':
				if ((bms == 0) || (bm == bms)) break;
				f = bdf[bm]; m = bdm[bm];
				wr_freq(); bf = 1;
				gotoxy(1,21);
				cprintf(" %2d: %s",bm+1,bds[bm]);
				break;
			case 'S':
				gotoxy(1,21);
				stream = fopen(fn,"wb");
				if (stream == NULL)
				{
					cprintf("**  Cannot Open %s  **",fn);
					break;
				}
				fprintf(stream,ptxt[0],addr);
				for (i=0 ; i < flh ; i++)
				{
					fprintf(stream,"* %10ld %10ld\r\n",fl[i],fh[i]);
				}
				for (i=1 ; parm[i] != NULL ; i++)
				{
					fprintf(stream,ptxt[i],*parm[i]);
				}
				if (bms)
					for (i=0 ; i < bms ; i++)
						fprintf(stream,"%10ld %2d\r\n%s\r\n",bdf[i],bdm[i],bds[i]);
				fclose(stream);
				cprintf("**  List Saved to Disk  **");
				break;
			case 'T':
				if (bp < 0) break;
				f = fh[bp];
				wr_freq();
				break;
			case 'U':
				ud = 1;
				break;
			case 'V':
				tv = 1;
				wr_tvfo();
				gotoxy(1,21);
				cprintf("**  Wrote Memory to Vfo  **");
				break;
			case 'Z':
				if (bms == 0) break;
				gotoxy(1,21);
				cprintf("Clear List of Bands/Modes? ");
				if (toupper(getch()) == 'Y')
				{
					bms = 0;
					gotoxy(1,21);
					cprintf("**  List of Bands/Modes are Clear  **");
				}
				else
				{
					gotoxy(1,21);
					cprintf("%80.80s","");
					gotoxy(1,1);
				}
				break;
			default:
				break;
			}
		}

		/*
			Handle output
		*/
		if (get != put)
		{
			ch = *get++;
			if (get == last) get = first;
			tx[ptx++] = ch;
			if (ch == 0xfd)		/* End Of Message Character */
			{
				if (rq) rq--; if (rq == 0) ticks = 0;
				dat[ptx*2] = 0;
				for (i=ptx-1, j=0 ; i >= 0 ; i--)
				{
					dat[j++] = hex[(tx[i] >> 4) & 0xf];
					dat[j++] = hex[tx[i] & 0xf];
				}

				if (j >= 12)
				{
					k = j - 10;
					strncpy(cmd,&dat[k],10);
					strncpy(dat,&dat[2],k-2);
					dat[k-2] = 0;

					if ((strcmp(cmd,prgm[0]) == 0) ||	/* Freq */
						(strcmp(cmd,prgm[1]) == 0) ||	/* Mode */
						(strcmp(cmd,prgm[2]) == 0) ||	/* Mem  */
						(strcmp(cmd,prgm[3]) == 0) ||	/* Mem->VFO */
						(strncmp(cmd,"0B",2) == 0) ||	/* Mem Clr */
						(strncmp(cmd,"0C",2) == 0) ||	/* Ofst Rd */
						(strncmp(cmd,"0D",2) == 0) ||	/* Ofst Wrt */
						(strncmp(cmd,"0E",2) == 0))		/* Scan S/S */
					{
					}
					else
					if (strcmp(cmd,prgm[4]) == 0)		/* VFO  */
					{
						v = atoi(dat);
						pvfo();
					}
					else
					if (strcmp(cmd,prgm[5]) == 0)		/* Chan */
					{
						c = atoi(dat);
						pchn();
					}
					else
					if ((strcmp(cmd,prgm[6]) == 0) ||	/* Freq */
						(strcmp(cmd,prgm[7]) == 0) ||
						(strcmp(cmd,prgm[8]) == 0))
					{
						f = atol(dat);
						pfreq();
						if (rqf) rd_mode();
					}
					else
					if ((strcmp(cmd,prgm[9]) == 0)  ||	/* Mode */
						(strcmp(cmd,prgm[10]) == 0) ||
						(strcmp(cmd,prgm[11]) == 0))
					{
						m = atoi(dat);
						pmode();
						if (rqf) rqf = 0;
					}
					else
					{
						gotoxy(1,21);
						cprintf("Data Error: %s%s",dat,cmd);
					}
				}
			}
			if ((ch == 0xfd) || (ch == 0xfb)) ptx = 0;
		}
	}
	while (-1);
}

/******************/
/*  Main Program  */
/******************/
main(int argc, char *argv[])
{

	/*
		Get previous setup

		Edit the file ICOM.INI for your own COM and Screen
		preferences.  This program will create this file,
		if it doesn't exist, by use of the "Save List Disk"
		option.  If this file does not exist at run time,
		defaults for the IC735 are used.
	*/
	fnsplit(argv[0],drv,dir,fn,fn);
	fnmerge(fn,drv,dir,"ICOM",".INI");
	if (ld_parm()) exit(1);

	if (argc == 2)
	{
		if (tolower(argv[argc-1][0]) == 'r')
		{
			printf("ICOM Programmer  Version %s  %s  %s\r\n\r\n",REV,__DATE__,__TIME__);
			sss = _SS;
	/*
				**  NOTE  **

		The value 2560 in the next statement is the number of bytes of
		stack space required by our program, space required for some
		arrays AND 1K of space for each file we open (i.e. 1 in the
		original program).  Be sure to allow sufficient space if you
		add additional file I/O.
	*/
			ssp = 2560 + ((unsigned int) _atexittbl / 16 + 1) * 16;
			active = 0;
			keep(0, ssp / 16 + 1);
		}
	}
	else
	{
		prog();
		rst_vect();
	}

	return;
}
