/*
Copyright 2001-2022 John Wiseman G8BPQ

This file is part of LinBPQ/BPQ32.

LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

LinBPQ/BPQ32 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with LinBPQ/BPQ32.  If not, see http://www.gnu.org/licenses
*/	

//
//	Rig Control Module
//

// Dec 29 2009

//	Add Scan Control for SCS 

// August 2010

// Fix logic error in Port Initialisation (wasn't always raising RTS and DTR
// Clear RTS and DTR on close

// Fix Kenwood processing of multiple messages in one packet.

// Fix reporting of set errors in scan to the wrong session


// Yaesu List

// FT990 define as FT100


#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE


#include <stdio.h>
#include <stdlib.h>
#include "time.h"

#include "cheaders.h"
#include "tncinfo.h"
#ifdef WIN32
#include <commctrl.h>
#else
char *fcvt(double number, int ndigits, int *decpt, int *sign);  
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
#include "bpq32.h"

#include "hidapi.h"

int Row = -20;

extern struct PORTCONTROL * PORTTABLE;

VOID __cdecl Debugprintf(const char * format, ...);

struct RIGINFO * RigConfig(struct TNCINFO * TNC, char * buf, int Port);
struct RIGPORTINFO * CreateTTYInfo(int port, int speed);
BOOL RigCloseConnection(struct RIGPORTINFO * PORT);
BOOL RigWriteCommBlock(struct RIGPORTINFO * PORT);
BOOL DestroyTTYInfo(int port);
void CheckRX(struct RIGPORTINFO * PORT);
static int OpenRigCOMMPort(struct RIGPORTINFO * PORT, VOID * Port, int Speed);
VOID ICOMPoll(struct RIGPORTINFO * PORT);
VOID ProcessFrame(struct RIGPORTINFO * PORT, UCHAR * rxbuff, int len);
VOID ProcessICOMFrame(struct RIGPORTINFO * PORT, UCHAR * rxbuffer, int Len);
int SendResponse(int Stream, char * Msg);
VOID ProcessYaesuFrame(struct RIGPORTINFO * PORT);
VOID YaesuPoll(struct RIGPORTINFO * PORT);
VOID ProcessYaesuCmdAck(struct RIGPORTINFO * PORT);
VOID ProcessKenwoodFrame(struct RIGPORTINFO * PORT, int Length);
VOID KenwoodPoll(struct RIGPORTINFO * PORT);
VOID DummyPoll(struct RIGPORTINFO * PORT);
VOID SwitchAntenna(struct RIGINFO * RIG, char Antenna);
VOID DoBandwidthandAntenna(struct RIGINFO *RIG, struct ScanEntry * ptr);
VOID SetupScanInterLockGroups(struct RIGINFO *RIG);
VOID ProcessFT100Frame(struct RIGPORTINFO * PORT);
VOID ProcessFT990Frame(struct RIGPORTINFO * PORT);
VOID ProcessFT1000Frame(struct RIGPORTINFO * PORT);
VOID AddNMEAChecksum(char * msg);
VOID ProcessNMEA(struct RIGPORTINFO * PORT, char * NMEAMsg, int len);
VOID COMSetDTR(HANDLE fd);
VOID COMClearDTR(HANDLE fd);
VOID COMSetRTS(HANDLE fd);
VOID COMClearRTS(HANDLE fd);
void CM108_set_ptt(struct RIGINFO *RIG, int PTTState);
BOOL OpenHIDPort(struct RIGPORTINFO * PORT, VOID * Port, int Speed);
int HID_Read_Block(struct RIGPORTINFO * PORT);
int HID_Write_Block(struct RIGPORTINFO * PORT);
HANDLE rawhid_open(char * Device);
int rawhid_recv(int num, void *buf, int len, int timeout);
int rawhid_send(int num, void *buf, int len, int timeout);
void rawhid_close(int num);
VOID ConnecttoHAMLIB(struct RIGPORTINFO * PORT);
VOID ConnecttoFLRIG(struct RIGPORTINFO * PORT);
int DecodeHAMLIBAddr(struct RIGPORTINFO * PORT, char * ptr);
void ProcessHAMLIBFrame(struct RIGPORTINFO * PORT, int Length);
VOID HAMLIBPoll(struct RIGPORTINFO * PORT);
void HAMLIBSlaveThread(VOID * Param);
void CheckAndProcessRTLUDP(struct RIGPORTINFO * PORT);
VOID RTLUDPPoll(struct RIGPORTINFO * PORT);
VOID ConnecttoRTLUDP(struct RIGPORTINFO * PORT);
VOID FLRIGPoll(struct RIGPORTINFO * PORT);
void ProcessFLRIGFrame(struct RIGPORTINFO * PORT);
VOID FLRIGSendCommand(struct RIGPORTINFO * PORT, char * Command, char * Value);

VOID ProcessSDRRadioFrame(struct RIGPORTINFO * PORT, int Length);
VOID SDRRadioPoll(struct RIGPORTINFO * PORT);

VOID SetupPortRIGPointers();
VOID PTTCATThread(void * Param);


// ----- G7TAJ ----
VOID ConnecttoSDRANGEL(struct RIGPORTINFO * PORT);
VOID SDRANGELPoll(struct RIGPORTINFO * PORT);
void ProcessSDRANGELFrame(struct RIGPORTINFO * PORT);
VOID SDRANGELSendCommand(struct RIGPORTINFO * PORT, char * Command, char * Value);
void SDRANGELProcessMessage(struct RIGPORTINFO * PORT);

// ----- G7TAJ ----


int SendPTCRadioCommand(struct TNCINFO * TNC, char * Block, int Length);
int GetPTCRadioCommand(struct TNCINFO * TNC, char * Block);
int BuildRigCtlPage(char * _REPLYBUFFER);
void SendRigWebPage();

extern  TRANSPORTENTRY * L4TABLE;
HANDLE hInstance;

VOID APIENTRY CreateOneTimePassword(char * Password, char * KeyPhrase, int TimeOffset); 
BOOL APIENTRY CheckOneTimePassword(char * Password, char * KeyPhrase);

char * GetApplCallFromName(char * App);

char Modes[25][6] = {"LSB",  "USB", "AM", "CW", "RTTY", "FM", "WFM", "CW-R", "RTTY-R",
					"????","????","????","????","????","????","????","????","DV", "LSBD1",
					"USBD1", "LSBD2","USBD2", "LSBD3","USBD3", "????"};

/*
DV = 17
F8101
(0000=LSB, 0001=USB, 0002=AM,
0003=CW, 0004=RTTY,
0018=LSB D1, 0019=USB D1,
0020=LSB D2, 0021=USB D2,
0022=LSB D3, 0023=USB D3
*/
//							0		1	  2		3	   4	5	6	7	8	9		0A  0B    0C    88

char YaesuModes[16][6] = {"LSB",  "USB", "CW", "CWR", "AM", "", "", "", "FM", "", "DIG", "", "PKT", "FMN", "????"};

char FT100Modes[9][6] = {"LSB",  "USB", "CW", "CWR", "AM", "DIG", "FM", "WFM", "????"};

char FT990Modes[13][6] = {"LSB",  "USB", "CW2k4", "CW500", "AM6k", "AM2k4", "FM", "FM", "RTTYL", "RTTYU", "PKTL", "PKTFM", "????"};

char FT1000Modes[13][6] = {"LSB",  "USB", "CW", "CWR", "AM", "AMS", "FM", "WFM", "RTTYL", "RTTYU", "PKTL", "PKTF", "????"};

char FTRXModes[8][6] = {"LSB", "USB", "CW", "AM", "FM", "RTTY", "PKT", ""};

char KenwoodModes[16][6] = {"????", "LSB",  "USB", "CW", "FM", "AM", "FSK", "????"};

char FT2000Modes[16][6] = {"????", "LSB",  "USB", "CW", "FM", "AM", "FSK", "CW-R", "PKT-L", "FSK-R", "PKT-FM", "FM-N", "PKT-U", "????"};

char FTDX10Modes[16][9] = {"????", "LSB",  "USB", "CW-U", "FM", "AM", "RTTY-L", "CW-L", "DATA-L", "RTTY-U", "DATA-FM", "FM-N", "DATA-U", "AM-N", "PSK", "DATA-FM-N"};

char FT991AModes[16][9] = {"????", "LSB",  "USB", "CW-U", "FM", "AM", "RTTY-LSB", "CW-L", "DATA-LSB", "RTTY-USB", "DATA-FM", "FM-N", "DATA-USB", "AM-N", "C4FM", "????"};

char FLEXModes[16][6] = {"LSB", "USB", "DSB", "CWL", "CWU", "FM", "AM", "DIGU", "SPEC", "DIGL", "SAM", "DRM"};

char AuthPassword[100] = "";

char LastPassword[17];

int NumberofPorts = 0;

BOOL EndPTTCATThread = FALSE;

int HAMLIBMasterRunning = 0;
int HAMLIBSlaveRunning = 0;
int FLRIGRunning = 0;

// ---- G7TAJ ----
int SDRANGELRunning = 0;
// ---- G7TAJ ----

char * RigWebPage = 0;
int RigWebPageLen = 0;


struct RIGPORTINFO * PORTInfo[MAXBPQPORTS + 2] = {NULL};		// Records are Malloc'd

struct RIGINFO * DLLRIG = NULL;			// Rig record for dll PTT interface (currently only for UZ7HO);


struct TimeScan * AllocateTimeRec(struct RIGINFO * RIG)
{
	struct TimeScan * Band = zalloc(sizeof (struct TimeScan));
	
	RIG->TimeBands = realloc(RIG->TimeBands, (++RIG->NumberofBands+2) * sizeof(void *));
	RIG->TimeBands[RIG->NumberofBands] = Band;
	RIG->TimeBands[RIG->NumberofBands+1] = NULL;

	return Band;
}

struct ScanEntry ** CheckTimeBands(struct RIGINFO * RIG)
{
	int i = 0;
	time_t NOW = time(NULL) % 86400;
				
	// Find TimeBand

	while (i < RIG->NumberofBands)
	{
		if (RIG->TimeBands[i + 1]->Start > NOW)
		{
			break;
		}
		i++;
	}

	RIG->FreqPtr = RIG->TimeBands[i]->Scanlist;

	return RIG->FreqPtr;
}

VOID Rig_PTTEx(struct RIGINFO * RIG, BOOL PTTState, struct TNCINFO * TNC);

VOID Rig_PTT(struct TNCINFO * TNC, BOOL PTTState)
{
	if (TNC == NULL) return;

	if (TNC->TXRIG)
		Rig_PTTEx(TNC->TXRIG, PTTState, TNC);
	else
		Rig_PTTEx(TNC->RIG, PTTState, TNC);
}

VOID Rig_PTTEx(struct RIGINFO * RIG, BOOL PTTState, struct TNCINFO * TNC)
{
	struct RIGPORTINFO * PORT;
	int i, Len;
	char cmd[32];
	char onString[128];			// Actual CAT strings to send. May be modified for QSY on PTT
	char offString[128];
	int onLen = 0, offLen = 0;

	if (RIG == NULL) return;

	PORT = RIG->PORT;

	if (PORT == NULL)
		return;

	// CAT string defaults to that set up by RIGConfig in RIG->PTTOn and RIG->PTTOff,
	// but can be overidden by Port specify strings from TNC->PTTOn and TNC->PTTOff.
	// If PTTSetsFreq is set on a Rig, that overrides the RIG->PTTOn but not TNC->PTTOn


	if (PTTState)
	{
		MySetWindowText(RIG->hPTT, "T");
		RIG->WEB_PTT = 'T';
		RIG->PTTTimer = PTTLimit;
		RIG->repeatPTTOFFTimer = 0;				// Cancel repeated off command

		if (TNC && TNC->PTTOn[0])
		{
			memcpy(onString, TNC->PTTOn, TNC->PTTOnLen);
			onLen = TNC->PTTOnLen;
		}
		else
		{
			memcpy(onString, RIG->PTTOn, RIG->PTTOnLen);
			onLen = RIG->PTTOnLen;

			// If PTT_SETS_FREQ set calculate TX Freq and see if changed

			// Freq can be set on the TNC, the RIG, or calculated from current rx freq + pttOffset

			if (TNC && RIG->PTTSetsFreq)
			{
				long long txfreq = 0;

				if (TNC->TXFreq)
					txfreq = TNC->TXFreq + TNC->TXOffset + RIG->txError;
				else if (TNC->RIG && TNC->RIG->txFreq)
					txfreq = RIG->txFreq;		// Used if not associated with a TNC port - eg HAMLIB + WSJT
				else if (TNC->RIG && TNC->RIG->RigFreq != 0.0)
				{
					// Use RigFreq + pttOffset, so TX Tracks RX
					
					long long rxfreq = (long long)(TNC->RIG->RigFreq * 1000000.0) - TNC->RIG->rxOffset;
					txfreq = rxfreq + RIG->pttOffset + RIG->txError;
					txfreq += RIG->rxError;
				}

				if (txfreq)
				{
					if (RIG->lastSetFreq != txfreq)
					{
						char FreqString[80];
						char * CmdPtr = onString;
						UCHAR * Poll = PORT->TXBuffer;


						RIG->lastSetFreq = txfreq;

						// Convert to CAT string

						sprintf(FreqString, "%012lld", txfreq);

						switch (PORT->PortType)
						{
						case ICOM:

							// CI-V must send all commands as one string, or Radio will start to ack them and
							// collide with rest of command

							// Set Freq is sent before set PTT, so set up QSY string then copy PTT string to buffer
							// Need to convert two chars to bcd digit

							*(CmdPtr++) = 0xFE;
							*(CmdPtr++) = 0xFE;
							*(CmdPtr++) = RIG->RigAddr;
							*(CmdPtr++) = 0xE0;
							*(CmdPtr++) = 0x5;		// Set frequency command

							*(CmdPtr++) = (FreqString[11] - 48) | ((FreqString[10] - 48) << 4);
							*(CmdPtr++) = (FreqString[9] - 48) | ((FreqString[8] - 48) << 4);
							*(CmdPtr++) = (FreqString[7] - 48) | ((FreqString[6] - 48) << 4);
							*(CmdPtr++) = (FreqString[5] - 48) | ((FreqString[4] - 48) << 4);
		
							if (RIG->IC735)
							{
								*(CmdPtr++) = 0xFD;
								onLen = 10;
							}
							else
							{
								*(CmdPtr++) = (FreqString[3] - 48);
								*(CmdPtr++) = 0xFD;
								onLen = 11;
							}

							// Now add PTT String

							memcpy(&onString[onLen], RIG->PTTOn, RIG->PTTOnLen);
							onLen += RIG->PTTOnLen;

							break;

						case YAESU:

							*(Poll++) = (FreqString[4] - 48) | ((FreqString[3] - 48) << 4);
							*(Poll++) = (FreqString[6] - 48) | ((FreqString[5] - 48) << 4);
							*(Poll++) = (FreqString[8] - 48) | ((FreqString[7] - 48) << 4);
							*(Poll++) = (FreqString[10] - 48) | ((FreqString[9] - 48) << 4);
							*(Poll++) = 1;		// Set Freq

							PORT->TXLen = 5;
							RigWriteCommBlock(PORT);


							if (RIG->PTTMode & PTTCI_V)
							{
								Sleep(150);
								Poll = PORT->TXBuffer;
								*(Poll++) = 0;
								*(Poll++) = 0;
								*(Poll++) = 0;

								*(Poll++) = 0;
								*(Poll++) = PTTState ? 0x08 : 0x88;		// CMD = 08 : PTT ON CMD = 88 : PTT OFF

								PORT->TXLen = 5;
								RigWriteCommBlock(PORT);
							}

							PORT->Retries = 1;
							PORT->Timeout = 0;

							return;



						case HAMLIB:

							// Dont need to save, as we can send strings separately

							Len = sprintf(cmd, "F %lld\n", txfreq);
							i = send(PORT->remoteSock, cmd, Len, 0);
							RIG->PollCounter = 100;		// Don't read for 10 secs to avoid clash with PTT OFF

							break;

						}
					}
				}
			}
		}
	}
	else
	{
		// Drop PTT

		MySetWindowText(RIG->hPTT, " ");
		RIG->WEB_PTT = ' ';
		RIG->PTTTimer = 0;
		if (PORT->PortType == ICOM)
			RIG->repeatPTTOFFTimer = 300;			// set 30 second repeated off command

		if (TNC && TNC->PTTOff[0])
		{
			memcpy(offString, TNC->PTTOff, TNC->PTTOffLen);
			offLen = TNC->PTTOffLen;
			RIG->lastSetFreq = 0;
		}
		else
		{
			memcpy(offString, RIG->PTTOff, RIG->PTTOffLen);
			offLen = RIG->PTTOffLen;

			// If PTT_SETS_FREQ set calculate TX Freq and see if changed

			if (PTTState == 0 && RIG->PTTSetsFreq && RIG->defaultFreq)
			{
				// Dropped PTT. See if need to set freq back to default

				long long txfreq = RIG->defaultFreq + RIG->txError;

				if (RIG->lastSetFreq != txfreq)
				{
					char FreqString[80];
					char * CmdPtr = offString;
					UCHAR * Poll = PORT->TXBuffer;

					RIG->lastSetFreq = txfreq;

					// Convert to CAT string

					sprintf(FreqString, "%012lld", txfreq);

					switch (PORT->PortType)
					{
					case ICOM:

						// CI-V must send all commands as one string, or Radio will start to ack them and
						// collide with rest of command

						// Set Freq is sent after drop PTT, so copy PTT string to buffer then set up QSY string  
						// Need to convert two chars to bcd digit

						// We copied off string earlier, so just append QSY string

						CmdPtr += offLen;

						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = RIG->RigAddr;
						*(CmdPtr++) = 0xE0;
						*(CmdPtr++) = 0x5;		// Set frequency command

						*(CmdPtr++) = (FreqString[11] - 48) | ((FreqString[10] - 48) << 4);
						*(CmdPtr++) = (FreqString[9] - 48) | ((FreqString[8] - 48) << 4);
						*(CmdPtr++) = (FreqString[7] - 48) | ((FreqString[6] - 48) << 4);
						*(CmdPtr++) = (FreqString[5] - 48) | ((FreqString[4] - 48) << 4);
						if (RIG->IC735)
						{
							*(CmdPtr++) = 0xFD;
							offLen += 10;
						}
						else
						{
							*(CmdPtr++) = (FreqString[3] - 48);
							*(CmdPtr++) = 0xFD;
							offLen += 11;
						}

					case FLRIG:
		
						sprintf(cmd, "<double>%lld</double>", txfreq);
						FLRIGSendCommand(PORT, "rig.set_vfo", cmd);
						RIG->PollCounter = 100;		// Don't read for 10 secs to avoid clash with PTT OFF

					case YAESU:

						// Easier to add PTT string, send and return;

						Len = 0;

						if (RIG->PTTMode & PTTCI_V)
						{
							*(Poll++) = 0;
							*(Poll++) = 0;
							*(Poll++) = 0;
							*(Poll++) = 0;
							*(Poll++) = PTTState ? 0x08 : 0x88;		// CMD = 08 : PTT ON CMD = 88 : PTT OFF

							PORT->TXLen = 5;
							RigWriteCommBlock(PORT);
							Poll = PORT->TXBuffer;
							Sleep(100);
						}

						*(Poll++) = (FreqString[4] - 48) | ((FreqString[3] - 48) << 4);
						*(Poll++) = (FreqString[6] - 48) | ((FreqString[5] - 48) << 4);
						*(Poll++) = (FreqString[8] - 48) | ((FreqString[7] - 48) << 4);
						*(Poll++) = (FreqString[10] - 48) | ((FreqString[9] - 48) << 4);
						*(Poll++) = 1;		// Set Freq

						PORT->TXLen = 5;
						RigWriteCommBlock(PORT);

						PORT->Retries = 1;
						PORT->Timeout = 0;

						return;

					case HAMLIB:

						// Dont need to save, as we can send strings separately

						Len = sprintf(cmd, "F %lld\n", txfreq);
						send(PORT->remoteSock, cmd, Len, 0);
						RIG->PollCounter = 100;		// Don't read for 10 secs to avoid clash with PTT OFF
					}
				}
			}
		}
	}

	// Now send the command

	if (RIG->PTTMode & PTTCI_V)
	{
		UCHAR * Poll = PORT->TXBuffer;

		// Don't read for 10 secs to avoid clash with PTT OFF
		// Should do this for all rigs on port

		for (i = 0; i< PORT->ConfiguredRigs; i++)
			PORT->Rigs[i].PollCounter = 100;

		PORT->AutoPoll = TRUE;

		switch (PORT->PortType)
		{
		case ICOM:
		case KENWOOD:
		case FT2000:
		case FTDX10:
		case FT991A:
		case FLEX:
		case NMEA:

			if (PTTState)
			{
				memcpy(Poll, onString, onLen);
				PORT->TXLen = onLen;
			}
			else
			{
				memcpy(Poll, offString, offLen);
				PORT->TXLen = offLen;
			}

			RigWriteCommBlock(PORT);

			if (PORT->PortType == ICOM && !PTTState)
				RigWriteCommBlock(PORT); // Send ICOM PTT OFF Twice

			PORT->Retries = 1;
			
			if (PORT->PortType != ICOM)
				PORT->Timeout = 0;
			
			return;

		case FT100:
		case FT990:
		case FT1000:

			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = PTTState;	// OFF/ON
			*(Poll++) = 15;
	
			PORT->TXLen = 5;
			RigWriteCommBlock(PORT);

			PORT->Retries = 1;
			PORT->Timeout = 0;

			return;

		case YAESU:  // 897 - maybe others

			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = PTTState ? 0x08 : 0x88;		// CMD = 08 : PTT ON CMD = 88 : PTT OFF
	
			PORT->TXLen = 5;
			RigWriteCommBlock(PORT);

			PORT->Retries = 1;
			PORT->Timeout = 0;

			return;

		case FLRIG:
		
			sprintf(cmd, "<i4>%d</i4>", PTTState);
			FLRIGSendCommand(PORT, "rig.set_ptt", cmd);
			RIG->PollCounter = 100;		// Don't read for 10 secs to avoid clash with PTT OFF

			return;

		case HAMLIB:
	
			Len = sprintf(cmd, "T %d\n", PTTState);
			send(PORT->remoteSock, cmd, Len, 0);
			RIG->PollCounter = 100;		// Don't read for 10 secs to avoid clash with PTT OFF
		
			return;
		}
	}

	if (RIG->PTTMode & PTTRTS)
		if (PTTState)
			COMSetRTS(PORT->hPTTDevice);
		else
			COMClearRTS(PORT->hPTTDevice);

	if (RIG->PTTMode & PTTDTR)
		if (PTTState)
			COMSetDTR(PORT->hPTTDevice);
		else
			COMClearDTR(PORT->hPTTDevice);

	if (RIG->PTTMode & PTTCM108)
		CM108_set_ptt(RIG, PTTState);

	if (RIG->PTTMode & PTTHAMLIB)
	{
		char Msg[16];
		int Len = sprintf(Msg, "T %d\n", PTTState);
	
		Len = send(PORT->remoteSock, Msg, Len, 0);
		RIG->PollCounter = 100;		// Don't read for 10 secs to avoid clash with PTT OFF
	}
	if (RIG->PTTMode & PTTFLRIG)
	{
		char cmd[32];

		sprintf(cmd, "<i4>%d</i4>", PTTState);
		FLRIGSendCommand(PORT, "rig.set_ptt", cmd);
		RIG->PollCounter = 100;		// Don't read for 10 secs to avoid clash with PTT OFF
	}
}

void saveNewFreq(struct RIGINFO * RIG, double Freq, char * Mode)
{
	if (Freq > 0.0)
	{
		_gcvt((Freq + RIG->rxOffset) / 1000000.0, 9, RIG->Valchar);
		strcpy(RIG->WEB_FREQ, RIG->Valchar);
		MySetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
	}

	if (Mode[0])
	{
		strcpy(RIG->ModeString, Mode);
		MySetWindowText(RIG->hMODE, Mode);
	}

}

// Need version that doesn't need Port Number

int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTRY * Session, char * Command);

int Rig_Command(TRANSPORTENTRY * Session, char * Command)
{
	char * ptr;
	int i, n, p, Port;
	TRANSPORTENTRY * L4 = L4TABLE;
	struct RIGPORTINFO * PORT;
	struct RIGINFO * RIG;

	//	Only Allow RADIO from Secure Applications

	_strupr(Command);

	ptr = strchr(Command, 13);
	if (ptr) *(ptr) = 0;						// Null Terminate

	if (memcmp(Command, "AUTH ", 5) == 0)
	{
		if (AuthPassword[0] && (memcmp(LastPassword, &Command[5], 16) != 0))
		{
			if (CheckOneTimePassword(&Command[5], AuthPassword))
			{
				Session->Secure_Session = 1;

				sprintf(Command, "Ok\r");

				memcpy(LastPassword, &Command[5], 16);	// Save

				return FALSE;
			}
		}
		
		sprintf(Command, "Sorry AUTH failed\r");
		return FALSE;
	}

	if (Session != (TRANSPORTENTRY *) -1)				// Used for internal Stop/Start
	{		
		if (Session->Secure_Session == 0)
		{
			sprintf(Command, "Sorry - you are not allowed to use this command\r");
			return FALSE;
		}
	}
	if (NumberofPorts == 0)
	{
		sprintf(Command, "Sorry - Rig Control not configured\r");
		return FALSE;
	}

	// if Port starts with 'R' then select Radio (was Interlock) number, not BPQ Port

	if (Command[0] == 'R')
	{
		n = sscanf(&Command[1],"%d ", &Port);

		for (p = 0; p < NumberofPorts; p++)
		{
			PORT = PORTInfo[p];
	
			for (i=0; i< PORT->ConfiguredRigs; i++)
			{
				RIG = &PORT->Rigs[i];

				if (RIG->Interlock == Port)
					goto portok;
			}
		}

		sprintf(Command, "Sorry - Port not found\r");
		return FALSE;
	}

	n = sscanf(Command,"%d ", &Port);

	// Look for the port 


	for (p = 0; p < NumberofPorts; p++)
	{
		PORT = PORTInfo[p];

		for (i=0; i< PORT->ConfiguredRigs; i++)
		{
			RIG = &PORT->Rigs[i];

			if (RIG->BPQPort & ((uint64_t)1 << Port))
				goto portok;
		}
	}

	sprintf(Command, "Sorry - Port not found\r");
	return FALSE;

portok:

	return Rig_CommandEx(PORT, RIG, Session, Command);
}



static char MsgHddr[] = "POST /RPC2 HTTP/1.1\r\n"
					"User-Agent: XMLRPC++ 0.8\r\n"
					"Host: 127.0.0.1:7362\r\n"
					"Content-Type: text/xml\r\n"
					"Content-length: %d\r\n"
					"\r\n%s";

static char Req[] = "<?xml version=\"1.0\"?>\r\n"
					"<methodCall><methodName>%s</methodName>\r\n"
					"%s"
					"</methodCall>\r\n";


// ---- G7TAJ ----
static char SDRANGEL_MsgHddr[] = "PATCH HTTP/1.1\r\n"
					"User-Agent: BPQ32\r\n"
					"Host: %s\r\n"
					"accept: application/json"
				 	"Content-Type: application/json"
					"Content-length: %d\r\n"
					"\r\n%s";

static char SDRANGEL_FREQ_DATA[] = "{"
    "\"deviceHwType\": \"%s\", "
    "\"direction\": 0,"
    "\"rtlSdrSettings\": {"
    "  \"centerFrequency\": \"%s\""
    "}}";

//freq =  10489630000

// ---- G7TAJ ----



