
// Program to Convert RTS changes on Virtual COM Port to hamlib PTT commands


// Version 1. 0. 0. 1 December 2020

// Version 1. 0. 2. 1 April 2018


#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE

#include <windows.h>

#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>	
#include <memory.h>
#include <Psapi.h>

#define LIBCONFIG_STATIC
#include "libconfig.h"


#include "BPQRemotePTTRes.h"

#define BPQICON 400

WSADATA WsaData;            // receives data from WSAStartup

#define WSA_READ WM_USER + 1

HINSTANCE hInst; 
char AppName[] = "BPQRemotePTT";
char Title[80] = "BPQRemotePTT";

TCHAR szTitle[]="GPSMuxPC";						// The title bar text
TCHAR szWindowClass[]="GPSMAINWINDOW";			// the main window class name


// Foward declarations of functions included in this code module:

ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap);
VOID WINAPI txCompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap);
VOID CATThread();
VOID runTimer();

int TimerHandle = 0;

LOGFONT LFTTYFONT ;

HFONT hFont;

struct sockaddr_in sinx; 
struct sockaddr rx;

int addrlen = sizeof(struct sockaddr_in);

int HAMLIBPORT;		// Port Number for HAMLIB (rigctld) Emulator
char * HAMLIBHOST[128];

BOOL MinimizetoTray=FALSE;

VOID __cdecl Debugprintf(const char * format, ...)
{
	char Mess[255];
	va_list(arglist);

	va_start(arglist, format);
	vsprintf(Mess, format, arglist);
	strcat(Mess, "\r\n");

	OutputDebugString(Mess);

	return;
}


char * strlop(char * buf, char delim)
{
	// Terminate buf at delim, and return rest of string

	char * ptr = strchr(buf, delim);

	if (ptr == NULL) return NULL;

	*(ptr)++=0;

	return ptr;
}

char * RigPort = NULL;
char * RigSpeed = NULL;
HANDLE RigHandle = 0;
int RigType = 0;			// Flag for possible RTS/DTR


char BPQHostIP[128];

char PTTCATPort[4][16];
HANDLE PTTCATHandle[4];
short HamLibPort[4];
SOCKET HamLibSock[4];				// rigctld socket

HWND comWnd[4];
HWND portWnd[4];
HWND stateWnd[4];
int stateCtl[4];

struct sockaddr_in remoteDest[4];

int RealMux[4];		// BPQ Virtual or Real

int EndPTTCATThread = 0;
	
char ConfigName[256] = "BPQRemotePTT.cfg";

BOOL GetStringValue(config_setting_t * group, char * name, char * value)
{
	const char * str;
	config_setting_t *setting;

	setting = config_setting_get_member (group, name);
	if (setting)
	{
		str =  config_setting_get_string (setting);
		strcpy(value, str);
		return TRUE;
	}
	return FALSE;
}

int GetIntValue(config_setting_t * group, char * name)
{
	config_setting_t *setting;

	setting = config_setting_get_member (group, name);
	if (setting)
		return config_setting_get_int (setting);

	return 0;
}

VOID SaveStringValue(config_setting_t * group, char * name, char * value)
{
	config_setting_t *setting;

	setting = config_setting_add(group, name, CONFIG_TYPE_STRING);
	if (setting)
		config_setting_set_string(setting, value);

}


VOID SaveIntValue(config_setting_t * group, char * name, int value)
{
	config_setting_t *setting;
	
	setting = config_setting_add(group, name, CONFIG_TYPE_INT);
	if(setting)
		config_setting_set_int(setting, value);
}
VOID GetConfig()
{
	config_setting_t *group;
	config_t cfg;

	memset((void *)&cfg, 0, sizeof(config_t));

	config_init(&cfg);

	if(!config_read_file(&cfg, ConfigName))
	{
		fprintf(stderr, "Config read error line %d - %s\n", config_error_line(&cfg), config_error_text(&cfg));
		config_destroy(&cfg);
		return;
	}

	group = config_lookup(&cfg, "main");

	if (group == NULL)
	{
		config_destroy(&cfg);
		return;
	}


	GetStringValue(group, "BPQHostIP", BPQHostIP);
	
	GetStringValue(group, "COM1", PTTCATPort[0]);
	GetStringValue(group, "COM2", PTTCATPort[1]);
	GetStringValue(group, "COM3", PTTCATPort[2]);
	GetStringValue(group, "COM4", PTTCATPort[3]);

	HamLibPort[0] = GetIntValue(group, "HamLibPort1");
	HamLibPort[1] = GetIntValue(group, "HamLibPort2");
	HamLibPort[2] = GetIntValue(group, "HamLibPort3");
	HamLibPort[3] = GetIntValue(group, "HamLibPort4");

	config_destroy(&cfg);
}