int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTRY * Session, char * Command)
{
	int n, ModeNo, Filter, Port = 0;
	double Freq = 0.0;
	char FreqString[80]="", FilterString[80]="", Mode[80]="", Data[80] = "", Dummy[80] = "";
	struct MSGWITHOUTLEN * buffptr;
	UCHAR * Poll;

	int i;
	TRANSPORTENTRY * L4 = L4TABLE;
	char * ptr;
	int Split, DataFlag, Bandwidth, Antenna;
	struct ScanEntry * FreqPtr;
	char * CmdPtr;
	int Len;
	char MemoryBank = 0;	// For Memory Scanning
	int MemoryNumber = 0;

	//	Only Allow RADIO from Secure Applications

	_strupr(Command);

	ptr = strchr(Command, 13);
	if (ptr) *(ptr) = 0;						// Null Terminate

	if (memcmp(Command, "AUTH ", 5) == 0)
	{
		if (AuthPassword[0] && (memcmp(LastPassword, &Command[5], 16) != 0))
		{
			if (CheckOneTimePassword(&Command[5], AuthPassword))
			{
				Session->Secure_Session = 1;

				sprintf(Command, "Ok\r");

				memcpy(LastPassword, &Command[5], 16);	// Save

				return FALSE;
			}
		}
		
		sprintf(Command, "Sorry AUTH failed\r");
		return FALSE;
	}

	if (Session != (TRANSPORTENTRY *) -1)				// Used for internal Stop/Start
	{		
		if (Session->Secure_Session == 0)
		{
			sprintf(Command, "Sorry - you are not allowed to use this command\r");
			return FALSE;
		}
	}
	if (NumberofPorts == 0)
	{
		sprintf(Command, "Sorry - Rig Control not configured\r");
		return FALSE;
	}

	// if Port starts with 'R' then select Radio (was Interlock) number, not BPQ Port

	if (Command[0] == 'R')
		n = sscanf(Command,"%s %s %s %s %s", &Dummy[0], &FreqString[0], &Mode[0], &FilterString[0], &Data[0]);
	else
		n = sscanf(Command,"%d %s %s %s %s", &Port, &FreqString[0], &Mode[0], &FilterString[0], &Data[0]);

	if (_stricmp(FreqString, "CLOSE") == 0)
	{
		PORT->Closed = 1;
		RigCloseConnection(PORT);

		MySetWindowText(RIG->hSCAN, "C");
		RIG->WEB_SCAN = 'C';

		sprintf(Command, "Ok\r");
		return FALSE;
	}

	if (_stricmp(FreqString, "OPEN") == 0)
	{
		PORT->ReopenDelay = 300;
		PORT->Closed = 0;
		
		MySetWindowText(RIG->hSCAN, "");
		RIG->WEB_SCAN = ' ';

		sprintf(Command, "Ok\r");
		return FALSE;
	}

	if (n > 1)
	{
		if (_stricmp(FreqString, "SCANSTART") == 0)
		{
			if (RIG->NumberofBands)
			{
				RIG->ScanStopped &= (0xffffffffffffffff ^ ((uint64_t)1 << Port));

				if (Session != (TRANSPORTENTRY *) -1)				// Used for internal Stop/Start
					RIG->ScanStopped &= 0xfffffffffffffffe;			// Clear Manual Stopped Bit

				if (n > 2)
					RIG->ScanCounter = atoi(Mode) * 10;  //Start Delay
				else
					RIG->ScanCounter = 10;

				RIG->WaitingForPermission = FALSE;		// In case stuck	

				if (RIG->ScanStopped == 0)
				{
					SetWindowText(RIG->hSCAN, "S");
					RIG->WEB_SCAN = 'S';
				}
				sprintf(Command, "Ok\r");

				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 SCANSTART Port %d", Port);
			}
			else
				sprintf(Command, "Sorry no Scan List defined for this port\r");

			return FALSE;
		}

		if (_stricmp(FreqString, "SCANSTOP") == 0)
		{
			RIG->ScanStopped |= ((uint64_t)1 << Port);

			if (Session != (TRANSPORTENTRY *) -1)				// Used for internal Stop/Start
				RIG->ScanStopped |= 1;		// Set Manual Stopped Bit

			MySetWindowText(RIG->hSCAN, "");
			RIG->WEB_SCAN = ' ';

			sprintf(Command, "Ok\r");

			if (RIG->RIG_DEBUG)
				Debugprintf("BPQ32 SCANSTOP Port %d", Port);

			RIG->PollCounter = 50 / RIG->PORT->ConfiguredRigs;	// Dont read freq for 5 secs

			return FALSE;
		}
	}



	if (RIG->RIGOK == 0)
	{
		if (Session != (TRANSPORTENTRY *) -1)
		{
			if (PORT->Closed)
				sprintf(Command, "Sorry - Radio port closed\r");
			else
				sprintf(Command, "Sorry - Radio not responding\r");
		}
		return FALSE;
	}

	if (n == 2 && _stricmp(FreqString, "FREQ") == 0)
	{
		if (RIG->Valchar[0])
			sprintf(Command, "Frequency is %s MHz\r", RIG->Valchar);
		else
			sprintf(Command, "Frequency not known\r");

		return FALSE;
	}

	if (n == 2 && _stricmp(FreqString, "PTT") == 0)
	{
		Rig_PTTEx(RIG, TRUE, NULL);
		RIG->PTTTimer = 10;				// 1 sec
		sprintf(Command, "Ok\r");
		return FALSE;
	}

	if (Session != (void *)-1)
	{
		if (Session->CIRCUITINDEX == 255)
			RIG->Session = -1;
		else
			RIG->Session = Session->CIRCUITINDEX;		// BPQ Stream
	
		RIG->PollCounter = 50;		// Dont read freq for 5 secs in case clash with Poll
	}

	if (_stricmp(FreqString, "TUNE") == 0)
	{
		char ReqBuf[256];
		char SendBuff[256];
		char FLPoll[80];

		switch (PORT->PortType)
		{ 
		case ICOM:

			buffptr = GetBuff();

			if (buffptr == 0)
			{
				sprintf(Command, "Sorry - No Buffers available\r");
				return FALSE;
			}

			
			// Build a ScanEntry in the buffer

			FreqPtr = (struct ScanEntry *)buffptr->Data;
			memset(FreqPtr, 0, sizeof(struct ScanEntry));

			CmdPtr = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;
			FreqPtr->Cmd2 = NULL;
			FreqPtr->Cmd3 = NULL;

			// IC7100 Tune  Fe fe 88 e0 1c 01 02 fd


			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = RIG->RigAddr;
			*(CmdPtr++) = 0xE0;
			*(CmdPtr++) = 0x1C;
			*(CmdPtr++) = 0x01;
			*(CmdPtr++) = 0x02;
			*(CmdPtr++) = 0xFD;
			FreqPtr[0].Cmd1Len = 8;
			
			C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);

			return TRUE;

		case KENWOOD:

			buffptr = GetBuff();
	
			if (buffptr == 0)
			{
				sprintf(Command, "Sorry - No Buffers available\r");
				return FALSE;
			}

			// Build a ScanEntry in the buffer

			FreqPtr = (struct ScanEntry *)buffptr->Data;
			memset(FreqPtr, 0, sizeof(struct ScanEntry));
	
			Poll = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;

			FreqPtr->Cmd1Len = sprintf(Poll, "AC111;AC;");

			C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);
			return TRUE;

		case FLRIG:

			strcpy(FLPoll, "rig.tune");

			Len = sprintf(ReqBuf, Req, FLPoll, "");
			Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);

			if (PORT->CONNECTED)
			{
				if (send(PORT->remoteSock, SendBuff, Len, 0) != Len)
				{
					if (PORT->remoteSock)
						closesocket(PORT->remoteSock);

					PORT->remoteSock = 0;
					PORT->CONNECTED = FALSE;
					PORT->hDevice = 0;	
				}
			}
			sprintf(Command, "Ok\r");
			return FALSE;
		}

		sprintf(Command, "Sorry - TUNE not supported on your radio\r");
		return FALSE;
	}

	if (_stricmp(FreqString, "POWER") == 0)
	{
		char PowerString[16] = "";
		int Power = atoi(Mode);
		int len;
		char cmd[80];

		switch (PORT->PortType)
		{ 
		case ICOM:

			if (n != 3 || Power > 255)
			{
				strcpy(Command, "Sorry - Invalid Format - should be POWER Level (0 - 255)\r");
				return FALSE;
			}

			sprintf(PowerString, "%04d", Power);

			buffptr = GetBuff();

			if (buffptr == 0)
			{
				sprintf(Command, "Sorry - No Buffers available\r");
				return FALSE;
			}

			// Build a ScanEntry in the buffer

			FreqPtr = (struct ScanEntry *)buffptr->Data;
			memset(FreqPtr, 0, sizeof(struct ScanEntry));

			CmdPtr = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;
			FreqPtr->Cmd2 = NULL;
			FreqPtr->Cmd3 = NULL;

			// IC7100 Set Power Fe fe 88 e0 14 0a xx xx fd


			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = RIG->RigAddr;
			*(CmdPtr++) = 0xE0;
			*(CmdPtr++) = 0x14;
			*(CmdPtr++) = 0x0A;

			// Need to convert param to decimal digits

			*(CmdPtr++) = (PowerString[1] - 48) | ((PowerString[0] - 48) << 4);
			*(CmdPtr++) = (PowerString[3] - 48) | ((PowerString[2] - 48) << 4);

			*(CmdPtr++) = 0xFD;
			FreqPtr[0].Cmd1Len = 9;
			
			C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);

			return TRUE;

		case KENWOOD:

			if (n != 3 || Power > 200 || Power < 5)
			{
				strcpy(Command, "Sorry - Invalid Format - should be POWER Level (5 - 200)\r");
				return FALSE;
			}

			buffptr = GetBuff();

			if (buffptr == 0)
			{
				sprintf(Command, "Sorry - No Buffers available\r");
				return FALSE;
			}

			// Build a ScanEntry in the buffer

			FreqPtr = (struct ScanEntry *)buffptr->Data;
			memset(FreqPtr, 0, sizeof(struct ScanEntry));
	
			Poll = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;

			FreqPtr->Cmd1Len = sprintf(Poll, "PC%03d;PC;", Power);

			C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);
			return TRUE;

		case FLRIG:

			len = sprintf(cmd, "<i4>%d</i4>", Power);

			FLRIGSendCommand(PORT, "rig.set_power", cmd);

			sprintf(Command, "Ok\r");
			return FALSE;
		}

		sprintf(Command, "Sorry - POWER not supported on your Radio\r");
		return FALSE;
	}

	if (_stricmp(FreqString, "CMD") == 0)
	{
		// Send arbitrary command to radio

		char c;
		int val;
 		char * ptr1;
		char * ptr2;
		int Len;

		if (n < 3)
		{
			strcpy(Command, "Sorry - Invalid Format - should be CMD Params\r");
			return FALSE;
		}

		buffptr = GetBuff();

		if (buffptr == NULL)
			return FALSE;

		ptr1 = strstr(Command, "CMD");

		if (ptr1 == NULL)
			return FALSE;

		ptr1 += 4;


		FreqPtr = (struct ScanEntry *)buffptr->Data;
		memset(FreqPtr, 0, sizeof(struct ScanEntry));

		CmdPtr = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;
		FreqPtr->Cmd2 = NULL;
		FreqPtr->Cmd3 = NULL;

	
		switch (PORT->PortType)
		{ 
		case ICOM:

			// String is in Hex

			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = RIG->RigAddr;
			*(CmdPtr++) = 0xE0;

			while (c = *(ptr1++))
			{
				if (c == ' ') continue;		// Allow space between pairs
			
				val = c - 0x30;
				if (val > 15) val -= 7;
				val <<= 4;
				c = *(ptr1++) - 0x30;
				if (c > 15) c -= 7;
				val |= c;
				*(CmdPtr++) = val;
			}

			*(CmdPtr++) = 0xFD;
			*(CmdPtr) = 0; 

			Len = (int)(CmdPtr - (char *)&buffptr[30]);
			break;

		case KENWOOD:
		case FT991A:
		case FT2000:
		case FTDX10:
		case FLEX:
		case NMEA:

			// use text command

			Len = sprintf(CmdPtr, "%s", ptr1);
			break;

		case YAESU:

			// String is in Hex (5 values)

			while (c = *(ptr1++))
			{
				if (c == ' ') continue;		// Allow space between pairs

				val = c - 0x30;
				if (val > 15) val -= 7;
				val <<= 4;
				c = *(ptr1++) - 0x30;
				if (c > 15) c -= 7;
				val |= c;
				*(CmdPtr++) = val;
			}

			*(CmdPtr) = 0; 

			Len = 5;
			break;

		case FLRIG:

			// Two string params - command and params eg rig.set_ptt <i4>1</i4>"
			// or maybe param could be format data - eg i 1

			_strlwr(ptr1);

			ptr2 = strlop(ptr1, ' ');

			if (ptr2 == 0)
			{
				strcpy(Command, "Sorry - Invalid Format - should be CMD cmd params\r");
				return FALSE;
			}

			strlop(ptr2, ' ');

			FLRIGSendCommand(PORT, ptr1, ptr2);

			return FALSE;





		default:
			sprintf(Command, "Sorry - CMD not supported on your Radio\r");
			return FALSE;
		}

		FreqPtr[0].Cmd1Len = Len;		// for ICOM
		C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);

		sprintf(Command, "Ok\r");
		return FALSE;
	}

	if (_memicmp(FreqString, "Chan", 4) == 0)
	{
		if (strchr(FreqString, '/')	)	// Bank/Chan
		{
			MemoryBank = FreqString[4];
			MemoryNumber = atoi(&FreqString[6]);
		}
		else
			MemoryNumber = atoi(&FreqString[4]);	// Just Chan

		Freq = 0.0;
	}
	else
	{
		Freq = atof(FreqString);

		if (Freq < 0.1 && PORT->PortType != FLRIG)
		{
			strcpy(Command, "Sorry - Invalid Frequency\r");
			return FALSE;
		}
	}

	Freq = Freq * 1000000.0;

	sprintf(FreqString, "%09.0f", Freq);

	if (PORT->PortType != ICOM)
		strcpy(Data, FilterString);			// Others don't have a filter.

	Split = DataFlag = Bandwidth = Antenna = 0;

	_strupr(Data);

	if (strchr(Data, '+'))
		Split = '+';
	else if (strchr(Data, '-'))				
		Split = '-';
	else if (strchr(Data, 'S'))
		Split = 'S';	
	else if (strchr(Data, 'D'))	
		DataFlag = 1;
								
	if (strchr(Data, 'W'))
		Bandwidth = 'W';	
	else if (strchr(Data, 'N'))
		Bandwidth = 'N';

	if (strstr(Data, "A1"))
		Antenna = '1';
	else if (strstr(Data, "A2"))
		Antenna = '2';
	else if (strstr(Data, "A3"))
		Antenna = '3';
	else if (strstr(Data, "A4"))
		Antenna = '4';
	else if (strstr(Data, "A5"))
		Antenna = '5';
	else if (strstr(Data, "A6"))
		Antenna = '6';

	switch (PORT->PortType)
	{ 
	case ICOM:

		if (n == 2)
			// Set Freq Only

			ModeNo = -1;
		else
		{
			if (n < 4 && RIG->ICF8101 == 0)
			{
				strcpy(Command, "Sorry - Invalid Format - should be Port Freq Mode Filter Width\r");
				return FALSE;
			}

			Filter = atoi(FilterString);

			for (ModeNo = 0; ModeNo < 24; ModeNo++)
			{
				if (_stricmp(Modes[ModeNo], Mode) == 0)
					break;
			}

			if (ModeNo == 24)
			{
				sprintf(Command, "Sorry - Invalid Mode\r");
				return FALSE;
			}
		}

		buffptr = GetBuff();

		if (buffptr == 0)
		{
			sprintf(Command, "Sorry - No Buffers available\r");
			return FALSE;
		}

		// Build a ScanEntry in the buffer

		FreqPtr = (struct ScanEntry *)buffptr->Data;
		memset(FreqPtr, 0, sizeof(struct ScanEntry));

		FreqPtr->Freq = Freq;
		FreqPtr->Bandwidth = Bandwidth;
		FreqPtr->Antenna = Antenna;
		FreqPtr->Dwell = 51;

		CmdPtr = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;
		FreqPtr->Cmd2 = NULL;
		FreqPtr->Cmd3 = NULL;

		*(CmdPtr++) = 0xFE;
		*(CmdPtr++) = 0xFE;
		*(CmdPtr++) = RIG->RigAddr;
		*(CmdPtr++) = 0xE0;


		if (MemoryNumber)
		{
			// Set Memory Channel instead of Freq, Mode, etc

			char ChanString[5];

			// Send Set Memory, then Channel
								
			*(CmdPtr++) = 0x08;
			*(CmdPtr++) = 0xFD;

			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = RIG->RigAddr;
			*(CmdPtr++) = 0xE0;

			sprintf(ChanString, "%04d", MemoryNumber); 
	
			*(CmdPtr++) = 0x08;
			*(CmdPtr++) = (ChanString[1] - 48) | ((ChanString[0] - 48) << 4);
			*(CmdPtr++) = (ChanString[3] - 48) | ((ChanString[2] - 48) << 4);
			*(CmdPtr++) = 0xFD;
				
			FreqPtr[0].Cmd1Len = 14;

			if (MemoryBank)
			{						
				*(CmdPtr++) = 0xFE;
				*(CmdPtr++) = 0xFE;
				*(CmdPtr++) = RIG->RigAddr;
				*(CmdPtr++) = 0xE0;
				*(CmdPtr++) = 0x08;
				*(CmdPtr++) = 0xA0;
				*(CmdPtr++) = MemoryBank - 0x40;
				*(CmdPtr++) = 0xFD;

				FreqPtr[0].Cmd1Len += 8;
			}	
		}
		else
		{
			if (RIG->ICF8101)
			{
				// Set Freq is 1A 35 and set Mode 1A 36

				*(CmdPtr++) = 0x1A;
				*(CmdPtr++) = 0x35;		// Set frequency command

				// Need to convert two chars to bcd digit

				*(CmdPtr++) = (FreqString[8] - 48) | ((FreqString[7] - 48) << 4);
				*(CmdPtr++) = (FreqString[6] - 48) | ((FreqString[5] - 48) << 4);
				*(CmdPtr++) = (FreqString[4] - 48) | ((FreqString[3] - 48) << 4);
				*(CmdPtr++) = (FreqString[2] - 48) | ((FreqString[1] - 48) << 4);
				*(CmdPtr++) = (FreqString[0] - 48);
				*(CmdPtr++) = 0xFD;
				FreqPtr[0].Cmd1Len = 12;

				if (ModeNo != -1)			// Dont Set
				{		
					CmdPtr = FreqPtr->Cmd2 = FreqPtr->Cmd2Msg;
					FreqPtr[0].Cmd2Len = 9;		

					*(CmdPtr++) = 0xFE;
					*(CmdPtr++) = 0xFE;
					*(CmdPtr++) = RIG->RigAddr;
					*(CmdPtr++) = 0xE0;
					*(CmdPtr++) = 0x1A;
					*(CmdPtr++) = 0x36;		// Set mode command
					*(CmdPtr++) = 0;
					if (ModeNo > 19)
						*(CmdPtr++) = ModeNo + 12;
					else if (ModeNo > 9)
						*(CmdPtr++) = ModeNo + 6;
					else
						*(CmdPtr++) = ModeNo;
					*(CmdPtr++) = 0xFD;

//			Mode = (Msg[7] >> 4);
//			Mode *= 10;
//			Mode += Msg[7] & 0xf;


				}
			}
			else
			{

				*(CmdPtr++) = 0x5;		// Set frequency command

				// Need to convert two chars to bcd digit

				*(CmdPtr++) = (FreqString[8] - 48) | ((FreqString[7] - 48) << 4);
				*(CmdPtr++) = (FreqString[6] - 48) | ((FreqString[5] - 48) << 4);
				*(CmdPtr++) = (FreqString[4] - 48) | ((FreqString[3] - 48) << 4);
				*(CmdPtr++) = (FreqString[2] - 48) | ((FreqString[1] - 48) << 4);
				if (RIG->IC735)
				{
					*(CmdPtr++) = 0xFD;
					FreqPtr[0].Cmd1Len = 10;
				}
				else
				{
					*(CmdPtr++) = (FreqString[0] - 48);
					*(CmdPtr++) = 0xFD;
					FreqPtr[0].Cmd1Len = 11;
				}

				// Send Set VFO in case last chan was memory

				//		*(CmdPtr++) = 0xFE;
				//		*(CmdPtr++) = 0xFE;
				//		*(CmdPtr++) = RIG->RigAddr;
				//		*(CmdPtr++) = 0xE0;

				//		*(CmdPtr++) = 0x07;
				//		*(CmdPtr++) = 0xFD;

				//		FreqPtr[0].Cmd1Len = 17;

				if (ModeNo != -1)			// Dont Set
				{		
					CmdPtr = FreqPtr->Cmd2 = FreqPtr->Cmd2Msg;
					*(CmdPtr++) = 0xFE;
					*(CmdPtr++) = 0xFE;
					*(CmdPtr++) = RIG->RigAddr;
					*(CmdPtr++) = 0xE0;
					*(CmdPtr++) = 0x6;		// Set Mode
					*(CmdPtr++) = ModeNo;
					*(CmdPtr++) = Filter;
					*(CmdPtr++) = 0xFD;

					FreqPtr->Cmd2Len = 8;

					if (Split)
					{
						CmdPtr = FreqPtr->Cmd3 = FreqPtr->Cmd3Msg;
						FreqPtr->Cmd3Len = 7;
						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = RIG->RigAddr;
						*(CmdPtr++) = 0xE0;
						*(CmdPtr++) = 0xF;		// Set Mode
						if (Split == 'S')
							*(CmdPtr++) = 0x10;
						else
							if (Split == '+')
								*(CmdPtr++) = 0x12;
							else
								if (Split == '-')
									*(CmdPtr++) = 0x11;

						*(CmdPtr++) = 0xFD;
					}
					else if (DataFlag)
					{
						CmdPtr = FreqPtr->Cmd3 = FreqPtr->Cmd3Msg;

						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = RIG->RigAddr;
						*(CmdPtr++) = 0xE0;
						*(CmdPtr++) = 0x1a;	

						if ((strcmp(RIG->RigName, "IC7100") == 0) ||
							(strcmp(RIG->RigName, "IC7410") == 0) ||
							(strcmp(RIG->RigName, "IC7600") == 0) ||
							(strcmp(RIG->RigName, "IC7610") == 0) ||
							(strcmp(RIG->RigName, "IC7300") == 0))
						{
							FreqPtr[0].Cmd3Len = 9;
							*(CmdPtr++) = 0x6;		// Send/read DATA mode with filter set
							*(CmdPtr++) = 0x1;		// Data On
							*(CmdPtr++) = Filter;	//Filter
						}
						else if (strcmp(RIG->RigName, "IC7200") == 0)
						{
							FreqPtr[0].Cmd3Len = 9;
							*(CmdPtr++) = 0x4;		// Send/read DATA mode with filter set
							*(CmdPtr++) = 0x1;		// Data On
							*(CmdPtr++) = Filter;	// Filter
						}
						else
						{
							FreqPtr[0].Cmd3Len = 8;
							*(CmdPtr++) = 0x6;		// Set Data
							*(CmdPtr++) = 0x1;		//On		
						}

						*(CmdPtr++) = 0xFD;
					}
				}

				if (Antenna == '5' || Antenna == '6')
				{
					// Antenna select for 746 and maybe others

					// Could be going in cmd2 3 or 4

					if (FreqPtr[0].Cmd2 == NULL)
					{
						CmdPtr = FreqPtr->Cmd2 = FreqPtr->Cmd2Msg;
						FreqPtr[0].Cmd2Len = 7;
					}
					else if (FreqPtr[0].Cmd3 == NULL)
					{
						CmdPtr = FreqPtr->Cmd3 = FreqPtr->Cmd3Msg;
						FreqPtr[0].Cmd3Len = 7;
					}
					else 
					{
						CmdPtr = FreqPtr->Cmd4 = FreqPtr->Cmd4Msg;
						FreqPtr[0].Cmd4Len = 7;
					}

					*(CmdPtr++) = 0xFE;
					*(CmdPtr++) = 0xFE;
					*(CmdPtr++) = RIG->RigAddr;
					*(CmdPtr++) = 0xE0;
					*(CmdPtr++) = 0x12;		// Set Antenna
					*(CmdPtr++) = Antenna - '5';	// 0 for A5 1 for A6
					*(CmdPtr++) = 0xFD;
				}
			}
		}
		
		C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);

		return TRUE;

	case YAESU:
			
		if (n == 2)			// Just set freq
		{
			ModeNo = -1;
		}
		else
		{
			for (ModeNo = 0; ModeNo < 15; ModeNo++)
			{
				if (_stricmp(YaesuModes[ModeNo], Mode) == 0)
					break;
			}

			if (ModeNo == 15)
			{
				sprintf(Command, "Sorry -Invalid Mode\r");
				return FALSE;
			}
		}

		buffptr = GetBuff();

		if (buffptr == 0)
		{
			sprintf(Command, "Sorry - No Buffers available\r");
			return FALSE;
		}

		// Build a ScanEntry in the buffer

		FreqPtr = (struct ScanEntry *)buffptr->Data;
		memset(FreqPtr, 0, sizeof(struct ScanEntry));

		FreqPtr->Freq = Freq;
		FreqPtr->Bandwidth = Bandwidth;
		FreqPtr->Antenna = Antenna;

		Poll = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;

		// Send Mode then Freq - setting Mode seems to change frequency

		FreqPtr->Cmd1Len = 0;

		if (ModeNo != -1)		// Set freq only
		{
			*(Poll++) = ModeNo;
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = 7;		// Set Mode
			FreqPtr->Cmd1Len = 5;
		}

		*(Poll++) = (FreqString[1] - 48) | ((FreqString[0] - 48) << 4);
		*(Poll++) = (FreqString[3] - 48) | ((FreqString[2] - 48) << 4);
		*(Poll++) = (FreqString[5] - 48) | ((FreqString[4] - 48) << 4);
		*(Poll++) = (FreqString[7] - 48) | ((FreqString[6] - 48) << 4);
		*(Poll++) = 1;		// Set Freq
					
		FreqPtr->Cmd1Len += 5;

		if (strcmp(PORT->Rigs[0].RigName, "FT847") == 0)
		{
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = 3;		// Status Poll
	
			FreqPtr->Cmd1Len = 15;
		}
		
		C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);

		saveNewFreq(RIG, Freq, Mode);

		return TRUE;


	case FT100:
	case FT990:
	case FT1000:

		if (n == 2)			// Set Freq Only
			ModeNo = -1;
		else
		{
			if (n < 3)
			{
				strcpy(Command, "Sorry - Invalid Format - should be Port Freq Mode\r");
				return FALSE;
			}
		
			if (PORT->PortType == FT100)
			{
				for (ModeNo = 0; ModeNo < 8; ModeNo++)	
				{
					if (_stricmp(FT100Modes[ModeNo], Mode) == 0)
						break;
				}

				if (ModeNo == 8)
				{
					sprintf(Command, "Sorry -Invalid Mode\r");
					return FALSE;
				}
			}
			else if (PORT->PortType == FT990)
			{
				for (ModeNo = 0; ModeNo < 12; ModeNo++)	
				{
					if (_stricmp(FT990Modes[ModeNo], Mode) == 0)
						break;
				}

				if (ModeNo == 12)
				{
					sprintf(Command, "Sorry -Invalid Mode\r");
					return FALSE;
				}
			}
			else
			{
				for (ModeNo = 0; ModeNo < 12; ModeNo++)	
				{
					if (_stricmp(FT1000Modes[ModeNo], Mode) == 0)
						break;
				}

				if (ModeNo == 12)
				{
					sprintf(Command, "Sorry -Invalid Mode\r");
					return FALSE;
				}
			}
		}

		buffptr = GetBuff();

		if (buffptr == 0)
		{
			sprintf(Command, "Sorry - No Buffers available\r");
			return FALSE;
		}

		// Build a ScanEntry in the buffer

		FreqPtr = (struct ScanEntry *)buffptr->Data;
		memset(FreqPtr, 0, sizeof(struct ScanEntry));

		FreqPtr->Freq = Freq;
		FreqPtr->Bandwidth = Bandwidth;
		FreqPtr->Antenna = Antenna;

		Poll = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;

		// Send Mode then Freq - setting Mode seems to change frequency

		if (ModeNo == -1)		// Don't set Mode
		{
			// Changing the length messes up a lot of code,
			// so set freq twice instead of omitting entry

			*(Poll++) = (FreqString[7] - 48) | ((FreqString[6] - 48) << 4);
			*(Poll++) = (FreqString[5] - 48) | ((FreqString[4] - 48) << 4);
			*(Poll++) = (FreqString[3] - 48) | ((FreqString[2] - 48) << 4);
			*(Poll++) = (FreqString[1] - 48) | ((FreqString[0] - 48) << 4);
			*(Poll++) = 10;		// Set Freq
		}
		else
		{
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = 0;
			*(Poll++) = ModeNo;
			*(Poll++) = 12;		// Set Mode
		}

		*(Poll++) = (FreqString[7] - 48) | ((FreqString[6] - 48) << 4);
		*(Poll++) = (FreqString[5] - 48) | ((FreqString[4] - 48) << 4);
		*(Poll++) = (FreqString[3] - 48) | ((FreqString[2] - 48) << 4);
		*(Poll++) = (FreqString[1] - 48) | ((FreqString[0] - 48) << 4);
		*(Poll++) = 10;		// Set Freq

		*(Poll++) = 0;
		*(Poll++) = 0;
		*(Poll++) = 0;
		if (PORT->PortType == FT990 || PORT->YaesuVariant == FT1000D)
			*(Poll++) = 3;
		else
			*(Poll++) = 2;		// 100 or 1000MP

		*(Poll++) = 16;		// Status Poll
	
		FreqPtr->Cmd1Len = 15;
		
		C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);

		return TRUE;

	case KENWOOD:
	case FT2000:
	case FTDX10:
	case FT991A:
	case FLEX:
			
		if (n < 3)
		{
			strcpy(Command, "Sorry - Invalid Format - should be Port Freq Mode\r");
			return FALSE;
		}

		for (ModeNo = 0; ModeNo < 16; ModeNo++)
		{
			if (PORT->PortType == FT2000)
				if (_stricmp(FT2000Modes[ModeNo], Mode) == 0)
				break;

			if (PORT->PortType == FTDX10)
				if (_stricmp(FTDX10Modes[ModeNo], Mode) == 0)
				break;

			if (PORT->PortType == FT991A)
				if (_stricmp(FT991AModes[ModeNo], Mode) == 0)
				break;

			if (PORT->PortType == KENWOOD)
				if (_stricmp(KenwoodModes[ModeNo], Mode) == 0)
				break;
			if (PORT->PortType == FLEX)
				if (_stricmp(FLEXModes[ModeNo], Mode) == 0)
				break;
		}

		if (ModeNo > 15)
		{
			sprintf(Command, "Sorry -Invalid Mode\r");
			return FALSE;
		}

		buffptr = GetBuff();

		if (buffptr == 0)
		{
			sprintf(Command, "Sorry - No Buffers available\r");
			return FALSE;
		}

		// Build a ScanEntry in the buffer

		FreqPtr = (struct ScanEntry *)buffptr->Data;
		memset(FreqPtr, 0, sizeof(struct ScanEntry));

		FreqPtr->Freq = Freq;
		FreqPtr->Bandwidth = Bandwidth;
		FreqPtr->Antenna = Antenna;

		Poll = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;

		if (PORT->PortType == FT2000)
			FreqPtr->Cmd1Len = sprintf(Poll, "FA%s;MD0%X;FA;MD;", &FreqString[1], ModeNo);
		else
		if (PORT->PortType == FT991A || PORT->PortType == FTDX10)
			FreqPtr->Cmd1Len = sprintf(Poll, "FA%s;MD0%X;FA;MD;", FreqString, ModeNo);
		else
		if (PORT->PortType == FLEX)
			FreqPtr->Cmd1Len = sprintf(Poll, "ZZFA00%s;ZZMD%02d;ZZFA;ZZMD;", &FreqString[1], ModeNo);
		else
		{
			if (Antenna == '5' || Antenna == '6')
				FreqPtr->Cmd1Len = sprintf(Poll, "FA00%s;MD%d;AN%c;FA;MD;", FreqString, ModeNo, Antenna - 4);
			else
				FreqPtr->Cmd1Len = sprintf(Poll, "FA00%s;MD%d;FA;MD;", FreqString, ModeNo);
		}
		C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);

		return TRUE;


	case SDRRADIO:
			
		if (n < 3)
		{
			strcpy(Command, "Sorry - Invalid Format - should be Port Freq Mode\r");
			return FALSE;
		}

		for (ModeNo = 0; ModeNo < 16; ModeNo++)
		{
			if (_stricmp(KenwoodModes[ModeNo], Mode) == 0)
				break;
		}

		if (ModeNo > 15)
		{
			sprintf(Command, "Sorry -Invalid Mode\r");
			return FALSE;
		}

		buffptr = GetBuff();

		if (buffptr == 0)
		{
			sprintf(Command, "Sorry - No Buffers available\r");
			return FALSE;
		}

		// Build a ScanEntry in the buffer

		FreqPtr = (struct ScanEntry *)buffptr->Data;
		memset(FreqPtr, 0, sizeof(struct ScanEntry));

		FreqPtr->Freq = Freq;
		FreqPtr->Bandwidth = Bandwidth;
		FreqPtr->Antenna = Antenna;

		Poll = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;

		FreqPtr->Cmd1Len = sprintf(Poll, "F%c00%s;MD%d;F%c;MD;", RIG->RigAddr, FreqString, ModeNo, RIG->RigAddr);

		C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);

		return TRUE;


	case NMEA:
			
		if (n < 3)
		{
			strcpy(Command, "Sorry - Invalid Format - should be Port Freq Mode\r");
			return FALSE;
		}
		buffptr = GetBuff();

		if (buffptr == 0)
		{
			sprintf(Command, "Sorry - No Buffers available\r");
			return FALSE;
		}

		// Build a ScanEntry in the buffer

		FreqPtr = (struct ScanEntry *)buffptr->Data;
		memset(FreqPtr, 0, sizeof(struct ScanEntry));

		FreqPtr->Freq = Freq;
		FreqPtr->Bandwidth = Bandwidth;
		FreqPtr->Antenna = Antenna;

		Poll = FreqPtr->Cmd1 = FreqPtr->Cmd1Msg;

		i = sprintf(Poll, "$PICOA,90,%02x,RXF,%.6f*xx\r\n", RIG->RigAddr, Freq/1000000.);
		AddNMEAChecksum(Poll);
		Len = i;
		i = sprintf(Poll + Len, "$PICOA,90,%02x,TXF,%.6f*xx\r\n", RIG->RigAddr, Freq/1000000.);
		AddNMEAChecksum(Poll + Len);
		Len += i;
		i = sprintf(Poll + Len, "$PICOA,90,%02x,MODE,%s*xx\r\n", RIG->RigAddr, Mode);
		AddNMEAChecksum(Poll + Len);
			
		FreqPtr->Cmd1Len = i + Len;
		
		C_Q_ADD(&RIG->BPQtoRADIO_Q, buffptr);

		return TRUE;

	case HAMLIB:
	{
		char cmd[200];

		int len = sprintf(cmd, "F %s\n+f\nM %s %d\n+m\n",
			FreqString, Mode, atoi(Data));
	
		send(PORT->remoteSock, cmd, len, 0);
		sprintf(Command, "Ok\r");
		
		saveNewFreq(RIG, Freq, Mode);

		return FALSE;
	}

	case FLRIG:
	{
		char cmd[80];

		int len = sprintf(cmd, "<double>%.0f</double>", Freq);

		strcpy(PORT->ScanEntry.Cmd2Msg, Mode);
		strcpy(PORT->ScanEntry.Cmd3Msg, FilterString);

		if (Freq > 0.0)
			FLRIGSendCommand(PORT, "rig.set_vfo", cmd);

		else if (PORT->ScanEntry.Cmd2Msg[0] && Mode[0] != '*')
		{
			sprintf(cmd, "<i4>%s</i4>", PORT->ScanEntry.Cmd2Msg);
			FLRIGSendCommand(PORT, "rig.set_mode", cmd);
		}

		else if (PORT->ScanEntry.Cmd3Msg[0] && strcmp(PORT->ScanEntry.Cmd3Msg, "0") != 0)
		{
			sprintf(cmd, "<i4>%s</i4>", PORT->ScanEntry.Cmd3Msg);
			FLRIGSendCommand(PORT, "rig.set_bandwidth", cmd);
		}
		else
		{
			sprintf(Command, "Sorry - Nothing to do\r");
			return FALSE;
		}
				
		PORT->AutoPoll = 0;

		saveNewFreq(RIG, Freq, Mode);
		return TRUE;
	}


	case RTLUDP:
	{
		char cmd[80];
		int len = 5;
		int FreqInt = (int)Freq;
		int FM = 0;
		int AM = 1;
		int USB = 2;
		int LSB = 3;
		
		cmd[0] = 0;	
		cmd[1] = FreqInt & 0xff;
		cmd[2] = (FreqInt >> 8) & 0xff;
		cmd[3] = (FreqInt >> 16) & 0xff;
		cmd[4] = (FreqInt >> 24) & 0xff;

		len = sendto(PORT->remoteSock, cmd, 5,  0, &PORT->remoteDest, sizeof(struct sockaddr));

		if (Mode[0])
		{
			if (strcmp(Mode, "FM") == 0)
				memcpy(&cmd[1], &FM, 4); 
			else if (strcmp(Mode, "AM") == 0)
				memcpy(&cmd[1], &AM, 4); 
			else if (strcmp(Mode, "USB") == 0)
				memcpy(&cmd[1], &USB, 4); 
			else if (strcmp(Mode, "LSB") == 0)
				memcpy(&cmd[1], &LSB, 4); 

			cmd[0] = 1;
			len = sendto(PORT->remoteSock, cmd, 5,  0, &PORT->remoteDest, sizeof(struct sockaddr));
		}

		saveNewFreq(RIG, Freq, Mode);

		sprintf(Command, "Ok\r");
		return FALSE;
	}
// --- G7TAJ ----
	case SDRANGEL:
	{
		char cmd[80];
		int len = sprintf(cmd, "%.0f", Freq);

		strcpy(PORT->ScanEntry.Cmd2Msg, Mode);
		strcpy(PORT->ScanEntry.Cmd3Msg, FilterString);
		
		if (Freq > 0.0)
		{
			SDRANGELSendCommand(PORT, "FREQSET", cmd);
			sprintf(Command, "Ok\r");
			return FALSE;
		}
//TODO
/*                else if (PORT->ScanEntry.Cmd2Msg[0] && Mode[0] != '*')
                {
                        sprintf(cmd, "<i4>%s</i4>", PORT->ScanEntry.Cmd2Msg);
                        FLRIGSendCommand(PORT, "rig.set_mode", cmd);
                }

                else if (PORT->ScanEntry.Cmd3Msg[0] && strcmp(PORT->ScanEntry.Cmd3Msg, "0") != 0)
                {
                        sprintf(cmd, "<i4>%s</i4>", PORT->ScanEntry.Cmd3Msg);
                        FLRIGSendCommand(PORT, "rig.set_bandwidth", cmd);
                }
*/
                else
                {
                        sprintf(Command, "Sorry - Nothing to do\r");
                        return FALSE;
                }

                PORT->AutoPoll = 0;
	}
// --- G7TAJ ----




	}
	return TRUE;
}

int BittoInt(UINT BitMask)
{
	// Returns bit position of first 1 bit in BitMask
	
	int i = 0;
	while ((BitMask & 1) == 0)
	{	
		BitMask >>= 1;
		i ++;
	}
	return i;
}

extern char * RadioConfigMsg[70];

struct TNCINFO RIGTNC;			// Dummy TNC Record for Rigcontrol without a corresponding TNC 

DllExport BOOL APIENTRY Rig_Init()
{
	struct RIGPORTINFO * PORT;
	int i, p, port;
	struct RIGINFO * RIG;
	struct TNCINFO * TNC = &RIGTNC;
	HWND hDlg;
#ifndef LINBPQ
	int RigRow = 0;
#endif
	int NeedRig = 0;
	int Interlock = 0;

	memset(&RIGTNC, 0, sizeof(struct TNCINFO));

	TNCInfo[70] = TNC;

	// Get config info

	NumberofPorts = 0;

	for (port = 0; port < MAXBPQPORTS; port++)
		PORTInfo[port] = NULL;

	// See if any rigcontrol defined (either RADIO or RIGCONTROL lines)

	for (port = 0; port < MAXBPQPORTS; port++)
	{
		if (RadioConfigMsg[port])
			NeedRig++;
	}

	if (NeedRig == 0)
	{
		SetupPortRIGPointers();			// Sets up Dummy Rig Pointer
		return FALSE;
	}


#ifndef LINBPQ

	TNC->Port = 70;
	CreatePactorWindow(TNC, "RIGCONTROL", "RigControl", 10, PacWndProc, 550, NeedRig * 20 + 60, NULL);
	hDlg = TNC->hDlg;

#endif

	TNC->ClientHeight = NeedRig * 20 + 60;
	TNC->ClientWidth = 550;

	for (port = 0; port < MAXBPQPORTS; port++)
	{
		if (RadioConfigMsg[port])
		{
			char msg[1000];

			char * SaveRigConfig = _strdup(RadioConfigMsg[port]);
			char * RigConfigMsg1 = _strdup(RadioConfigMsg[port]);

			Interlock = atoi(&RigConfigMsg1[5]);

			RIG = RigConfig(TNC, RigConfigMsg1, port);

			if (RIG == NULL)
			{
				// Report Error

				sprintf(msg,"Port %d Invalid Rig Config %s", port, SaveRigConfig);
				WritetoConsole(msg);
				free(SaveRigConfig);
				free(RigConfigMsg1);
				continue;
			}

			RIG->Interlock = Interlock;

			if (RIG->PORT->IOBASE[0] == 0)
			{
				// We have to find the SCS TNC in this scan group as TNC is now a dummy

				struct TNCINFO * PTCTNC;
				int n;

				for (n = 1; n < MAXBPQPORTS; n++)
				{
					PTCTNC = TNCInfo[n];

					if (PTCTNC == NULL || (PTCTNC->Hardware != H_SCS && PTCTNC->Hardware != H_ARDOP))
						continue;

					if (PTCTNC->RXRadio != Interlock)
						continue;

					RIG->PORT->PTC = PTCTNC;
				}
			}

#ifndef LINBPQ

			// Create line for this rig

			RIG->hLabel = CreateWindow(WC_STATIC , "", WS_CHILD | WS_VISIBLE,
				10, RigRow, 80,20, hDlg, NULL, hInstance, NULL);

			//			RIG->hCAT = CreateWindow(WC_STATIC , "",  WS_CHILD | WS_VISIBLE,
			//                 90, RigRow, 40,20, hDlg, NULL, hInstance, NULL);

			RIG->hFREQ = CreateWindow(WC_STATIC , "",  WS_CHILD | WS_VISIBLE,
				95, RigRow, 100,20, hDlg, NULL, hInstance, NULL);

			RIG->hMODE = CreateWindow(WC_STATIC , "",  WS_CHILD | WS_VISIBLE,
				200, RigRow, 100,20, hDlg, NULL, hInstance, NULL);

			RIG->hSCAN = CreateWindow(WC_STATIC , "",  WS_CHILD | WS_VISIBLE,
				300, RigRow, 20,20, hDlg, NULL, hInstance, NULL);

			RIG->hPTT = CreateWindow(WC_STATIC , "",  WS_CHILD | WS_VISIBLE,
				320, RigRow, 20,20, hDlg, NULL, hInstance, NULL);

			RIG->hPORTS = CreateWindow(WC_STATIC , "",  WS_CHILD | WS_VISIBLE,
				340, RigRow, 210, 20, hDlg, NULL, hInstance, NULL);

			RigRow += 20;

			//if (PORT->PortType == ICOM)
			//{
			//	sprintf(msg,"%02X", PORT->Rigs[i].RigAddr);
			//	SetWindowText(RIG->hCAT, msg);
			//}
			SetWindowText(RIG->hLabel, RIG->RigName);
#endif

			RIG->WEB_Label = _strdup(RIG->RigName);
			//		RIG->WEB_CAT;
			RIG->WEB_FREQ = zalloc(80);
			RIG->WEB_MODE = zalloc(80);
			RIG->WEB_PORTS = zalloc(80);
			strcpy(RIG->WEB_FREQ, "-----------");
			strcpy(RIG->WEB_MODE, "------");

			RIG->WEB_PTT = ' ';
			RIG->WEB_SCAN = ' ';
		}
	}

	for (p = 0; p < NumberofPorts; p++)
	{
		PORT = PORTInfo[p];

		if (PORT->PortType == HAMLIB)
		{
			HAMLIBMasterRunning = 1;
			ConnecttoHAMLIB(PORT);
		}
		else if (PORT->PortType == FLRIG)
		{
			FLRIGRunning = 1;
			ConnecttoFLRIG(PORT);
		}
		else if (PORT->PortType == RTLUDP)
			ConnecttoRTLUDP(PORT);
//---- G7TAJ ----
		else if (PORT->PortType == SDRANGEL)
		{
			SDRANGELRunning = 1;
			ConnecttoSDRANGEL(PORT);
		}
//---- G7TAJ ----
		else if (PORT->HIDDevice)		// This is RAWHID, Not CM108
			OpenHIDPort(PORT, PORT->IOBASE, PORT->SPEED);
		else if (PORT->PTC == 0 && _stricmp(PORT->IOBASE, "CM108") != 0)
			OpenRigCOMMPort(PORT, PORT->IOBASE, PORT->SPEED);

		if (PORT->PTTIOBASE[0])		// Using separate port for PTT?
		{
			if (PORT->PTTIOBASE[3] == '=')
				PORT->hPTTDevice = OpenCOMPort(&PORT->PTTIOBASE[4], PORT->SPEED, FALSE, FALSE, FALSE, 0);
			else
				PORT->hPTTDevice = OpenCOMPort(&PORT->PTTIOBASE[3], PORT->SPEED, FALSE, FALSE, FALSE, 0);
		}
		else
			PORT->hPTTDevice = PORT->hDevice;	// Use same port for PTT
	}

	for (p = 0; p < NumberofPorts; p++)
	{
		PORT = PORTInfo[p];

		for (i=0; i < PORT->ConfiguredRigs; i++)
		{
			int j;
			int k = 0;
			uint64_t BitMask;
			struct _EXTPORTDATA * PortEntry;

			RIG = &PORT->Rigs[i];

			SetupScanInterLockGroups(RIG);

			// Get record for each port in Port Bitmap

			// The Scan "Request Permission to Change" code needs the Port Records in order - 
			// Those with active connect lock (eg SCS) first, then those with just a connect pending lock (eg WINMOR)
			// then those with neither

			BitMask = RIG->BPQPort;
			for (j = 0; j < MAXBPQPORTS; j++)
			{
				if (BitMask & 1)
				{
					PortEntry = (struct _EXTPORTDATA *)GetPortTableEntryFromPortNum(j);		// BPQ32 port record for this port
					if (PortEntry)
						if (PortEntry->SCANCAPABILITIES == CONLOCK)
							RIG->PortRecord[k++] = PortEntry;
				}
				BitMask >>= 1;
			}

			BitMask = RIG->BPQPort;
			for (j = 0; j < MAXBPQPORTS; j++)
			{
				if (BitMask & 1)
				{
					PortEntry = (struct _EXTPORTDATA *)GetPortTableEntryFromPortNum(j);		// BPQ32 port record for this port
					if (PortEntry)
						if (PortEntry->SCANCAPABILITIES == SIMPLE)
							RIG->PortRecord[k++] = PortEntry;
				}
				BitMask >>= 1;
			}

			BitMask = RIG->BPQPort;
			for (j = 0; j < MAXBPQPORTS; j++)
			{
				if (BitMask & 1)
				{
					PortEntry = (struct _EXTPORTDATA *)GetPortTableEntryFromPortNum(j);		// BPQ32 port record for this port
					if (PortEntry)
						if (PortEntry->SCANCAPABILITIES == NONE)
							RIG->PortRecord[k++] = PortEntry;
				}
				BitMask >>= 1;
			}

			RIG->PORT = PORT;		// For PTT

			if (RIG->NumberofBands)
				CheckTimeBands(RIG);		// Set initial timeband

#ifdef WIN32
			if (RIG->PTTCATPort[0])			// Serial port RTS to CAT 
				_beginthread(PTTCATThread,0,RIG);
#endif
			if (RIG->HAMLIBPORT)
			{
				// Open listening socket

				struct sockaddr_in local_sin;  /* Local socket - internet style */
				struct sockaddr_in * psin;
				SOCKET sock = 0;
				u_long param=1;

				char szBuff[80];

				psin=&local_sin;
				psin->sin_family = AF_INET;
				psin->sin_addr.s_addr = INADDR_ANY;

				sock = socket(AF_INET, SOCK_STREAM, 0);

				setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *)&param,4);

				psin->sin_port = htons(RIG->HAMLIBPORT);        // Convert to network ordering 

				if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR)
				{
					sprintf(szBuff, "bind(sock) failed port %d Error %d\n", port, WSAGetLastError());
					WritetoConsoleLocal(szBuff);
					closesocket(sock);
				}
				else
				{
					if (listen(sock, 5) < 0)
					{
						sprintf(szBuff, "listen(sock) failed port %d Error %d\n", port, WSAGetLastError());
						WritetoConsoleLocal(szBuff);
					}
					else
					{
						ioctl(sock, FIONBIO, &param);
						RIG->ListenSocket = sock;
						_beginthread(HAMLIBSlaveThread, 0, RIG);
					}
				}
			}
			Rig_PTTEx(RIG, 0, NULL);				// Send initial PTT Off (Mainly to set input mux on soundcard rigs)
		}
	}

	//	MoveWindow(hDlg, Rect.left, Rect.top, Rect.right - Rect.left, Row + 100, TRUE);

	SetupPortRIGPointers();

	RigWebPage = zalloc(10);

	WritetoConsole("\nRig Control Enabled\n");

	return TRUE;
}

DllExport BOOL APIENTRY Rig_Close()
{
	struct RIGPORTINFO * PORT;
	struct TNCINFO * TNC;
	int n, p;

	HAMLIBMasterRunning = 0;			// Close HAMLIB thread(s)
	HAMLIBSlaveRunning = 0;				// Close HAMLIB thread(s)
	FLRIGRunning = 0;				// Close FLRIG thread(s)
// ---- G7TAJ ----
	SDRANGELRunning = 0;				// Close SDRANGEL thread(s)
// ---- G7TAJ ----

	for (p = 0; p < NumberofPorts; p++)
	{
		PORT = PORTInfo[p];

		if (PORT->PortType == NMEA)
		{
			// Send Remote OFF

			int i;
			char REMOFF[80];

			i = sprintf(REMOFF, "$PICOA,90,%02x,REMOTE,OFF*xx\r\n", PORT->Rigs[0].RigAddr);
			AddNMEAChecksum(REMOFF);

			WriteCOMBlock(PORT->hDevice, REMOFF, i);
			Sleep(200);
		}

		if (PORT->PortType != HAMLIB && PORT->PortType != RTLUDP && PORT->PortType != FLRIG && strcmp(PORT->IOBASE, "RAWHID") != 0)
		{
			if (PORT->hPTTDevice != PORT->hDevice)
				CloseCOMPort(PORT->hPTTDevice);

			CloseCOMPort(PORT->hDevice);
		}

		PORT->hDevice = 0;
		PORT->hPTTDevice = 0;

		// Free the RIG and Port Records

		for (n = 0; n < PORT->ConfiguredRigs; n++)
		{
			struct RIGINFO * RIG = &PORT->Rigs[n];
			struct HAMLIBSOCK * Entry = RIG->Sockets;
			struct HAMLIBSOCK * Save;

			// if RIG has any HAMLIB slave connections, close them

			Entry = RIG->Sockets;

			while (Entry)
			{
				closesocket(Entry->Sock);
				Save = Entry;
				Entry = Entry->Next;
				free(Save);
			}

			RIG->Sockets = 0;
		
			if (RIG->TimeBands)
				free (RIG->TimeBands[1]->Scanlist);

			if (RIG->PTTCATPort[0])
			{
				Rig_PTTEx(RIG, FALSE, NULL);				// Make sure PTT is down
				EndPTTCATThread = TRUE;
			}
		}

		free (PORT);
		PORTInfo[p] = NULL;
	}

	NumberofPorts = 0;		// For possible restart

	// And free the TNC config info

	for (p = 1; p < MAXBPQPORTS; p++)
	{
		TNC = TNCInfo[p];

		if (TNC == NULL)
			continue;

		TNC->RIG = NULL;

		//		memset(TNC->WL2KInfoList, 0, sizeof(TNC->WL2KInfoList));

	}

	return TRUE;
}



BOOL Rig_Poll()
{
	int p, i, Len;
	char RigWeb[16384];

	struct RIGPORTINFO * PORT;
	struct RIGINFO * RIG;

	for (p = 0; p < NumberofPorts; p++)
	{
		PORT = PORTInfo[p];

		if (PORT->PortType == DUMMY)
		{
			DummyPoll(PORT);
			return TRUE;
		}

		if (PORT->hDevice == 0)
		{
			// Try to reopen every 15 secs 

			PORT->ReopenDelay++;

			if (PORT->ReopenDelay > 150)
			{
				PORT->ReopenDelay = 0;

				if (PORT->PortType == HAMLIB)
					ConnecttoHAMLIB(PORT);
				else if (PORT->PortType == FLRIG)
					ConnecttoFLRIG(PORT);
				else if (PORT->PortType == RTLUDP)
					ConnecttoRTLUDP(PORT);
// ---- G7TAJ ----
				else if (PORT->PortType == SDRANGEL)
					ConnecttoSDRANGEL(PORT);
// ---- G7TAJ ----
				else if (PORT->HIDDevice)
					OpenHIDPort(PORT, PORT->IOBASE, PORT->SPEED);
				else if (PORT->PTC == 0
					&& _stricmp(PORT->IOBASE, "REMOTE") != 0
					&& _stricmp(PORT->IOBASE, "CM108") != 0)
				{
					if (PORT->Closed == 0)
					{
						OpenRigCOMMPort(PORT, PORT->IOBASE, PORT->SPEED);
						if (PORT->IOBASE && PORT->PTTIOBASE[0] == 0)		// Using separate port for PTT?
							PORT->hPTTDevice = PORT->hDevice;
					}
				}
			}
		}

		if (PORT == NULL || (PORT->hDevice == 0 && PORT->PTC == 0 && PORT->remoteSock == 0))
			continue;

		// Check PTT Timers

		for (i=0; i< PORT->ConfiguredRigs; i++)
		{
			RIG = &PORT->Rigs[i];

			// Active PTT command

			if (RIG->PTTTimer)
			{
				RIG->PTTTimer--;
				if (RIG->PTTTimer == 0)
					Rig_PTTEx(RIG, FALSE, NULL);
			}

			// repeated off timer

			if (RIG->repeatPTTOFFTimer)
			{
				RIG->repeatPTTOFFTimer--;
				if (RIG->repeatPTTOFFTimer == 0)
				{
					Rig_PTTEx(RIG, FALSE, NULL);
					RIG->repeatPTTOFFTimer = 0;			// Don't repeat repeat!
				}
			}
		}

		CheckRX(PORT);

		switch (PORT->PortType)
		{ 
		case ICOM:

			ICOMPoll(PORT);
			break;

		case YAESU:
		case FT100:
		case FT990:
		case FT1000:

			YaesuPoll(PORT);
			break;

		case KENWOOD:
		case FT2000:
		case FTDX10:
		case FT991A:
		case FLEX:
		case NMEA:

			KenwoodPoll(PORT);
			break;


		case SDRRADIO:
			SDRRadioPoll(PORT);
			break;

		case HAMLIB:
			HAMLIBPoll(PORT);
			break;

		case RTLUDP:
			RTLUDPPoll(PORT);
			break;

		case FLRIG:
			FLRIGPoll(PORT);
			break;
// ---- G7TAJ ----
		case SDRANGEL:
			SDRANGELPoll(PORT);
			break;		}
// ---- G7TAJ ----
	}

	// Build page for Web Display

	Len = BuildRigCtlPage(RigWeb);

	if (strcmp(RigWebPage, RigWeb) == 0)
		return TRUE;				// No change

	free(RigWebPage);
	
	RigWebPage = _strdup(RigWeb);

	SendRigWebPage();

	return TRUE;
}


BOOL RigCloseConnection(struct RIGPORTINFO * PORT)
{
	// disable event notification and wait for thread
	// to halt

	CloseCOMPort(PORT->hDevice); 
	PORT->hDevice = 0;
	return TRUE;

} // end of CloseConnection()

#ifndef WIN32
#define ONESTOPBIT          0
#define ONE5STOPBITS        1
#define TWOSTOPBITS         2
#endif

int OpenRigCOMMPort(struct RIGPORTINFO * PORT, VOID * Port, int Speed)
{
	if (PORT->remoteSock)		// Using WINMORCONTROL
		return TRUE;

	if (PORT->PortType == FT2000 || PORT->PortType == FT991A || PORT->PortType == FTDX10 || strcmp(PORT->Rigs[0].RigName, "FT847") == 0)		// FT2000 and similar seem to need two stop bits
		PORT->hDevice = OpenCOMPort((VOID *)Port, Speed, FALSE, FALSE, PORT->Alerted, TWOSTOPBITS);
	else if (PORT->PortType == NMEA)
		PORT->hDevice = OpenCOMPort((VOID *)Port, Speed, FALSE, FALSE, PORT->Alerted, ONESTOPBIT);
	else
		PORT->hDevice = OpenCOMPort((VOID *)Port, Speed, FALSE, FALSE, PORT->Alerted, TWOSTOPBITS);

	if (PORT->hDevice == 0)
	{
		PORT->Alerted = TRUE;
		return FALSE;
	}

	PORT->Alerted = FALSE;

	if (PORT->PortType == PTT || (PORT->Rigs[0].PTTMode & PTTRTS))
		COMClearRTS(PORT->hDevice);
	else
		COMSetRTS(PORT->hDevice);

	if (PORT->PortType == PTT || (PORT->Rigs[0].PTTMode & PTTDTR))
		COMClearDTR(PORT->hDevice);
	else
		COMSetDTR(PORT->hDevice);
	if (strcmp(PORT->Rigs[0].RigName, "FT847") == 0)
	{
		// Looks like FT847 Needa a "Cat On" Command

		UCHAR CATON[6] = {0,0,0,0,0};

		WriteCOMBlock(PORT->hDevice, CATON, 5);
	}


	if (PORT->PortType == NMEA)
	{
		// Looks like NMEA Needs Remote ON

		int i;
		char REMON[80];

		i = sprintf(REMON, "$PICOA,90,%02x,REMOTE,ON*xx\r\n", PORT->Rigs[0].RigAddr);
		AddNMEAChecksum(REMON);

		WriteCOMBlock(PORT->hDevice, REMON, i);
	}


	return TRUE;
}

void CheckRX(struct RIGPORTINFO * PORT)
{
	int Length;
	char NMEAMsg[100];
	unsigned char * ptr;
	int len;

	if (PORT->PortType == FLRIG)
	{
		// Data received in thread
		
		return;
	}

	if (PORT->PortType == HAMLIB)
	{
		// Data received in thread (do we need thread??
		
		Length = PORT->RXLen;
		PORT->RXLen = 0;
	}

	else if (PORT->PortType == RTLUDP)
	{
		CheckAndProcessRTLUDP(PORT);
		Length = 0;
		PORT->RXLen = 0;
		return;
	}

	else if (PORT->HIDDevice)
		Length = HID_Read_Block(PORT);
	else if (PORT->PTC)
		Length = GetPTCRadioCommand(PORT->PTC, &PORT->RXBuffer[PORT->RXLen]);
	else if (PORT->remoteSock)
	{
		struct sockaddr_in rxaddr;
		int addrlen = sizeof(struct sockaddr_in);

		Length = recvfrom(PORT->remoteSock, PORT->RXBuffer, 500, 0, (struct sockaddr *)&rxaddr, &addrlen);
		if (Length == -1)
			Length = 0;
	}
	else
	{
		if (PORT->hDevice == 0) 
			return;

		// only try to read number of bytes in queue 

		if (PORT->RXLen == 500)
			PORT->RXLen = 0;

		Length = 500 - (DWORD)PORT->RXLen;

		Length = ReadCOMBlock(PORT->hDevice, &PORT->RXBuffer[PORT->RXLen], Length);
	}

	if (Length == 0)
		return;					// Nothing doing
	
	PORT->RXLen += Length;

	Length = PORT->RXLen;

	switch (PORT->PortType)
	{ 
	case ICOM:
	
		if (Length < 6)				// Minimum Frame Sise
			return;

		if (PORT->RXBuffer[Length-1] != 0xfd)
			return;					// Echo

		ProcessICOMFrame(PORT, PORT->RXBuffer, Length);	// Could have multiple packets in buffer

		PORT->RXLen = 0;		// Ready for next frame	
		return;
	
	case YAESU:

		// Possible responses are a single byte ACK/NAK or a 5 byte info frame

		if (Length == 1 && PORT->CmdSent > 0)
		{
			ProcessYaesuCmdAck(PORT);
			return;
		}
	
		if (Length < 5)			// Frame Sise
			return;

		if (Length > 5)			// Frame Sise
		{
			PORT->RXLen = 0;	// Corruption - reset and wait for retry	
			return;
		}

		ProcessYaesuFrame(PORT);

		PORT->RXLen = 0;		// Ready for next frame	
		return;

	case FT100:

		// Only response should be a 16 byte info frame

		if (Length < 32)		// Frame Sise  why???????
			return;

		if (Length > 32)			// Frame Sise
		{
			PORT->RXLen = 0;	// Corruption - reset and wait for retry	
			return;
		}

		ProcessFT100Frame(PORT);

		PORT->RXLen = 0;		// Ready for next frame	
		return;

	case FT990:

		// Only response should be a 32 byte info frame
	
		if (Length < 32)			// Frame Sise
			return;

		if (Length > 32)			// Frame Sise
		{
			PORT->RXLen = 0;		// Corruption - reset and wait for retry	
			return;
		}

		ProcessFT990Frame(PORT);
		PORT->RXLen = 0;		// Ready for next frame	
		return;


	case FT1000:

		// Only response should be a 16 byte info frame
	
		ptr = PORT->RXBuffer;

		if (Length < 16)			// Frame Sise
			return;

		if (Length > 16)			// Frame Sise
		{
			PORT->RXLen = 0;		// Corruption - reset and wait for retry	
			return;
		}

		ProcessFT1000Frame(PORT);

		PORT->RXLen = 0;		// Ready for next frame	
		return;

	case KENWOOD:
	case FT2000:
	case FTDX10:
	case FT991A:
	case FLEX:

		if (Length < 2)				// Minimum Frame Sise
			return;

		if (Length > 50)			// Garbage
		{
			PORT->RXLen = 0;		// Ready for next frame	
			return;
		}

		if (PORT->RXBuffer[Length-1] != ';')
			return;	

		ProcessKenwoodFrame(PORT, Length);	

		PORT->RXLen = 0;		// Ready for next frame	
		return;
	
	case SDRRADIO:

		if (Length < 2)				// Minimum Frame Sise
			return;

		if (Length > 50)			// Garbage
		{
			PORT->RXLen = 0;		// Ready for next frame	
			return;
		}

		if (PORT->RXBuffer[Length-1] != ';')
			return;	

		ProcessSDRRadioFrame(PORT, Length);	

		PORT->RXLen = 0;		// Ready for next frame	
		return;
	
	case NMEA:

		ptr = memchr(PORT->RXBuffer, 0x0a, Length);

		while (ptr != NULL)
		{
			ptr++;									// include lf
			len = (int)(ptr - &PORT->RXBuffer[0]);	
			
			memcpy(NMEAMsg, PORT->RXBuffer, len);	

			NMEAMsg[len] = 0;

//			if (Check0183CheckSum(NMEAMsg, len))
				ProcessNMEA(PORT, NMEAMsg, len);

			Length -= len;							// bytes left

			if (Length > 0)
			{
				memmove(PORT->RXBuffer, ptr, Length);
				ptr = memchr(PORT->RXBuffer, 0x0a, Length);
			}
			else
				ptr=0;
		}

		PORT->RXLen = Length;
		return;
	
	case HAMLIB:

		ProcessHAMLIBFrame(PORT, Length);
		PORT->RXLen = 0;
		return;
	}
}

VOID ProcessICOMFrame(struct RIGPORTINFO * PORT, UCHAR * rxbuffer, int Len)
{
	UCHAR * FendPtr;
	int NewLen;

	//	Split into Packets. By far the most likely is a single frame
	//	so treat as special case
	
	FendPtr = memchr(rxbuffer, 0xfd, Len);
	
	if (FendPtr == &rxbuffer[Len-1])
	{
		ProcessFrame(PORT, rxbuffer, Len);
		return;
	}
		
	// Process the first Packet in the buffer

	NewLen =  (int)(FendPtr - rxbuffer + 1);

	ProcessFrame(PORT, rxbuffer, NewLen);
	
	// Loop Back

	ProcessICOMFrame(PORT, FendPtr+1, Len - NewLen);
	return;
}


BOOL RigWriteCommBlock(struct RIGPORTINFO * PORT)
{
	// if using a PTC radio interface send to the SCSPactor Driver, else send to COM port

	int ret;

	if (PORT->HIDDevice)
		HID_Write_Block(PORT);
	else
	if (PORT->PTC)
		SendPTCRadioCommand(PORT->PTC, PORT->TXBuffer, PORT->TXLen);
	else if (PORT->remoteSock)
		ret = sendto(PORT->remoteSock, PORT->TXBuffer, PORT->TXLen,  0, &PORT->remoteDest, sizeof(struct sockaddr));
	else
	{
		BOOL        fWriteStat;
		DWORD       BytesWritten;

#ifndef WIN32
		BytesWritten = write(PORT->hDevice, PORT->TXBuffer, PORT->TXLen);
#else
		DWORD Mask = 0;
		int Err;

		Err = GetCommModemStatus(PORT->hDevice, &Mask);

		if (Mask == 0)		// trap com0com other end not open
			return TRUE;

		fWriteStat = WriteFile(PORT->hDevice, PORT->TXBuffer, PORT->TXLen, &BytesWritten, NULL );
#endif
		if (PORT->TXLen != BytesWritten)
		{
			struct RIGINFO * RIG = &PORT->Rigs[PORT->CurrentRig];		// Only one on Yaseu

			if (RIG->RIGOK)
			{
				SetWindowText(RIG->hFREQ, "Port Closed");
				SetWindowText(RIG->hMODE, "----------");
				strcpy(RIG->WEB_FREQ, "-----------");;
				strcpy(RIG->WEB_MODE, "------");
			}

			RIG->RIGOK = FALSE;

			if (PORT->hDevice)
				 CloseCOMPort(PORT->hDevice);
		
			OpenRigCOMMPort(PORT, PORT->IOBASE, PORT->SPEED);
			
			if (PORT->IOBASE && PORT->PTTIOBASE[0] == 0)		// Using separate port for PTT?
				PORT->hPTTDevice = PORT->hDevice;
			
			if (PORT->hDevice)
			{
				// Try Again

#ifndef WIN32
				BytesWritten = write(PORT->hDevice, PORT->TXBuffer, PORT->TXLen);
#else
				fWriteStat = WriteFile(PORT->hDevice, PORT->TXBuffer, PORT->TXLen, &BytesWritten, NULL );
#endif
			}
		}
	}

	ret = GetLastError();

	PORT->Timeout = 100;		// 2 secs
	return TRUE;  
}

VOID ReleasePermission(struct RIGINFO *RIG)
{
	int i = 0;
	struct _EXTPORTDATA * PortRecord;

	while (RIG->PortRecord[i])
	{
		PortRecord = RIG->PortRecord[i];
		PortRecord->PORT_EXT_ADDR(6, PortRecord->PORTCONTROL.PORTNUMBER, (PDATAMESSAGE)3);	// Release Perrmission
		i++;
	}
}

int GetPermissionToChange(struct RIGPORTINFO * PORT, struct RIGINFO *RIG)
{
	struct ScanEntry ** ptr;
	struct _EXTPORTDATA * PortRecord;
	int i = 0;

	// Get Permission to change

	if (RIG->RIG_DEBUG)
		Debugprintf("GetPermissionToChange - WaitingForPermission = %d",  RIG->WaitingForPermission);

	// See if any two stage (CONLOCK) ports

	if (RIG->PortRecord[0] && RIG->PortRecord[0]->SCANCAPABILITIES != CONLOCK)
		goto CheckOtherPorts;

	
	if (RIG->WaitingForPermission)
	{
		// This code should only be called if port needs two stage
		// eg Request then confirm. only SCS Pactor at the moment.
		
		// TNC has been asked for permission, and we are waiting respoonse
		// Only SCS pactor returns WaitingForPrmission, so check shouldn't be called on others
		
		RIG->OKtoChange = (int)(intptr_t)RIG->PortRecord[0]->PORT_EXT_ADDR(6, RIG->PortRecord[0]->PORTCONTROL.PORTNUMBER, (PDATAMESSAGE)2);	// Get Ok Flag
	
		if (RIG->OKtoChange == 1)
		{
			if (RIG->RIG_DEBUG)
				Debugprintf("Check Permission returned OK to change");

			i = 1;
			goto CheckOtherPorts;
		}

		if (RIG->OKtoChange == -1)
		{
			// Permission Refused. Wait Scan Interval and try again

			if (RIG->RIG_DEBUG)
				Debugprintf("Scan Debug %s Refused permission - waiting ScanInterval %d",
						RIG->PortRecord[0]->PORT_DLL_NAME, PORT->FreqPtr->Dwell ); 

			RIG->WaitingForPermission = FALSE;
			SetWindowText(RIG->hSCAN, "-");
			RIG->WEB_SCAN = '=';

			RIG->ScanCounter = PORT->FreqPtr->Dwell; 
			
			if (RIG->ScanCounter == 0)		// ? After manual change
				RIG->ScanCounter = 50;

			return FALSE;
		}

		if (RIG->RIG_DEBUG)
			Debugprintf("Scan Debug %s Still Waiting", RIG->PortRecord[0]->PORT_DLL_NAME); 

		
		return FALSE;			// Haven't got reply yet. Will re-enter next tick
	}
	else
	{
		// not waiting for permission, so must be first call of a cycle

		if (RIG->PortRecord[0] && RIG->PortRecord[0]->PORT_EXT_ADDR)
			RIG->WaitingForPermission = (int)(intptr_t)RIG->PortRecord[0]->PORT_EXT_ADDR(6, RIG->PortRecord[0]->PORTCONTROL.PORTNUMBER, (PDATAMESSAGE)1);	// Request Perrmission
				
		// If it returns zero there is no need to wait.
		// Normally SCS Returns True for first call, but returns 0 if Link not running

		if (RIG->WaitingForPermission)
			return FALSE;		// Wait till driver has status

		if (RIG->RIG_DEBUG)
			Debugprintf("First call to %s returned OK to change", RIG->PortRecord[0]->PORT_DLL_NAME);

		i = 1;
	}

CheckOtherPorts:

	// Either first TNC gave permission or there are no SCS like ports.
	// Ask any others (these are assumed to give immediate yes/no

	while (RIG->PortRecord[i])
	{
		PortRecord = RIG->PortRecord[i];

		if (PortRecord->PORT_EXT_ADDR && PortRecord->PORT_EXT_ADDR(6, PortRecord->PORTCONTROL.PORTNUMBER, (PDATAMESSAGE)1))
		{
			// 1 means can't change - release all

			if (RIG->RIG_DEBUG && PORT->FreqPtr)
				Debugprintf("Scan Debug %s Refused permission - waiting ScanInterval %d",
						PortRecord->PORT_DLL_NAME, PORT->FreqPtr->Dwell); 

			RIG->WaitingForPermission = FALSE;
			MySetWindowText(RIG->hSCAN, "-");
			RIG->WEB_SCAN = '-';

			if (PORT->FreqPtr)
				RIG->ScanCounter = PORT->FreqPtr->Dwell;

			if (RIG->ScanCounter == 0)		// ? After manual change
				RIG->ScanCounter = 50; 

			ReleasePermission(RIG);
			return FALSE;
		}
		else
			if (RIG->RIG_DEBUG)
				Debugprintf("Scan Debug %s gave permission", PortRecord->PORT_DLL_NAME); 

		i++;
	}


	RIG->WaitingForPermission = FALSE;

	// Update pointer to next frequency

	RIG->FreqPtr++;

	ptr = RIG->FreqPtr;

	if (ptr == NULL)
	{
		Debugprintf("Scan Debug - No freqs - quitting"); 
		return FALSE;					 // No Freqs
	}

	if (ptr[0] == (struct ScanEntry *)0) // End of list - reset to start
	{
 		ptr = CheckTimeBands(RIG);
	
		if (ptr[0] == (struct ScanEntry *)0)
		{
			// Empty Timeband - delay 60 secs (we need to check for timeband change sometimes)

			RIG->ScanCounter = 600;
			ReleasePermission(RIG);
			return FALSE;
		}
	}

	PORT->FreqPtr = ptr[0];				// Save Scan Command Block

	RIG->ScanCounter = PORT->FreqPtr->Dwell; 
		
	if (RIG->ScanCounter == 0)		// ? After manual change
		RIG->ScanCounter = 150;
	
	MySetWindowText(RIG->hSCAN, "S");
	RIG->WEB_SCAN = 'S';

	// Do Bandwidth and antenna switches (if needed)

	DoBandwidthandAntenna(RIG, ptr[0]);

	return TRUE;
}

VOID DoBandwidthandAntenna(struct RIGINFO *RIG, struct ScanEntry * ptr)
{
	// If Bandwidth Change needed, do it

	int i;
	struct _EXTPORTDATA * PortRecord;

	if (ptr->Bandwidth || ptr->RPacketMode || ptr->HFPacketMode 
		|| ptr->PMaxLevel || ptr->ARDOPMode[0] || ptr->VARAMode)
	{
		i = 0;

		while (RIG->PortRecord[i])
		{
			PortRecord = RIG->PortRecord[i];

			RIG->CurrentBandWidth = ptr->Bandwidth;

			PortRecord->PORT_EXT_ADDR(6, PortRecord->PORTCONTROL.PORTNUMBER, (PDATAMESSAGE)ptr);

/*			if (ptr->Bandwidth == 'R')			// Robust Packet
				PortRecord->PORT_EXT_ADDR(6, PortRecord->PORTCONTROL.PORTNUMBER, 6);	// Set Robust Packet
			else 
				
			if (ptr->Bandwidth == 'W')
				PortRecord->PORT_EXT_ADDR(6, PortRecord->PORTCONTROL.PORTNUMBER, 4);	// Set Wide Mode
			else
				PortRecord->PORT_EXT_ADDR(6, PortRecord->PORTCONTROL.PORTNUMBER, 5);	// Set Narrow Mode
*/
			i++;
		}
	}

	// If Antenna Change needed, do it
		
	// 5 and 6 are used for CI-V switching so ignore here

	if (ptr->Antenna && ptr->Antenna < '5')
	{
		SwitchAntenna(RIG, ptr->Antenna);
	}

	return;	
}

VOID ICOMPoll(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	int i;

	struct RIGINFO * RIG;

	for (i=0; i< PORT->ConfiguredRigs; i++)
	{
		RIG = &PORT->Rigs[i];

		if (RIG->ScanStopped == 0)
			if (RIG->ScanCounter)
				RIG->ScanCounter--;
	}

	if (PORT->Timeout)
	{
		PORT->Timeout--;
		
		if (PORT->Timeout)			// Still waiting
			return;

		PORT->Retries--;

		if(PORT->Retries)
		{
			RigWriteCommBlock(PORT);	// Retransmit Block
			return;
		}

		RIG = &PORT->Rigs[PORT->CurrentRig];


		SetWindowText(RIG->hFREQ, "-----------");
		strcpy(RIG->WEB_FREQ, "-----------");
		SetWindowText(RIG->hMODE, "------");
		strcpy(RIG->WEB_MODE, "------");

//		SetWindowText(RIG->hFREQ, "145.810000");
//		SetWindowText(RIG->hMODE, "RTTY/1");

		PORT->Rigs[PORT->CurrentRig].RIGOK = FALSE;

		return;

	}

	// Send Data if avail, else send poll

	PORT->CurrentRig++;

	if (PORT->CurrentRig >= PORT->ConfiguredRigs)
		PORT->CurrentRig = 0;

	RIG = &PORT->Rigs[PORT->CurrentRig];

/*
	RIG->DebugDelay ++;

	if (RIG->DebugDelay > 600)
	{
		RIG->DebugDelay = 0;
		Debugprintf("Scan Debug %d %d %d %d %d %d", PORT->CurrentRig, 
			RIG->NumberofBands, RIG->RIGOK, RIG->ScanStopped, RIG->ScanCounter,
			RIG->WaitingForPermission);
	}
*/
	if (RIG->NumberofBands && RIG->RIGOK && (RIG->ScanStopped == 0))
	{
		if (RIG->ScanCounter <= 0)
		{
			//	Send Next Freq

			if	(GetPermissionToChange(PORT, RIG))
			{
				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq/1000000.0);

				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);
	
				if (PORT->FreqPtr->Freq > 0.0)
				{
					_gcvt((PORT->FreqPtr->Freq + RIG->rxOffset) / 1000000.0, 9, RIG->Valchar); // For MH
					strcpy(RIG->WEB_FREQ, RIG->Valchar);
					SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
				}

		
				PORT->TXLen = PORT->FreqPtr->Cmd1Len;
				RigWriteCommBlock(PORT);
				PORT->Retries = 2;
				PORT->AutoPoll = TRUE;

				return;
			}
		}
	}

	if (RIG->RIGOK && RIG->BPQtoRADIO_Q)
	{
		struct MSGWITHOUTLEN * buffptr;
			
		buffptr = Q_REM(&RIG->BPQtoRADIO_Q);

		// Copy the ScanEntry struct from the Buffer to the PORT Scanentry

		memcpy(&PORT->ScanEntry, buffptr->Data, sizeof(struct ScanEntry));

		PORT->FreqPtr = &PORT->ScanEntry;		// Block we are currently sending.

		if (RIG->RIG_DEBUG)
			Debugprintf("BPQ32 Manual Change Freq to %9.4f", PORT->FreqPtr->Freq/1000000.0);


		memcpy(Poll, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);

		DoBandwidthandAntenna(RIG, &PORT->ScanEntry);

		if (PORT->FreqPtr->Freq > 0.0)
		{
			_gcvt((PORT->FreqPtr->Freq + RIG->rxOffset) / 1000000.0, 9, RIG->Valchar); // For MH
			strcpy(RIG->WEB_FREQ, RIG->Valchar);
			SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
		}

		PORT->TXLen = PORT->FreqPtr->Cmd1Len;					// First send the set Freq
		RigWriteCommBlock(PORT);
		PORT->Retries = 2;

		ReleaseBuffer(buffptr);

		PORT->AutoPoll = FALSE;

		return;
	}

		
	if (RIG->RIGOK && RIG->ScanStopped == 0 && RIG->NumberofBands &&
		RIG->ScanCounter && RIG->ScanCounter < 30) // no point in reading freq if we are about to change
		return;

	if (RIG->PollCounter)
	{
		RIG->PollCounter--;
		if (RIG->PollCounter)
			return;
	}

	// Need to make sure we don't poll multiple rigs on port at the same time

	if (RIG->RIGOK)
	{
		PORT->Retries = 2;
		RIG->PollCounter = 10 / PORT->ConfiguredRigs;			// Once Per Sec
	}
	else
	{
		PORT->Retries = 1;
		RIG->PollCounter = 100 / PORT->ConfiguredRigs;			// Slow Poll if down
	}

	RIG->PollCounter += PORT->CurrentRig * 3;

	PORT->AutoPoll = TRUE;

	// Read Frequency 

	Poll[0] = 0xFE;
	Poll[1] = 0xFE;
	Poll[2] = RIG->RigAddr;
	Poll[3] = 0xE0;
	Poll[4] = 0x3;		// Get frequency command
	Poll[5] = 0xFD;

	PORT->TXLen = 6;

	RigWriteCommBlock(PORT);

	PORT->Retries = 1;
	PORT->Timeout = 10;

	return;
}


VOID ProcessFrame(struct RIGPORTINFO * PORT, UCHAR * Msg, int framelen)
{
	UCHAR * Poll = PORT->TXBuffer;
	struct RIGINFO * RIG;
	int i;
	int cmdSent = PORT->TXBuffer[4];

	if (Msg[0] != 0xfe || Msg[1] != 0xfe)

		// Duff Packet - return

		return;	

	if (Msg[2] != 0xe0 && Msg[2] != 0)
	{
		// Echo - Proves a CI-V interface is attached

		if (PORT->PORTOK == FALSE)
		{
			// Just come up		
			PORT->PORTOK = TRUE;
			Debugprintf("Cat Port OK");
		}
		return;
	}

	for (i=0; i< PORT->ConfiguredRigs; i++)
	{
		RIG = &PORT->Rigs[i];
		if (Msg[3] == RIG->RigAddr)
			goto ok;
	}

	return;

ok:

	if (Msg[4] == 0xFB)
	{
		// Accept

		if (cmdSent == 0x1C && PORT->TXBuffer[5] == 1)		// Tune
		{
			if (!PORT->AutoPoll)
				SendResponse(RIG->Session, "Tune OK");
		
			PORT->Timeout = 0;
			return;
		}

		if (cmdSent == 0x14 && PORT->TXBuffer[5] == 0x0A)		// Power
		{
			if (!PORT->AutoPoll)
				SendResponse(RIG->Session, "Set Power OK");
		
			PORT->Timeout = 0;
			return;
		}

		// if it was the set freq, send the set mode

		if (RIG->ICF8101)
		{
			if (cmdSent == 0x1A && PORT->TXBuffer[5] == 0x35)
			{
				if (PORT->FreqPtr->Cmd2)
				{
					memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd2, PORT->FreqPtr->Cmd2Len);
					PORT->TXLen = PORT->FreqPtr->Cmd2Len;
					RigWriteCommBlock(PORT);
					PORT->Retries = 2;
				}
				else
				{
					if (!PORT->AutoPoll)
						SendResponse(RIG->Session, "Frequency Set OK");

					PORT->Timeout = 0;
				}
				return;
			}

			if (cmdSent == 0x1a && PORT->TXBuffer[5] == 0x36)
			{
				// Set Mode Response - if scanning read freq, else return OK to user

				if (RIG->ScanStopped == 0)
				{
					ReleasePermission(RIG);	// Release Perrmission

					Poll[0] = 0xFE;
					Poll[1] = 0xFE;
					Poll[2] = RIG->RigAddr;
					Poll[3] = 0xE0;
					Poll[4] = 0x3;		// Get frequency command
					Poll[5] = 0xFD;

					PORT->TXLen = 6;
					RigWriteCommBlock(PORT);
					PORT->Retries = 2;
					return;
				}
				else
				{
					if (!PORT->AutoPoll)
						SendResponse(RIG->Session, "Frequency and Mode Set OK");

					RIG->PollCounter = 30 / RIG->PORT->ConfiguredRigs;	// Dont read freq for 3 secs
				}
			}

			PORT->Timeout = 0;
			return;
		}	

		if (cmdSent == 5 || cmdSent == 7) // Freq or VFO
		{
			if (PORT->FreqPtr && PORT->FreqPtr->Cmd2)
			{
				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd2, PORT->FreqPtr->Cmd2Len);
				PORT->TXLen = PORT->FreqPtr->Cmd2Len;
				RigWriteCommBlock(PORT);
				PORT->Retries = 2;
			}
			else
			{
				if (!PORT->AutoPoll)
 					SendResponse(RIG->Session, "Frequency Set OK");
		
				PORT->Timeout = 0;
			}
			return;
		}

		if (cmdSent == 6)		// Set Mode
		{
			if (PORT->FreqPtr && PORT->FreqPtr->Cmd3)
			{
				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd3, PORT->FreqPtr->Cmd3Len);
				PORT->TXLen = PORT->FreqPtr->Cmd3Len;
				RigWriteCommBlock(PORT);
				PORT->Retries = 2;
				return;
			}

			goto SetFinished;
		}

		if (cmdSent == 0x08)
		{
			// Memory Chan
			
			cmdSent = 0;			// So we only do it once

			goto SetFinished;
		}

		if (cmdSent == 0x12)
			goto SetFinished;		// Antenna always sent last


		if (cmdSent == 0x0f || cmdSent == 0x01a)	// Set DUP or Data
		{
			// These are send from cmd3. There may be a cmd4
			// for antenna switching

			if (PORT->FreqPtr && PORT->FreqPtr->Cmd4)
			{
				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd4, PORT->FreqPtr->Cmd4Len);
				PORT->TXLen = PORT->FreqPtr->Cmd4Len;
				RigWriteCommBlock(PORT);
				PORT->Retries = 2;
				return;
			}