VOID SaveConfig()
{
	config_setting_t *root, *group;
	config_t cfg;

	//	Get rid of old config before saving
	
	config_init(&cfg);

	root = config_root_setting(&cfg);

	group = config_setting_add(root, "main", CONFIG_TYPE_GROUP);

	SaveStringValue(group, "BPQHostIP", BPQHostIP);
	
	SaveStringValue(group, "COM1", PTTCATPort[0]);
	SaveStringValue(group, "COM2", PTTCATPort[1]);
	SaveStringValue(group, "COM3", PTTCATPort[2]);
	SaveStringValue(group, "COM4", PTTCATPort[3]);

	SaveIntValue(group, "HamLibPort1", HamLibPort[0]);
	SaveIntValue(group, "HamLibPort2", HamLibPort[1]);
	SaveIntValue(group, "HamLibPort3", HamLibPort[2]);
	SaveIntValue(group, "HamLibPort4", HamLibPort[3]);

	if(!config_write_file(&cfg, ConfigName))
	{
		fprintf(stderr, "Error while writing file.\n");
		config_destroy(&cfg);
		return;
	}

	config_destroy(&cfg);
}




int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	MSG msg;

	if (lpCmdLine[0])
	{
		// Port Name and Speed for Remote CAT

		RigPort = _strdup(lpCmdLine);
		RigSpeed = strlop(RigPort, ':');
	}

	MyRegisterClass(hInstance);

	GetConfig();

	if (!InitInstance(hInstance, nCmdShow))
		return (FALSE);

	// Main message loop:

	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	KillTimer(NULL, TimerHandle);

	return (msg.wParam);
}

//

//
//  FUNCTION: InitApplication(HANDLE)
//
//  PURPOSE: Initializes window data and registers window class 
//
//  COMMENTS:
//
//       In this function, we initialize a window class by filling out a data
//       structure of type WNDCLASS and calling either RegisterClass or 
//       the internal MyRegisterClass.
//

#define BGCOLOUR RGB(236,233,216)
HBRUSH bgBrush;
HBRUSH RedBrush;
HBRUSH GreenBrush;

HWND hWnd;

BOOL InitApplication(HINSTANCE hInstance)
{
	return TRUE;
}

//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   PURPOSE: Saves instance handle and creates main window 
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//

HFONT FAR PASCAL MyCreateFont( void ) 
{ 
    CHOOSEFONT cf; 
    LOGFONT lf; 
    HFONT hfont; 
 
    // Initialize members of the CHOOSEFONT structure.  
 
    cf.lStructSize = sizeof(CHOOSEFONT); 
    cf.hwndOwner = (HWND)NULL; 
    cf.hDC = (HDC)NULL; 
    cf.lpLogFont = &lf; 
    cf.iPointSize = 0; 
    cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY; 
    cf.rgbColors = RGB(0,0,0); 
    cf.lCustData = 0L; 
    cf.lpfnHook = (LPCFHOOKPROC)NULL; 
    cf.lpTemplateName = (LPSTR)NULL; 
    cf.hInstance = (HINSTANCE) NULL; 
    cf.lpszStyle = (LPSTR)NULL; 
    cf.nFontType = SCREEN_FONTTYPE; 
    cf.nSizeMin = 0; 
    cf.nSizeMax = 0; 
 
    // Display the CHOOSEFONT common-dialog box.  
 
    ChooseFont(&cf); 
 
    // Create a logical font based on the user's  
    // selection and return a handle identifying  
    // that font.  
 
    hfont = CreateFontIndirect(cf.lpLogFont); 
    return (hfont); 
}