SetFinished:

			// Set Mode Response - if scanning read freq, else return OK to user

			if (RIG->ScanStopped == 0 && PORT->AutoPoll)
			{
				ReleasePermission(RIG);	// Release Perrmission

				Poll[0] = 0xFE;
				Poll[1] = 0xFE;
				Poll[2] = RIG->RigAddr;
				Poll[3] = 0xE0;
				Poll[4] = 0x3;		// Get frequency command
				Poll[5] = 0xFD;

				PORT->TXLen = 6;
				RigWriteCommBlock(PORT);
				PORT->Retries = 2;
				return;
			}

			else
			{
				if (!PORT->AutoPoll)
					SendResponse(RIG->Session, "Frequency and Mode Set OK");

				RIG->PollCounter = 30 / RIG->PORT->ConfiguredRigs;	// Dont read freq for 3 secs
			}
		}

		PORT->Timeout = 0;
		return;
	}

	if (Msg[4] == 0xFA)
	{
		// Reject

		PORT->Timeout = 0;

		if (!PORT->AutoPoll)
		{
			if (cmdSent == 5)
				SendResponse(RIG->Session, "Sorry - Set Frequency Command Rejected");
			else
			if (cmdSent == 6)
				SendResponse(RIG->Session, "Sorry - Set Mode Command Rejected");
			else
			if (cmdSent == 0x0f)
				SendResponse(RIG->Session, "Sorry - Set Shift Command Rejected");
			else
			if (cmdSent == 0x12)
				SendResponse(RIG->Session, "Sorry - Set Antenna Command Rejected");
			else
			if (cmdSent == 0x1C && PORT->TXBuffer[5] == 1)		// Tune
				SendResponse(RIG->Session, "Sorry - Tune Command Rejected");
			else
			if (cmdSent == 0x14 && PORT->TXBuffer[5] == 0x0a)		// Power
				SendResponse(RIG->Session, "Sorry - Power Command Rejected");
			else
				SendResponse(RIG->Session, "Sorry - Command Rejected");

		}
		return;
	}

	if (Msg[4] == PORT->TXBuffer[4])
	{
		// Response to our command

		// Any valid frame is an ACK

		RIG->RIGOK = TRUE;
		PORT->Timeout = 0;

		if (!PORT->AutoPoll)
		{
			// Manual response probably to CMD Query. Return response

			char reply[256] = "CMD Response ";
			char * p1 = &reply[13];
			UCHAR * p2 = &Msg[4];
			int n = framelen - 4;

			while (n > 0)
			{
				sprintf(p1, "%02X ", *(p2));
				p1 += 3;
				p2++;
				n--;
			}

			SendResponse(RIG->Session, reply);

		}

	}
	else 
		return;		// What does this mean??


	if (PORT->PORTOK == FALSE)
	{
		// Just come up
//		char Status[80];
		
		PORT->PORTOK = TRUE;
//		sprintf(Status,"COM%d PORT link OK", PORT->IOBASE);
//		SetWindowText(PORT->hStatus, Status);
	}

	if (Msg[4] == 3)
	{
		// Rig Frequency
		int n, j, decdigit;
		long long Freq = 0;
		int start = 9;
		long long MHz, Hz;
		char CharMHz[16] = "";
		char CharHz[16] = "";

		int i;

	
		if (RIG->IC735)
			start = 8;		// shorted msg

		for (j = start; j > 4; j--)
		{
			n = Msg[j];
			decdigit = (n >> 4);
			decdigit *= 10;
			decdigit += n & 0xf;
			Freq = (Freq *100 ) + decdigit;
		}

		Freq += RIG->rxOffset;

		RIG->RigFreq = Freq / 1000000.0;

		// If we convert to float to display we get rounding errors, so convert to MHz and Hz to display

		MHz = Freq / 1000000;

		Hz = Freq - MHz * 1000000;

		sprintf(CharMHz, "%lld", MHz);
		sprintf(CharHz, "%06lld", Hz);

		for (i = 5; i > 2; i--)
		{
			if (CharHz[i] == '0')
				CharHz[i] = 0;
			else
				break;
		}

		sprintf(RIG->WEB_FREQ,"%lld.%s", MHz, CharHz);
		SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
		strcpy(RIG->Valchar, RIG->WEB_FREQ);
 

		// Now get Mode

		Poll[0] = 0xFE;
		Poll[1] = 0xFE;
		Poll[2] = RIG->RigAddr;
		Poll[3] = 0xE0;

		if (RIG->ICF8101)
		{
			Poll[4] = 0x1A;		// Get Mode
			Poll[5] = 0x34;
			Poll[6] = 0xFD;
			PORT->TXLen = 7;
		}
		else
		{
			Poll[4] = 0x4;		// Get Mode
			Poll[5] = 0xFD;

			PORT->TXLen = 6;
		}

		RigWriteCommBlock(PORT);
		PORT->Retries = 2;
		return;
	}

	if (RIG->ICF8101)
	{
		if (cmdSent == 0x1A && PORT->TXBuffer[5] == 0x34)
		{
			// Get Mode

			unsigned int Mode;

			Mode = (Msg[7] >> 4);
			Mode *= 10;
			Mode += Msg[7] & 0xf;

			if (Mode > 24) Mode = 24;

			sprintf(RIG->WEB_MODE,"%s", Modes[Mode]);

			strcpy(RIG->ModeString, Modes[Mode]);
			SetWindowText(RIG->hMODE, RIG->WEB_MODE);



			return;
		}
	}


	if (Msg[4] == 4)
	{
		// Mode

		unsigned int Mode;

		Mode = (Msg[5] >> 4);
		Mode *= 10;
		Mode += Msg[5] & 0xf;

		if (Mode > 24) Mode = 24;

		if (RIG->IC735)
			sprintf(RIG->WEB_MODE,"%s", Modes[Mode]);
		else
			sprintf(RIG->WEB_MODE,"%s/%d", Modes[Mode], Msg[6]);

		strcpy(RIG->ModeString, Modes[Mode]);
		SetWindowText(RIG->hMODE, RIG->WEB_MODE);
	}
}

int SendResponse(int Session, char * Msg)
{
	PDATAMESSAGE Buffer;
	BPQVECSTRUC * VEC;
	TRANSPORTENTRY * L4 = L4TABLE;

	if (Session == -1)
		return 0;

	Buffer = GetBuff();

	L4 += Session;

	Buffer->PID = 0xf0;
	Buffer->LENGTH = MSGHDDRLEN + 1; // Includes PID
	Buffer->LENGTH += sprintf(Buffer->L2DATA, "%s\r", Msg);

	VEC = L4->L4TARGET.HOST;

	C_Q_ADD(&L4->L4TX_Q, (UINT *)Buffer);

#ifndef LINBPQ

	if (VEC)
		PostMessage(VEC->HOSTHANDLE, BPQMsg, VEC->HOSTSTREAM, 2);  
#endif
	return 0;
}

VOID ProcessFT100Frame(struct RIGPORTINFO * PORT)
{
	// Only one we should see is a Status Message

	UCHAR * Poll = PORT->TXBuffer;
	UCHAR * Msg = PORT->RXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Yaseu
	int Freq;
	double FreqF;
	unsigned int Mode;
	
	RIG->RIGOK = TRUE;
	PORT->Timeout = 0;

	// Bytes 0 is Band
	// 1 - 4 is Freq in binary in units of 1.25 HZ (!)
	// Byte 5 is Mode

	Freq =  (Msg[1] << 24) + (Msg[2] << 16) + (Msg[3] << 8) + Msg[4];
	
	FreqF = (Freq * 1.25) / 1000000;

	if (PORT->YaesuVariant == FT1000MP)
		FreqF = FreqF / 2;				// No idea why!

	RIG->RigFreq = FreqF;

	_gcvt(FreqF, 9, RIG->Valchar);

	sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
	SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);

	if (PORT->PortType == FT100)
	{
		Mode = Msg[5] & 15;
		if (Mode > 8) Mode = 8;
		sprintf(RIG->WEB_MODE,"%s", FT100Modes[Mode]);
	}
	else	// FT1000
	{
		Mode = Msg[7] & 7;
		sprintf(RIG->WEB_MODE,"%s", FTRXModes[Mode]);
	}

	strcpy(RIG->ModeString, RIG->WEB_MODE);
	SetWindowText(RIG->hMODE, RIG->WEB_MODE);

	if (!PORT->AutoPoll)
		SendResponse(RIG->Session, "Mode and Frequency Set OK");
	else
		if (PORT->TXLen > 5)		// Poll is 5 Change is more
			ReleasePermission(RIG);		// Release Perrmission to change
}



VOID ProcessFT990Frame(struct RIGPORTINFO * PORT)
{
	// Only one we should see is a Status Message

	UCHAR * Poll = PORT->TXBuffer;
	UCHAR * Msg = PORT->RXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Yaseu
	int Freq;
	double FreqF;
	unsigned int Mode;
	
	RIG->RIGOK = TRUE;
	PORT->Timeout = 0;

	// Bytes 0 is Band
	// 1 - 4 is Freq in units of 10Hz (I think!)
	// Byte 5 is Mode

	Freq =  (Msg[1] << 16) + (Msg[2] << 8) + Msg[3];
	
	FreqF = (Freq * 10.0) / 1000000;

	RIG->RigFreq = FreqF;

	_gcvt(FreqF, 9, RIG->Valchar);

	sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
	SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);

	Mode = Msg[7] & 7;
	sprintf(RIG->WEB_MODE,"%s", FTRXModes[Mode]);

	strcpy(RIG->ModeString, RIG->WEB_MODE);
	SetWindowText(RIG->hMODE, RIG->WEB_MODE);

	if (!PORT->AutoPoll)
		SendResponse(RIG->Session, "Mode and Frequency Set OK");
	else
		if (PORT->TXLen > 5)		// Poll is 5 change is more
			ReleasePermission(RIG);		// Release Perrmission to change
}

VOID ProcessFT1000Frame(struct RIGPORTINFO * PORT)
{
	// Only one we should see is a Status Message

	UCHAR * Poll = PORT->TXBuffer;
	UCHAR * Msg = PORT->RXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Yaseu
	int Freq;
	double FreqF;
	unsigned int Mode;
	
	RIG->RIGOK = TRUE;
	PORT->Timeout = 0;

	// I think the FT1000/1000D is same as 990
	//	FT1000MP is similar to FT100, but steps on .625 Hz (despite manual)
	// Bytes 0 is Band
	// 1 - 4 is Freq in binary in units of 1.25 HZ (!)
	// Byte 5 is Mode

	if (PORT->YaesuVariant == FT1000MP)
	{
		Freq =  (Msg[1] << 24) + (Msg[2] << 16) + (Msg[3] << 8) + Msg[4];	
		FreqF = (Freq * 1.25) / 1000000;
		FreqF = FreqF / 2;				// No idea why!
	}
	else
	{
		Freq =  (Msg[1] << 16) + (Msg[2] << 8) + Msg[3];
		FreqF = (Freq * 10.0) / 1000000;
	}

	RIG->RigFreq = FreqF;

	_gcvt(FreqF, 9, RIG->Valchar);

	sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
	SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);

	if (PORT->PortType == FT100)
	{
		Mode = Msg[5] & 15;
		if (Mode > 8) Mode = 8;
		sprintf(RIG->WEB_MODE,"%s", FT100Modes[Mode]);
	}
	else	// FT1000
	{
		Mode = Msg[7] & 7;
		sprintf(RIG->WEB_MODE,"%s", FTRXModes[Mode]);
	}

	strcpy(RIG->ModeString, RIG->WEB_MODE);
	SetWindowText(RIG->hMODE, RIG->WEB_MODE);

	if (!PORT->AutoPoll)
		SendResponse(RIG->Session, "Mode and Frequency Set OK");
	else
		if (PORT->TXLen > 5)		// Poll is 5 change is more
			ReleasePermission(RIG);		// Release Perrmission to change
}





VOID ProcessYaesuCmdAck(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	UCHAR * Msg = PORT->RXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Yaseu

	PORT->Timeout = 0;
	PORT->RXLen = 0;					// Ready for next frame	

	if (PORT->CmdSent == 1)				// Set Freq
	{
		ReleasePermission(RIG);			// Release Perrmission

		if (Msg[0])
		{
			// I think nonzero is a Reject

			if (!PORT->AutoPoll)
				SendResponse(RIG->Session, "Sorry - Set Frequency Rejected");

			return;
		}
		else
		{
			if (RIG->ScanStopped == 0)
			{
				// Send a Get Freq - We Don't Poll when scanning

				Poll[0] = Poll[1] = Poll[2] = Poll[3] = 0;
				Poll[4] = 0x3;		// Get frequency amd mode command

				RigWriteCommBlock(PORT);
				PORT->Retries = 2;
				PORT->CmdSent = 0;
			}
			else

			if (!PORT->AutoPoll)
				SendResponse(RIG->Session, "Mode and Frequency Set OK");

			return;
		}
	}

	if (PORT->CmdSent == 7)						// Set Mode
	{
		if (Msg[0])
		{
			// I think nonzero is a Reject

			if (!PORT->AutoPoll)
				SendResponse(RIG->Session, "Sorry - Set Mode Rejected");

			return;
		}
		else
		{
			// Send the Frequency
			
			memcpy(Poll, &Poll[5], 5);
			RigWriteCommBlock(PORT);
			PORT->CmdSent = Poll[4];
			PORT->Retries = 2;

			return;
		}
	}

}
VOID ProcessYaesuFrame(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	UCHAR * Msg = PORT->RXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Yaseu
	int n, j, Freq = 0, decdigit;
	double FreqF;
	unsigned int Mode;

	// I'm not sure we get anything but a Command Response,
	// and the only command we send is Get Rig Frequency and Mode

	
	RIG->RIGOK = TRUE;
	PORT->Timeout = 0;

	for (j = 0; j < 4; j++)
	{
		n = Msg[j];
		decdigit = (n >> 4);
		decdigit *= 10;
		decdigit += n & 0xf;
		Freq = (Freq *100 ) + decdigit;
	}

	FreqF = Freq / 100000.0;

	RIG->RigFreq = FreqF;

//		Valchar = _fcvt(FreqF, 6, &dec, &sign);
	_gcvt(FreqF, 9, RIG->Valchar);

	sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
	SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);

	Mode = Msg[4];

	if (Mode > 15) Mode = 15;

	sprintf(RIG->WEB_MODE,"%s", YaesuModes[Mode]);
	strcpy(RIG->ModeString, RIG->WEB_MODE);
	SetWindowText(RIG->hMODE, RIG->WEB_MODE);

	//	FT847 Manual Freq Change response ends up here
	
	if (strcmp(RIG->RigName, "FT847") == 0)
	{
		if (!PORT->AutoPoll)
			SendResponse(RIG->Session, "Mode and Frequency Set OK");
			
		if (PORT->CmdSent == -1)
			ReleasePermission(RIG);			// Release Perrmission to change
	}
}

VOID YaesuPoll(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Yaseu

	if (RIG->ScanStopped == 0)
		if (RIG->ScanCounter)
			RIG->ScanCounter--;

	if (PORT->Timeout)
	{
		PORT->Timeout--;
		
		if (PORT->Timeout)			// Still waiting
			return;

		PORT->Retries--;

		if(PORT->Retries)
		{
			RigWriteCommBlock(PORT);	// Retransmit Block
			return;
		}

		SetWindowText(RIG->hFREQ, "------------------");
		SetWindowText(RIG->hMODE, "----------");
		strcpy(RIG->WEB_FREQ, "-----------");;
		strcpy(RIG->WEB_MODE, "------");


		PORT->Rigs[PORT->CurrentRig].RIGOK = FALSE;

		return;

	}

	// Send Data if avail, else send poll

	if (RIG->NumberofBands && (RIG->ScanStopped == 0))
	{
		if (RIG->ScanCounter <= 0)
		{
			//	Send Next Freq

			if	(GetPermissionToChange(PORT, RIG))
			{
				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

				_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd1, 24);

				if (PORT->PortType == YAESU)
				{
					if (strcmp(PORT->Rigs[0].RigName, "FT847") == 0)
					{
						PORT->TXLen = 15; // No Cmd ACK, so send Mode, Freq and Poll
						PORT->CmdSent = -1;
					}
					else
					{
						PORT->TXLen = 5;
						PORT->CmdSent = Poll[4];
					}
					RigWriteCommBlock(PORT);
					PORT->Retries = 2;
					PORT->AutoPoll = TRUE;
					return;
				}

				// FT100

				PORT->TXLen = 15;			// Set Mode, Set Freq, Poll
				RigWriteCommBlock(PORT);
				PORT->Retries = 2;
				PORT->AutoPoll = TRUE;
			}
		}
	}
	
	if (RIG->RIGOK && RIG->BPQtoRADIO_Q)
	{
		struct MSGWITHOUTLEN * buffptr;
			
		buffptr = Q_REM(&RIG->BPQtoRADIO_Q);

		// Copy the ScanEntry struct from the Buffer to the PORT Scanentry

		memcpy(&PORT->ScanEntry, buffptr->Data, sizeof(struct ScanEntry));

		PORT->FreqPtr = &PORT->ScanEntry;		// Block we are currently sending.
		
		if (RIG->RIG_DEBUG)
			Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

		_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

		DoBandwidthandAntenna(RIG, &PORT->ScanEntry);

		memcpy(Poll, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);

		if (PORT->PortType == YAESU)
		{
			if (strcmp(PORT->Rigs[0].RigName, "FT847") == 0)
			{
				PORT->TXLen = 15;					// Send all
				PORT->CmdSent = -1;
			}
			else
			{
				PORT->TXLen = 5;					// First send the set Freq
				PORT->CmdSent = Poll[4];
			}
		}
		else
			PORT->TXLen = 15;					// Send all

		RigWriteCommBlock(PORT);
		PORT->Retries = 2;

		ReleaseBuffer(buffptr);
		PORT->AutoPoll = FALSE;
	
		return;
	}

	if (RIG->RIGOK && RIG->ScanStopped == 0 && RIG->NumberofBands &&
		RIG->ScanCounter && RIG->ScanCounter < 30) // no point in reading freq if we are about to change
		return;
	
	if (RIG->PollCounter)
	{
		RIG->PollCounter--;
		if (RIG->PollCounter)
			return;
	}

	RIG->PollCounter = 10;			// Once Per Sec

	// Read Frequency 

	Poll[0] = 0;
	Poll[1] = 0;
	Poll[2] = 0;

	if (PORT->PortType == FT990 || PORT->PortType == YAESU || PORT->YaesuVariant == FT1000D)
		Poll[3] = 3;
	else
		Poll[3] = 2;
	
	if (PORT->PortType == YAESU)
		Poll[4] = 0x3;		// Get frequency amd mode command
	else
		Poll[4] = 16;		// FT100/990/1000 Get frequency amd mode command

	PORT->TXLen = 5;
	RigWriteCommBlock(PORT);
	PORT->Retries = 2;
	PORT->CmdSent = 0;

	PORT->AutoPoll = TRUE;

	return;
}

VOID ProcessNMEA(struct RIGPORTINFO * PORT, char * Msg, int Length)
{
	UCHAR * Poll = PORT->TXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Yaseu

	Msg[Length] = 0;
	
	if (PORT->PORTOK == FALSE)
	{
		// Just come up		
		PORT->PORTOK = TRUE;
	}

	RIG->RIGOK = TRUE;
	PORT->Timeout = 0;

	if (!PORT->AutoPoll)
	{
		// Response to a RADIO Command

		if (Msg[0] == '?')
			SendResponse(RIG->Session, "Sorry - Command Rejected");
		else
			SendResponse(RIG->Session, "Mode and Frequency Set OK");
	
		PORT->AutoPoll = TRUE;
	}

	if (memcmp(&Msg[13], "RXF", 3) == 0)
	{
		if (Length < 24)
			return;

		RIG->RigFreq = atof(&Msg[17]);
	
		sprintf(RIG->WEB_FREQ,"%f", RIG->RigFreq);
		SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
		strcpy(RIG->Valchar, RIG->WEB_FREQ);

		return;
	}

	if (memcmp(&Msg[13], "MODE", 3) == 0)
	{
		char * ptr;

		if (Length < 24)
			return;

		ptr = strchr(&Msg[18], '*');
		if (ptr) *(ptr) = 0;

		SetWindowText(RIG->hMODE, &Msg[18]);
		strcpy(RIG->WEB_MODE, &Msg[18]);
		strcpy(RIG->ModeString, RIG->WEB_MODE);
		return;
	}


}


//FA00014103000;MD2;


VOID ProcessSDRRadioFrame(struct RIGPORTINFO * PORT, int Length)
{
	UCHAR * Poll = PORT->TXBuffer;
	UCHAR * Msg = PORT->RXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];
	UCHAR * ptr;
	int CmdLen;
	int i;

	Msg[Length] = 0;

	if (PORT->PORTOK == FALSE)
	{
		// Just come up		
		PORT->PORTOK = TRUE;
	}

	if (!PORT->AutoPoll)
	{
		// Response to a RADIO Command

		if (Msg[0] == '?')
			SendResponse(RIG->Session, "Sorry - Command Rejected");
		else if (Msg[0] == 'A' && Msg[1] == 'C')
			SendResponse(RIG->Session, "TUNE OK");
		else if (Msg[0] == 'P' && Msg[1] == 'C') 
			SendResponse(RIG->Session, "Power Set OK");
		else
			SendResponse(RIG->Session, "Mode and Frequency Set OK");
	
		PORT->AutoPoll = TRUE;
		return;
	}


LoopR:

	ptr = strchr(Msg, ';');
	CmdLen = (int)(ptr - Msg + 1);

	// Find Device. FA to FF for frequency

	// Note. SDRConsole reports the same mode for all receivers, so don't rely on reported mode

	if (Msg[0] == 'F')
	{
		for (i = 0; i < PORT->ConfiguredRigs; i++)
		{
			RIG = &PORT->Rigs[i];
			if (Msg[1] == RIG->RigAddr)
				goto ok;
		}
		return;
ok:

		if (CmdLen > 9)
		{
			char CharMHz[16] = "";
			char CharHz[16] = "";

			int i;
			long long Freq;
			long long MHz, Hz;

			RIG->RIGOK = TRUE;

			Freq = strtoll(&Msg[2], NULL, 10) + RIG->rxOffset;

			RIG->RigFreq = Freq / 1000000.0;

			// If we convert to float to display we get rounding errors, so convert to MHz and Hz to display

			MHz = Freq / 1000000;

			Hz = Freq - MHz * 1000000;

			sprintf(CharMHz, "%lld", MHz);
			sprintf(CharHz, "%06lld", Hz);

			for (i = 5; i > 2; i--)
			{
				if (CharHz[i] == '0')
					CharHz[i] = 0;
				else
					break;
			}


			sprintf(RIG->WEB_FREQ,"%lld.%s", MHz, CharHz);
			SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
			strcpy(RIG->Valchar, RIG->WEB_FREQ);

			PORT->Timeout = 0;
		}
	}
	else if (Msg[0] == 'M' && Msg[1] == 'D')
	{
		int Mode;

		Mode = Msg[2] - 48;
		if (Mode > 7) Mode = 7;
		SetWindowText(RIG->hMODE, KenwoodModes[Mode]);
		strcpy(RIG->WEB_MODE, KenwoodModes[Mode]);
		strcpy(RIG->ModeString, RIG->WEB_MODE);
	
	}

	if (CmdLen < Length)
	{
		// Another Message in Buffer

		ptr++;
		Length -= (int)(ptr - Msg);

		if (Length <= 0)
			return;

		memmove(Msg, ptr, Length +1);

		goto LoopR;
	}
}



VOID ProcessKenwoodFrame(struct RIGPORTINFO * PORT, int Length)
{
	UCHAR * Poll = PORT->TXBuffer;
	UCHAR * Msg = PORT->RXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Yaseu
	UCHAR * ptr;
	int CmdLen;

	Msg[Length] = 0;
	
	if (PORT->PORTOK == FALSE)
	{
		// Just come up		
		PORT->PORTOK = TRUE;
	}

	RIG->RIGOK = TRUE;

	if (!PORT->AutoPoll)
	{
		// Response to a RADIO Command

		if (Msg[0] == '?')
			SendResponse(RIG->Session, "Sorry - Command Rejected");
		else if (Msg[0] == 'A' && Msg[1] == 'C')
			SendResponse(RIG->Session, "TUNE OK");
		else if (Msg[0] == 'P' && Msg[1] == 'C') 
			SendResponse(RIG->Session, "Power Set OK");
		else
			SendResponse(RIG->Session, "Mode and Frequency Set OK");
	
		PORT->AutoPoll = TRUE;
		return;
	}

Loop:

	if (PORT->PortType == FLEX)
	{
		Msg += 2;						// Skip ZZ
		Length -= 2;
	}

	ptr = strchr(Msg, ';');
	CmdLen = (int)(ptr - Msg + 1);

	if (Msg[0] == 'F' && Msg[1] == 'A' && CmdLen > 9)
	{
		char CharMHz[16] = "";
		char CharHz[16] = "";

		int i;
		long long Freq;
		long long MHz, Hz;

		Freq = strtoll(&Msg[2], NULL, 10) + RIG->rxOffset;

		RIG->RigFreq = Freq / 1000000.0;

		// If we convert to float to display we get rounding errors, so convert to MHz and Hz to display

		MHz = Freq / 1000000;

		Hz = Freq - MHz * 1000000;

		sprintf(CharMHz, "%lld", MHz);
		sprintf(CharHz, "%06lld", Hz);

/*
		if (PORT->PortType == FT2000)
		{
			memcpy(FreqDecimal,&Msg[4], 6);
			Msg[4] = 0;
		}
		else if (PORT->PortType == FT991A)
		{
			memcpy(FreqDecimal,&Msg[5], 6);
			Msg[5] = 0;
		}

		else
		{
			memcpy(FreqDecimal,&Msg[7], 6);
			Msg[7] = 0;
		}
		FreqDecimal[6] = 0;
*/

		for (i = 5; i > 2; i--)
		{
			if (CharHz[i] == '0')
				CharHz[i] = 0;
			else
				break;
		}


		sprintf(RIG->WEB_FREQ,"%lld.%s", MHz, CharHz);
		SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
		strcpy(RIG->Valchar, RIG->WEB_FREQ);

		PORT->Timeout = 0;
	}
	else if (Msg[0] == 'M' && Msg[1] == 'D')
	{
		int Mode;
		
		if (PORT->PortType == FT2000)
		{
			Mode = Msg[3] - 48;
			if (Mode > 13) Mode = 13;
			SetWindowText(RIG->hMODE, FT2000Modes[Mode]);
			strcpy(RIG->WEB_MODE, FT2000Modes[Mode]);
			strcpy(RIG->ModeString, RIG->WEB_MODE);
		}
		else if (PORT->PortType == FT991A)
		{
			Mode = Msg[3] - 48;
			if (Mode > 16)
				Mode -= 7;
			
			if (Mode > 15) Mode = 13;
			SetWindowText(RIG->hMODE, FT991AModes[Mode]);
			strcpy(RIG->WEB_MODE, FT991AModes[Mode]);
			strcpy(RIG->ModeString, RIG->WEB_MODE);
		}
		else if (PORT->PortType == FTDX10)
		{
			Mode = Msg[3] - 48;
			if (Mode > 16)
				Mode -= 7;
			
			if (Mode > 15) Mode = 15;
			SetWindowText(RIG->hMODE, FTDX10Modes[Mode]);
			strcpy(RIG->WEB_MODE, FTDX10Modes[Mode]);
			strcpy(RIG->ModeString, RIG->WEB_MODE);
		}
		else if (PORT->PortType == FLEX)
		{
			Mode = atoi(&Msg[3]);
			if (Mode > 12) Mode = 12;
			SetWindowText(RIG->hMODE, FLEXModes[Mode]);
			strcpy(RIG->WEB_MODE, FLEXModes[Mode]);
			strcpy(RIG->ModeString, RIG->WEB_MODE);
		}
		else
		{
			Mode = Msg[2] - 48;
			if (Mode > 7) Mode = 7;
			SetWindowText(RIG->hMODE, KenwoodModes[Mode]);
			strcpy(RIG->WEB_MODE, KenwoodModes[Mode]);
			strcpy(RIG->ModeString, RIG->WEB_MODE);
		}
	}

	if (CmdLen < Length)
	{
		// Another Message in Buffer

		ptr++;
		Length -= (int)(ptr - Msg);

		if (Length <= 0)
			return;

		memmove(Msg, ptr, Length +1);

		goto Loop;
	}
}


VOID KenwoodPoll(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Kenwood

	if (RIG->ScanStopped == 0)
		if (RIG->ScanCounter)
			RIG->ScanCounter--;

	if (PORT->Timeout)
	{
		PORT->Timeout--;
		
		if (PORT->Timeout)			// Still waiting
			return;

		PORT->Retries--;

		if(PORT->Retries)
		{
			RigWriteCommBlock(PORT);	// Retransmit Block
			return;
		}

		SetWindowText(RIG->hFREQ, "------------------");
		SetWindowText(RIG->hMODE, "----------");
		strcpy(RIG->WEB_FREQ, "-----------");;
		strcpy(RIG->WEB_MODE, "------");

		RIG->RIGOK = FALSE;

		return;
	}

	// Send Data if avail, else send poll

	if (RIG->NumberofBands && RIG->RIGOK && (RIG->ScanStopped == 0))
	{
		if (RIG->ScanCounter <= 0)
		{
			//	Send Next Freq

			if (GetPermissionToChange(PORT, RIG))
			{
				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);
				PORT->TXLen = PORT->FreqPtr->Cmd1Len;

				_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

				RigWriteCommBlock(PORT);
				PORT->CmdSent = 1;
				PORT->Retries = 0;	
				PORT->Timeout = 0;
				PORT->AutoPoll = TRUE;

				// There isn't a response to a set command, so clear Scan Lock here
			
				ReleasePermission(RIG);			// Release Perrmission

			return;
			}
		}
	}
	
	if (RIG->RIGOK && RIG->BPQtoRADIO_Q)
	{
		struct MSGWITHOUTLEN * buffptr;
			
		buffptr = Q_REM(&RIG->BPQtoRADIO_Q);

		// Copy the ScanEntry struct from the Buffer to the PORT Scanentry

		memcpy(&PORT->ScanEntry, buffptr->Data, sizeof(struct ScanEntry));

		PORT->FreqPtr = &PORT->ScanEntry;		// Block we are currently sending.
		
		if (RIG->RIG_DEBUG)
			Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

		DoBandwidthandAntenna(RIG, &PORT->ScanEntry);

		_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

		memcpy(Poll, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);

		PORT->TXLen = PORT->FreqPtr->Cmd1Len;
		RigWriteCommBlock(PORT);
		PORT->CmdSent = Poll[4];
		PORT->Timeout = 0;
		RIG->PollCounter = 10;

		ReleaseBuffer(buffptr);
		PORT->AutoPoll = FALSE;
	
		return;
	}
		
	if (RIG->PollCounter)
	{
		RIG->PollCounter--;
		if (RIG->PollCounter > 1)
			return;
	}

	if (RIG->RIGOK && RIG->ScanStopped == 0 && RIG->NumberofBands &&
		RIG->ScanCounter && RIG->ScanCounter < 30)
		return;						// no point in reading freq if we are about to change it

	RIG->PollCounter = 10;			// Once Per Sec
		
	// Read Frequency 

	PORT->TXLen = RIG->PollLen;
	strcpy(Poll, RIG->Poll);
	
	RigWriteCommBlock(PORT);
	PORT->Retries = 1;
	PORT->Timeout = 10;
	PORT->CmdSent = 0;

	PORT->AutoPoll = TRUE;

	return;
}

VOID SDRRadioPoll(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	struct RIGINFO * RIG;
	int i;

	for (i=0; i< PORT->ConfiguredRigs; i++)
	{
		RIG = &PORT->Rigs[i];

		if (RIG->ScanStopped == 0)
			if (RIG->ScanCounter)
				RIG->ScanCounter--;
	}

	if (PORT->Timeout)
	{
		PORT->Timeout--;
		
		if (PORT->Timeout)			// Still waiting
			return;

		PORT->Retries--;

		if(PORT->Retries)
		{
			RigWriteCommBlock(PORT);	// Retransmit Block
			return;
		}

		SetWindowText(RIG->hFREQ, "------------------");
		SetWindowText(RIG->hMODE, "----------");
		strcpy(RIG->WEB_FREQ, "-----------");;
		strcpy(RIG->WEB_MODE, "------");

		RIG->RIGOK = FALSE;

		return;
	}

	// Send Data if avail, else send poll


	PORT->CurrentRig++;

	if (PORT->CurrentRig >= PORT->ConfiguredRigs)
		PORT->CurrentRig = 0;

	RIG = &PORT->Rigs[PORT->CurrentRig];


	if (RIG->NumberofBands && RIG->RIGOK && (RIG->ScanStopped == 0))
	{
		if (RIG->ScanCounter <= 0)
		{
			//	Send Next Freq

			if (GetPermissionToChange(PORT, RIG))
			{
				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);
				PORT->TXLen = PORT->FreqPtr->Cmd1Len;

				_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

				RigWriteCommBlock(PORT);
				PORT->CmdSent = 1;
				PORT->Retries = 0;	
				PORT->Timeout = 0;
				PORT->AutoPoll = TRUE;

				// There isn't a response to a set command, so clear Scan Lock here
			
				ReleasePermission(RIG);			// Release Perrmission

			return;
			}
		}
	}
	
	if (RIG->RIGOK && RIG->BPQtoRADIO_Q)
	{
		struct MSGWITHOUTLEN * buffptr;
			
		buffptr = Q_REM(&RIG->BPQtoRADIO_Q);

		// Copy the ScanEntry struct from the Buffer to the PORT Scanentry

		memcpy(&PORT->ScanEntry, buffptr->Data, sizeof(struct ScanEntry));

		PORT->FreqPtr = &PORT->ScanEntry;		// Block we are currently sending.
		
		if (RIG->RIG_DEBUG)
			Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

		DoBandwidthandAntenna(RIG, &PORT->ScanEntry);

		_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

		memcpy(Poll, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);

		PORT->TXLen = PORT->FreqPtr->Cmd1Len;
		RigWriteCommBlock(PORT);
		PORT->CmdSent = Poll[4];
		PORT->Timeout = 0;
		RIG->PollCounter = 10;

		ReleaseBuffer(buffptr);
		PORT->AutoPoll = FALSE;
	
		return;
	}
		
	if (RIG->PollCounter)
	{
		RIG->PollCounter--;
		if (RIG->PollCounter > 1)
			return;
	}

	if (RIG->RIGOK && RIG->ScanStopped == 0 && RIG->NumberofBands &&
		RIG->ScanCounter && RIG->ScanCounter < 30)
		return;						// no point in reading freq if we are about to change it

	// Need to make sure we don't poll multiple rigs on port at the same time

	if (RIG->RIGOK)
	{
		PORT->Retries = 2;
		RIG->PollCounter = 10 / PORT->ConfiguredRigs;			// Once Per Sec
	}
	else
	{
		PORT->Retries = 1;
		RIG->PollCounter = 100 / PORT->ConfiguredRigs;			// Slow Poll if down
	}

	RIG->PollCounter += PORT->CurrentRig * 3;

	// Read Frequency 

	PORT->TXLen = RIG->PollLen;
	strcpy(Poll, RIG->Poll);
	
	RigWriteCommBlock(PORT);
	PORT->Retries = 1;
	PORT->Timeout = 10;
	PORT->CmdSent = 0;

	PORT->AutoPoll = TRUE;

	return;
}

VOID DummyPoll(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];

	if (RIG->ScanStopped == 0)
		if (RIG->ScanCounter)
			RIG->ScanCounter--;
	
	if (RIG->NumberofBands && RIG->RIGOK && (RIG->ScanStopped == 0))
	{
		if (RIG->ScanCounter <= 0)
		{
			//	Send Next Freq

			if (GetPermissionToChange(PORT, RIG))
			{
				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

				_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);
				PORT->TXLen = PORT->FreqPtr->Cmd1Len;
/*
				RigWriteCommBlock(PORT);
				PORT->CmdSent = 1;
				PORT->Retries = 0;	
				PORT->Timeout = 0;
				PORT->AutoPoll = TRUE;
*/
				// There isn't a response to a set command, so clear Scan Lock here
			
				ReleasePermission(RIG);			// Release Perrmission

			return;
			}
		}
	}
	
	return;
}

VOID SwitchAntenna(struct RIGINFO * RIG, char Antenna)
{
	struct RIGPORTINFO * PORT;
	char Ant[3]="  ";

	if (RIG == NULL) return;

	PORT = RIG->PORT;

	Ant[1] = Antenna;

	SetWindowText(RIG->hPTT, Ant);

	switch (Antenna)
	{
	case '1':
		COMClearDTR(PORT->hDevice);
		COMClearRTS(PORT->hDevice);
		break;
	case '2':
		COMSetDTR(PORT->hDevice);
		COMClearRTS(PORT->hDevice);
		break;
	case '3':
		COMClearDTR(PORT->hDevice);
		COMSetRTS(PORT->hDevice);
		break;
	case '4':
		COMSetDTR(PORT->hDevice);
		COMSetRTS(PORT->hDevice);
		break;
	}	
}

BOOL DecodeModePtr(char * Param, double * Dwell, double * Freq, char * Mode,
				   char * PMinLevel, char * PMaxLevel, char * PacketMode,
				   char * RPacketMode, char * Split, char * Data, char * WinmorMode,
				   char * Antenna, BOOL * Supress, char * Filter, char * Appl,
				   char * MemoryBank, int * MemoryNumber, char * ARDOPMode, char * VARAMode, int * BandWidth, int * Power)
{
	char * Context;
	char * ptr;

	*Filter = '1';			// Defaults
	*PMinLevel = 1;
	*MemoryBank = 0;
	*MemoryNumber = 0;
	*Mode = 0;
	*ARDOPMode = 0;
	*VARAMode = 0;
	*Power = 0;

	
	ptr = strtok_s(Param, ",", &Context);

	if (ptr == NULL)
		return FALSE;

	// "New" format - Dwell, Freq, Params.
	
	//	Each param is a 2 char pair, separated by commas

	// An - Antenna
	// Pn - Pactor
	// Wn - Winmor
	// Pn - Packet
	// Fn - Filter
	// Sx - Split

	// 7.0770/LSB,F1,A3,WN,P1,R1 

	*Dwell = atof(ptr);
	
	ptr = strtok_s(NULL, ",", &Context);

	if (ptr == NULL)
		return FALSE;


	// May be a frequency or a Memory Bank/Channel 

	if (_memicmp(ptr, "Chan", 4) == 0)
	{
		if (strchr(ptr, '/'))		// Bank/Chan
		{
			memcpy(MemoryBank, &ptr[4], 1);
			*MemoryNumber = atoi(&ptr[6]);
		}
		else
			*MemoryNumber = atoi(&ptr[4]);	// Just Chan

		*Freq = 0.0;
	}
	else
		*Freq = atof(ptr);

	ptr = strtok_s(NULL, ",", &Context);

	if (ptr == NULL)
		if (*MemoryNumber)		// If channel, dont need mode
			return TRUE;

	if (ptr == NULL || strlen(ptr) >  8)
		return FALSE;		// Mode Missing

	// If channel, dont need mode

	if (*MemoryNumber == 0)
	{
		strcpy(Mode, ptr); 
		ptr = strtok_s(NULL, ",", &Context);
	}

	while (ptr)
	{
		if (isdigit(ptr[0]))
			*BandWidth = atoi(ptr);

		else if (memcmp(ptr, "APPL=", 5) == 0)
			strcpy(Appl, ptr + 5);

		else if (memcmp(ptr, "POWER=", 6) == 0)
			*Power = atoi(ptr + 6);

		else if (ptr[0] == 'A' && (ptr[1] == 'S' || ptr[1] == '0') && strlen(ptr) < 7)
			strcpy(ARDOPMode, "S");

		else if (ptr[0] == 'A' && strlen(ptr) > 2 && strlen(ptr) < 7)
			strcpy(ARDOPMode, &ptr[1]);

		else if (ptr[0] == 'A' && strlen(ptr) == 2)
			*Antenna = ptr[1];
		
		else if (ptr[0] == 'F')
			*Filter = ptr[1];

		else if (ptr[0] == 'R')
			*RPacketMode = ptr[1];
		
		else if (ptr[0] == 'H')
			*PacketMode = ptr[1];

		else if (ptr[0] == 'N')
			*PacketMode = ptr[1];

		else if (ptr[0] == 'P')
		{
			*PMinLevel = ptr[1];
			*PMaxLevel = ptr[strlen(ptr) - 1];
		}
		else if (ptr[0] == 'W')
		{
			*WinmorMode = ptr[1];
			if (*WinmorMode == '0')
				*WinmorMode = 'X';
			else if (*WinmorMode == '1')
				*WinmorMode = 'N';
			else if (*WinmorMode == '2')
				*WinmorMode = 'W';
		}

		else if (ptr[0] == 'V')
		{
			*VARAMode = ptr[1];
			// W N S T (skip) or 0 (also Skip)
			if (ptr[1] == '0')
				*VARAMode = 'S';
		}
		else if (ptr[0] == '+')
			*Split = '+';
		else if (ptr[0] == '-')
			*Split = '-';
		else if (ptr[0] == 'S')
			*Split = 'S';
		else if (ptr[0] == 'D')
			*Data = 1;
		else if (ptr[0] == 'X')
			*Supress = TRUE;

		ptr = strtok_s(NULL, ",", &Context);
	}
	return TRUE;
}

VOID AddNMEAChecksum(char * msg)
{
	UCHAR CRC = 0;

	msg++;					// Skip $

	while (*(msg) != '*')
	{
		CRC ^= *(msg++);
	}

	sprintf(++msg, "%02X\r\n", CRC);
}

void DecodeRemote(struct RIGPORTINFO * PORT, char * ptr)
{
	// Param is IPHOST:PORT for use with WINMORCONTROL
	
	struct sockaddr_in * destaddr = (SOCKADDR_IN * )&PORT->remoteDest;
	UCHAR param = 1;
	u_long ioparam = 1;

	char * port = strlop(ptr, ':');

	PORT->remoteSock = socket(AF_INET,SOCK_DGRAM,0);

	if (PORT->remoteSock == INVALID_SOCKET)
		return;

	setsockopt (PORT->remoteSock, SOL_SOCKET, SO_BROADCAST, &param, 1);

	if (port == NULL)
		return;

	ioctl (PORT->remoteSock, FIONBIO, &ioparam);

	destaddr->sin_family = AF_INET;
	destaddr->sin_addr.s_addr = inet_addr(ptr);
	destaddr->sin_port = htons(atoi(port));

	if (destaddr->sin_addr.s_addr == INADDR_NONE)
	{
		//	Resolve name to address

		struct hostent * HostEnt = gethostbyname(ptr);
		 
		if (!HostEnt)
			return;			// Resolve failed

		memcpy(&destaddr->sin_addr.s_addr,HostEnt->h_addr,4);
	}

	return;
}


char * CM108Device = NULL;

void DecodeCM108(int Port, char * ptr)
{
	// Called if Device Name or PTT = Param is CM108

#ifdef WIN32

	// Next Param is VID and PID - 0xd8c:0x8 or Full device name
	// On Windows device name is very long and difficult to find, so 
	//	easier to use VID/PID, but allow device in case more than one needed

	char * next;
	int32_t  VID = 0, PID = 0;
	char product[256];
	char sernum[256] = "NULL";

	struct hid_device_info *devs, *cur_dev;
	const char *path_to_open = NULL;
	hid_device *handle = NULL;

	if (strlen(ptr) > 16)
	{
		path_to_open = _strdup(ptr);

		handle = hid_open_path(path_to_open);
	
		if (handle)
		{
			hid_close(handle);
			CM108Device = _strdup(path_to_open);
		}
		else
		{
			char msg[128];
			sprintf(msg,"Port %d Unable to open CM108 device %s", Port, path_to_open);
			WritetoConsole(msg);
		}
	}

	
	
	else
	{
		VID = strtol(ptr, &next, 0);
		if (next)
			PID = strtol(++next, &next, 0);

		// Look for Device
	
		devs = hid_enumerate(0,0); // so we list devices(USHORT)VID, (USHORT)PID);
		cur_dev = devs;
		while (cur_dev)
		{
			wcstombs(product, cur_dev->product_string, 255);
			if (cur_dev->serial_number)
				wcstombs(sernum, cur_dev->serial_number, 255);

			if (product)
				Debugprintf("HID Device %s VID %X PID %X Ser %s %s", product, cur_dev->vendor_id, cur_dev->product_id, sernum, cur_dev->path);
			else
				Debugprintf("HID Device %s VID %X PID %X Ser %s %s", "Missing Product", cur_dev->vendor_id, cur_dev->product_id, sernum, cur_dev->path);
				
			if (cur_dev->vendor_id == VID && cur_dev->product_id == PID)
				path_to_open = cur_dev->path;

			cur_dev = cur_dev->next;
		}
	
		if (path_to_open)
		{
			handle = hid_open_path(path_to_open);
	
			if (handle)
			{
				hid_close(handle);
				CM108Device = _strdup(path_to_open);
			}
			else
			{
				char msg[128];
				sprintf(msg,"Port %d Unable to open CM108 device %x %x", Port, VID, PID);
				WritetoConsole(msg);
			}
		}
		hid_free_enumeration(devs);
	}
#else
		
	// Linux - Next Param HID Device, eg /dev/hidraw0

	CM108Device = _strdup(ptr);
#endif
}



// Called by Port Driver .dll to add/update rig info 

// RIGCONTROL COM60 19200 ICOM IC706 5e 4 14.103/U1w 14.112/u1 18.1/U1n 10.12/l1


struct RIGINFO * RigConfig(struct TNCINFO * TNC, char * buf, int Port)
{
	int i;
	char * ptr;
	char * COMPort = NULL;
	char * RigName;
	int RigAddr;
	struct RIGPORTINFO * PORT;
	struct RIGINFO * RIG;
	struct ScanEntry ** FreqPtr;
	char * CmdPtr;
	char * Context;
	struct TimeScan * SaveBand;
	char PTTRigName[] = "PTT";
	double ScanFreq;
	double Dwell;
	char MemoryBank;	// For Memory Scanning
	int MemoryNumber;
	BOOL RIG_DEBUG = FALSE;

	BOOL PTTControlsInputMUX = FALSE;
	BOOL DataPTT = FALSE;
	int DataPTTOffMode = 1;				// ACC
	int ICF8101Mode = 8;				// USB (as in upper sideband)

	char onString[256] = "";
	char offString[256] = "";
	int onLen = 0;
	int offLen = 0;

	CM108Device = NULL;
	Debugprintf("Processing RIG line %s", buf);

	// Starts RADIO Interlockgroup

	ptr = strtok_s(&buf[5], " \t\n\r", &Context);	// Skip Interlock
	if (ptr == NULL) return FALSE;

	ptr = strtok_s(NULL, " \t\n\r", &Context);

	if (ptr == NULL) return FALSE;

	if (_memicmp(ptr, "DEBUG", 5) == 0)
	{
		ptr = strtok_s(NULL, " \t\n\r", &Context);
		RIG_DEBUG = TRUE;
	}

	if (_memicmp(ptr, "AUTH", 4) == 0)
	{
		ptr = strtok_s(NULL, " \t\n\r", &Context);
		if (ptr == NULL) return FALSE;
		if (strlen(ptr) > 100) return FALSE;

		strcpy(AuthPassword, ptr);
		ptr = strtok_s(NULL, " \t\n\r", &Context);
	}

	if (ptr == NULL || ptr[0] == 0)
		return FALSE;

	if (_memicmp(ptr, "DUMMY", 5) == 0)
	{
		// Dummy to allow PTC application scanning

		PORT = PORTInfo[NumberofPorts++] = zalloc(sizeof(struct RIGPORTINFO));
		PORT->PortType = DUMMY;
		PORT->ConfiguredRigs = 1;
		RIG = &PORT->Rigs[0];
		RIG->RIGOK = TRUE;

		ptr = strtok_s(NULL, " \t\n\r", &Context);

		goto CheckScan;
	}

	if (_memicmp(ptr, "FLRIG", 5) == 0)
	{
		// Use FLRIG

		// Need parameter - Host:Port

		ptr = strtok_s(NULL, " \t\n\r", &Context);

		if (ptr == NULL || strlen(ptr) > 79) return FALSE;

		// Have a parameter to define port. Will decode it later

		PORT = PORTInfo[NumberofPorts++] = zalloc(sizeof(struct RIGPORTINFO));
		PORT->PortType = FLRIG;
		PORT->ConfiguredRigs = 1;
		RIG = &PORT->Rigs[0];
		RIG->RIGOK = TRUE;
		RIG->PORT = PORT;

		strcpy(PORT->IOBASE, ptr);
		strcpy(RIG->RigName, "FLRIG");

		// Decode host

		DecodeHAMLIBAddr(PORT, ptr);

		ptr = strtok_s(NULL, " \t\n\r", &Context);

		// look for other config statementes and scan params

		goto CheckOtherParams;
	}

	if (_memicmp(ptr, "HAMLIB", 5) == 0)
	{
		// Use rigctld

		// Need parameter - Host:Port

		ptr = strtok_s(NULL, " \t\n\r", &Context);

		if (ptr == NULL || strlen(ptr) > 79) return FALSE;

		// Have a parameter to define port. Will decode it later

		PORT = PORTInfo[NumberofPorts++] = zalloc(sizeof(struct RIGPORTINFO));
		PORT->PortType = HAMLIB;
		PORT->ConfiguredRigs = 1;
		RIG = &PORT->Rigs[0];
		RIG->RIGOK = TRUE;
		RIG->PORT = PORT;

		strcpy(PORT->IOBASE, ptr);
		strcpy(RIG->RigName, "HAMLIB");

		// Decode host

		DecodeHAMLIBAddr(PORT, ptr);

		ptr = strtok_s(NULL, " \t\n\r", &Context);

		// look for scan params

		goto CheckOtherParams;
	}

	if (_memicmp(ptr, "rtludp", 5) == 0)
	{
		// rtl_fm with udp freq control 

		// Need parameter - Host:Port

		ptr = strtok_s(NULL, " \t\n\r", &Context);

		if (ptr == NULL || strlen(ptr) > 79) return FALSE;

		// Have a parameter to define port. Will decode it later

		PORT = PORTInfo[NumberofPorts++] = zalloc(sizeof(struct RIGPORTINFO));
		PORT->PortType = RTLUDP;
		PORT->ConfiguredRigs = 1;
		RIG = &PORT->Rigs[0];
		RIG->RIGOK = TRUE;
		RIG->PORT = PORT;

		strcpy(PORT->IOBASE, ptr);
		strcpy(RIG->RigName, "RTLUDP");

		// Decode host

		DecodeHAMLIBAddr(PORT, ptr);

		ptr = strtok_s(NULL, " \t\n\r", &Context);

		// look for scan params

		goto CheckOtherParams;
	}

// ---- G7TAJ ----

	if (_memicmp(ptr, "sdrangel", 5) == 0)
	{
		// each instance (ip addr/port) of sdrangle can have one or more sampling devices (eg rltsdr) each with one ot
		// more channels (eg ssb demod, ssb mod). each set of sampling device = channel(s) is a device set.

		// We poll all devices/channels at once. we one PORT record plus a RIG record for each channel

		// Need parameters - Host:Port device channel. Device and Channel will default to zero

		int device = 0, channel = 0;
		char * Name;
		char * nptr1;
		char * nptr2;


		ptr = strtok_s(NULL, " \t\n\r", &Context);

		if (ptr == NULL || strlen(ptr) > 79) return FALSE;

		Name = strtok_s(NULL, " \t\n\r", &Context);
		nptr1 = strtok_s(NULL, " \t\n\r", &Context);
		nptr2 = strtok_s(NULL, " \t\n\r", &Context);

		if (nptr1 == 0 || nptr2 == 0 || Name == NULL || strlen(Name) > 9)
			return FALSE;

		device = atoi(nptr1);	
		channel = atoi(nptr2);

		// Have a parameter to define port. Will decode it later

		// See if already defined. PORT->IOBASE has Host:Port

		for (i = 0; i < NumberofPorts; i++)
		{
			PORT = PORTInfo[i];

			if (strcmp(PORT->IOBASE, ptr) == 0) 
				goto AngelRigFound;
		}

		// New Port

		PORT = PORTInfo[NumberofPorts++] = zalloc(sizeof(struct RIGPORTINFO));
		PORT->PortType = SDRANGEL;
		PORT->ConfiguredRigs = 0;
		strcpy(PORT->IOBASE, ptr);

		// Decode host
		
		DecodeHAMLIBAddr(PORT, ptr);


AngelRigFound:

		RIG = &PORT->Rigs[PORT->ConfiguredRigs++];
		RIG->RIGOK = TRUE;
		RIG->PORT = PORT;
		RIG->RigAddr = device;
		RIG->Channel = channel;

		strcpy(RIG->RigName, Name);

		ptr = strtok_s(NULL, " \t\n\r", &Context);

		// look for scan params

		goto CheckOtherParams;
	}
// ---- G7TAJ ----

	if ((_memicmp(ptr, "VCOM", 4) == 0) && TNC->Hardware == H_SCS)		// Using Radio Port on PTC
		COMPort = 0;
	else if (_memicmp(ptr, "PTCPORT", 7) == 0)
		COMPort = 0;
	else
		COMPort = ptr;

	// See if port is already defined. We may be adding another radio (ICOM or SDRRADIO only) or updating an existing one

	// Unless CM108 - they must be on separate Ports

	if (COMPort && _stricmp("CM108", COMPort) != 0)
	{
		for (i = 0; i < NumberofPorts; i++)
		{
			PORT = PORTInfo[i];

			if (COMPort)
				if (strcmp(PORT->IOBASE, COMPort) == 0)
					goto PortFound;

			if (COMPort == 0)
				if (PORT->IOBASE == COMPort)
					goto PortFound;
		}
	}

	// Allocate a new one

	PORT = PORTInfo[NumberofPorts++] = zalloc(sizeof(struct RIGPORTINFO));

	if (COMPort)
		strcpy(PORT->IOBASE, COMPort);

PortFound:

	ptr = strtok_s(NULL, " \t\n\r", &Context);

	if (ptr == NULL) return (FALSE);

	if (_stricmp(PORT->IOBASE, "RAWHID") == 0) // HID Addr instead of Speed
	{
		DecodeCM108(Port, ptr);
		if (CM108Device)	
			PORT->HIDDevice = CM108Device;
		else
			PORT->HIDDevice = _strdup ("MissingHID");

		CM108Device = 0;
	}

	if ( _stricmp(PORT->IOBASE, "CM108") == 0) // HID Addr instead of Speed
	{
		DecodeCM108(Port, ptr);
	}

	if (_stricmp(PORT->IOBASE, "REMOTE") == 0) // IP Addr/Port
		DecodeRemote(PORT, ptr);
	else	
		PORT->SPEED = atoi(ptr);

	ptr = strtok_s(NULL, " \t\n\r", &Context);

	if (ptr == NULL) return (FALSE);

	if (_memicmp(ptr, "PTTCOM", 6) == 0 || _memicmp(ptr, "PTT=", 4) == 0)
	{
		if (_stricmp(ptr, "PTT=CM108") == 0)
		{
			// PTT on CM108 GPIO

			ptr = strtok_s(NULL, " \t\n\r", &Context);
			if (ptr == NULL) return (FALSE);

			DecodeCM108(Port, ptr);
		}
		else
		{
			strcpy(PORT->PTTIOBASE, ptr);
		}
		ptr = strtok_s(NULL, " \t\n\r", &Context);
		if (ptr == NULL) return (FALSE);

	}

	//		if (strcmp(ptr, "ICOM") == 0 || strcmp(ptr, "YAESU") == 0 
	//			|| strcmp(ptr, "KENWOOD") == 0 || strcmp(ptr, "PTTONLY") == 0 || strcmp(ptr, "ANTENNA") == 0)

	// RADIO IC706 4E 5 14.103/U1 14.112/u1 18.1/U1 10.12/l1
	// Read RADIO Lines

	_strupr(ptr);


	if (strcmp(ptr, "ICOM") == 0)
		PORT->PortType = ICOM;
	else if (strcmp(ptr, "YAESU") == 0)
		PORT->PortType = YAESU;
	else if (strcmp(ptr, "KENWOOD") == 0)
		PORT->PortType = KENWOOD;
	else if (strcmp(ptr, "SDRRADIO") == 0)
		PORT->PortType = SDRRADIO;				// Varient of KENWOOD that supports multiple devices on one serial port
	else if (strcmp(ptr, "FLEX") == 0)
		PORT->PortType = FLEX;
	else if (strcmp(ptr, "NMEA") == 0)
		PORT->PortType = NMEA;
	else if (strcmp(ptr, "PTTONLY") == 0)
		PORT->PortType = PTT;
	else if (strcmp(ptr, "ANTENNA") == 0)
		PORT->PortType = ANT;
	else
		return FALSE;

	Debugprintf("Port type = %d", PORT->PortType);

	_strupr(Context);

	ptr = strtok_s(NULL, " \t\n\r", &Context);

	if (ptr && memcmp(ptr, "HAMLIB=", 7) == 0)
	{
		// HAMLIB Emulator - param is port to listen on

		if (PORT->PortType == PTT)
		{
			RIG = &PORT->Rigs[PORT->ConfiguredRigs++];
			strcpy(RIG->RigName, PTTRigName);

			RIG->HAMLIBPORT = atoi(&ptr[7]);
			ptr = strtok_s(NULL, " \t\n\r", &Context);

		}
	}

	if (ptr && strcmp(ptr, "PTTMUX") == 0)
	{
		if (PORT->PortType == PTT)
		{
			RIG = &PORT->Rigs[PORT->ConfiguredRigs++];
			strcpy(RIG->RigName, PTTRigName);
			goto domux;	// PTTONLY with PTTMUX
		}
	}


	if (ptr == NULL)
	{
		if (PORT->PortType == PTT)
			ptr = PTTRigName;
		else
			return FALSE;
	}

	if (strlen(ptr) > 9) return FALSE;

	RigName =  ptr;

	Debugprintf("Rigname = *%s*", RigName);

	// FT100 seems to be different to most other YAESU types

	if (strcmp(RigName, "FT100") == 0 && PORT->PortType == YAESU)
	{
		PORT->PortType = FT100;
	}

	// FT990 seems to be different to most other YAESU types

	if (strcmp(RigName, "FT990") == 0 && PORT->PortType == YAESU)
	{
		PORT->PortType = FT990;
	}

	// FT1000 seems to be different to most other YAESU types

	if (strstr(RigName, "FT1000") && PORT->PortType == YAESU)
	{
		PORT->PortType = FT1000;

		// Subtypes need different code. D and no suffix are same

		if (strstr(RigName, "FT1000MP"))
			PORT->YaesuVariant = FT1000MP;
		else
			PORT->YaesuVariant = FT1000D;
	}

	// FT2000 seems to be different to most other YAESU types

	if (strcmp(RigName, "FT2000") == 0 && PORT->PortType == YAESU)
	{
		PORT->PortType = FT2000;
	}

	// FTDX10 seems to be different to most other YAESU types

	if (strcmp(RigName, "FTDX10") == 0 && PORT->PortType == YAESU)
	{
		PORT->PortType = FTDX10;
	}

	// FT991A seems to be different to most other YAESU types

	if (strcmp(RigName, "FT991A") == 0 && PORT->PortType == YAESU)
	{
		PORT->PortType = FT991A;
	}


	// If ICOM or SDRRADIO, we may be adding a new Rig

	ptr = strtok_s(NULL, " \t\n\r", &Context);

	if (PORT->PortType == ICOM || PORT->PortType == NMEA || PORT->PortType == SDRRADIO)
	{
		if (ptr == NULL) return (FALSE);

		if (PORT->PortType == SDRRADIO)
			RigAddr = ptr[0];
		else
			sscanf(ptr, "%x", &RigAddr);

		// See if already defined

		for (i = 0; i < PORT->ConfiguredRigs; i++)
		{
			RIG = &PORT->Rigs[i];

			if (RIG->RigAddr == RigAddr)
				goto RigFound;
		}

		// Allocate a new one

		RIG = &PORT->Rigs[PORT->ConfiguredRigs++];
		RIG->RigAddr = RigAddr;

RigFound:

		ptr = strtok_s(NULL, " \t\n\r", &Context);
		//		if (ptr == NULL) return (FALSE);
	}
	else
	{
		// Only allows one RIG

		PORT->ConfiguredRigs = 1;
		RIG = &PORT->Rigs[0];
	}

	RIG->RIG_DEBUG = RIG_DEBUG;
	RIG->PORT = PORT;

	strcpy(RIG->RigName, RigName);

	RIG->TSMenu = 63;		// Default to TS590S

	// IC735 uses shorter freq message

	if (strcmp(RigName, "IC735") == 0 && PORT->PortType == ICOM)
		RIG->IC735 = TRUE;

	// IC-F8101 uses a different set of commands

	if (strstr(RigName, "F8101") && PORT->PortType == ICOM)
		RIG->ICF8101 = TRUE;

	if (PORT->PortType == KENWOOD)
	{
		RIG->TSMenu = 63;		// Default to TS590S

		if (strcmp(RigName, "TS590SG") == 0)
			RIG->TSMenu = 69;
	}

	if (PORT->PortType == FT991A)
		RIG->TSMenu = 72;			//Menu for Data/USB siwtching

domux:	

	RIG->CM108Device = CM108Device;

CheckOtherParams:

	while (ptr)
	{
		if (strcmp(ptr, "PTTMUX") == 0)
		{
			// Ports whose RTS/DTR will be converted to CAT commands (for IC7100/IC7200 etc)

			int PIndex = 0;

			ptr = strtok_s(NULL, " \t\n\r", &Context);

			while (memcmp(ptr, "COM", 3) == 0)
			{
				char * tncport = strlop(ptr, '/');

				strcpy(RIG->PTTCATPort[PIndex], &ptr[3]);

				if (tncport)
					RIG->PTTCATTNC[PIndex] = TNCInfo[atoi(tncport)];
				
				if (PIndex < 3)
					PIndex++;

				ptr = strtok_s(NULL, " \t\n\r", &Context);

				if (ptr == NULL)
					break;
			}
			if (ptr == NULL)
				break;
			else 
				continue;
		}
		else if (strcmp(ptr, "PTT_SETS_INPUT") == 0)
		{
			// Send Select Soundcard as mod source with PTT commands

			PTTControlsInputMUX = TRUE;

			// See if following param is an PTT Off Mode

			ptr = strtok_s(NULL, " \t\n\r", &Context);

			if (ptr == NULL)
				break;

			if (strcmp(ptr, "MIC") == 0)
				DataPTTOffMode = 0;
			else if (strcmp(ptr, "AUX") == 0)
				DataPTTOffMode = 1;
			else if (strcmp(ptr, "MICAUX") == 0)
				DataPTTOffMode = 2;
			else if (RIG->ICF8101 && strcmp(ptr, "LSB") == 0)
				ICF8101Mode = 0x7;
			else if (RIG->ICF8101 && strcmp(ptr, "USB") == 0)
				ICF8101Mode = 0x8;
			else if (RIG->ICF8101 && strcmp(ptr, "LSBD1") == 0)
				ICF8101Mode = 0x18;
			else if (RIG->ICF8101 && strcmp(ptr, "USBD1") == 0)
				ICF8101Mode = 0x19;
			else if (RIG->ICF8101 && strcmp(ptr, "LSBD2") == 0)
				ICF8101Mode = 0x20;
			else if (RIG->ICF8101 && strcmp(ptr, "USBD2") == 0)
				ICF8101Mode = 0x21;
			else if (RIG->ICF8101 && strcmp(ptr, "LSBD3") == 0)
				ICF8101Mode = 0x22;
			else if (RIG->ICF8101 && strcmp(ptr, "USBD3") == 0)
				ICF8101Mode = 0x23;
			else
				continue;

			ptr = strtok_s(NULL, " \t\n\r", &Context);

			continue;

		}
		else if (strcmp(ptr, "PTT_SETS_FREQ") == 0)
		{
			// Send Select Soundcard as mod source with PTT commands

			RIG->PTTSetsFreq = TRUE;
			ptr = strtok_s(NULL, " \t\n\r", &Context);

			continue;

		}

		else if (strcmp(ptr, "DATAPTT") == 0)
		{
			// Send Select Soundcard as mod source with PTT commands

			DataPTT = TRUE;
		}

		else if (memcmp(ptr, "PTTONHEX=", 9) == 0)
		{
			// Hex String to use for PTT on

			char * ptr1 = ptr;
			char * ptr2 = onString ;
			int i, j, len;

			ptr1 += 9;
			onLen = len = strlen(ptr1) / 2;

			if (len < 240)
			{
				while ((len--) > 0)
				{
					i = *(ptr1++);
					i -= '0';
					if (i > 9)
						i -= 7;

					j = i << 4;

					i = *(ptr1++);
					i -= '0';
					if (i > 9)
						i -= 7;

					*(ptr2++) = j | i;
				}
			}

			ptr = strtok_s(NULL, " \t\n\r", &Context);

			if (ptr == NULL)
				break;
		}

		else if (memcmp(ptr, "PTTOFFHEX=", 10) == 0)
		{
			// Hex String to use for PTT off

			char * ptr2 = offString ;
			int i, j, len;

			ptr += 10;
			offLen = len = strlen(ptr) / 2;

			if (len < 240)
			{
				while ((len--) > 0)
				{
					i = *(ptr++);
					i -= '0';
					if (i > 9)
						i -= 7;

					j = i << 4;

					i = *(ptr++);
					i -= '0';
					if (i > 9)
						i -= 7;

					*(ptr2++) = j | i;
				}
			}
			ptr = strtok_s(NULL, " \t\n\r", &Context);

			if (ptr == NULL)
				break;

		}

		else if (memcmp(ptr, "HAMLIB=", 7) == 0)
		{
			// HAMLIB Emulator - param is port to listen on

			RIG->HAMLIBPORT = atoi(&ptr[7]);
		}

		else if (memcmp(ptr, "TXOFFSET", 8) == 0)
		{
			RIG->txOffset =  strtoll(&ptr[9], NULL, 10);
		}

		else if (memcmp(ptr, "RXOFFSET", 8) == 0)
		{
			RIG->rxOffset =  strtoll(&ptr[9], NULL, 10);
		}

		else if (memcmp(ptr, "PTTOFFSET", 9) == 0)
		{
			RIG->pttOffset =  strtoll(&ptr[10], NULL, 10);
		}

		else if (memcmp(ptr, "RXERROR", 7) == 0)
		{
			RIG->rxError = atoi(&ptr[8]);
		}

		else if (memcmp(ptr, "TXERROR", 7) == 0)
		{
			RIG->txError = atoi(&ptr[8]);
		}

		else if (memcmp(ptr, "REPORTFREQS", 11) == 0)
		{
			RIG->reportFreqs = _strdup(&ptr[12]);
		}

		else if (memcmp(ptr, "DEFAULTFREQ", 11) == 0)
		{
			RIG->defaultFreq = atoi(&ptr[12]);
		}
		
		else if (atoi(ptr) || ptr[2] == ':')
			break;					// Not scan freq oe timeband, so see if another param

		ptr = strtok_s(NULL, " \t\n\r", &Context);
	}

	if (PORT->PortType == PTT || PORT->PortType == ANT)
		return RIG;

	// Set up PTT and Poll Strings