VOID Rig_PTT(int n, BOOL PTTState)
{

	char Msg[16];
	int Len = sprintf(Msg, "T %d\n", PTTState);

	if (HamLibSock[n])
	{
		send(HamLibSock[n], Msg, Len, 0);

		if (PTTState)
			SetDlgItemText(hWnd, stateCtl[n], "PTT");
		else
			SetDlgItemText(hWnd, stateCtl[n], "");
	}
}



VOID PTTCATThread()
{
	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;
	DWORD EvtMask[4];
	OVERLAPPED Overlapped[4];
	char Port[32];
	int PIndex = 0;
	int HIndex = 0;
	int rc;

	EndPTTCATThread = FALSE;

	while (PIndex < 4 && PTTCATPort[PIndex][0])
	{
		RealMux[HIndex] = 0;

		sprintf(Port, "\\\\.\\pipe\\BPQ%s", PTTCATPort[PIndex]);

		PTTCATHandle[HIndex] = CreateFile(Port, GENERIC_READ | GENERIC_WRITE,
                  0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);

		if (PTTCATHandle[HIndex] == INVALID_HANDLE_VALUE)
		{
			int Err = GetLastError();
//			Consoleprintf("PTTMUX port BPQCOM%s Open failed code %d", RIG->PTTCATPort[PIndex], Err);

			// See if real com port

			sprintf(Port, "\\\\.\\\\%s", PTTCATPort[PIndex]);

			PTTCATHandle[HIndex] = CreateFile(Port, GENERIC_READ | GENERIC_WRITE,
				0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

			RealMux[HIndex] = 1;

			if (PTTCATHandle[HIndex] == INVALID_HANDLE_VALUE)
			{
				int Err = GetLastError();
				PTTCATHandle[HIndex] = 0;
				Debugprintf("PTTMUX port COM%s Open failed code %d", PTTCATPort[PIndex], Err);
			}
			else
			{
				rc = SetCommMask(PTTCATHandle[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 (RealMux[i])
		{
			// Request Interface change notifications

			rc = WaitCommEvent(PTTCATHandle[i], &EvtMask[i], &Overlapped[i]);
			rc = GetLastError();
 
		}
		else
		{
			// Prime a read on each PTTCATHandle

			ReadFile(PTTCATHandle[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(PTTCATHandle[i]);
					CloseHandle(PTTCATHandle[i]);
					PTTCATHandle[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(PTTCATHandle[i], &Overlapped[i], &Length, FALSE);

			if (ret)
			{
				if (RealMux[i])
				{
					// Request Interface change notifications

					DWORD Mask;

					GetCommModemStatus(PTTCATHandle[i], &Mask);

					if (Mask & MS_CTS_ON)
						Rig_PTT(i, TRUE);
					else
						Rig_PTT(i, FALSE);

					memset(&Overlapped[i], 0, sizeof(OVERLAPPED));
					Overlapped[i].hEvent = Event;
					WaitCommEvent(PTTCATHandle[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_PTT(i, TRUE);
								else
									Rig_PTT(i, FALSE);

								CurrentState[i] = c;
								continue;
							}
						}
					}

					memset(&Overlapped[i], 0, sizeof(OVERLAPPED));
					Overlapped[i].hEvent = Event;

					ReadFile(PTTCATHandle[i], Block[i], 80, &Length, &Overlapped[i]);
				}
			}
		}
	}
	EndPTTCATThread = FALSE;
}

char ClassName[]="BPQMAIL";

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASS  wc;

	bgBrush = CreateSolidBrush(BGCOLOUR);
	RedBrush = CreateSolidBrush(RGB(255,0,0));
	GreenBrush = CreateSolidBrush(RGB(0,255,0));
//	BlueBrush = CreateSolidBrush(RGB(0,0,255));

    wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; 
    wc.lpfnWndProc = WndProc;       
                                        
    wc.cbClsExtra = 0;                
    wc.cbWndExtra = DLGWINDOWEXTRA;
	wc.hInstance = hInstance;
    wc.hIcon = NULL; //LoadIcon( hInstance, MAKEINTRESOURCE(IDI_GPSMUXPC));
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = bgBrush; 

	wc.lpszMenuName = NULL;//"MENU_1";	
	wc.lpszClassName = szWindowClass; 

//	RegisterClass(&wc);

 //   wc.lpfnWndProc = TraceWndProc;       
 // 	wc.lpszClassName = TraceClassName;

//	RegisterClass(&wc);

//    wc.lpfnWndProc = ConfigWndProc;       
//  	wc.lpszClassName = ConfigClassName;

	return (RegisterClass(&wc));

}


BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	u_long param=1;
	BOOL bcopt=TRUE;
	int ret;
	WNDCLASS  wc = {0};
	int n = 0;


	hInst = hInstance; // Store instance handle in our global variable

	WSAStartup(MAKEWORD(2, 0), &WsaData);


   hWnd=CreateDialog(hInst,szWindowClass,0,NULL);

  if (!hWnd)
   {
      ret=GetLastError();
	  return FALSE;
   }
		
	// setup default font information

   LFTTYFONT.lfHeight =			12;
   LFTTYFONT.lfWidth =          8 ;
   LFTTYFONT.lfEscapement =     0 ;
   LFTTYFONT.lfOrientation =    0 ;
   LFTTYFONT.lfWeight =         0 ;
   LFTTYFONT.lfItalic =         0 ;
   LFTTYFONT.lfUnderline =      0 ;
   LFTTYFONT.lfStrikeOut =      0 ;
   LFTTYFONT.lfCharSet =        OEM_CHARSET ;
   LFTTYFONT.lfOutPrecision =   OUT_DEFAULT_PRECIS ;
   LFTTYFONT.lfClipPrecision =  CLIP_DEFAULT_PRECIS ;
   LFTTYFONT.lfQuality =        DEFAULT_QUALITY ;
   LFTTYFONT.lfPitchAndFamily = FIXED_PITCH | FF_MODERN ;
   lstrcpy( LFTTYFONT.lfFaceName, "Fixedsys" ) ;

	hFont = CreateFontIndirect(&LFTTYFONT) ;
//	hFont = MyCreateFont();

	SetWindowText(hWnd,Title);

	comWnd[0] = GetDlgItem(hWnd, IDC_COM1);
	comWnd[1] = GetDlgItem(hWnd, IDC_COM2);
	comWnd[2] = GetDlgItem(hWnd, IDC_COM3);
	comWnd[3] = GetDlgItem(hWnd, IDC_COM4);

	portWnd[0] = GetDlgItem(hWnd, IDC_HAMLIBPORT1);
	portWnd[1] = GetDlgItem(hWnd, IDC_HAMLIBPORT2);
	portWnd[2] = GetDlgItem(hWnd, IDC_HAMLIBPORT3);
	portWnd[3] = GetDlgItem(hWnd, IDC_HAMLIBPORT4);

	stateWnd[0] = GetDlgItem(hWnd, IDC_STATE1);
	stateWnd[1] = GetDlgItem(hWnd, IDC_STATE2);
	stateWnd[2] = GetDlgItem(hWnd, IDC_STATE3);
	stateWnd[3] = GetDlgItem(hWnd, IDC_STATE4);


	stateCtl[0] = IDC_STATE1;
	stateCtl[1] = IDC_STATE2;
	stateCtl[2] = IDC_STATE3;
	stateCtl[3] = IDC_STATE4;

	ShowWindow(hWnd, nCmdShow);

	SetDlgItemText(hWnd, IDC_BPQHOST, BPQHostIP);	

	SetDlgItemText(hWnd, IDC_COM1, PTTCATPort[0]);			
	SetDlgItemText(hWnd, IDC_COM2, PTTCATPort[1]);			
	SetDlgItemText(hWnd, IDC_COM3, PTTCATPort[2]);			
	SetDlgItemText(hWnd, IDC_COM4, PTTCATPort[3]);	

	SetDlgItemInt(hWnd, IDC_HAMLIBPORT1, HamLibPort[0], 0);
	SetDlgItemInt(hWnd, IDC_HAMLIBPORT2, HamLibPort[1], 0);
	SetDlgItemInt(hWnd, IDC_HAMLIBPORT3, HamLibPort[2], 0);
	SetDlgItemInt(hWnd, IDC_HAMLIBPORT4, HamLibPort[3], 0);

//	ioctlsocket (sock, FIONBIO, &param);
 
	if (RigPort)
	{
		int Speed = 9600;

		if (RigSpeed)
			Speed = atoi(RigSpeed);
	}

	TimerHandle = SetTimer(hWnd, 1, 10000, NULL);

	runTimer();					// Open Hamlib connections

	_beginthread(PTTCATThread, 0);

	return TRUE;
}

VOID ConnecttoHAMLIB(int n);

VOID runTimer()
{
	int n;

	for (n = 0; n < 4; n++)
	{
		if (HamLibPort[n] && HamLibSock[n] == 0)
		{
			// try to connect

			ConnecttoHAMLIB(n);

		}
	}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;

	switch (message) 
	{ 
	case WM_TIMER:

		runTimer();
		break;

	case WM_CTLCOLOREDIT:
	{
		HDC hdc = (HDC) wParam;   // handle to display context 
		HWND hwnd = (HWND) lParam; // handle to control window
		int n;

		for (n = 0; n < 4; n++)
		{
			if (hwnd == comWnd[n] && PTTCATPort[n][0])
				if (PTTCATHandle[n])
					return (INT_PTR)GreenBrush;
				else
					return (INT_PTR)RedBrush;
				
			if (hwnd == portWnd[n] && HamLibPort[n])
				if (HamLibSock[n])
					return (INT_PTR)GreenBrush;
				else
					return (INT_PTR)RedBrush;
		}

		//return (INT_PTR)RedBrush;

		return (DefWindowProc(hWnd, message, wParam, lParam));
	}

	case WM_SYSCOMMAND:

		wmId    = LOWORD(wParam); // Remember, these are...
		wmEvent = HIWORD(wParam); // ...different for Win32!

		switch (wmId)
		{ 
		case  SC_MINIMIZE: 

			if (MinimizetoTray)

				return ShowWindow(hWnd, SW_HIDE);
			else
				return (DefWindowProc(hWnd, message, wParam, lParam));


			break;


		default:

			return (DefWindowProc(hWnd, message, wParam, lParam));
		}

	case WM_CLOSE:

		PostQuitMessage(0);
		break;

	case WM_COMMAND:

		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);

		switch (wmId)
		{
			int OK;

		case IDC_TEST1:

			Rig_PTT(0, 1);
			Sleep(1500);
			Rig_PTT(0, 0);
			break;

		case IDC_TEST2:

			Rig_PTT(1, 1);
			Sleep(1500);
			Rig_PTT(1, 0);
			break;

		case IDC_TEST3:

			Rig_PTT(2, 1);
			Sleep(1500);
			Rig_PTT(2, 0);
			break;

		case IDC_TEST4:

			Rig_PTT(3, 1);
			Sleep(1500);
			Rig_PTT(3, 0);
			break;

		case IDOK:

			GetDlgItemText(hWnd, IDC_BPQHOST, BPQHostIP, 127);	

			GetDlgItemText(hWnd, IDC_COM1, PTTCATPort[0], 15);			
			GetDlgItemText(hWnd, IDC_COM2, PTTCATPort[1], 15);			
			GetDlgItemText(hWnd, IDC_COM3, PTTCATPort[2], 15);			
			GetDlgItemText(hWnd, IDC_COM4, PTTCATPort[3], 15);	

			HamLibPort[0] = GetDlgItemInt(hWnd, IDC_HAMLIBPORT1, &OK, 0);
			HamLibPort[1] = GetDlgItemInt(hWnd, IDC_HAMLIBPORT2, &OK, 0);
			HamLibPort[2] = GetDlgItemInt(hWnd, IDC_HAMLIBPORT3, &OK, 0);
			HamLibPort[3] = GetDlgItemInt(hWnd, IDC_HAMLIBPORT4, &OK, 0);

			SaveConfig();

	//		EndPTTCATThread = 1;

	//		Sleep(1100);

	//		_beginthread(PTTCATThread, 0);

			break;

		default:
			return (DefWindowProc(hWnd, message, wParam, lParam));
		}
	}

	return (DefWindowProc(hWnd, message, wParam, lParam));

}

void HAMLIBProcessMessage(int n)
{
	char RXBuffer[256];

	int InputLen = recv(HamLibSock[n], RXBuffer, 256, 0);

	if (InputLen == 0 || InputLen == SOCKET_ERROR)
	{
		if (HamLibSock[n])
			closesocket(HamLibSock[n]);
		
		HamLibSock[n] = 0;
		RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);

		return;					
	}
}


VOID HAMLIBThread(int n);

VOID ConnecttoHAMLIB(int n)
{
	_beginthread(HAMLIBThread, 0, n);
	return ;
}

VOID HAMLIBThread(int n)
{
	// Opens sockets and looks for data
	
	char Msg[255];
	int err, i, ret;
	u_long param=1;
	BOOL bcopt=TRUE;
	fd_set readfs;
	fd_set errorfs;
	struct timeval timeout;

	if (HamLibSock[n])
		closesocket(HamLibSock[n]);

		// Param is IPADDR:PORT. Only Allow numeric addresses 
	
	if (HamLibPort[n] == 0)
		return;

	remoteDest[n].sin_family = AF_INET;
	remoteDest[n].sin_addr.s_addr = inet_addr(BPQHostIP);
	remoteDest[n].sin_port = htons(HamLibPort[n]);
	
	HamLibSock[n] = 0;
	HamLibSock[n] = socket(AF_INET,SOCK_STREAM,0);

	if (HamLibSock[n] == INVALID_SOCKET)
	{
		i=sprintf(Msg, "Socket Failed for HAMLIB socket - error code = %d\r\n", WSAGetLastError());
		Debugprintf(Msg);

  	 	return; 
	}

	setsockopt(HamLibSock[n], SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
	setsockopt(HamLibSock[n], IPPROTO_TCP, TCP_NODELAY, (const char FAR *)&bcopt, 4); 

	if (connect(HamLibSock[n],(LPSOCKADDR)&remoteDest[n],sizeof(remoteDest[n])) == 0)
	{
		//
		//	Connected successful
		//
	}
	else
	{
		err=WSAGetLastError();
   		i=sprintf(Msg, "Connect Failed for HAMLIB socket %d - error code = %d\r\n", n, err);
		Debugprintf(Msg);
		
		closesocket(HamLibSock[n]);

		HamLibSock[n] = 0;

		RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);

		return;
	}

	RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);

	ret = GetLastError();

	while (HamLibSock[n])
	{
		FD_ZERO(&readfs);	
		FD_ZERO(&errorfs);

		FD_SET(HamLibSock[n],&readfs);
		FD_SET(HamLibSock[n],&errorfs);
		
		timeout.tv_sec = 60;
		timeout.tv_usec = 0;
		
		ret = select((int)HamLibSock[n] + 1, &readfs, NULL, &errorfs, &timeout);

		if (ret == SOCKET_ERROR)
		{
			Debugprintf("HAMLIB Select failed %d ", WSAGetLastError());
			goto Lost;
		}

		if (ret > 0)
		{
			//	See what happened

			if (FD_ISSET(HamLibSock[n], &readfs))
			{
				HAMLIBProcessMessage(n);
			}

			if (FD_ISSET(HamLibSock[n], &errorfs))
			{
Lost:	
				sprintf(Msg, "HAMLIB Connection lost for Port %d\r\n", n);
				Debugprintf(Msg);

				closesocket(HamLibSock[n]);
				HamLibSock[n] = 0;
				RedrawWindow(hWnd, NULL, NULL, 0);

				return;
			}
			continue;
		}
		else
		{
		}
	}
	sprintf(Msg, "HAMLIB Thread Terminated Port %d\r\n", n);
	Debugprintf(Msg);
}