	if (PORT->PortType == ICOM)
	{
		char * Poll;
		Poll = &RIG->PTTOn[0];

		if (onLen && offLen)
		{
			memcpy(RIG->PTTOn, onString, onLen);
			RIG->PTTOnLen = onLen;
			memcpy(RIG->PTTOff, offString, offLen);
			RIG->PTTOffLen = offLen;
		}

		else if (RIG->ICF8101)
		{
			// Need to send ACC PTT command (1A 37 0002), not normal ICOM IC 00

			if (PTTControlsInputMUX)
			{
				*(Poll++) = 0xFE;
				*(Poll++) = 0xFE;
				*(Poll++) = RIG->RigAddr;
				*(Poll++) = 0xE0;
				*(Poll++) = 0x1a;
				*(Poll++) = 0x05;
				*(Poll++) = ICF8101Mode;
				*(Poll++) = 0x03;			// USB Data Mode Source
				*(Poll++) = 0x00;
				*(Poll++) = 0x01;			// Soundcard
				*(Poll++) = 0xFD;
			}
			*(Poll++) = 0xFE;
			*(Poll++) = 0xFE;
			*(Poll++) = RIG->RigAddr;
			*(Poll++) = 0xE0;
			*(Poll++) = 0x1A; 
			*(Poll++) = 0x37;		// Send/read the TX status
			*(Poll++) = 0x00;
			*(Poll++) = 0x02;		// ACC PTT
			*(Poll++) = 0xFD;

			RIG->PTTOnLen = (int)(Poll - &RIG->PTTOn[0]);

			Poll = &RIG->PTTOff[0];

			*(Poll++) = 0xFE;
			*(Poll++) = 0xFE;
			*(Poll++) = RIG->RigAddr;
			*(Poll++) = 0xE0;
			*(Poll++) = 0x1A; 
			*(Poll++) = 0x37;		// Send/read the TX status
			*(Poll++) = 0x00;
			*(Poll++) = 0x00;		// RX
			*(Poll++) = 0xFD;

			if (PTTControlsInputMUX)
			{
				*(Poll++) = 0xFE;
				*(Poll++) = 0xFE;
				*(Poll++) = RIG->RigAddr;
				*(Poll++) = 0xE0;
				*(Poll++) = 0x1a;

				*(Poll++) = 0x05;
				*(Poll++) = ICF8101Mode;
				*(Poll++) = 0x03;			// USB Data Mode Source
				*(Poll++) = 0x00;
				*(Poll++) = 0x02;			// ACC
				*(Poll++) = 0xFD;
			}
			RIG->PTTOffLen = (int)(Poll - &RIG->PTTOff[0]);
		}
		else
		{
			if (PTTControlsInputMUX)
			{
				*(Poll++) = 0xFE;
				*(Poll++) = 0xFE;
				*(Poll++) = RIG->RigAddr;
				*(Poll++) = 0xE0;
				*(Poll++) = 0x1a;

				if (strcmp(RIG->RigName, "IC7100") == 0)
				{
					*(Poll++) = 0x05;
					*(Poll++) = 0x00;
					*(Poll++) = 0x91;			// Data Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7200") == 0)
				{
					*(Poll++) = 0x03;
					*(Poll++) = 0x24;			// Data Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7300") == 0)
				{
					*(Poll++) = 0x05;
					*(Poll++) = 0x00;
					*(Poll++) = 0x67;			// Data Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7600") == 0)
				{
					*(Poll++) = 0x05;
					*(Poll++) = 0x00;
					*(Poll++) = 0x31;			// Data1 Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7610") == 0)
				{
					*(Poll++) = 0x05;
					*(Poll++) = 0x00;
					*(Poll++) = 0x92;			// Data1 Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7410") == 0)
				{
					*(Poll++) = 0x03;
					*(Poll++) = 0x39;			// Data Mode Source
				}

				*(Poll++) = 0x03;			// USB Soundcard
				*(Poll++) = 0xFD;
			}

			*(Poll++) = 0xFE;
			*(Poll++) = 0xFE;
			*(Poll++) = RIG->RigAddr;
			*(Poll++) = 0xE0;
			*(Poll++) = 0x1C;		// RIG STATE
			*(Poll++) = 0x00;		// PTT
			*(Poll++) = 1;			// ON
			*(Poll++) = 0xFD;

			RIG->PTTOnLen = (int)(Poll - &RIG->PTTOn[0]);

			Poll = &RIG->PTTOff[0];

			*(Poll++) = 0xFE;
			*(Poll++) = 0xFE;
			*(Poll++) = RIG->RigAddr;
			*(Poll++) = 0xE0;
			*(Poll++) = 0x1C;		// RIG STATE
			*(Poll++) = 0x00;		// PTT
			*(Poll++) = 0;			// OFF
			*(Poll++) = 0xFD;

			if (PTTControlsInputMUX)
			{
				*(Poll++) = 0xFE;
				*(Poll++) = 0xFE;
				*(Poll++) = RIG->RigAddr;
				*(Poll++) = 0xE0;
				*(Poll++) = 0x1a;

				if (strcmp(RIG->RigName, "IC7100") == 0)
				{
					*(Poll++) = 0x05;
					*(Poll++) = 0x00;
					*(Poll++) = 0x91;			// Data Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7200") == 0)
				{
					*(Poll++) = 0x03;
					*(Poll++) = 0x24;			// Data Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7300") == 0)
				{
					*(Poll++) = 0x05;
					*(Poll++) = 0x00;
					*(Poll++) = 0x67;			// Data Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7410") == 0)
				{
					*(Poll++) = 0x03;
					*(Poll++) = 0x39;			// Data Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7600") == 0)
				{
					*(Poll++) = 0x05;
					*(Poll++) = 0x00;
					*(Poll++) = 0x31;			// Data1 Mode Source
				}
				else if (strcmp(RIG->RigName, "IC7610") == 0)
				{
					*(Poll++) = 0x05;
					*(Poll++) = 0x00;
					*(Poll++) = 0x92;			// Data1 Mode Source
				}

				*(Poll++) = DataPTTOffMode;
				*(Poll++) = 0xFD;
			}
			RIG->PTTOffLen = (int)(Poll - &RIG->PTTOff[0]);
		}
	}
	else if	(PORT->PortType == KENWOOD)
	{	
		RIG->PollLen = 6;
		strcpy(RIG->Poll, "FA;MD;");

		if (PTTControlsInputMUX)
		{
			sprintf(RIG->PTTOn, "EX%03d00001;TX1;", RIG->TSMenu); // Select USB before PTT
			sprintf(RIG->PTTOff, "RX;EX%03d00000;", RIG->TSMenu); // Select ACC after dropping PTT
		}
		else
		{
			strcpy(RIG->PTTOff, "RX;");

			if (DataPTT)
				strcpy(RIG->PTTOn, "TX1;");
			else
				strcpy(RIG->PTTOn, "TX;");
		}

		RIG->PTTOnLen = (int)strlen(RIG->PTTOn);
		RIG->PTTOffLen = (int)strlen(RIG->PTTOff);

	}
	else if	(PORT->PortType == SDRRADIO)
	{	
		RIG->PollLen = sprintf(RIG->Poll, "F%c;MD;", RIG->RigAddr);

/*		if (PTTControlsInputMUX)
		{
			sprintf(RIG->PTTOn, "EX%03d00001;TX1;", RIG->TSMenu); // Select USB before PTT
			sprintf(RIG->PTTOff, "RX;EX%03d00000;", RIG->TSMenu); // Select ACC after dropping PTT
		}
		else
		{
			strcpy(RIG->PTTOff, "RX;");

			if (DataPTT)
				strcpy(RIG->PTTOn, "TX1;");
			else
				strcpy(RIG->PTTOn, "TX;");
		}
*/
		RIG->PTTOnLen = (int)strlen(RIG->PTTOn);
		RIG->PTTOffLen = (int)strlen(RIG->PTTOff);

	}	else if	(PORT->PortType == FLEX)
	{	
		RIG->PollLen = 10;
		strcpy(RIG->Poll, "ZZFA;ZZMD;");

		strcpy(RIG->PTTOn, "ZZTX1;");
		RIG->PTTOnLen = 6;
		strcpy(RIG->PTTOff, "ZZTX0;");
		RIG->PTTOffLen = 6;
	}
	else if	(PORT->PortType == FT2000)
	{	
		RIG->PollLen = 6;
		strcpy(RIG->Poll, "FA;MD;");

		strcpy(RIG->PTTOn, "TX1;");
		RIG->PTTOnLen = 4;
		strcpy(RIG->PTTOff, "TX0;");
		RIG->PTTOffLen = 4;
	}
	else if	(PORT->PortType == FT991A || PORT->PortType == FTDX10)
	{	
		RIG->PollLen = 7;
		strcpy(RIG->Poll, "FA;MD0;");

		if (PTTControlsInputMUX)
		{
			RIG->PTTOnLen = sprintf(RIG->PTTOn, "EX0721;TX1;");    // Select USB before PTT
			RIG->PTTOffLen = sprintf(RIG->PTTOff, "TX0;EX0720;");  // Select DATA after dropping PTT
		}
		else
		{
			strcpy(RIG->PTTOn, "TX1;");
			RIG->PTTOnLen = 4;
			strcpy(RIG->PTTOff, "TX0;");
			RIG->PTTOffLen = 4;
		}
	}
	else if	(PORT->PortType == NMEA)
	{	
		int Len;

		i = sprintf(RIG->Poll, "$PICOA,90,%02x,RXF*xx\r\n", RIG->RigAddr);
		AddNMEAChecksum(RIG->Poll);
		Len = i;
		i = sprintf(RIG->Poll + Len, "$PICOA,90,%02x,MODE*xx\r\n", RIG->RigAddr);
		AddNMEAChecksum(RIG->Poll + Len);
		RIG->PollLen = Len + i;

		i = sprintf(RIG->PTTOn, "$PICOA,90,%02x,TRX,TX*xx\r\n", RIG->RigAddr);
		AddNMEAChecksum(RIG->PTTOn);
		RIG->PTTOnLen = i;

		i = sprintf(RIG->PTTOff, "$PICOA,90,%02x,TRX,RX*xx\r\n", RIG->RigAddr);
		AddNMEAChecksum(RIG->PTTOff);
		RIG->PTTOffLen = i;
	}

	if (ptr == NULL) return RIG;			// No Scanning, just Interactive control

	if (strchr(ptr, ',') == 0 && strchr(ptr, ':') == 0) // Old Format
	{
		ScanFreq = atof(ptr);

#pragma warning(push)
#pragma warning(disable : 4244)

		RIG->ScanFreq = ScanFreq * 10;

#pragma warning(push)

		ptr = strtok_s(NULL, " \t\n\r", &Context);
	}

	// Frequency List

CheckScan:

	if (ptr)
		if (ptr[0] == ';' || ptr[0] == '#')
			ptr = NULL;

	if (ptr != NULL)
	{
		// Create Default Timeband

		struct TimeScan * Band;
		
		RIG->TimeBands = zalloc(sizeof(void *));

		Band = AllocateTimeRec(RIG);
		SaveBand = Band;

		Band->Start = 0;
		Band->End = 84540;	//23:59
		FreqPtr = Band->Scanlist = RIG->FreqPtr = malloc(1000);
		memset(FreqPtr, 0, 1000);
	}

	while(ptr)
	{
		int ModeNo;
		BOOL Supress;
		double Freq = 0.0;
		int FreqInt = 0;
		char FreqString[80]="";
		char * Modeptr = NULL;
		char Split, Data, PacketMode, RPacketMode, PMinLevel, PMaxLevel, Filter;
		char Mode[10] = "";
		char WinmorMode, Antenna;
		char ARDOPMode[6] = "";
		char VARAMode[6] = "";
		char Appl[13];
		char * ApplCall;
		int BandWidth;
		int Power;

		if (ptr[0] == ';' || ptr[0] == '#')
			break;

		Filter = PMinLevel = PMaxLevel = PacketMode = RPacketMode = Split =
			Data = WinmorMode = Antenna = ModeNo = Supress = 
			MemoryBank = MemoryNumber = BandWidth = 0;

		Appl[0] = 0;
		ARDOPMode[0] = 0;
		VARAMode[0] = 0;
		Dwell = 0.0;

		while (ptr && strchr(ptr, ':'))
		{
			// New TimeBand

			struct TimeScan * Band;

			Band = AllocateTimeRec(RIG);

			*FreqPtr = (struct ScanEntry *)0;		// Terminate Last Band

			Band->Start = (atoi(ptr) * 3600) + (atoi(&ptr[3]) * 60);
			Band->End = 84540;	//23:59
			SaveBand->End = Band->Start - 60;

			SaveBand = Band;

			FreqPtr = Band->Scanlist = RIG->FreqPtr = malloc(1000);
			memset(FreqPtr, 0, 1000);

			ptr = strtok_s(NULL, " \t\n\r", &Context);										
		}

		if (ptr == 0)
			break;

		if (strchr(ptr, ','))			// New Format
		{
			DecodeModePtr(ptr, &Dwell, &Freq, Mode, &PMinLevel, &PMaxLevel, &PacketMode,
				&RPacketMode, &Split, &Data, &WinmorMode, &Antenna, &Supress, &Filter, &Appl[0],
				&MemoryBank, &MemoryNumber, ARDOPMode, VARAMode, &BandWidth, &Power);
		}
		else
		{
			Modeptr = strchr(ptr, '/');

			if (Modeptr)
				*Modeptr++ = 0;

			Freq = atof(ptr);

			if (Modeptr)
			{
				// Mode can include 1/2/3 for Icom Filers. W/N for Winmor/Pactor Bandwidth, and +/-/S for Repeater Shift (S = Simplex) 
				// First is always Mode
				// First char is Mode (USB, LSB etc)

				Mode[0] = Modeptr[0];
				Filter = Modeptr[1];

				if (strchr(&Modeptr[1], '+'))
					Split = '+';
				else if (strchr(&Modeptr[1], '-'))
					Split = '-';
				else if (strchr(&Modeptr[1], 'S'))
					Split = 'S';
				else if (strchr(&Modeptr[1], 'D'))
					Data = 1;

				if (strchr(&Modeptr[1], 'W'))
				{
					WinmorMode = 'W';
					PMaxLevel = '3';
					PMinLevel = '1';
				}
				else if (strchr(&Modeptr[1], 'N'))
				{
					WinmorMode = 'N';
					PMaxLevel = '2';
					PMinLevel = '1';
				}

				if (strchr(&Modeptr[1], 'R'))		// Robust Packet
					RPacketMode = '2';				// R600
				else if (strchr(&Modeptr[1], 'H'))	// HF Packet on Tracker
					PacketMode = '1';				// 300

				if (strchr(&Modeptr[1], 'X'))		// Dont Report to WL2K
					Supress = 1;

				if (strstr(&Modeptr[1], "A1"))
					Antenna = '1';
				else if (strstr(&Modeptr[1], "A2"))
					Antenna = '2';
				else if (strstr(&Modeptr[1], "A3"))
					Antenna = '3';
				else if (strstr(&Modeptr[1], "A4"))
					Antenna = '4';
				else if (strstr(&Modeptr[1], "A5"))
					Antenna = '5';
				else if (strstr(&Modeptr[1], "A6"))
					Antenna = '6';
			}
		}

		switch(PORT->PortType)
		{
		case ICOM:						

			for (ModeNo = 0; ModeNo < 24; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (Modes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(Modes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;

		case YAESU:						

			for (ModeNo = 0; ModeNo < 16; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (YaesuModes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(YaesuModes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;

		case KENWOOD:

			for (ModeNo = 0; ModeNo < 8; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (KenwoodModes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(KenwoodModes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;

		case FLEX:

			for (ModeNo = 0; ModeNo < 12; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (FLEXModes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(FLEXModes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;

		case FT2000:

			if (Modeptr)
			{
				if (strstr(Modeptr, "PL"))
				{
					ModeNo = 8;
					break;
				}
				if (strstr(Modeptr, "PU"))
				{
					ModeNo = 12;
					break;
				}
			}
			for (ModeNo = 0; ModeNo < 14; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (FT2000Modes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(FT2000Modes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;
			
		case FT991A:

/*			if (Modeptr)
			{
				if (strstr(Modeptr, "PL"))
				{
					ModeNo = 8;
					break;
				}
				if (strstr(Modeptr, "PU"))
				{
					ModeNo = 12;
					break;
				}
			}
*/	
			for (ModeNo = 0; ModeNo < 15; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (FT991AModes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(FT991AModes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;

		case FTDX10:

			for (ModeNo = 0; ModeNo < 16; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (FTDX10Modes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(FTDX10Modes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;



		case FT100:						

			for (ModeNo = 0; ModeNo < 8; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (FT100Modes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(FT100Modes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;

		case FT990:	

			for (ModeNo = 0; ModeNo < 12; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (FT990Modes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(FT990Modes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;

		case FT1000:						

			for (ModeNo = 0; ModeNo < 12; ModeNo++)
			{
				if (strlen(Mode) == 1)
				{
					if (FT1000Modes[ModeNo][0] == Mode[0])
						break;
				}
				else
				{
					if (_stricmp(FT1000Modes[ModeNo], Mode) == 0)
						break;
				}
			}
			break;
		}

		Freq = Freq * 1000000.0;

		sprintf(FreqString, "%09.0f", Freq);

		FreqInt = Freq;

		FreqPtr[0] = malloc(sizeof(struct ScanEntry));
		memset(FreqPtr[0], 0, sizeof(struct ScanEntry));

#pragma warning(push)
#pragma warning(disable : 4244)

		if (Dwell == 0.0)
			FreqPtr[0]->Dwell = ScanFreq * 10;
		else
			FreqPtr[0]->Dwell = Dwell * 10;

#pragma warning(pop) 

		FreqPtr[0]->Freq = Freq;
		FreqPtr[0]->Bandwidth = WinmorMode;
		FreqPtr[0]->RPacketMode = RPacketMode;
		FreqPtr[0]->HFPacketMode = PacketMode;
		FreqPtr[0]->PMaxLevel = PMaxLevel;
		FreqPtr[0]->PMinLevel = PMinLevel;
		FreqPtr[0]->Antenna = Antenna;
		strcpy(FreqPtr[0]->ARDOPMode, ARDOPMode);
		FreqPtr[0]->VARAMode = VARAMode[0];

		strcpy(FreqPtr[0]->APPL, Appl);

		ApplCall = GetApplCallFromName(Appl);

		if (strcmp(Appl, "NODE") == 0)
		{
			memcpy(FreqPtr[0]->APPLCALL, TNC->NodeCall, 9);
			strlop(FreqPtr[0]->APPLCALL, ' ');
		}
		else
		{
			if (ApplCall && ApplCall[0] > 32)
			{
				memcpy(FreqPtr[0]->APPLCALL, ApplCall, 9);
				strlop(FreqPtr[0]->APPLCALL, ' ');
			}
		}

		CmdPtr = FreqPtr[0]->Cmd1 = malloc(100);

		if (PORT->PortType == ICOM)
		{
			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = 0xFE;
			*(CmdPtr++) = RIG->RigAddr;
			*(CmdPtr++) = 0xE0;

			if (RIG->ICF8101)
			{
				// Set Freq is 1A 35 and set Mode 1A 36


				*(CmdPtr++) = 0x1A;
				*(CmdPtr++) = 0x35;		// Set frequency command

				// Need to convert two chars to bcd digit

				*(CmdPtr++) = (FreqString[8] - 48) | ((FreqString[7] - 48) << 4);
				*(CmdPtr++) = (FreqString[6] - 48) | ((FreqString[5] - 48) << 4);
				*(CmdPtr++) = (FreqString[4] - 48) | ((FreqString[3] - 48) << 4);
				*(CmdPtr++) = (FreqString[2] - 48) | ((FreqString[1] - 48) << 4);
				*(CmdPtr++) = (FreqString[0] - 48);
				*(CmdPtr++) = 0xFD;
				FreqPtr[0]->Cmd1Len = 12;

				CmdPtr = FreqPtr[0]->Cmd2 = malloc(10);
				FreqPtr[0]->Cmd2Len = 9;		

				*(CmdPtr++) = 0xFE;
				*(CmdPtr++) = 0xFE;
				*(CmdPtr++) = RIG->RigAddr;
				*(CmdPtr++) = 0xE0;
				*(CmdPtr++) = 0x1A;
				*(CmdPtr++) = 0x36;		// Set mode command
				*(CmdPtr++) = 0;

				if (ModeNo > 19)
					*(CmdPtr++) = ModeNo + 12;
				else if (ModeNo > 9)
					*(CmdPtr++) = ModeNo + 6;
				else
					*(CmdPtr++) = ModeNo;

				*(CmdPtr++) = 0xFD;
			}
			else
			{
				if (MemoryNumber)
				{
					// Set Memory Channel instead of Freq, Mode, etc

					char ChanString[5];

					// Send Set Memory, then Channel

					*(CmdPtr++) = 0x08;
					*(CmdPtr++) = 0xFD;

					*(CmdPtr++) = 0xFE;
					*(CmdPtr++) = 0xFE;
					*(CmdPtr++) = RIG->RigAddr;
					*(CmdPtr++) = 0xE0;

					sprintf(ChanString, "%04d", MemoryNumber); 

					*(CmdPtr++) = 0x08;
					*(CmdPtr++) = (ChanString[1] - 48) | ((ChanString[0] - 48) << 4);
					*(CmdPtr++) = (ChanString[3] - 48) | ((ChanString[2] - 48) << 4);
					*(CmdPtr++) = 0xFD;

					FreqPtr[0]->Cmd1Len = 14;

					if (MemoryBank)
					{						
						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = RIG->RigAddr;
						*(CmdPtr++) = 0xE0;
						*(CmdPtr++) = 0x08;
						*(CmdPtr++) = 0xA0;
						*(CmdPtr++) = MemoryBank - 0x40;
						*(CmdPtr++) = 0xFD;

						FreqPtr[0]->Cmd1Len += 8;
					}
				}	
				else
				{
					*(CmdPtr++) = 0x5;		// Set frequency command

					// Need to convert two chars to bcd digit

					*(CmdPtr++) = (FreqString[8] - 48) | ((FreqString[7] - 48) << 4);
					*(CmdPtr++) = (FreqString[6] - 48) | ((FreqString[5] - 48) << 4);
					*(CmdPtr++) = (FreqString[4] - 48) | ((FreqString[3] - 48) << 4);
					*(CmdPtr++) = (FreqString[2] - 48) | ((FreqString[1] - 48) << 4);
					if (RIG->IC735)
					{
						*(CmdPtr++) = 0xFD;
						FreqPtr[0]->Cmd1Len = 10;
					}
					else
					{
						*(CmdPtr++) = (FreqString[0] - 48);
						*(CmdPtr++) = 0xFD;
						FreqPtr[0]->Cmd1Len = 11;
					}

					// Send Set VFO in case last chan was memory

					//				*(CmdPtr++) = 0xFE;
					//				*(CmdPtr++) = 0xFE;
					//				*(CmdPtr++) = RIG->RigAddr;
					//				*(CmdPtr++) = 0xE0;

					//				*(CmdPtr++) = 0x07;
					//				*(CmdPtr++) = 0xFD;

					//				FreqPtr[0]->Cmd1Len = 17;

					if (Filter)
					{						
						CmdPtr = FreqPtr[0]->Cmd2 = malloc(10);
						FreqPtr[0]->Cmd2Len = 8;		
						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = RIG->RigAddr;
						*(CmdPtr++) = 0xE0;
						*(CmdPtr++) = 0x6;		// Set Mode
						*(CmdPtr++) = ModeNo;
						*(CmdPtr++) = Filter - '0'; //Filter
						*(CmdPtr++) = 0xFD;

						if (Split)
						{
							CmdPtr = FreqPtr[0]->Cmd3 = malloc(10);
							FreqPtr[0]->Cmd3Len = 7;
							*(CmdPtr++) = 0xFE;
							*(CmdPtr++) = 0xFE;
							*(CmdPtr++) = RIG->RigAddr;
							*(CmdPtr++) = 0xE0;
							*(CmdPtr++) = 0xF;		// Set Mode
							if (Split == 'S')
								*(CmdPtr++) = 0x10;
							else
								if (Split == '+')
									*(CmdPtr++) = 0x12;
								else
									if (Split == '-')
										*(CmdPtr++) = 0x11;

							*(CmdPtr++) = 0xFD;
						}
						else
						{
							if (Data)
							{
								CmdPtr = FreqPtr[0]->Cmd3 = malloc(10);

								*(CmdPtr++) = 0xFE;
								*(CmdPtr++) = 0xFE;
								*(CmdPtr++) = RIG->RigAddr;
								*(CmdPtr++) = 0xE0;
								*(CmdPtr++) = 0x1a;	


								if ((strcmp(RIG->RigName, "IC7100") == 0) ||
									(strcmp(RIG->RigName, "IC7410") == 0) ||
									(strcmp(RIG->RigName, "IC7600") == 0) ||
									(strcmp(RIG->RigName, "IC7610") == 0) ||
									(strcmp(RIG->RigName, "IC7300") == 0))
								{
									FreqPtr[0]->Cmd3Len = 9;
									*(CmdPtr++) = 0x6;		// Send/read DATA mode with filter set
									*(CmdPtr++) = 0x1;		// Data On
									*(CmdPtr++) = Filter - '0'; //Filter
								}
								else if (strcmp(RIG->RigName, "IC7200") == 0)
								{
									FreqPtr[0]->Cmd3Len = 9;
									*(CmdPtr++) = 0x4;		// Send/read DATA mode with filter set
									*(CmdPtr++) = 0x1;		// Data On
									*(CmdPtr++) = Filter - '0'; //Filter
								}
								else
								{
									FreqPtr[0]->Cmd3Len = 8;
									*(CmdPtr++) = 0x6;		// Set Data
									*(CmdPtr++) = 0x1;		//On		
								}

								*(CmdPtr++) = 0xFD;
							}
						}
					}

					if (Antenna == '5' || Antenna == '6')
					{
						// Antenna select for 746 and maybe others

						// Could be going in cmd2 3 or 4

						if (FreqPtr[0]->Cmd2 == NULL)
						{
							CmdPtr = FreqPtr[0]->Cmd2 = malloc(10);
							FreqPtr[0]->Cmd2Len = 7;
						}
						else if (FreqPtr[0]->Cmd3 == NULL)
						{
							CmdPtr = FreqPtr[0]->Cmd3 = malloc(10);
							FreqPtr[0]->Cmd3Len = 7;
						}
						else 
						{
							CmdPtr = FreqPtr[0]->Cmd4 = malloc(10);
							FreqPtr[0]->Cmd4Len = 7;
						}

						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = 0xFE;
						*(CmdPtr++) = RIG->RigAddr;
						*(CmdPtr++) = 0xE0;
						*(CmdPtr++) = 0x12;		// Set Antenna
						*(CmdPtr++) = Antenna - '5';	// 0 for A5 1 for A6
						*(CmdPtr++) = 0xFD;
					}
				}
			}
		}
		else if	(PORT->PortType == YAESU)
		{	
			//Send Mode first - changing mode can change freq

			*(CmdPtr++) = ModeNo;
			*(CmdPtr++) = 0;
			*(CmdPtr++) = 0;
			*(CmdPtr++) = 0;
			*(CmdPtr++) = 7;

			*(CmdPtr++) = (FreqString[1] - 48) | ((FreqString[0] - 48) << 4);
			*(CmdPtr++) = (FreqString[3] - 48) | ((FreqString[2] - 48) << 4);
			*(CmdPtr++) = (FreqString[5] - 48) | ((FreqString[4] - 48) << 4);
			*(CmdPtr++) = (FreqString[7] - 48) | ((FreqString[6] - 48) << 4);
			*(CmdPtr++) = 1;

			// FT847 Needs a Poll Here. Set up anyway, but only send if 847

			*(CmdPtr++) = 0;
			*(CmdPtr++) = 0;
			*(CmdPtr++) = 0;
			*(CmdPtr++) = 0;
			*(CmdPtr++) = 3;


		}
		else if	(PORT->PortType == KENWOOD)
		{	
			if (Power == 0)
			{
				if (Antenna == '5' || Antenna == '6')
					FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "FA00%s;MD%d;AN%c;FA;MD;", FreqString, ModeNo, Antenna - 4);
				else
					FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "FA00%s;MD%d;FA;MD;", FreqString, ModeNo);
			}
			else
			{
				if (Antenna == '5' || Antenna == '6')
					FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "FA00%s;MD%d;AN%c;PC%03d;FA;MD;PC;", FreqString, ModeNo, Antenna - 4, Power);
				else
					FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "FA00%s;MD%d;PC%03d;FA;MD;PC;", FreqString, ModeNo, Power);
			}
		}
		else if	(PORT->PortType == FLEX)
		{	
			FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "ZZFA00%s;ZZMD%02d;ZZFA;ZZMD;", FreqString, ModeNo);
		}
		else if	(PORT->PortType == FT2000)
		{	
			FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "FA%s;MD0%X;FA;MD;", &FreqString[1], ModeNo);
		}
		else if	(PORT->PortType == FT991A || PORT->PortType == FTDX10)
		{	
			FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "FA%s;MD0%X;FA;MD0;", &FreqString[0], ModeNo);
		}
		else if	(PORT->PortType == FT100 || PORT->PortType == FT990
			|| PORT->PortType == FT1000)
		{
			// Allow Mode = "LEAVE" to suppress mode change

			//Send Mode first - changing mode can change freq

			if (strcmp(Mode, "LEAVE") == 0)
			{
				// we can't easily change the string length,
				// so just set freq twice

				*(CmdPtr++) = (FreqString[7] - 48) | ((FreqString[6] - 48) << 4);
				*(CmdPtr++) = (FreqString[5] - 48) | ((FreqString[4] - 48) << 4);
				*(CmdPtr++) = (FreqString[3] - 48) | ((FreqString[2] - 48) << 4);
				*(CmdPtr++) = (FreqString[1] - 48) | ((FreqString[0] - 48) << 4);
				*(CmdPtr++) = 10;
			}
			else
			{
				*(CmdPtr++) = 0;
				*(CmdPtr++) = 0;
				*(CmdPtr++) = 0;
				*(CmdPtr++) = ModeNo;
				*(CmdPtr++) = 12;
			}

			*(CmdPtr++) = (FreqString[7] - 48) | ((FreqString[6] - 48) << 4);
			*(CmdPtr++) = (FreqString[5] - 48) | ((FreqString[4] - 48) << 4);
			*(CmdPtr++) = (FreqString[3] - 48) | ((FreqString[2] - 48) << 4);
			*(CmdPtr++) = (FreqString[1] - 48) | ((FreqString[0] - 48) << 4);
			*(CmdPtr++) = 10;

			// Send Get Status, as these types doesn't ack commands

			*(CmdPtr++) = 0;
			*(CmdPtr++) = 0;
			*(CmdPtr++) = 0;

			if (PORT->PortType == FT990 || PORT->YaesuVariant == FT1000D)
				*(CmdPtr++) = 3;
			else
				*(CmdPtr++) = 2;		// F100 or FT1000MP

			*(CmdPtr++) = 16;			// Get Status
		}
		else if	(PORT->PortType == NMEA)
		{	
			int Len;

			i = sprintf(CmdPtr, "$PICOA,90,%02x,RXF,%.6f*xx\r\n", RIG->RigAddr, Freq/1000000.);
			AddNMEAChecksum(CmdPtr);
			Len = i;
			i = sprintf(CmdPtr + Len, "$PICOA,90,%02x,TXF,%.6f*xx\r\n", RIG->RigAddr, Freq/1000000.);
			AddNMEAChecksum(CmdPtr + Len);
			Len += i;
			i = sprintf(CmdPtr + Len, "$PICOA,90,%02x,MODE,%s*xx\r\n", RIG->RigAddr, Mode);
			AddNMEAChecksum(CmdPtr + Len);
			FreqPtr[0]->Cmd1Len = Len + i;

			i = sprintf(RIG->Poll, "$PICOA,90,%02x,RXF*xx\r\n", RIG->RigAddr);
			AddNMEAChecksum(RIG->Poll);
			Len = i;
			i = sprintf(RIG->Poll + Len, "$PICOA,90,%02x,MODE*xx\r\n", RIG->RigAddr);
			AddNMEAChecksum(RIG->Poll + Len);
			RIG->PollLen = Len + i;
		}
		else if	(PORT->PortType == HAMLIB)
		{
			FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "F %s\n+f\nM %s %d\n+m\n", FreqString, Mode, BandWidth);
		}

		else if	(PORT->PortType == FLRIG)
		{
			sprintf(FreqPtr[0]->Cmd1Msg, "%.0f", Freq);
			sprintf(FreqPtr[0]->Cmd2Msg, "%s", Mode);
			sprintf(FreqPtr[0]->Cmd3Msg, "%d", BandWidth);
		}

		else if	(PORT->PortType == RTLUDP)
		{
			int FM = 0;
			int AM = 1;
			int USB = 2;
			int LSB = 3;
		
			CmdPtr[0] = 0;
			memcpy(&CmdPtr[1], &FreqInt, 4); 

			CmdPtr[1] = FreqInt & 0xff;
			CmdPtr[2] = (FreqInt >> 8) & 0xff;
			CmdPtr[3] = (FreqInt >> 16) & 0xff;
			CmdPtr[4] = (FreqInt >> 24) & 0xff;

			FreqPtr[0]->Cmd1Len = 5;
	
			if (Mode[0])
			{
				CmdPtr[5] = 1;
				FreqPtr[0]->Cmd1Len = 10;

				if (strcmp(Mode, "FM") == 0)
					memcpy(&CmdPtr[6], &FM, 4); 
				else if (strcmp(Mode, "AM") == 0)
					memcpy(&CmdPtr[6], &AM, 4); 
				else if (strcmp(Mode, "USB") == 0)
					memcpy(&CmdPtr[6], &USB, 4); 
				else if (strcmp(Mode, "LSB") == 0)
					memcpy(&CmdPtr[6], &LSB, 4); 
			}
		
		}

		FreqPtr++;

		RIG->ScanCounter = 20;

		ptr = strtok_s(NULL, " \t\n\r", &Context);		// Next Freq
	}



	if (RIG->NumberofBands)
	{
		CheckTimeBands(RIG);		// Set initial FreqPtr;
		PORT->FreqPtr = RIG->FreqPtr[0];	
	}

	return RIG;
}

VOID SetupScanInterLockGroups(struct RIGINFO *RIG)
{
	struct PORTCONTROL * PortRecord;
	struct TNCINFO * TNC;
	int port;
	int Interlock = RIG->Interlock;
	char PortString[128] = "";
	char TxPortString[128] = "";
	int n = 0;
	int nn = 0;

	// Find TNC ports in this Rig's scan group

	for (port = 1; port < MAXBPQPORTS; port++)
	{
		TNC = TNCInfo[port];

		if (TNC == NULL)
			continue;

		PortRecord = &TNC->PortRecord->PORTCONTROL;

		if (TNC->RXRadio == Interlock)
		{
			int p = PortRecord->PORTNUMBER;
			RIG->BPQPort |= ((uint64_t)1 << p);
			n += sprintf(&PortString[n], ",%d", p);
			TNC->RIG = RIG;

			if (RIG->PTTMode == 0 && TNC->PTTMode)
				RIG->PTTMode = TNC->PTTMode;
		}
		if (TNC->TXRadio == Interlock && TNC->TXRadio != TNC->RXRadio)
		{
			int p = PortRecord->PORTNUMBER;
			RIG->BPQPort |= ((uint64_t)1 << p);
			nn += sprintf(&TxPortString[nn], ",%d", p);
			TNC->TXRIG = RIG;

			if (RIG->PTTMode == 0 && TNC->PTTMode)
				RIG->PTTMode = TNC->PTTMode;
		}
	}

	if (RIG->PTTMode == 0 && (RIG->PTTCATPort[0] || RIG->HAMLIBPORT)) // PTT Mux Implies CAT
		RIG->PTTMode = PTTCI_V;

	if (PortString[0] && TxPortString[0])			// Have both
		sprintf(RIG->WEB_PORTS, "Rx: %s Tx: %s", &PortString[1], &TxPortString[1]);
	else if (PortString[0])
		strcpy(RIG->WEB_PORTS, &PortString[1]);
	else  if (TxPortString[0])
		sprintf(RIG->WEB_PORTS, "Tx: %s", &TxPortString[1]);

	SetWindowText(RIG->hPORTS, RIG->WEB_PORTS);
}

VOID SetupPortRIGPointers()
{
	struct TNCINFO * TNC;
	int port;

	for (port = 1; port < MAXBPQPORTS; port++)
	{
		TNC = TNCInfo[port];

		if (TNC == NULL)
			continue;

		if (TNC->RIG == NULL)
			TNC->RIG = &TNC->DummyRig;		// Not using Rig control, so use Dummy
	}
}

#ifdef WIN32

VOID PTTCATThread(void * Param)
{
	struct RIGINFO * RIG = 	(struct RIGINFO *)Param;
	DWORD dwLength = 0;
	int Length, ret, i;
	UCHAR * ptr1;
	UCHAR * ptr2;
	UCHAR c;
	UCHAR Block[4][80];
	UCHAR CurrentState[4] = {0};
#define RTS 2
#define DTR 4
	HANDLE Event;
	HANDLE Handle[4];
	DWORD EvtMask[4];
	OVERLAPPED Overlapped[4];
	char Port[32];
	int PIndex = 0;
	int HIndex = 0;
	int rc;

	EndPTTCATThread = FALSE;

	while (PIndex < 4 && RIG->PTTCATPort[PIndex][0])
	{
		RIG->RealMux[HIndex] = 0;

		sprintf(Port, "\\\\.\\pipe\\BPQCOM%s", RIG->PTTCATPort[PIndex]);

		Handle[HIndex] = CreateFile(Port, GENERIC_READ | GENERIC_WRITE,
                  0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);

		if (Handle[HIndex] == (HANDLE) -1)
		{
			int Err = GetLastError();
			char errmsg[256] = "";

			// Only report if both BPQCOM and Real COM fail

			sprintf(errmsg, "PTTMUX port BPQCOM%s Open failed code %d - trying real com port", RIG->PTTCATPort[PIndex], Err);

			// See if real com port

			sprintf(Port, "\\\\.\\\\COM%s", RIG->PTTCATPort[PIndex]);

			Handle[HIndex] = CreateFile(Port, GENERIC_READ | GENERIC_WRITE,
				0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

			RIG->RealMux[HIndex] = 1;

			if (Handle[HIndex] == (HANDLE) -1)
			{
				int Err = GetLastError();
				if (errmsg[0])
				{
					Consoleprintf("%s", errmsg);
					Consoleprintf("PTTMUX port COM%s Open failed code %d", RIG->PTTCATPort[PIndex], Err);
				}
			}
			else
			{
				rc = SetCommMask(Handle[HIndex], EV_CTS | EV_DSR);		// Request notifications
				HIndex++;
			}
		}
		else
			HIndex++;

		PIndex++;

	}

	if (PIndex == 0)
		return;				// No ports

	Event = CreateEvent(NULL, TRUE, FALSE, NULL);

	for (i = 0; i < HIndex; i ++)
	{
		memset(&Overlapped[i], 0, sizeof(OVERLAPPED));
		Overlapped[i].hEvent = Event;

		if (RIG->RealMux[i])
		{
			// Request Interface change notifications

			rc = WaitCommEvent(Handle[i], &EvtMask[i], &Overlapped[i]);
			rc = GetLastError();
 
		}
		else
		{

			// Prime a read on each handle

			ReadFile(Handle[i], Block[i], 80, &Length, &Overlapped[i]);
		}
	}
		
	while (EndPTTCATThread == FALSE)
	{

WaitAgain:

		ret = WaitForSingleObject(Event, 1000);

		if (ret == WAIT_TIMEOUT)
		{
			if (EndPTTCATThread)
			{
				for (i = 0; i < HIndex; i ++)
				{
					CancelIo(Handle[i]);
					CloseHandle(Handle[i]);
					Handle[i] = INVALID_HANDLE_VALUE;
				}
				CloseHandle(Event);
				return;
			}
			goto WaitAgain;
		}

		ResetEvent(Event);

		// See which request(s) have completed

		for (i = 0; i < HIndex; i ++)
		{
			ret =  GetOverlappedResult(Handle[i], &Overlapped[i], &Length, FALSE);

			if (ret)
			{
				if (RIG->RealMux[i])
				{
					// Request Interface change notifications

					DWORD Mask;

					GetCommModemStatus(Handle[i], &Mask);

					if (Mask & MS_CTS_ON)
						Rig_PTTEx(RIG, TRUE, RIG->PTTCATTNC[i]);
					else
						Rig_PTTEx(RIG, FALSE, RIG->PTTCATTNC[i]);

					memset(&Overlapped[i], 0, sizeof(OVERLAPPED));
					Overlapped[i].hEvent = Event;
					WaitCommEvent(Handle[i], &EvtMask[i], &Overlapped[i]);

				}
				else
				{

					ptr1 = Block[i];
					ptr2 = Block[i];

					while (Length > 0)
					{
						c = *(ptr1++);

						Length--;

						if (c == 0xff)
						{
							c = *(ptr1++);
							Length--;

							if (c == 0xff)			// ff ff means ff
							{
								Length--;
							}
							else
							{
								// This is connection / RTS/DTR statua from other end
								// Convert to CAT Command

								if (c == CurrentState[i])
									continue;

								if (c & RTS)
									Rig_PTTEx(RIG, TRUE, RIG->PTTCATTNC[i]);
								else
									Rig_PTTEx(RIG, FALSE, RIG->PTTCATTNC[i]);

								CurrentState[i] = c;
								continue;
							}
						}
					}

					memset(&Overlapped[i], 0, sizeof(OVERLAPPED));
					Overlapped[i].hEvent = Event;

					ReadFile(Handle[i], Block[i], 80, &Length, &Overlapped[i]);
				}
			}
		}
	}
	EndPTTCATThread = FALSE;
}

/*
		memset(&Overlapped, 0, sizeof(Overlapped));
		Overlapped.hEvent = Event;
		ResetEvent(Event);

		ret = ReadFile(Handle, Block, 80, &Length, &Overlapped);
		
		if (ret == 0)
		{
			ret = GetLastError();

			if (ret != ERROR_IO_PENDING)
			{
				if (ret == ERROR_BROKEN_PIPE || ret == ERROR_INVALID_HANDLE)
				{
					CloseHandle(Handle);
					RIG->PTTCATHandles[0] = INVALID_HANDLE_VALUE;
					return;
				}
			}
		}	
*/
#endif

// HAMLIB Support Code

VOID HAMLIBPoll(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on HAMLIB
	char cmd[80];
	int len;

	if (RIG->ScanStopped == 0)
		if (RIG->ScanCounter)
			RIG->ScanCounter--;

	if (PORT->Timeout)
	{
		PORT->Timeout--;
		
		if (PORT->Timeout)			// Still waiting
			return;

		SetWindowText(RIG->hFREQ, "------------------");
		SetWindowText(RIG->hMODE, "----------");
		strcpy(RIG->WEB_FREQ, "-----------");;
		strcpy(RIG->WEB_MODE, "------");

		RIG->RIGOK = FALSE;
		return;
	}

	// Send Data if avail, else send poll

	if (RIG->NumberofBands && RIG->RIGOK && (RIG->ScanStopped == 0))
	{
		if (RIG->ScanCounter <= 0)
		{
			//	Send Next Freq

			if (GetPermissionToChange(PORT, RIG))
			{
				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);
				PORT->TXLen = PORT->FreqPtr->Cmd1Len;

				_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

				send(PORT->remoteSock, PORT->TXBuffer, PORT->TXLen, 0);
				PORT->CmdSent = 1;
				PORT->Retries = 0;	
				PORT->Timeout = 0;
				PORT->AutoPoll = TRUE;

				// There isn't a response to a set command, so clear Scan Lock here
			
				ReleasePermission(RIG);			// Release Perrmission
				return;
			}
		}
	}
			
	if (RIG->PollCounter)
	{
		RIG->PollCounter--;
		if (RIG->PollCounter > 1)
			return;
	}

	if (RIG->RIGOK && (RIG->ScanStopped == 0) && RIG->NumberofBands)
		return;						// no point in reading freq if we are about to change it

	RIG->PollCounter = 10;			// Once Per Sec
		
	// Read Frequency 

	len = sprintf(cmd, "+f\n+m\n");

	send(PORT->remoteSock, cmd, len, 0);

	PORT->Timeout = 10;
	PORT->CmdSent = 0;

	PORT->AutoPoll = TRUE;

	return;
}


void HAMLIBProcessMessage(struct RIGPORTINFO * PORT)
{
	// Called from Background thread

	int InputLen = recv(PORT->remoteSock, &PORT->RXBuffer[PORT->RXLen], 500 - PORT->RXLen, 0);

	if (InputLen == 0 || InputLen == SOCKET_ERROR)
	{
		if (PORT->remoteSock)
			closesocket(PORT->remoteSock);

		PORT->remoteSock = 0;

		PORT->CONNECTED = FALSE;
		PORT->hDevice = 0;
		return;					
	}

	PORT->RXLen += InputLen;
}

void FLRIGProcessMessage(struct RIGPORTINFO * PORT)
{
	// Called from Background thread

	int InputLen = recv(PORT->remoteSock, &PORT->RXBuffer[PORT->RXLen], 500 - PORT->RXLen, 0);

	if (InputLen == 0 || InputLen == SOCKET_ERROR)
	{
		if (PORT->remoteSock)
			closesocket(PORT->remoteSock);

		PORT->remoteSock = 0;

		PORT->CONNECTED = FALSE;
		PORT->hDevice = 0;
		return;					
	}

	PORT->RXLen += InputLen;
	ProcessFLRIGFrame(PORT);
}

void ProcessHAMLIBFrame(struct RIGPORTINFO * PORT, int Length)
{
	char * msg = PORT->RXBuffer;
	char * rest;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on Yaseu
	msg[Length] = 0;

	PORT->Timeout = 0;
	RIG->RIGOK = 1;

	// extract lines from input

	while (msg && msg[0])
	{
		rest = strlop(msg, 10);

		if (memcmp(msg, "Frequency:", 10) == 0)
		{
			RIG->RigFreq = atof(&msg[11]) / 1000000.0;

			_gcvt(RIG->RigFreq, 9, RIG->Valchar);
 
			sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
			SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
		}

		else if (memcmp(msg, "Mode:", 5) == 0)
		{
			if (strlen(&msg[6]) < 15)
				strcpy(RIG->ModeString, &msg[6]);
		}

		else if (memcmp(msg, "Passband:", 9) == 0)
		{
			RIG->Passband = atoi(&msg[10]);
			sprintf(RIG->WEB_MODE, "%s/%d", RIG->ModeString, RIG->Passband);
			SetWindowText(RIG->hMODE, RIG->WEB_MODE);
		}
		
		msg = rest;
	}
}


void ProcessFLRIGFrame(struct RIGPORTINFO * PORT)
{
	char * msg;
	int Length;

	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one 
	char * ptr1, * ptr2, * val;
	int Len, TotalLen;
	char cmd[80];
	char ReqBuf[256];
	char SendBuff[256];

	while (PORT->RXLen > 0)
	{
		int b1 = 0, b2 = 0;

		msg = PORT->RXBuffer;
		Length = PORT->RXLen;

		msg[Length] = 0;

		ptr1 = strstr(msg, "Content-length:");

		if (ptr1 == NULL)
			return;

		ptr2 = strstr(ptr1, "\r\n\r\n");

		if (ptr2 == NULL)
			return;

		Len = atoi(&ptr1[15]);

		TotalLen = ptr2 + 4 + Len - msg;

		if (TotalLen > Length)		// Don't have it all
			return;

		val = strstr(ptr2, "<value>");

		if (val)
		{
			val += 7;

			RIG->RIGOK = 1;
			PORT->RXLen -= TotalLen;

			// It is quite difficult to corrolate responses with commands, but we only poll for freq, mode and bandwidth
			// and the responses can be easily identified

			if (strstr(val, "<i4>") || memcmp(val, "</value>", 8) == 0)
			{
				// Reply to set command - may need to send next in set or use to send OK if interactive

				if (PORT->ScanEntry.Cmd2Msg[0])
				{
					sprintf(cmd, "<string>%s</string>", PORT->ScanEntry.Cmd2Msg);
					FLRIGSendCommand(PORT, "rig.set_mode", cmd);
					PORT->ScanEntry.Cmd2Msg[0] = 0;
				}

				else if (PORT->ScanEntry.Cmd3Msg[0] && strcmp(PORT->ScanEntry.Cmd3Msg, "0") != 0)
				{
					sprintf(cmd, "<i4>%s</i4>", PORT->ScanEntry.Cmd3Msg);
					FLRIGSendCommand(PORT, "rig.set_bandwidth", cmd);
					PORT->ScanEntry.Cmd3Msg[0] = 0;
				}

				else if (!PORT->AutoPoll)
				{
					GetSemaphore(&Semaphore, 61);
					SendResponse(RIG->Session, "Set OK");
					FreeSemaphore(&Semaphore);
					PORT->AutoPoll = 1;		// So we dond send another
				}
			}
			else if(strstr(val, "<array>"))
			{
				// Reply to get BW

				char * p1, * p2;

				p1 = strstr(val, "<value>");

				if (p1)
				{
					p1 += 7;
					b1 = atoi(p1);

					p2 = strstr(p1, "<value>");

					if (p2)
					{
						p2 +=7;
						b2 = atoi(p2);
					}
				}

				if (b1)
				{
					if (b2)
						sprintf(RIG->WEB_MODE, "%s/%d:%d", RIG->ModeString, b1, b2);
					else
						sprintf(RIG->WEB_MODE, "%s/%d", RIG->ModeString, b1);

					MySetWindowText(RIG->hMODE, RIG->WEB_MODE);
				}
			}
			else
			{
				// Either freq or mode. See if numeric

				double freq;

				strlop(val, '<');

				freq = atof(val) / 1000000.0;

				if (freq > 0.0)
				{
					RIG->RigFreq = freq; 
					_gcvt(RIG->RigFreq, 9, RIG->Valchar);

					sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
					MySetWindowText(RIG->hFREQ, RIG->WEB_FREQ);

					// Read Mode

					Len = sprintf(ReqBuf, Req, "rig.get_mode", "");
					Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);
					send(PORT->remoteSock, SendBuff, Len, 0);

				}
				else
				{
					if (strlen(val)> 1)
					{
						strcpy(RIG->ModeString, val);

						if (b1)
						{
							if (b2)
								sprintf(RIG->WEB_MODE, "%s/%d:%d", RIG->ModeString, b1, b2);
							else
								sprintf(RIG->WEB_MODE, "%s/%d", RIG->ModeString, b1);
						}
						else
							SetWindowText(RIG->hMODE, RIG->WEB_MODE);

						MySetWindowText(RIG->hMODE, RIG->WEB_MODE);

						Len = sprintf(ReqBuf, Req, "rig.get_bw", "");
						Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);

						send(PORT->remoteSock, SendBuff, Len, 0);
					}
				}
			}



			// We now send all setting commands at once

			/*


			if (memcmp(PORT->TXBuffer, "rig.set_vfo", 11) == 0)
			{
			//	Set Freq - Send Set Mode if needed

			if (PORT->ScanEntry.Cmd2Msg[0])
			{
			sprintf(cmd, "<string>%s</string>", PORT->ScanEntry.Cmd2Msg);
			FLRIGSendCommand(PORT, "rig.set_mode", cmd);
			if (strcmp(PORT->ScanEntry.Cmd3Msg, "0") != 0)
			{
			sprintf(cmd, "<i4>%s</i4>", PORT->ScanEntry.Cmd3Msg);
			FLRIGSendCommand(PORT, "rig.set_bandwidth", cmd);
			}
			strcpy(RIG->ModeString, PORT->ScanEntry.Cmd2Msg);
			}
			else
			{
			if (!PORT->AutoPoll)
			SendResponse(RIG->Session, "Set Freq OK");

			strcpy(PORT->TXBuffer, "rig.get_vfo"); 
			Len = sprintf(ReqBuf, Req, "rig.get_vfo", "");
			Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);
			strcpy(PORT->TXBuffer, "rig.get_bw"); 
			Len = sprintf(ReqBuf, Req, "rig.get_bw", "");
			Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);

			send(PORT->remoteSock, SendBuff, Len, 0);
			}
			continue;
			}

			if (memcmp(PORT->TXBuffer, "rig.set_mode", 11) == 0)
			{
			strcpy(PORT->TXBuffer, "rig.get_vfo"); 		
			Len = sprintf(ReqBuf, Req, "rig.get_vfo", "");
			Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);

			send(PORT->remoteSock, SendBuff, Len, 0);

			if (!PORT->AutoPoll)
			SendResponse(RIG->Session, "Set Freq and Mode OK");

			continue;
			}

			if (memcmp(PORT->TXBuffer, "rig.get_vfo", 11) == 0)
			{
			RIG->RigFreq = atof(val) / 1000000.0;

			_gcvt(RIG->RigFreq, 9, RIG->Valchar);

			sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
			MySetWindowText(RIG->hFREQ, RIG->WEB_FREQ);

			strcpy(PORT->TXBuffer, "rig.get_mode"); 
			Len = sprintf(ReqBuf, Req, "rig.get_mode", "");
			Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);
			send(PORT->remoteSock, SendBuff, Len, 0);

			Len = sprintf(ReqBuf, Req, "rig.get_bw", "");
			Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);
			send(PORT->remoteSock, SendBuff, Len, 0);
			continue;
			}

			if (memcmp(PORT->TXBuffer, "rig.get_mode", 11) == 0)
			{
			strlop(val, '<');
			sprintf(RIG->WEB_MODE, "%s", val);
			MySetWindowText(RIG->hMODE, RIG->WEB_MODE);
			}
			}

			*/
		}

		if (PORT->RXLen > 0)
			memmove(PORT->RXBuffer, &PORT->RXBuffer[TotalLen], PORT->RXLen);
		else
			PORT->RXLen = 0;

		PORT->Timeout = 0;
	}

	/*
	POST /RPC2 HTTP/1.1
	User-Agent: XMLRPC++ 0.8
	Host: 127.0.0.1:12345
	Content-type: text/xml
	Content-length: 89

	<?xml version="1.0"?>
	<methodCall><methodName>rig.get_vfoA</methodName>
	</methodCall>
	HTTP/1.1 200 OK
	Server: XMLRPC++ 0.8
	Content-Type: text/xml
	Content-length: 118

	<?xml version="1.0"?>
	<methodResponse><params><param>
	<value>14070000</value>
	</param></params></methodResponse>
	*/


}





void HLSetMode(SOCKET Sock, struct RIGINFO * RIG, unsigned char * Msg, char sep)
{
	char Resp[120];
	int Len;
	char mode[80] = "";
	int filter = 0;
	int n = sscanf(&Msg[1], "%s %d", mode, &filter); 

	// Send to RIGCommand. Can't set Mode without Freq so need to use current

	// ?? Should be try to convert bandwidth to filter ??

	RIG->Passband = filter;

	if (RIG->PORT->PortType == ICOM)		// Needs a Filter
		sprintf(Resp, "%d %s %s 1\n", 0, RIG->Valchar, mode);
	else
		sprintf(Resp, "%d %s %s\n", 0, RIG->Valchar, mode);

	GetSemaphore(&Semaphore, 60);
	Rig_CommandEx(RIG->PORT, RIG, (TRANSPORTENTRY *) -1, Resp);
	FreeSemaphore(&Semaphore);

	if (sep)
		Len = sprintf(Resp, "set_mode: %s %d%cRPRT 0\n", mode, filter, sep);
	else
		Len = sprintf(Resp, "RPRT 0\n");

	send(Sock, Resp, Len, 0);
}


void HLSetFreq(SOCKET Sock, struct RIGINFO * RIG, unsigned char * Msg, char sep)
{
	char Resp[80];
	int Len;
	int freq = atoi(&Msg[1]);

	// Send to RIGCommand

	sprintf(Resp, "%d %f\n", 0, freq/1000000.0);
	GetSemaphore(&Semaphore, 60);
	Rig_CommandEx(RIG->PORT, RIG, (TRANSPORTENTRY *) -1, Resp);
	FreeSemaphore(&Semaphore);

	if (sep)
		Len = sprintf(Resp, "set_freq: %d%cRPRT 0\n", freq, sep);
	else
		Len = sprintf(Resp, "RPRT 0\n");

	send(Sock, Resp, Len, 0);
}


void HLGetPTT(SOCKET Sock, struct RIGINFO * RIG, char sep)
{
	char Resp[80];
	int Len;
	int ptt = 0;
	
	if (RIG->PTTTimer)
		ptt = 1;

	if (sep)
		Len = sprintf(Resp, "get_ptt:%cPTT: %d%cRPRT 0\n", sep, ptt, sep);
	else
		Len = sprintf(Resp, "%d\n", ptt);

	send(Sock, Resp, Len, 0);
}

void HLSetPTT(SOCKET Sock, struct RIGINFO * RIG, unsigned char * Msg, char sep)
{
	char Resp[80];
	int Len;
	int ptt = atoi(&Msg[1]);

	if (ptt)
		Rig_PTTEx(RIG, 1, NULL);
	else
		Rig_PTTEx(RIG, 0, NULL);

	if (sep)
		Len = sprintf(Resp, "set_ptt: %d%cRPRT 0\n", ptt, sep);
	else
		Len = sprintf(Resp, "RPRT 0\n");

	send(Sock, Resp, Len, 0);
}

void HLGetMode(SOCKET Sock, struct RIGINFO * RIG, char sep)
{
	char Resp[80];
	int Len;

	if (sep)
		Len = sprintf(Resp, "get_mode:%cMode: %s%cPassband: %d%cRPRT 0\n", sep, RIG->ModeString, sep, RIG->Passband, sep);
	else
		Len = sprintf(Resp, "%s\n%d\n", RIG->ModeString, RIG->Passband);

	send(Sock, Resp, Len, 0);

}

void HLGetFreq(SOCKET Sock, struct RIGINFO * RIG, char sep)
{
	char Resp[80];
	int Len;
	char freqval[64];
	double freq = atof(RIG->Valchar) * 1000000.0;

	sprintf(freqval, "%f", freq);
	strlop(freqval, '.');

	if (sep)
		Len = sprintf(Resp, "get_freq:%cFrequency: %s%cRPRT 0\n", sep, freqval, sep);
	else
		Len = sprintf(Resp, "%s\n", freqval);

	send(Sock, Resp, Len, 0);
}

void HLGetVFO(SOCKET Sock, struct RIGINFO * RIG, char sep)
{
	char Resp[80];
	int Len;

	if (sep)
		Len = sprintf(Resp, "get_vfo:%s%cRPRT 0\n", "VFOA", sep);
	else
		Len = sprintf(Resp, "%s\n", "VFOA");

	send(Sock, Resp, Len, 0);
}

void HLGetSplit(SOCKET Sock, struct RIGINFO * RIG, char sep)
{
	char Resp[80];
	int Len;

	if (sep)
		Len = sprintf(Resp, "get_vfo:%s%cRPRT 0\n", "VFOA", sep);
	else
		Len = sprintf(Resp, "0\n%s\n", "VFOA");

	send(Sock, Resp, Len, 0);

}



int ProcessHAMLIBSlaveMessage(SOCKET Sock, struct RIGINFO * RIG, unsigned char * Msg, int MsgLen)
{
	// We only process a pretty small subset of rigctl messages

	// commands are generally a single character, upper case for set
	// and lower case for get. If preceeded by + ; | or , response will
	// be in extended form. + adds an LF between field, other values the
	// supplied char is used as seperator.

	// At the moments we support freq (F) mode (m) and PTT (T)

	char sep = 0;

	if (Msg[0] == '#')
		return 0;				// Comment

	strlop(Msg, 13);
	strlop(Msg, 10);

	// \ on front is used for long mode. Hopefully not used much

	// WSJT seems ro need \chk_vfo and \dump_state

	if (Msg[0] == '\\')
	{
		if (strcmp(&Msg[1], "chk_vfo") == 0)
		{
			char Reply[80];
			int Len = sprintf(Reply, "CHKVFO 0\n");
			send(Sock, Reply, Len, 0);
			return 0;
		}

		if (strcmp(&Msg[1], "dump_state") == 0)
		{
			char Reply[4096];
			int Len = sprintf(Reply,
				"0\n"
				"1\n"
				"2\n"
				"150000.000000 1500000000.000000 0x1ff -1 -1 0x10000003 0x3\n"
				"0 0 0 0 0 0 0\n"
				"0 0 0 0 0 0 0\n"
				"0x1ff 1\n"
				"0x1ff 0\n"
				"0 0\n"
				"0x1e 2400\n"
				"0x2 500\n"
				"0x1 8000\n"
				"0x1 2400\n"
				"0x20 15000\n"
				"0x20 8000\n"
				"0x40 230000\n"
				"0 0\n"
				"9990\n"
				"9990\n"
				"10000\n"
				"0\n"
				"10 \n"
				"10 20 30 \n"
				"0xffffffff\n"
				"0xffffffff\n"
				"0xf7ffffff\n"
				"0x83ffffff\n"
				"0xffffffff\n"
				"0xffffffbf\n");

			send(Sock, Reply, Len, 0);
			return 0;
		}
	}

	if (Msg[0] == 'q' || Msg[0] == 'Q')
	{
		// close connection

		return 1;
	}

	if (Msg[0] == '+')
	{
		sep = 10;
		Msg++;
		MsgLen --;
	}
	else if (Msg[0] == '_' || Msg[0] == '?')
	{
	}
	else if (ispunct(Msg[0]))
	{
		sep = Msg[0];	
		Msg++;
		MsgLen --;
	}

	switch (Msg[0])
	{
	case 'f':			// Get Frequency

		HLGetFreq(Sock, RIG, sep);
		return 0;

	case 'm':			// Get Mode

		HLGetMode(Sock, RIG, sep);
		return 0;

	case 't':			// Get PTT

		HLGetPTT(Sock, RIG, sep);
		return 0;

	case 'v':			// Get VFO

		HLGetVFO(Sock, RIG, sep);
		return 0;

	case 's':			// Get Split

		HLGetSplit(Sock, RIG, sep);
		return 0;

	case 'F':

		HLSetFreq(Sock, RIG, Msg, sep);
		return 0;

	case 'M':

		HLSetMode(Sock, RIG, Msg, sep);
		return 0;

	case 'T':

		HLSetPTT(Sock, RIG, Msg, sep);
		return 0;
	}
	return 0;
}

int DecodeHAMLIBAddr(struct RIGPORTINFO * PORT, char * ptr)
{
	// Param is IPADDR:PORT. Only Allow numeric addresses 
	
	struct sockaddr_in * destaddr = (SOCKADDR_IN *)&PORT->remoteDest;

	char * port = strlop(ptr, ':');

	if (port == NULL)
		return 0;

	destaddr->sin_family = AF_INET;
	destaddr->sin_addr.s_addr = inet_addr(ptr);
	destaddr->sin_port = htons(atoi(port));

	return 1;
}

VOID HAMLIBThread(void * Param);

VOID ConnecttoHAMLIB(struct RIGPORTINFO * PORT)
{
	if (HAMLIBMasterRunning)
		_beginthread(HAMLIBThread, 0, (void *)PORT);

	return ;
}

VOID HAMLIBThread(void * Param)
{
	// Opens sockets and looks for data

	struct RIGPORTINFO * PORT = (struct RIGPORTINFO * )Param;
	char Msg[255];
	int err, i, ret;
	u_long param=1;
	BOOL bcopt=TRUE;
	fd_set readfs;
	fd_set errorfs;
	struct timeval timeout;

	if (PORT->remoteSock)
	{
		closesocket(PORT->remoteSock);
	}

	PORT->remoteSock = 0;
	PORT->remoteSock = socket(AF_INET,SOCK_STREAM,0);

	if (PORT->remoteSock == INVALID_SOCKET)
	{
		i=sprintf(Msg, "Socket Failed for HAMLIB socket - error code = %d\r\n", WSAGetLastError());
		WritetoConsole(Msg);

	 	PORT->CONNECTING = FALSE;
  	 	return; 
	}

	setsockopt(PORT->remoteSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
	setsockopt(PORT->remoteSock, IPPROTO_TCP, TCP_NODELAY, (const char FAR *)&bcopt, 4); 

	if (connect(PORT->remoteSock,(LPSOCKADDR) &PORT->remoteDest,sizeof(PORT->remoteDest)) == 0)
	{
		//
		//	Connected successful
		//

		ioctl(PORT->remoteSock, FIONBIO, &param);
	}
	else
	{
		if (PORT->Alerted == FALSE)
		{
			struct sockaddr_in * destaddr = (SOCKADDR_IN * )&PORT->remoteDest;

			err = WSAGetLastError();

   			sprintf(Msg, "Connect Failed for HAMLIB socket - error code = %d Addr %s\r\n", err, PORT->IOBASE);

			WritetoConsole(Msg);
				PORT->Alerted = TRUE;
		}
		
		closesocket(PORT->remoteSock);

		PORT->remoteSock = 0;
	 	PORT->CONNECTING = FALSE;
		return;
	}

	PORT->CONNECTED = TRUE;
	PORT->hDevice = (HANDLE)1;				// simplifies check code

	PORT->Alerted = TRUE;

	while (PORT->CONNECTED)
	{
		FD_ZERO(&readfs);	
		FD_ZERO(&errorfs);

		FD_SET(PORT->remoteSock,&readfs);
		FD_SET(PORT->remoteSock,&errorfs);
		
		timeout.tv_sec = 5;
		timeout.tv_usec = 0;
		
		ret = select((int)PORT->remoteSock + 1, &readfs, NULL, &errorfs, &timeout);

		if (HAMLIBMasterRunning == 0)
			return;

		if (ret == SOCKET_ERROR)
		{
			Debugprintf("HAMLIB Select failed %d ", WSAGetLastError());
			goto Lost;
		}

		if (ret > 0)
		{
			//	See what happened

			if (FD_ISSET(PORT->remoteSock, &readfs))
			{
				HAMLIBProcessMessage(PORT);
			}

			if (FD_ISSET(PORT->remoteSock, &errorfs))
			{
Lost:	
				sprintf(Msg, "HAMLIB Connection lost for Addr %s\r\n", PORT->IOBASE);
				WritetoConsole(Msg);

				PORT->CONNECTED = FALSE;
				PORT->Alerted = FALSE;
				PORT->hDevice = 0;				// simplifies check code

				closesocket(PORT->remoteSock);
				PORT->remoteSock = 0;
				return;
			}


			continue;
		}
		else
		{
		}
	}
	sprintf(Msg, "HAMLIB Thread Terminated Addr %s\r\n", PORT->IOBASE);
	WritetoConsole(Msg);
}



void HAMLIBSlaveThread(VOID * Param)
{
	// Wait for connections and messages from HAMLIB Clients

	struct RIGINFO * RIG = (struct RIGINFO *)Param;
	fd_set readfs;
	fd_set errorfs;
	struct timeval timeout;
	int ret;
	unsigned int maxsock;

	HAMLIBSlaveRunning = 1;

	Consoleprintf("HAMLIB Slave Thread %d Running", RIG->HAMLIBPORT);

	while (HAMLIBSlaveRunning)
	{
		struct HAMLIBSOCK * Entry = RIG->Sockets;
		struct HAMLIBSOCK * Prev;
	
		FD_ZERO(&readfs);	
		FD_ZERO(&errorfs);

		FD_SET(RIG->ListenSocket, &readfs);
		FD_SET(RIG->ListenSocket, &errorfs);
	
		maxsock = RIG->ListenSocket;

		while (Entry && HAMLIBSlaveRunning)
		{
			FD_SET(Entry->Sock, &readfs);
			FD_SET(Entry->Sock, &errorfs);

			if (Entry->Sock > maxsock)
				maxsock = Entry->Sock;

			Entry = Entry->Next;
		}

		timeout.tv_sec = 5;
		timeout.tv_usec = 0;

		ret = select(maxsock + 1, &readfs, NULL, &errorfs, &timeout);

		if (HAMLIBSlaveRunning == 0)
			return;

		if (ret == -1)
		{
			perror("listen select");
			continue;
		}

		if (ret)
		{
			if (FD_ISSET(RIG->ListenSocket, &readfs))
			{
				// Connection. Accept it and create a socket enty

				int addrlen = sizeof(struct sockaddr_in6);
				struct sockaddr_in6 sin6; 
				struct HAMLIBSOCK * Entry = zalloc(sizeof(struct HAMLIBSOCK));

				Entry->Sock = accept(RIG->ListenSocket, (struct sockaddr *)&sin6, &addrlen);
				
				if (RIG->Sockets)
					Entry->Next = RIG->Sockets;

				RIG->Sockets = Entry;
			}

			// See if any Data Sockets

			Entry = RIG->Sockets;
			Prev = 0;

			while (Entry)
			{
				unsigned char MsgBuf[256];
				unsigned char * Msg = MsgBuf;
				int MsgLen;

				if (FD_ISSET(Entry->Sock, &readfs))
				{
					MsgLen = recv(Entry->Sock, Msg, 256, 0);

					if (MsgLen <= 0)
					{
						// Closed - close socket and remove from chain

						closesocket(Entry->Sock);

						if (Prev == 0)
							RIG->Sockets = Entry->Next;
						else
							Prev->Next = Entry->Next;

						free (Entry);
						break;
					}
					else
					{
						// Could have multiple messages in packet
						// Terminator can be CR LF or CRLF

						char * ptr;
						int Len;

						Msg[MsgLen] = 0;
Loop:
						ptr = strlop(Msg, 10);
						if (ptr == NULL)
							strlop(Msg, 13);

						Len = strlen(Msg);

						if (ProcessHAMLIBSlaveMessage(Entry->Sock, RIG, Msg, Len) == 1)
						{
							// close request

							closesocket(Entry->Sock);

							if (Prev == 0)
								RIG->Sockets = Entry->Next;
							else
								Prev->Next = Entry->Next;

							free (Entry);
							break;
						}
						Msg = ptr;

						if (Msg)
						{
							while (Msg[0] == 10 || Msg[0] == 13)
								Msg++;

							if (Msg[0])
								goto Loop;
						}
					}
				}

				if (FD_ISSET(Entry->Sock, &errorfs))
				{
					// Closed - close socket and remove from chai

					closesocket(Entry->Sock);

					if (Prev == 0)
						RIG->Sockets = Entry->Next;
					else
						Prev->Next = Entry->Next;

					free (Entry);
					break;
				}

				// Check Next Client

				Prev = Entry;
				Entry = Entry->Next;
			}
		}
	}
	Consoleprintf("HAMLIB Slave Thread %d Exited", RIG->HAMLIBPORT);
}


VOID FLRIGPoll(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];
	int Len;
	char ReqBuf[256];
	char SendBuff[256];

	if (RIG->ScanStopped == 0)
		if (RIG->ScanCounter)
			RIG->ScanCounter--;

	if (PORT->Timeout)
	{
		PORT->Timeout--;
		
		if (PORT->Timeout)			// Still waiting
			return;

		SetWindowText(RIG->hFREQ, "------------------");
		SetWindowText(RIG->hMODE, "----------");
		strcpy(RIG->WEB_FREQ, "-----------");;
		strcpy(RIG->WEB_MODE, "------");

		RIG->RIGOK = FALSE;
		return;
	}

	// Send Data if avail, else send poll

	if (RIG->NumberofBands && RIG->RIGOK && (RIG->ScanStopped == 0))
	{
		if (RIG->ScanCounter <= 0)
		{
			//	Send Next Freq

			if (GetPermissionToChange(PORT, RIG))
			{
				char cmd[80];
				double freq;

				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

				_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

				// Send the Set Freq here, send set mode when we get a response
				
				memcpy(&PORT->ScanEntry, PORT->FreqPtr, sizeof(struct ScanEntry));

				sprintf(cmd, "<double>%s</double>", PORT->FreqPtr->Cmd1Msg);
				FLRIGSendCommand(PORT, "rig.set_vfo", cmd);

				// Update display as we don't get a response

				freq = atof(PORT->FreqPtr->Cmd1Msg) / 1000000.0;

				if (freq > 0.0)
				{
					RIG->RigFreq = freq; 
					_gcvt(RIG->RigFreq, 9, RIG->Valchar);

					sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
					MySetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
				}


				PORT->CmdSent = 1;
				PORT->Retries = 0;	
				PORT->Timeout = 10;
				PORT->AutoPoll = TRUE;

				// There isn't a response to a set command, so clear Scan Lock here
			
				ReleasePermission(RIG);			// Release Perrmission
				return;
			}
		}
	}
			
	if (RIG->PollCounter)
	{
		RIG->PollCounter--;
		if (RIG->PollCounter > 1)
			return;
	}

	if (RIG->RIGOK && (RIG->ScanStopped == 0) && RIG->NumberofBands)
		return;						// no point in reading freq if we are about to change it

	RIG->PollCounter = 10;			// Once Per Sec
		
	// Read Frequency 

	strcpy(Poll, "rig.get_vfo");

	Len = sprintf(ReqBuf, Req, Poll, "");
	Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);

	if (PORT->CONNECTED)
	{
		if (send(PORT->remoteSock, SendBuff, Len, 0) != Len)
		{
			if (PORT->remoteSock)
				closesocket(PORT->remoteSock);

			PORT->remoteSock = 0;
			PORT->CONNECTED = FALSE;
			PORT->hDevice = 0;	
			return;
		}
	}

	PORT->Timeout = 10;
	PORT->CmdSent = 0;

	PORT->AutoPoll = TRUE;

	return;
}

VOID FLRIGSendCommand(struct RIGPORTINFO * PORT, char * Command, char * Value)
{
	int Len;
	char ReqBuf[512];
	char SendBuff[512];
	char ValueString[256] ="";

	if (!PORT->CONNECTED)
		return;
	
	sprintf(ValueString, "<params><param><value>%s</value></param></params\r\n>", Value);
	
	strcpy(PORT->TXBuffer, Command);
	Len = sprintf(ReqBuf, Req, PORT->TXBuffer, ValueString);
	Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);
	if (send(PORT->remoteSock, SendBuff, Len, 0) != Len)
	{
		if (PORT->remoteSock)
			closesocket(PORT->remoteSock);

		PORT->remoteSock = 0;
		PORT->CONNECTED = FALSE;
		PORT->hDevice = 0;				
	}

	return;
}



VOID FLRIGThread(VOID * Param);

VOID ConnecttoFLRIG(struct RIGPORTINFO * PORT)
{
	if (FLRIGRunning)
		_beginthread(FLRIGThread, 0, (void *)PORT);
	return ;
}

VOID FLRIGThread(VOID * Param)
{
	// Opens sockets and looks for data
	
	struct RIGPORTINFO * PORT = (struct RIGPORTINFO *)Param;
	char Msg[255];
	int err, i, ret;
	u_long param=1;
	BOOL bcopt=TRUE;
	fd_set readfs;
	fd_set errorfs;
	struct timeval timeout;

	if (PORT->remoteSock)
	{
		closesocket(PORT->remoteSock);
	}

	PORT->remoteSock = 0;
	PORT->remoteSock = socket(AF_INET,SOCK_STREAM,0);

	if (PORT->remoteSock == INVALID_SOCKET)
	{
		i=sprintf(Msg, "Socket Failed for FLRIG socket - error code = %d\r\n", WSAGetLastError());
		WritetoConsole(Msg);

	 	PORT->CONNECTING = FALSE;
  	 	return; 
	}

	setsockopt(PORT->remoteSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
	setsockopt(PORT->remoteSock, IPPROTO_TCP, TCP_NODELAY, (const char FAR *)&bcopt, 4); 

	if (connect(PORT->remoteSock,(LPSOCKADDR) &PORT->remoteDest, sizeof(PORT->remoteDest)) == 0)
	{
		//
		//	Connected successful
		//

		ioctl(PORT->remoteSock, FIONBIO, &param);
	}
	else
	{
		if (PORT->Alerted == FALSE)
		{
			struct sockaddr_in * destaddr = (SOCKADDR_IN * )&PORT->remoteDest;

			err = WSAGetLastError();

   			sprintf(Msg, "Connect Failed for FLRIG socket - error code = %d Port %d\r\n",
				err, htons(destaddr->sin_port));

			WritetoConsole(Msg);
				PORT->Alerted = TRUE;
		}
		
		closesocket(PORT->remoteSock);

		PORT->remoteSock = 0;
	 	PORT->CONNECTING = FALSE;
		return;
	}

	PORT->CONNECTED = TRUE;
	PORT->hDevice = (HANDLE)1;				// simplifies check code

	PORT->Alerted = TRUE;

	while (PORT->CONNECTED && FLRIGRunning)
	{
		FD_ZERO(&readfs);	
		FD_ZERO(&errorfs);

		FD_SET(PORT->remoteSock,&readfs);
		FD_SET(PORT->remoteSock,&errorfs);
		
		timeout.tv_sec = 5;
		timeout.tv_usec = 0;
		
		ret = select((int)PORT->remoteSock + 1, &readfs, NULL, &errorfs, &timeout);

		if (FLRIGRunning == 0)
			return;

		if (ret == SOCKET_ERROR)
		{
			Debugprintf("FLRIG Select failed %d ", WSAGetLastError());
			goto Lost;
		}

		if (ret > 0)
		{
			//	See what happened

			if (FD_ISSET(PORT->remoteSock, &readfs))
			{
				FLRIGProcessMessage(PORT);
			}

			if (FD_ISSET(PORT->remoteSock, &errorfs))
			{
Lost:	
				sprintf(Msg, "FLRIG Connection lost for Port %s\r\n", PORT->IOBASE);
				WritetoConsole(Msg);

				PORT->CONNECTED = FALSE;
				PORT->Alerted = FALSE;
				PORT->hDevice = 0;				// simplifies check code

				closesocket(PORT->remoteSock);
				PORT->remoteSock = 0;
				return;
			}
			continue;
		}
		else
		{
		}
	}
	sprintf(Msg, "FLRIG Thread Terminated Port %s\r\n", PORT->IOBASE);
	WritetoConsole(Msg);
}




// HID Support Code

int HID_Read_Block(struct RIGPORTINFO * PORT)
{
	int Len;
	unsigned char Msg[65] = "";

	if (PORT->RXLen > 400)
		PORT->RXLen = 0;

	// Don't try to read more than 64

#ifdef WIN32
	Len = rawhid_recv(0, Msg, 64, 100);
#else
	Len = read(PORT->hDevice, Msg, 64);
#endif

	if (Len <= 0)
		return 0;

	// First byte is actual length

	Len = Msg[0];

	if (Len > 0)
	{
		if (Len < 64)		// Max in HID Packet
		{
			memcpy(&PORT->RXBuffer[PORT->RXLen], Msg + 1, Len);
			return Len;
		}
	}
	return 0;
}

void rawhid_close(int num);

BOOL HID_Write_Block(struct RIGPORTINFO * PORT)
{
	int n = PORT->TXLen;
	UCHAR * ptr = PORT->TXBuffer;
	UCHAR Msg[64] = "";
	int ret, i;

	while (n)
	{
		i = n;
		if (i > 63)
			i = 63;

		Msg[0] = i;		// Length on front
		memcpy(&Msg[1], ptr, i);
		ptr += i;
		n -= i;
		//	n = hid_write(PORT->hDevice, PORT->TXBuffer, PORT->TXLen);
#ifdef WIN32
		ret = rawhid_send(0, Msg, 64, 100);		// Always send 64

		if (ret < 0)
		{
			Debugprintf("Rigcontrol HID Write Failed %d", errno);
			rawhid_close(0);
			PORT->hDevice = NULL;
			return FALSE;
		}
#else
		ret = write(PORT->hDevice, Msg, 64);

		if (ret != 64)
		{
			printf ("Write to %s failed, n=%d, errno=%d\n", PORT->HIDDevice, ret, errno);
			close (PORT->hDevice);
			PORT->hDevice = 0;
			return FALSE;
		}

//		printf("HID Write %d\n", i);
#endif
	}
	return TRUE;
}


BOOL OpenHIDPort(struct RIGPORTINFO * PORT, VOID * Port, int Speed)
{
#ifdef WIN32

	if (PORT->HIDDevice== NULL)
		return FALSE;

	PORT->hDevice = rawhid_open(PORT->HIDDevice);

	if (PORT->hDevice)
		Debugprintf("Rigcontrol HID Device %s opened", PORT->HIDDevice);

	/*
	handle = hid_open_path(PORT->HIDDevice);

	if (handle)
	hid_set_nonblocking(handle, 1);

	PORT->hDevice = handle;
	*/
#else
	int fd;
	unsigned int param = 1;

	if (PORT->HIDDevice== NULL)
		return FALSE;

	fd = open (PORT->HIDDevice, O_RDWR);
		
	if (fd == -1)
	{
          printf ("Could not open %s, errno=%d\n", PORT->HIDDevice, errno);
          return FALSE;
	}

	ioctl(fd, FIONBIO, &param);
	printf("Rigcontrol HID Device %s opened", PORT->HIDDevice);
	
	PORT->hDevice = fd;
#endif
	if (PORT->hDevice == 0)
		return (FALSE);

	return TRUE;
}


void CM108_set_ptt(struct RIGINFO *RIG, int PTTState)
{
	char io[5];
	hid_device *handle;
	int n;

	io[0] = 0;
	io[1] = 0;
	io[2] = 1 << (3 - 1);
	io[3] = PTTState << (3 - 1);
	io[4] = 0;

	if (RIG->CM108Device == NULL)
		return;

#ifdef WIN32
	handle = hid_open_path(RIG->CM108Device);

	if (!handle) {
		printf("unable to open device\n");
 		return;
	}

	n = hid_write(handle, io, 5);
	if (n < 0)
	{
		Debugprintf("Unable to write()\n");
		Debugprintf("Error: %ls\n", hid_error(RIG->PORT->hDevice));
	}
	
	hid_close(handle);

#else

	int fd;

	fd = open (RIG->CM108Device, O_WRONLY);
	
	if (fd == -1)
	{
          printf ("Could not open %s for write, errno=%d\n", RIG->CM108Device, errno);
          return;
	}
	
	io[0] = 0;
	io[1] = 0;
	io[2] = 1 << (3 - 1);
	io[3] = PTTState << (3 - 1);
	io[4] = 0;

	n = write (fd, io, 5);
	if (n != 5)
	{
		printf ("Write to %s failed, n=%d, errno=%d\n", RIG->CM108Device, n, errno);
	}
	
	close (fd);
#endif
	return;

}

/*
int CRow;

HANDLE hComPort, hSpeed, hRigType, hButton, hAddr, hLabel, hTimes, hFreqs, hBPQPort;

VOID CreateRigConfigLine(HWND hDlg, struct RIGPORTINFO * PORT, struct RIGINFO * RIG)
{
	char Port[10];

	hButton =  CreateWindow(WC_BUTTON , "", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_TABSTOP,
					10, CRow+5, 10,10, hDlg, NULL, hInstance, NULL);

	if (PORT->PortType == ICOM)
	{
		char Addr[10];

		sprintf(Addr, "%X", RIG->RigAddr);

		hAddr =  CreateWindow(WC_EDIT , Addr, WS_CHILD | WS_VISIBLE  | WS_TABSTOP | WS_BORDER,
                 305, CRow, 30,20, hDlg, NULL, hInstance, NULL);

	}
	hLabel =  CreateWindow(WC_EDIT , RIG->RigName, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER,
                 340, CRow, 60,20, hDlg, NULL, hInstance, NULL);

	sprintf(Port, "%d", RIG->PortRecord->PORTCONTROL.PORTNUMBER);
	hBPQPort =  CreateWindow(WC_EDIT , Port, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL,
                 405, CRow, 20, 20, hDlg, NULL, hInstance, NULL);

	hTimes =  CreateWindow(WC_COMBOBOX , "", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | 
                    WS_VSCROLL | WS_TABSTOP,
                 430, CRow, 100,80, hDlg, NULL, hInstance, NULL);

	hFreqs =  CreateWindow(WC_EDIT , RIG->FreqText, WS_CHILD | WS_VISIBLE| WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL,
                 535, CRow, 300, 20, hDlg, NULL, hInstance, NULL);

	SendMessage(hTimes, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "0000:1159");
	SendMessage(hTimes, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "1200:2359");
	SendMessage(hTimes, CB_SETCURSEL, 0, 0);

	CRow += 30;	

}

VOID CreatePortConfigLine(HWND hDlg, struct RIGPORTINFO * PORT)
{	
	char Port[20]; 
	int i;

	hComPort =  CreateWindow(WC_COMBOBOX , "", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | 
                    WS_VSCROLL | WS_TABSTOP,
                 30, CRow, 90, 160, hDlg, NULL, hInstance, NULL);

	for (i = 1; i < 256; i++)
	{
		sprintf(Port, "COM%d", i);
		SendMessage(hComPort, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) Port);
	}

	sprintf(Port, "COM%d", PORT->IOBASE);

	i = SendMessage(hComPort, CB_FINDSTRINGEXACT, 0,(LPARAM) Port);

	SendMessage(hComPort, CB_SETCURSEL, i, 0);
	
	
	hSpeed =  CreateWindow(WC_COMBOBOX , "", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | 
                    WS_VSCROLL | WS_TABSTOP,
                 120, CRow, 75, 80, hDlg, NULL, hInstance, NULL);

	SendMessage(hSpeed, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "1200");
	SendMessage(hSpeed, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "2400");
	SendMessage(hSpeed, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "4800");
	SendMessage(hSpeed, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "9600");
	SendMessage(hSpeed, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "19200");
	SendMessage(hSpeed, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "38400");

	sprintf(Port, "%d", PORT->SPEED);

	i = SendMessage(hSpeed, CB_FINDSTRINGEXACT, 0, (LPARAM)Port);

	SendMessage(hSpeed, CB_SETCURSEL, i, 0);

	hRigType =  CreateWindow(WC_COMBOBOX , "", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP,
                 200, CRow, 100,80, hDlg, NULL, hInstance, NULL);

	SendMessage(hRigType, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "ICOM");
	SendMessage(hRigType, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "YAESU");
	SendMessage(hRigType, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "KENWOOD");

	SendMessage(hRigType, CB_SETCURSEL, PORT->PortType -1, 0);

}

INT_PTR CALLBACK ConfigDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	int Cmd = LOWORD(wParam);

	switch (message)
	{
	case WM_INITDIALOG:
	{
		struct RIGPORTINFO * PORT;
		struct RIGINFO * RIG;
		int i, p;

		CRow = 40;

		for (p = 0; p < NumberofPorts; p++)
		{
			PORT = PORTInfo[p];

			CreatePortConfigLine(hDlg, PORT);
		
			for (i=0; i < PORT->ConfiguredRigs; i++)
			{
				RIG = &PORT->Rigs[i];
				CreateRigConfigLine(hDlg, PORT, RIG);
			}
		}



//	 CreateWindow(WC_STATIC , "",  WS_CHILD | WS_VISIBLE,
//                 90, Row, 40,20, hDlg, NULL, hInstance, NULL);
	
//	 CreateWindow(WC_STATIC , "",  WS_CHILD | WS_VISIBLE,
//                 135, Row, 100,20, hDlg, NULL, hInstance, NULL);

return TRUE; 
	}

	case WM_SIZING:
	{
		return TRUE;
	}

	case WM_ACTIVATE:

//		SendDlgItemMessage(hDlg, IDC_MESSAGE, EM_SETSEL, -1, 0);

		break;


	case WM_COMMAND:

		if (Cmd == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}

		return (INT_PTR)TRUE;

		break;
	}
	return (INT_PTR)FALSE;
}

*/

#ifdef WIN32

/* Simple Raw HID functions for Windows - for use with Teensy RawHID example
 * http://www.pjrc.com/teensy/rawhid.html
 * Copyright (c) 2009 PJRC.COM, LLC
 *
 *  rawhid_open - open 1 or more devices
 *  rawhid_recv - receive a packet
 *  rawhid_send - send a packet
 *  rawhid_close - close a device
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above description, website URL and copyright notice and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * Version 1.0: Initial Release
 */

#include <stdio.h>
#include <stdlib.h>
//
//#include <windows.h>
#include <setupapi.h>
//#include <ddk/hidsdi.h>
//#include <ddk/hidclass.h>

typedef USHORT USAGE;


typedef struct _HIDD_CONFIGURATION {
	PVOID cookie;
 	ULONG size;
	ULONG RingBufferSize;
} HIDD_CONFIGURATION, *PHIDD_CONFIGURATION;

typedef struct _HIDD_ATTRIBUTES {
	ULONG Size;
	USHORT VendorID;
	USHORT ProductID;
	USHORT VersionNumber;
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;


typedef struct _HIDP_CAPS {
  USAGE  Usage;
  USAGE  UsagePage;
  USHORT  InputReportByteLength;
  USHORT  OutputReportByteLength;
  USHORT  FeatureReportByteLength;
  USHORT  Reserved[17];
  USHORT  NumberLinkCollectionNodes;
  USHORT  NumberInputButtonCaps;
  USHORT  NumberInputValueCaps;
  USHORT  NumberInputDataIndices;
  USHORT  NumberOutputButtonCaps;
  USHORT  NumberOutputValueCaps;
  USHORT  NumberOutputDataIndices;
  USHORT  NumberFeatureButtonCaps;
  USHORT  NumberFeatureValueCaps;
  USHORT  NumberFeatureDataIndices;
} HIDP_CAPS, *PHIDP_CAPS;


typedef struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA;



// a list of all opened HID devices, so the caller can
// simply refer to them by number
typedef struct hid_struct hid_t;
static hid_t *first_hid = NULL;
static hid_t *last_hid = NULL;
struct hid_struct {
	HANDLE handle;
	int open;
	struct hid_struct *prev;
	struct hid_struct *next;
};
static HANDLE rx_event=NULL;
static HANDLE tx_event=NULL;
static CRITICAL_SECTION rx_mutex;
static CRITICAL_SECTION tx_mutex;


// private functions, not intended to be used from outside this file
static void add_hid(hid_t *h);
static hid_t * get_hid(int num);
static void free_all_hid(void);
void print_win32_err(void);




//  rawhid_recv - receive a packet
//    Inputs:
//	num = device to receive from (zero based)
//	buf = buffer to receive packet
//	len = buffer's size
//	timeout = time to wait, in milliseconds
//    Output:
//	number of bytes received, or -1 on error
//
int rawhid_recv(int num, void *buf, int len, int timeout)
{
	hid_t *hid;
	unsigned char tmpbuf[516];
	OVERLAPPED ov;
	DWORD r;
	int n;

	if (sizeof(tmpbuf) < len + 1) return -1;
	hid = get_hid(num);
	if (!hid || !hid->open) return -1;
	EnterCriticalSection(&rx_mutex);
	ResetEvent(&rx_event);
	memset(&ov, 0, sizeof(ov));
	ov.hEvent = rx_event;
	if (!ReadFile(hid->handle, tmpbuf, len + 1, NULL, &ov)) {
		if (GetLastError() != ERROR_IO_PENDING) goto return_error;
		r = WaitForSingleObject(rx_event, timeout);
		if (r == WAIT_TIMEOUT) goto return_timeout;
		if (r != WAIT_OBJECT_0) goto return_error;
	}
	if (!GetOverlappedResult(hid->handle, &ov, &n, FALSE)) goto return_error;
	LeaveCriticalSection(&rx_mutex);
	if (n <= 0) return -1;
	n--;
	if (n > len) n = len;
	memcpy(buf, tmpbuf + 1, n);
	return n;
return_timeout:
	CancelIo(hid->handle);
	LeaveCriticalSection(&rx_mutex);
	return 0;
return_error:
	print_win32_err();
	LeaveCriticalSection(&rx_mutex);
	return -1;
}

//  rawhid_send - send a packet
//    Inputs:
//	num = device to transmit to (zero based)
//	buf = buffer containing packet to send
//	len = number of bytes to transmit
//	timeout = time to wait, in milliseconds
//    Output:
//	number of bytes sent, or -1 on error
//
int rawhid_send(int num, void *buf, int len, int timeout)
{
	hid_t *hid;
	unsigned char tmpbuf[516];
	OVERLAPPED ov;
	DWORD n, r;

	if (sizeof(tmpbuf) < len + 1) return -1;
	hid = get_hid(num);
	if (!hid || !hid->open) return -1;
	EnterCriticalSection(&tx_mutex);
	ResetEvent(&tx_event);
	memset(&ov, 0, sizeof(ov));
	ov.hEvent = tx_event;
	tmpbuf[0] = 0;
	memcpy(tmpbuf + 1, buf, len);
	if (!WriteFile(hid->handle, tmpbuf, len + 1, NULL, &ov)) {
		if (GetLastError() != ERROR_IO_PENDING) goto return_error;
		r = WaitForSingleObject(tx_event, timeout);
		if (r == WAIT_TIMEOUT) goto return_timeout;
		if (r != WAIT_OBJECT_0) goto return_error;
	}
	if (!GetOverlappedResult(hid->handle, &ov, &n, FALSE)) goto return_error;
	LeaveCriticalSection(&tx_mutex);
	if (n <= 0) return -1;
	return n - 1;
return_timeout:
	CancelIo(hid->handle);
	LeaveCriticalSection(&tx_mutex);
	return 0;
return_error:
	print_win32_err();
	LeaveCriticalSection(&tx_mutex);
	return -1;
}

HANDLE rawhid_open(char * Device)
{
	DWORD index=0;
	HANDLE h;
	hid_t *hid;
	int count=0;

	if (first_hid) free_all_hid();

	if (!rx_event)
	{
		rx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
		tx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
		InitializeCriticalSection(&rx_mutex);
		InitializeCriticalSection(&tx_mutex);
	}
	h = CreateFile(Device, GENERIC_READ|GENERIC_WRITE,
		FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
		OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

	if (h == INVALID_HANDLE_VALUE) 
		return 0;

	hid = (struct hid_struct *)malloc(sizeof(struct hid_struct));
	if (!hid)
	{
		CloseHandle(h);
		return 0;
	}
	hid->handle = h;
	hid->open = 1;
	add_hid(hid);

	return h;
}


//  rawhid_close - close a device
//
//    Inputs:
//	num = device to close (zero based)
//    Output
//	(nothing)
//
void rawhid_close(int num)
{
	hid_t *hid;

	hid = get_hid(num);
	if (!hid || !hid->open) return;

	CloseHandle(hid->handle);
	hid->handle = NULL;
	hid->open = FALSE;
}




static void add_hid(hid_t *h)
{
	if (!first_hid || !last_hid) {
		first_hid = last_hid = h;
		h->next = h->prev = NULL;
		return;
	}
	last_hid->next = h;
	h->prev = last_hid;
	h->next = NULL;
	last_hid = h;
}


static hid_t * get_hid(int num)
{
	hid_t *p;
	for (p = first_hid; p && num > 0; p = p->next, num--) ;
	return p;
}


static void free_all_hid(void)
{
	hid_t *p, *q;

	for (p = first_hid; p; p = p->next)
	{
		CloseHandle(p->handle);
		p->handle = NULL;
		p->open = FALSE;
	}
	p = first_hid;
	while (p) {
		q = p;
		p = p->next;
		free(q);
	}
	first_hid = last_hid = NULL;
}



void print_win32_err(void)
{
	char buf[256];
	DWORD err;

	err = GetLastError();
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
		0, buf, sizeof(buf), NULL);
	Debugprintf("err %ld: %s\n", err, buf);
}

#endif

// RTL_SDR support code

char RTLModes[5][6] = {"FM",  "AM", "USB", "LSB", "????"};


void CheckAndProcessRTLUDP(struct RIGPORTINFO * PORT)
{
	int Length;
	struct sockaddr_in rxaddr;
	int addrlen = sizeof(struct sockaddr_in);
	int Freq;
	unsigned char RXBuffer[16];

	struct RIGINFO * RIG = &PORT->Rigs[0];

	Length = recvfrom(PORT->remoteSock, RXBuffer, 16, 0, (struct sockaddr *)&rxaddr, &addrlen);

	if (Length == 6)
	{
		long long MHz, Hz;
		char CharMHz[16] = "";
		char CharHz[16] = "";
		int i;
		int Mode;

		PORT->Timeout = 0;
		RIG->RIGOK = TRUE;

		Freq = (RXBuffer[4] << 24) + (RXBuffer[3] << 16) + (RXBuffer[2] << 8) + RXBuffer[1];
		Mode = RXBuffer[5]; 

		Freq += RIG->rxOffset;

		RIG->RigFreq = Freq / 1000000.0;

		// If we convert to float to display we get rounding errors, so convert to MHz and Hz to display

		MHz = Freq / 1000000;

		Hz = Freq - MHz * 1000000;

		sprintf(CharMHz, "%lld", MHz);
		sprintf(CharHz, "%06lld", Hz);

		for (i = 5; i > 2; i--)
		{
			if (CharHz[i] == '0')
				CharHz[i] = 0;
			else
				break;
		}

		sprintf(RIG->WEB_FREQ,"%lld.%s", MHz, CharHz);
		SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
		strcpy(RIG->Valchar, RIG->WEB_FREQ);

		sprintf(RIG->WEB_MODE,"%s", RTLModes[Mode]);

		strcpy(RIG->ModeString, Modes[Mode]);
			SetWindowText(RIG->hMODE, RIG->WEB_MODE);

	}
}

VOID RTLUDPPoll(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;
	struct RIGINFO * RIG = &PORT->Rigs[0];		// Only one on HAMLIB
	char cmd[80];
	int len;

	if (RIG->ScanStopped == 0)
		if (RIG->ScanCounter)
			RIG->ScanCounter--;

	if (PORT->Timeout)
	{
		PORT->Timeout--;
		
		if (PORT->Timeout)			// Still waiting
			return;

		SetWindowText(RIG->hFREQ, "------------------");
		SetWindowText(RIG->hMODE, "----------");
		strcpy(RIG->WEB_FREQ, "-----------");;
		strcpy(RIG->WEB_MODE, "------");

		RIG->RIGOK = FALSE;
		return;
	}

	// Send Data if avail, else send poll

	if (RIG->NumberofBands && RIG->RIGOK && (RIG->ScanStopped == 0))
	{
		if (RIG->ScanCounter <= 0)
		{
			//	Send Next Freq

			if (GetPermissionToChange(PORT, RIG))
			{
				int n;
				
				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

				memcpy(PORT->TXBuffer, PORT->FreqPtr->Cmd1, PORT->FreqPtr->Cmd1Len);
				PORT->TXLen = PORT->FreqPtr->Cmd1Len;

				_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

				n = sendto(PORT->remoteSock, PORT->TXBuffer, 5,  0, &PORT->remoteDest, sizeof(struct sockaddr));
				
				if (PORT->TXLen == 10)
					n = sendto(PORT->remoteSock, PORT->TXBuffer + 5, 5,  0, &PORT->remoteDest, sizeof(struct sockaddr));

				PORT->TXBuffer[0] = 'P';		// Send Poll
				
				n = sendto(PORT->remoteSock, PORT->TXBuffer, 5,  0, &PORT->remoteDest, sizeof(struct sockaddr));

				PORT->CmdSent = 1;
				PORT->Retries = 0;	
				PORT->Timeout = 0;
				PORT->AutoPoll = TRUE;

				// There isn't a response to a set command, so clear Scan Lock here
			
				ReleasePermission(RIG);			// Release Perrmission
				return;
			}
		}
	}
			
	if (RIG->PollCounter)
	{
		RIG->PollCounter--;
		if (RIG->PollCounter > 1)
			return;
	}

	if (RIG->RIGOK && (RIG->ScanStopped == 0) && RIG->NumberofBands)
		return;						// no point in reading freq if we are about to change it

	RIG->PollCounter = 10;			// Once Per Sec
		
	// Read Frequency 

	cmd[0] = 'P';
	
	len = sendto(PORT->remoteSock, cmd, 5,  0, &PORT->remoteDest, sizeof(struct sockaddr));

	PORT->Timeout = 10;
	PORT->CmdSent = 0;

	PORT->AutoPoll = TRUE;

	return;
}

VOID ConnecttoRTLUDP(struct RIGPORTINFO * PORT)
{
	char Msg[255];
	int i;
	u_long param=1;
	BOOL bcopt=TRUE;
	struct sockaddr_in sinx;

	if (PORT->remoteSock)
	{
		closesocket(PORT->remoteSock);
	}

	PORT->remoteSock = 0;
	PORT->remoteSock = socket(AF_INET,SOCK_DGRAM,0);

	if (PORT->remoteSock == INVALID_SOCKET)
	{
		i=sprintf(Msg, "Socket Failed for RTLUDP socket - error code = %d\r\n", WSAGetLastError());
		WritetoConsole(Msg);

	 	PORT->CONNECTING = FALSE;
  	 	return; 
	}

	ioctl(PORT->remoteSock, FIONBIO, &param);

	sinx.sin_family = AF_INET;
	sinx.sin_addr.s_addr = INADDR_ANY;
	sinx.sin_port = 0;

	PORT->CONNECTED = TRUE;
	PORT->hDevice = (HANDLE)1;				// simplifies check code
	PORT->Alerted = TRUE;
}

char * getObjectFromArray(char * Msg);	// This gets the next object from an array ({} = object, [] = array



char * getArrayFromMsg(char * Msg)
{
	// This gets the next object from an array ({} = object, [] = array
	// We look for the end of the object same number of { and }, teminate after } and return pointer to next object
	// So we have terminated Msg, and returned next object in array

	// Only call if Msg is the next array in Msg


	char * ptr = Msg;
	char c;

	int Open = 0;
	int Close = 0;
		
	while (c = *(ptr++))
	{
		if (c == '[') Open ++; else if (c == ']') Close ++;

		if (Open == Close)
		{
			*(ptr++) = 0;
			return ptr;
		}
	}
	return 0;
}


//----- G7TAJ -----

void ProcessSDRANGELFrame(struct RIGPORTINFO * PORT)
{

	int Length;

	char * msg;

	struct RIGINFO * RIG;
	char * ptr, * ptr1, * ptr2, * ptr3, * pos;
	char cmd[80];
	int chunklength;
	int headerlen;
	int i, n = 0;
	char * Sets;
	char * Rest;
	char * Set;
	int channelcount;
	char * channels;
	char * channel;
	char * samplingDevice;
	char * save;
  
	//Debugprintf("Process SDRANGEL Frame %d\n", PORT->RXLen);

	msg = PORT->RXBuffer;
	Length = PORT->RXLen;

	msg[Length] = 0;

	ptr1 = strstr(msg, "Transfer-Encoding: chunked" );

	if (ptr1 == NULL)
		return;

	ptr2 = strstr(ptr1, "\r\n\r\n");

	if (ptr2 == NULL)
		return;

	// ptr2 +4 points to the length of the first chunk (in hex), terminated by crlf

	chunklength = (int)strtol(ptr2 + 4, &ptr3, 16); 
	ptr3 += 2;		// pointer to first chunk data
	headerlen = ptr3 - msg;

	// make sure we have first chunk

	if (chunklength + headerlen > Length)
		return;

	PORT->RXLen = 0; //we have all the frame now
	PORT->Timeout = 0;

	if (strstr(ptr3, "deviceSets") == 0)
	{
		return;
	}

	// Message has info for all rigs

	// As we mess with the message, save a copy and restore for each Rig

	save = _strdup(ptr3);

	for (i = 0; i < PORT->ConfiguredRigs; i++)
	{
		strcpy(ptr3, save);
		n = 0;

		RIG = &PORT->Rigs[i];	
		RIG->RIGOK = 1;

		// we can have one or more sampling devices (eg rltsdr) each with one or
		// more channels (eg ssb demod, ssb mod). each set of sampling device = channel(s) is a device set.

		// Find Device Set for this device (in RIG->

		// Message Structure is

		//{
		//	"deviceSets": [...].
		//	"devicesetcount": 2,
		//	"devicesetfocus": 0
		//}

		// Get the device sets (JSON [..] is an array

		Sets = strchr(ptr3, '[');

		if (Sets == 0)
			continue;

		Rest = getArrayFromMsg(Sets);

		// Do we need to check devicesetcount ??. Maybe use to loop through sets, or just stop at end

		// get the set for our device

		while (RIG->RigAddr >= n)
		{
			Set = strchr(Sets, '{');		// Position to start of first Object

			if (Set == 0)
				break;

			Sets = getObjectFromArray(Set);
			n++;
		}

		if (Set == 0)
			continue;


		// Now get the channel. looking for key "index": 

		// we could have a number of sampling devices and channels but for now get sampling device freq
		// and first channel freq. Channels are in an Array

		if ((ptr = strstr(Set, "channelcount")) == 0)
			continue;
	
		channelcount = atoi(&ptr[15]);
		
		if ((channels = strchr(Set, '[')) == 0)
			continue;

		samplingDevice = getArrayFromMsg(channels);

		while(channelcount--)
		{
			channel = strchr(channels, '{');
			channels = getObjectFromArray(channel);

			if ((ptr = strstr(channel, "index")))
			{
				n = atoi(&ptr[7]);
				if (n == RIG->Channel)
					break;
			}
		}



		if (pos = strstr(samplingDevice, "centerFrequency")) 	//"centerFrequency": 10489630000,
		{
			pos += 18;
			strncpy(cmd, pos, 20);
			RIG->RigFreq = atof(cmd) / 1000000.0;
		}

		if (pos = strstr(channel, "deltaFrequency")) 
		{
			pos += 17;
			strncpy(cmd, pos, 20);
			RIG->RigFreq += (atof(cmd) + RIG->rxOffset) / 1000000.0;;
		}


		_gcvt(RIG->RigFreq, 9, RIG->Valchar);

		sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
		SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);

		// we could get mode from Title line:
		//"title": "SSB Demodulator",

		if (pos = strstr(channel, "title")) 	
		{
			pos += 9;
			strncpy(cmd, pos, 20);
			strlop(pos, ' ');
			strncpy(RIG->ModeString, pos, 15);
			sprintf(RIG->WEB_MODE, "%s", RIG->ModeString);
			SetWindowText(RIG->hMODE, RIG->WEB_MODE);
		}

	}


	/*
	while (msg && msg[0])
	{
	rest = strlop(msg, ',');

	if ( pos = strstr(msg, "centerFrequency")) 	//"centerFrequency": 10489630000,
	{
	pos += 18;
	strncpy(cmd, pos,20);

	RIG->RigFreq = atof(cmd) / 1000000.0;

	//					printf("FREQ=%f\t%s\n", RIG->RigFreq, cmd);

	_gcvt(RIG->RigFreq, 9, RIG->Valchar);

	sprintf(RIG->WEB_FREQ,"%s", RIG->Valchar);
	SetWindowText(RIG->hFREQ, RIG->WEB_FREQ);
	}

	else if (memcmp(msg, "Mode:", 5) == 0)
	{
	if (strlen(&msg[6]) < 15)
	strcpy(RIG->ModeString, &msg[6]);
	}

	else if (memcmp(msg, "Passband:", 9) == 0)
	{
	RIG->Passband = atoi(&msg[10]);
	sprintf(RIG->WEB_MODE, "%s/%d", RIG->ModeString, RIG->Passband);
	SetWindowText(RIG->hMODE, RIG->WEB_MODE);
	}

	msg = rest;
	}
	*/
	free (save);
}



VOID SDRANGELThread(VOID * Param);

VOID ConnecttoSDRANGEL(struct RIGPORTINFO * PORT)
{
	if (SDRANGELRunning)
		_beginthread(SDRANGELThread, 0, (void *)PORT);
	return ;
}

VOID SDRANGELThread(VOID * Param)
{
	// Opens sockets and looks for data

	struct RIGPORTINFO * PORT = (struct RIGPORTINFO *)Param;
	char Msg[512];
	int err, i, ret;
	u_long param=1;
	BOOL bcopt=TRUE;
	fd_set readfs;
	fd_set errorfs;
	struct timeval timeout;

	if (PORT->CONNECTING)
		return;

	PORT->RXLen = 0;

	PORT->CONNECTING = 1;

	if (PORT->remoteSock)
	{
		closesocket(PORT->remoteSock);
	}

	PORT->remoteSock = 0;
	PORT->remoteSock = socket(AF_INET,SOCK_STREAM,0);

	if (PORT->remoteSock == INVALID_SOCKET)
	{
		i=sprintf(Msg, "Socket Failed for SDRAngel socket - error code = %d\r\n", WSAGetLastError());
		WritetoConsole(Msg);

	 	PORT->CONNECTING = FALSE;
  	 	return;
	}

	setsockopt(PORT->remoteSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
	setsockopt(PORT->remoteSock, IPPROTO_TCP, TCP_NODELAY, (const char FAR *)&bcopt, 4);

	if (connect(PORT->remoteSock,(LPSOCKADDR) &PORT->remoteDest,sizeof(PORT->remoteDest)) == 0)
	{
		//
		//	Connected successful
		//

		ioctl(PORT->remoteSock, FIONBIO, &param);
	}
	else
	{
		if (PORT->Alerted == FALSE)
		{
			struct sockaddr_in * destaddr = (SOCKADDR_IN * )&PORT->remoteDest;

			err = WSAGetLastError();

   			sprintf(Msg, "Connect Failed for SDRAngel socket - error code = %d Port %d\r\n",
				err, htons(destaddr->sin_port));

			WritetoConsole(Msg);
				PORT->Alerted = TRUE;
		}

		closesocket(PORT->remoteSock);

		PORT->remoteSock = 0;
	 	PORT->CONNECTING = FALSE;
		return;
	}

	PORT->CONNECTED = TRUE;
	PORT->CONNECTING = 0;

	PORT->hDevice = (HANDLE)1;				// simplifies check code

	PORT->Alerted = TRUE;

	while (PORT->CONNECTED && SDRANGELRunning)
	{
		FD_ZERO(&readfs);
		FD_ZERO(&errorfs);

		FD_SET(PORT->remoteSock,&readfs);
		FD_SET(PORT->remoteSock,&errorfs);

		timeout.tv_sec = 5;
		timeout.tv_usec = 0;

		ret = select((int)PORT->remoteSock + 1, &readfs, NULL, &errorfs, &timeout);

		if (SDRANGELRunning == 0)
			return;

		if (ret == SOCKET_ERROR)
		{
			Debugprintf("SDRAngel Select failed %d ", WSAGetLastError());
			goto Lost;
		}

		if (ret > 0)
		{
			//	See what happened

			if (FD_ISSET(PORT->remoteSock, &readfs))
			{
				SDRANGELProcessMessage(PORT);
			}

			if (FD_ISSET(PORT->remoteSock, &errorfs))
			{
Lost:	
				sprintf(Msg, "SDRAngel Connection lost for Port %s\r\n", PORT->IOBASE);
				WritetoConsole(Msg);

				PORT->CONNECTED = FALSE;
				PORT->Alerted = FALSE;
				PORT->hDevice = 0;				// simplifies check code

				closesocket(PORT->remoteSock);
				PORT->remoteSock = 0;
				return;
			}
			continue;
		}
		else
		{
		}
	}
	sprintf(Msg, "SDRAngel Thread Terminated Port %s\r\n", PORT->IOBASE);
	WritetoConsole(Msg);
}

/*
# 10489630000

CURL_DATA='{
    "deviceHwType": "RTLSDR",
    "direction": 0,
    "rtlSdrSettings": {
       "centerFrequency": "'$1'"
     }

}';


curl -X PATCH "http://127.0.0.1:8091/sdrangel/deviceset/0/device/settings" \
     -H  "accept: application/json" \
     -H  "Content-Type: application/json" \
     -d "$CURL_DATA"









*/


VOID SDRANGELPoll(struct RIGPORTINFO * PORT)
{
	UCHAR * Poll = PORT->TXBuffer;

	// SDRAngel can have muliple rigs but we only need to poll once to get info for all rigs so just use first entry

	struct RIGINFO * RIG = &PORT->Rigs[0];
	int Len, i;
	char SendBuff[256];
	//char * SDRANGEL_GETheader = "GET /sdrangel/deviceset/%d/device/settings "
	//			   "HTTP/1.1\nHost: %s\nConnection: keep-alive\n\r\n";

	char * SDRANGEL_GETheader = "GET /sdrangel/devicesets "
				   "HTTP/1.1\nHost: %s\nConnection: keep-alive\n\r\n";


	if (RIG->ScanStopped == 0)
		if (RIG->ScanCounter)
			RIG->ScanCounter--;

	if (PORT->Timeout)
	{
		PORT->Timeout--;

		if (PORT->Timeout)			// Still waiting
			return;

		// Loop through all Rigs

		for (i = 0; i <	PORT->ConfiguredRigs; i++)
		{
			RIG = &PORT->Rigs[i];

			SetWindowText(RIG->hFREQ, "------------------");
			SetWindowText(RIG->hMODE, "----------");
			strcpy(RIG->WEB_FREQ, "-----------");;
			strcpy(RIG->WEB_MODE, "------");
	
			RIG->RIGOK = FALSE;
		}
		return;
	}

	// Send Data if avail, else send poll

	if (RIG->NumberofBands && RIG->RIGOK && (RIG->ScanStopped == 0))
	{
		if (RIG->ScanCounter <= 0)
		{
			//	Send Next Freq

			if (GetPermissionToChange(PORT, RIG))
			{
				char cmd[80];

				if (RIG->RIG_DEBUG)
					Debugprintf("BPQ32 Change Freq to %9.4f", PORT->FreqPtr->Freq);

				_gcvt(PORT->FreqPtr->Freq / 1000000.0, 9, RIG->Valchar); // For MH

				// Send the Set Freq here, send set mode when we get a response

				memcpy(&PORT->ScanEntry, PORT->FreqPtr, sizeof(struct ScanEntry));

//TODO
				sprintf(cmd, "%.0f", PORT->FreqPtr->Freq);
				SDRANGELSendCommand(PORT, "SETFREQ", cmd);


				PORT->CmdSent = 1;
				PORT->Retries = 0;
				PORT->Timeout = 10;
				PORT->AutoPoll = TRUE;

				// There isn't a response to a set command, so clear Scan Lock here
				ReleasePermission(RIG);			// Release Perrmission
				return;
			}
		}
	}

	if (RIG->PollCounter)
	{
		RIG->PollCounter--;
		if (RIG->PollCounter > 1)
			return;
	}

	if (RIG->RIGOK && (RIG->ScanStopped == 0) && RIG->NumberofBands)
		return;						// no point in reading freq if we are about to change it

	RIG->PollCounter = 40;	

	// Read Frequency
//TODO


//	Len = sprintf(SendBuff, SDRANGEL_GETheader, 0, &PORT->remoteDest );  // devicenum, host:port
	Len = sprintf(SendBuff, SDRANGEL_GETheader, &PORT->remoteDest );  // devicenum, host:port

	if (PORT->CONNECTED)
	{
		if (send(PORT->remoteSock, SendBuff, Len, 0) != Len)
		{
			if (PORT->remoteSock)
				closesocket(PORT->remoteSock);

			PORT->remoteSock = 0;
			PORT->CONNECTED = FALSE;
			PORT->hDevice = 0;
			return;
		}
	}

	PORT->Timeout = 10;
	PORT->CmdSent = 0;

	PORT->AutoPoll = TRUE;

	return;
}

VOID SDRANGELSendCommand(struct RIGPORTINFO * PORT, char * Command, char * Value)
{
	int Len, ret;
	char SendBuff[512];
	char ValueString[256] ="";
	char * SDRANGEL_PATCHheader = "PATCH /sdrangel/deviceset/%d/device/settings "
 				     "HTTP/1.1\nHost: %s\n"
				     "accept: application/json\n"
				     "Content-Type: application/json\n"
				     "Connection: keep-alive\n"
				     "Content-length: %d\r\n"
				     "\r\n%s";

	if (!PORT->CONNECTED)
		return;

	sprintf(ValueString, SDRANGEL_FREQ_DATA, "RTLSDR", Value);

	Len = sprintf(SendBuff, SDRANGEL_PATCHheader, 0, &PORT->remoteDest, strlen(ValueString), ValueString);

	ret = send(PORT->remoteSock, SendBuff, Len, 0);
	
	if (ret != Len)
	{
		if (PORT->remoteSock)
			closesocket(PORT->remoteSock);

		PORT->remoteSock = 0;
		PORT->CONNECTED = FALSE;
		PORT->hDevice = 0;
	}

	return;
}


void SDRANGELProcessMessage(struct RIGPORTINFO * PORT)
{
	// Called from Background thread

	int InputLen = recv(PORT->remoteSock, &PORT->RXBuffer[PORT->RXLen], 8192 - PORT->RXLen, 0);

	if (InputLen == 0 || InputLen == SOCKET_ERROR)
	{
		if (PORT->remoteSock)
			closesocket(PORT->remoteSock);

		PORT->remoteSock = 0;

		PORT->CONNECTED = FALSE;
		PORT->hDevice = 0;
		return;
	}

	PORT->RXLen += InputLen;
	ProcessSDRANGELFrame(PORT);
}



// ---- G7TAJ ----
