//---------------------------------------------------------------------------
/*
Remote Train Control Program for Windows

© Copyright 2019 by Mark DiVecchio

    This file is part of Remote Train Control.

    Remote Train Control 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.

    Remote Train Control 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 Remote Train Control.  If not, see <http://www.gnu.org/licenses/>.

*/
// Home Page : http://www.silogic.com/trains/RTC_Running.html
//---------------------------------------------------------------------------
#include <vcl.h>
#include <tchar.h>
#pragma hdrstop

#include "Message_Popup.h"
#include "Train_Control.h"
#include "Setup_Control.h"
#include "PBFileThread.h"

#include "Debug_Controls.h"
#include "Super_TIU_Mode.h"
#include "TIUSetup.h"
#include "Clipbrd.hpp"
#include "Message_Thread.h"

#if __BORLANDC__ >= 0x720
// Defined for CB10.1 C++ programs that use the VCL.
//#include <stdlib.h>
//#include <stdarg.h>
//#include <stdint.h>
//#include <io.h>
//typedef unsigned int socklen_t;
//#include <stddef.h>
//#include <stdio.h>
//#include <string.h>
//#include <sys/types.h>
//#include <winsock2.h>
#include <ws2ipdef.h>
//#include <process.h>
#else
// else for BCB4.0 C++ programs that use the VCL
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned int socklen_t;
#include <stdio.h>
//#include <winsock.h> 		// was winsock2.h
//#include <winsock2.h>
#endif

// mDNSThread does mDNS requests searching for mDNS servers
#include "mDNSThread.h"
// mDNSServices does mDNS requests searching for mDNS servers AND responds to mDNS requests
#include "mDNSServices.h"

#include <stdio.h>
#include <stdlib.h>
//---------------------------------------------------------------------------
//
// This form must be auto create because information is retained
// only by this form for the communications parameters
//
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "QuitButton"
#pragma link "_GClass"
#pragma link "SyncListBox"
#pragma resource "*.dfm"
TSetup *Setup;

extern bool Ignore_FF_Char;	// used by Comm_Thread.cpp
extern TThread * PBThread;	// pointer to Setup's playback thread
//extern struct AIU_EMU AIUEmulator[TIUMAX];				// Flags to indicate an AIU Emulator is attached to an emulated TIU
//extern struct MSG_DISPLAY MessageDisplay[100];          // Flags to indicate a message display ( 1 - 100 ) is available
extern struct SIGNAL Signals[SIGNALMAX];				// Flags to indicate a Signal was found
extern struct DETECTOR Detector[RFIDMAX];              // Flags to indicate an RFID detector device with up to 2 readers was found

extern bool TIUSelection[TIUMAX];                       // Flags to indicate that a TIU is present
extern bool SuperTIUMode, TIUSuperMode[TIUMAX];         // Flags to indicate if Super TIU Mode is active
extern bool RequestyCommand;       // When true during WIU_WiFi_Mode, generate a 'y' command

// mDNSThread does mDNS requests searching for mDNS servers
TMultiDNS    * ptrMultiDNSThread;				    // pointer to MultiDNS thread
// mDNSServices advertises services and responds to mDNS requests regarding those services handled by RTC
mDNSServices * ptrmDNSServices[MAXINTERFACES];   		// pointer to mDNS Services advertisers
//---------------------------------------------------------------------------
__fastcall TSetup::TSetup(TComponent* Owner)
	: TForm(Owner)
{
assert(false);	// never called since I used the overloaded constructor below
}

//---------------------------------------------------------------------------
__fastcall TSetup::TSetup(TComponent* Owner, int TIU, int Remote)
	: TForm(Owner)
{
// grab the Remote Number, TIU number not needed but here to prevent Stack Overflow
RemoteNo = Remote;
assert(RemoteNo >= 0 && RemoteNo <= REMOTEMAX);

for (int idx = 0 ; idx < MAXINTERFACES ; idx++) {
    ptrmDNSServices[idx] = NULL;		// mDNS server not running
    }
for (int iTIU = 1; iTIU <= TIUMAX ; iTIU++) { // TIU 1-5
    TIUSelection[iTIU-1] = false;
    }
TIUSelection[0] = true;     // always start with TIU 1 set active

// read preferences from the Registry
RegFileRootKey = MainForm->RegFileRootKey;
// read Preferences from registry if they exist
TRegIniFile * const RegFile = new TRegIniFile(RegFileRootKey);
assert(RegFile != NULL);
__try {

    // Radio/WiFi Mode
    // Saved on a per program basis
    RadioCOMPortNum->ValueAsInt = RegFile->ReadInteger("Speed", "COMPort", RadioCOMPortNum->ValueAsInt);
    RFIDCOMPortNum->ValueAsInt = RegFile->ReadInteger("Speed", "RFIDPort", RFIDCOMPortNum->ValueAsInt);

#ifdef OLDWAY
    not used
	// Load the HostIP IP Addresses
	const String HostIPFile = String(MainForm->cStartDir)  + "\\" + "HostIP.ini";
	if (FileExists(HostIPFile)) {
		IPComboBox->Items->LoadFromFile(HostIPFile);
    	// Host IP -  stored by C++ version
        IPComboBox->ItemIndex = RegFile->ReadInteger("Options", "HostIPIndex" + IntToHex(__BORLANDC__, 3), IPComboBox->ItemIndex);
		// maintain ItemIndex == -1 meaning use "All" IP port for Scan
        if (IPComboBox->ItemIndex == -1) {
	    	// Scan for Hosts
    		ScanHostIPButtonClick(NULL);
            }
		} else {
		// Scan for Hosts
		ScanHostIPButtonClick(NULL);
		// maintain ItemIndex == -1 meaning use "All" IP for Scan
        }
#else
	// Scan for Hosts
	ScanHostIPButtonClick(NULL);
	// maintain ItemIndex == -1 meaning use "All" IP for Scan

#endif
    // Saved on a per program basis
    BaudRateSel->ItemIndex = RegFile->ReadInteger("Speed", "Baud", BaudRateSel->ItemIndex);
    ParitySel->ItemIndex = RegFile->ReadInteger("Speed", "Parity", ParitySel->ItemIndex);
    BitsSel->ItemIndex = RegFile->ReadInteger("Speed", "Bits", BitsSel->ItemIndex);
    StopSel->ItemIndex = RegFile->ReadInteger("Speed", "Stop", StopSel->ItemIndex);
	Echo->Checked = RegFile->ReadInteger("Options", "Echo", Echo->Checked);
	Ignore_FF->Checked = RegFile->ReadInteger("Options", "Ignore_FF", Ignore_FF->Checked);
	Hex->Checked = RegFile->ReadInteger("Options", "Hex", Hex->Checked);
	Duplex->Checked = RegFile->ReadInteger("Options", "Duplex", Duplex->Checked);
  	TXOnlyComm->Checked = RegFile->ReadInteger("Options", "TXOnlyComm", TXOnlyComm->Checked);

    //-----------------------------------------
    // Communications Modes - stored in "WiFi" Key in Registry
	AIUIP->Text = RegFile->ReadString("WiFi", "AIUIP", AIUIP->Text); 	// Should be multicast   239.255.200.3
	AIUPort->Text = RegFile->ReadString("WiFi", "AIUPort", AIUPort->Text);
    //-----------------------------------------
    // Communications Modes - stored in "WiFi" Key in Registry
    // RFID Modes - one or both can be checked
	RFID_COM_Mode->Checked = RegFile->ReadInteger("WiFi", "RFID", RFID_COM_Mode->Checked);
	RFID_WiFi_Mode->Checked = RegFile->ReadInteger("WiFi", "RFIDWiFi", RFID_WiFi_Mode->Checked);
        MainForm->ConnectedRFIDLED->Visible = (RFID_COM_Mode->Checked || RFID_WiFi_Mode->Checked);
    // ----------------------------------------
    // AIU WiFi Mode
	AIU_WiFi_Mode->Checked = RegFile->ReadInteger("WiFi", "AIUWiFi", AIU_WiFi_Mode->Checked);
	AIU_WiFi_Multicast->Checked = RegFile->ReadInteger("WiFi", "AIU_Multicast", AIU_WiFi_Multicast->Checked);
    //-----------------------------------------
    // Signals WiFi Mode
	Signals_WiFi_Mode->Checked = RegFile->ReadInteger("WiFi", "SignalsWiFi", Signals_WiFi_Mode->Checked);
    //-----------------------------------------
	// TIU/WTIU Modes - one of the two modes can be selected, not both
	Radio_COM_Mode->Checked = RegFile->ReadInteger("WiFi", "Radio", Radio_COM_Mode->Checked);
	WTIU_WiFi_Mode->Checked = RegFile->ReadInteger("WiFi", "WTIU", WTIU_WiFi_Mode->Checked);
    //-----------------------------------------
    RadioCOMPortNum->Enabled = Radio_COM_Mode->Checked;
    RadioCOMLabel->Enabled = Radio_COM_Mode->Checked;
    //
    WTIULabel->Enabled = WTIU_WiFi_Mode->Checked;
    //
    RFIDCOMPortNum->Enabled = RFID_COM_Mode->Checked;
    RFIDCOMLabel->Enabled = RFID_COM_Mode->Checked;
    //
    RFIDWiFiLabel->Enabled = RFID_WiFi_Mode->Checked;
    RFIDListBox->Enabled = RFID_WiFi_Mode->Checked || RFID_COM_Mode->Checked;
    //-----------------------------------------
    //
	SpareCheckbox->Checked = RegFile->ReadInteger("Options", "SpareCheckbox", SpareCheckbox->Checked);
  	NumRetries->Value = RegFile->ReadInteger("Options", "NumRetries", NumRetries->Value);
    // next adjustment removed trying to get WiFi mode to retry successfully
    //if (NumRetries->Value > 1 ) NumRetries->Value = 1;	// on startup, NumRetries can't be higher than 1
	//													// I've found that additional retries don't help
	// new way to look at  it:
	if (Radio_COM_Mode->Checked) NumRetries->Value = 1; 	// in Radio mode, 1 retry
	if (WTIU_WiFi_Mode->Checked) NumRetries->Value = 2;     // in WiFi mode, 2 retries
	// Other setup
  	AllowZero->Checked = RegFile->ReadInteger("Options", "AllowZero", AllowZero->Checked);
  	BrakeBoost->ItemIndex = RegFile->ReadInteger("Options", "BrakeBoost", BrakeBoost->ItemIndex);
  	AutoCoupler->Checked = RegFile->ReadInteger("Options", "AutoCoupler", AutoCoupler->Checked);
  	MaxSpeed->Value = RegFile->ReadInteger("Options", "MaxSpeed", MaxSpeed->Value);
  	EncodedRecordFormat->Checked = RegFile->ReadInteger("Options", "EncodedRecordFormat", EncodedRecordFormat->Checked);
    MainForm->EncodedRecordFormat = EncodedRecordFormat->Checked;
	MPHScaling->Value = RegFile->ReadInteger("Options", "MPHScaling", MPHScaling->Value);
	MainForm->GlobalMPHScaling = MPHScaling->Value;
  	AutoBell->Checked = RegFile->ReadInteger("Options", "AutoBell", AutoBell->Checked);
  	AutoBellOff->Checked = RegFile->ReadInteger("Options", "AutoBellOff", AutoBellOff->Checked);
    BellOffTime->Value = RegFile->ReadInteger("Options", "BellOffTime", BellOffTime->Value);
  	AutoWhistle->Checked = RegFile->ReadInteger("Options", "AutoWhistle", AutoWhistle->Checked);
  	ExtendedSUSD->Checked = RegFile->ReadInteger("Options", "ExtendedSUSD", ExtendedSUSD->Checked);
  	RepeatPlayback->Checked = RegFile->ReadInteger("Options", "RepeatPlayback", RepeatPlayback->Checked);
  	Speed_Mode->Checked = RegFile->ReadInteger("Options", "Speed_Mode", Speed_Mode->Checked);

//    DropDTRonIdle->Checked = RegFile->ReadInteger("Options", "DropDTRonIdle", DropDTRonIdle->Checked);
//    DropRTSonIdle->Checked = RegFile->ReadInteger("Options", "DropRTSonIdle", DropRTSonIdle->Checked);
//    DTRAlwaysOn->Checked = RegFile->ReadInteger("Options", "DTRAlwaysOn", DTRAlwaysOn->Checked);
  	KeepEngines->Checked = RegFile->ReadInteger("Options", "KeepEngines", KeepEngines->Checked);
  	StandardAccDec->Checked = RegFile->ReadInteger("Options", "StandardAccDec", StandardAccDec->Checked);
  	AutoConnect->Checked = RegFile->ReadInteger("Options", "AutoConnect", AutoConnect->Checked);
  	ShortBellWhistleSequence->Checked = RegFile->ReadInteger("Options", "ShortBellWhistleSequence", ShortBellWhistleSequence->Checked);
  	AutoPFA->Checked = RegFile->ReadInteger("Options", "AutoPFA", AutoPFA->Checked);
  	DisableEmergencyStopButton->Checked = RegFile->ReadInteger("Options", "DisableEmergencyStop", DisableEmergencyStopButton->Checked);
  	AutoHotButtons->Checked = RegFile->ReadInteger("Options", "AutoHotButtons", AutoHotButtons->Checked);
  	AutoQuickControls->Checked = RegFile->ReadInteger("Options", "AutoQuickControls", AutoQuickControls->Checked);
	Allow255Sounds->Checked = RegFile->ReadInteger("Options", "Allow255Sounds", Allow255Sounds->Checked);
  	Safety_Mode->Checked = RegFile->ReadInteger("Options", "Safety_Mode", Safety_Mode->Checked);
  	AutoFindEngines->Checked = RegFile->ReadInteger("Options", "AutoFindEngines", AutoFindEngines->Checked);
  	GeneralSounds->Checked = RegFile->ReadInteger("Options", "GeneralSounds", GeneralSounds->Checked);
  	NoSleep->Checked = RegFile->ReadInteger("Options", "NoSleep", NoSleep->Checked);
  	ShutdownOnRead->Checked = RegFile->ReadInteger("Options", "ShutdownOnRead", ShutdownOnRead->Checked);
  	AutoSoundCtrls->Checked = RegFile->ReadInteger("Options", "AutoSoundCtrls", AutoSoundCtrls->Checked);
  	SmokeOFFatStartup->Checked = RegFile->ReadInteger("Options", "SmokeOFF", SmokeOFFatStartup->Checked);
  	Quick_Ctrl_Scaling->Value = RegFile->ReadInteger("Options", "Quick_Ctrl_Scaling", Quick_Ctrl_Scaling->Value * 10) / 10.0;
    TransparentSpin->Value = RegFile->ReadInteger("Options", "Transparent", TransparentSpin->Value);
    // Super TIU Mode and Active TIU Selection
    // These settings are so we can correctly setup the Super TIU Mode window
    // The TIU remember if they are in Super TIU Mode so they don't need to be intialized at startup
  	SuperTIUMode = RegFile->ReadInteger("Options", "SuperTIUMode", SuperTIUMode);
    for (int iTIU = 1 ; iTIU <= TIUMAX ; iTIU++) {	 // TIU 1-5/8
    	// Super TIU Mode by TIU number
	  	TIUSuperMode[iTIU-1] = RegFile->ReadInteger("Options", "TIU" + String(iTIU) + "SuperMode", TIUSuperMode[iTIU-1]);
        // Active TIU Selection by TIU Number
	  	TIUSelection[iTIU-1] = RegFile->ReadInteger("Options", "TIU" + String(iTIU) + "TIUSelection", TIUSelection[iTIU-1]);
        // AIU Emulator Attached to this TIU number
        //AIUEmulator[iTIU-1].Found = RegFile->ReadInteger("Options", "TIU" + String(iTIU) + "AIUEmulator", AIUEmulator[iTIU-1].Found);
    	}
	}
__finally {
	// Deallocate RegFile
	delete RegFile;
	}

SwitchStraight = "Normal";
SwitchDiverge = "Reverse";

#ifdef NOLONGERNEEDED
// Load the RFID WiFi IP Addresses and Ports
const String WiFiRFIDFile = String(MainForm->cStartDir)  + "\\" + "WiFiRFID.ini";
if (FileExists(WiFiRFIDFile)) {
	RFIDListBox->Clear();
	RFIDListBox->Items->LoadFromFile(WiFiRFIDFile);
    }
#endif

// Find all TIU/WTIU Ports (Serial or WiFi) - done when the WTIU WiFi Enable check box is checked
//ScanTIUWTIUButtonClick(NULL);   // based on the check boxes, load the TIUWTIUListBox with ports

// Load the AIU WiFi IP Addresses and Ports
const String AIURadioFile = String(MainForm->cStartDir)  + "\\" + "WiFiAIU.ini";
if (FileExists(AIURadioFile)) {
	AIUListBox->Clear();
	AIUListBox->Items->LoadFromFile(AIURadioFile);
    }
// in debugging mode, make a few more controls visible
if (DEBUGGING) {
	AIU_WiFi_Multicast->Visible = true;
    AIUEmulatorPortsSetup->TabVisible = true;
    }
//

CommSetupPageControl->ActivePage = TIUPortSetup;

//if ((ModeSelect->ItemIndex == 0)) {
//	// "Wired" selected
//	TIUSelGroup->Caption = "TIU/WTIU for TIU" + String(TIUNo);
//	} else {
    Set_Comment();
//    }
//
//
PBThread = NULL;
DragAcceptFiles (Handle, True);		//  Accept drag and drop from the Explorer
//
// Setup window is always opaque
//
}
//---------------------------------------------------------------------------
__fastcall TSetup::~TSetup(void)
{
// Stop Setup's playback thread
if (PBThread != NULL) {
	PBThread->Terminate();
	PBThread->WaitFor();	// do not use FreeOnTerminate
	delete PBThread;
	PBThread = NULL;	// release the pointer
	}

HideButtonClick(HideButton);   // save settings to Registry
// alternate coding : HideButton->OnClick(HideButton);	// save setting to Registry
//
if (NoSleep->Checked) {
	// This allows the system to sleep normally
	SetThreadExecutionState(ES_CONTINUOUS);
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::HideButtonClick(TObject *Sender)
{
if (SuperTIU) SuperTIU->Hide();	// hide the Super TIU Mode Setup window
if (ActiveTIU) ActiveTIU->Hide();	// hide the Active TIU Selection window

// if we just cleared data, don't save it
if (MainForm->bSaveRegistryInfo) {
    // write preferences to the Registry
    TRegIniFile * const RegFile = new TRegIniFile(RegFileRootKey);
    assert(RegFile != NULL);
    __try {
        // Radio/WiFi Mode
        // Saved on a per program basis
        RegFile->WriteInteger("Speed", "COMPort", RadioCOMPortNum->ValueAsInt);
        RegFile->WriteInteger("Speed", "RFIDPort", RFIDCOMPortNum->ValueAsInt);

        RegFile->WriteInteger("Speed", "Baud", BaudRateSel->ItemIndex);
        RegFile->WriteInteger("Speed", "Parity", ParitySel->ItemIndex);
        RegFile->WriteInteger("Speed", "Bits", BitsSel->ItemIndex);
        RegFile->WriteInteger("Speed", "Stop", StopSel->ItemIndex);
        RegFile->WriteInteger("Options", "Echo", Echo->Checked);
        RegFile->WriteInteger("Options", "Ignore_FF", Ignore_FF->Checked);
        RegFile->WriteInteger("Options", "Hex", Hex->Checked);
        RegFile->WriteInteger("Options", "Duplex", Duplex->Checked);
        RegFile->WriteInteger("Options", "TXOnlyComm", TXOnlyComm->Checked);
        //-----------------------------------------
        // Communications Modes - stored in "WiFi" Key in Registry

        RegFile->WriteInteger("WiFi", "RFID", RFID_COM_Mode->Checked);
        RegFile->WriteInteger("WiFi", "RFIDWiFi", RFID_WiFi_Mode->Checked);
        RegFile->WriteInteger("WiFi", "AIUWiFi", AIU_WiFi_Mode->Checked);
        RegFile->WriteInteger("WiFi", "SignalsWiFi", Signals_WiFi_Mode->Checked);
        // one and only one of these three modes can be selected
        RegFile->WriteInteger("WiFi", "Radio", Radio_COM_Mode->Checked);
        RegFile->WriteInteger("WiFi", "WTIU", WTIU_WiFi_Mode->Checked);
        // Currently selected WTIU in list. If none selected, delete the key
        // The ItemIndex of the first item in the list box is 0. If no item is selected, the value is -1.
        //if (WTIU_WiFi_Mode->Checked) {
        //    if (TIUWTIUListBox->ItemIndex != -1) {
        //        RegFile->WriteString("WiFi", "LastWTIU", WTIUName);
        //        } else {
        //        LastTWIU = "";
        //        RegFile->DeleteKey("WiFi", "LastWTIU");
        //        }
        //    }

        //-----------------------------------------
        // Communications Modes - stored in "WiFi" Key in Registry

        RegFile->WriteString("WiFi", "AIUIP", AIUIP->Text);
        RegFile->WriteString("WiFi", "AIUPort", AIUPort->Text);
//        RegFile->WriteString("WiFi", "TIUIP", TIUIP->Text);
//		RegFile->WriteString("WiFi", "TIUPort", TIUPort->Text);
//        RegFile->WriteString("WiFi", "RFIDIP", RFIDIP->Text);
//        RegFile->WriteString("WiFi", "RFIDPort", RFIDPort->Text);
        RegFile->WriteInteger("WiFi", "AIU_Multicast", AIU_WiFi_Multicast->Checked);

        //-----------------------------------------
        // Other Options
        RegFile->WriteInteger("Options", "SpareCheckbox", SpareCheckbox->Checked);
        RegFile->WriteInteger("Options", "NumRetries", NumRetries->Value);
#ifdef OLDWAY
        not used
		// Host IP -  stored by C++ version
        RegFile->WriteInteger("Options", "HostIPIndex" + IntToHex(__BORLANDC__, 3), IPComboBox->ItemIndex);
		// Save all of the HostIP IP Addresses
		const String HostIPFile = String(MainForm->cStartDir)  + "\\" + "HostIP.ini";
        IPComboBox->Items->SaveToFile(HostIPFile);
#endif
        //
        RegFile->WriteInteger("Options", "AllowZero", AllowZero->Checked);
        RegFile->WriteInteger("Options", "BrakeBoost", BrakeBoost->ItemIndex);
        RegFile->WriteInteger("Options", "AutoCoupler", AutoCoupler->Checked);
        RegFile->WriteInteger("Options", "MaxSpeed", MaxSpeed->Value);
        RegFile->WriteInteger("Options", "EncodedRecordFormat", EncodedRecordFormat->Checked);
        RegFile->WriteInteger("Options", "MPHScaling", MPHScaling->Value);
        RegFile->WriteInteger("Options", "AutoBell", AutoBell->Checked);
        RegFile->WriteInteger("Options", "AutoBellOff", AutoBellOff->Checked);
        RegFile->WriteInteger("Options", "BellOffTime", BellOffTime->Value);
        RegFile->WriteInteger("Options", "AutoWhistle", AutoWhistle->Checked);
        RegFile->WriteInteger("Options", "ExtendedSUSD", ExtendedSUSD->Checked);
        RegFile->WriteInteger("Options", "RepeatPlayback", RepeatPlayback->Checked);
        RegFile->WriteInteger("Options", "Speed_Mode", Speed_Mode->Checked);
//        RegFile->WriteInteger("Options", "DropDTRonIdle", DropDTRonIdle->Checked);
//        RegFile->WriteInteger("Options", "DropRTSonIdle", DropRTSonIdle->Checked);
//        RegFile->WriteInteger("Options", "DTRAlwaysOn", DTRAlwaysOn->Checked);
        RegFile->WriteInteger("Options", "KeepEngines", KeepEngines->Checked);
        RegFile->WriteInteger("Options", "StandardAccDec", StandardAccDec->Checked);
        RegFile->WriteInteger("Options", "AutoConnect", AutoConnect->Checked);
        RegFile->WriteInteger("Options", "ShortBellWhistleSequence", ShortBellWhistleSequence->Checked);
        RegFile->WriteInteger("Options", "AutoPFA", AutoPFA->Checked);
        RegFile->WriteInteger("Options", "DisableEmergencyStop", DisableEmergencyStopButton->Checked);
		RegFile->WriteInteger("Options", "AutoHotButtons", AutoHotButtons->Checked);
        RegFile->WriteInteger("Options", "AutoQuickControls", AutoQuickControls->Checked);
        RegFile->WriteInteger("Options", "Safety_Mode", Safety_Mode->Checked);
        RegFile->WriteInteger("Options", "AutoFindEngines", AutoFindEngines->Checked);
        RegFile->WriteInteger("Options", "GeneralSounds", GeneralSounds->Checked);
        RegFile->WriteInteger("Options", "NoSleep", NoSleep->Checked);
        RegFile->WriteInteger("Options", "ShutdownOnRead", ShutdownOnRead->Checked);
        RegFile->WriteInteger("Options", "Allow255Sounds", Allow255Sounds->Checked);
        RegFile->WriteInteger("Options", "AutoSoundCtrls", AutoSoundCtrls->Checked);
        RegFile->WriteInteger("Options", "SmokeOFF", SmokeOFFatStartup->Checked);
        RegFile->WriteInteger("Options", "Quick_Ctrl_Scaling", Quick_Ctrl_Scaling->Value * 10);
        RegFile->WriteInteger("Options", "Transparent", TransparentSpin->Value);
        // Super TIU Mode and Active TIU Selection
        RegFile->WriteInteger("Options", "SuperTIUMode", SuperTIUMode);
    	for (int iTIU = 1 ; iTIU <= TIUMAX ; iTIU++) {	 // TIU 1-5/8
        	// Super TIU Mode by TIU number
	  		RegFile->WriteInteger("Options", "TIU" + String(iTIU) + "SuperMode", TIUSuperMode[iTIU-1]);
        	// Active TIU Selection by TIU number
	  		RegFile->WriteInteger("Options", "TIU" + String(iTIU) + "TIUSelection", TIUSelection[iTIU-1]);
        	// AIU Emulator Attached to this TIU number
        	//RegFile->WriteInteger("Options", "TIU" + String(iTIU) + "AIUEmulator", AIUEmulator[iTIU-1].Found);
			}

        // Copyright
        RegFile->WriteString("Copyright", "Symbol", "©");
        RegFile->WriteString("Copyright", "By", "Mark C. DiVecchio");
        RegFile->WriteString("Copyright", "Year", "2024");
        }
    __finally {
        // Deallocate RegFile
        delete RegFile;
        }
    }
#ifdef NOLONGERNEEDED
// Save the RFID Serial Port
const String WiFiRFIDFile = String(MainForm->cStartDir)  + "\\" + "WiFiRFID.ini";
RFIDListBox->Items->SaveToFile(WiFiRFIDFile);
#endif
#ifdef NOTUSED
not used
// Save the TIU/WTIU Serial Port and WiFi IP Addresses and Ports
const String WiFiTIUWTIUFile = String(MainForm->cStartDir)  + "\\" + "WiFiTIUWTIU.ini";
TIUWTIUListBox->Items->SaveToFile(WiFiTIUWTIUFile);
#endif
// Save the AIU WiFi IP Addresses and Ports
if (AIUEmulatorPortsSetup->TabVisible) {
    const String AIURadioFile = String(MainForm->cStartDir)  + "\\" + "WiFiAIU.ini";
    AIUListBox->Items->SaveToFile(AIURadioFile);
    }
Hide();
}
//---------------------------------------------------------------------------

void __fastcall TSetup::AllowZeroClick(TObject *Sender)
{
// This checkbox allows the user to select engine 0, which is sent
// in the command as 1. This should allow you to use engines which
// have been factory reset and not "added" yet
if (AllowZero->Checked) {
	MainForm->EngineSpin->MinValue = 0;   // New Min Value
    } else {
    MainForm->EngineSpin->MinValue = 1;
    // if the Engine number is 0, set it to 1
    if (MainForm->EngineSpin->Value == 0) MainForm->EngineSpin->Value = 1;
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::Radio_COM_ModeClick(TObject *Sender)
{
//
// Setup Radio Comm mode
//
// only one Radio COM/WTIU mode can be selected and one must be selected
//
// Update labels on MainForm
//
if (Radio_COM_Mode->Checked){
    // disable other COM/WTIU mode
    WTIU_WiFi_Mode->Checked = false;
    // enable all items
    RadioCOMPortNum->Enabled = true;
    RadioCOMLabel->Enabled = true;
    EncodedRecordFormat->Enabled = true;
    } else {
    RadioCOMPortNum->Enabled = false;
    RadioCOMLabel->Enabled = false;
    }
Set_Comment();
}
//---------------------------------------------------------------------------

void __fastcall TSetup::Radio_WiFi_ModeClick(TObject *Sender)
{
//
// Setup Radio or WiFi Mode
//
// only one Radio COM/WTIU WiFi mode can be selected and one must be selected
//
// Update labels on MainForm
//
Set_Comment();
}
//---------------------------------------------------------------------------

void __fastcall TSetup::WTIU_WiFi_ModeClick(TObject *Sender)
{
//
// Setup WTIU Mode
//
// only one Radio COM/WTIU mode can be selected and one must be selected
//
// Update labels on MainForm
if (WTIU_WiFi_Mode->Checked) {
    // disable other COM/WTIU mode
    Radio_COM_Mode->Checked = false;
    // enable all items
    HostIPPage->Enabled = true;
    WTIULabel->Enabled = true;
    ScanTIUWTIUButtonClick(Sender);
    // disable other options
    RadioCOMLabel->Enabled = false;
    RadioCOMPortNum->Enabled = false;
    EncodedRecordFormat->Enabled = false;
    } else {
    WTIULabel->Enabled = false;
    }
Set_Comment();
}
//---------------------------------------------------------------------------
void __fastcall TSetup::RFID_COM_ModeClick(TObject *Sender)
{
//
// setup RFID COM Port
//
// none, one or both RFID modes can be selected
//
MainForm->ConnectedRFIDLED->Visible = (RFID_WiFi_Mode->Checked || RFID_COM_Mode->Checked);
if (!RFID_WiFi_Mode->Checked && !RFID_COM_Mode->Checked) {
    RFIDListBox->Clear();
    }
//
// Update labels on MainForm
//
if (RFID_COM_Mode->Checked){
    // enable all items
    MainForm->RFIDBuffer->Enabled = true;
    MainForm->RFIDBuffer->Color = clWindow;
    //
    RFIDCOMPortNum->Enabled = true;
    RFIDCOMLabel->Enabled = true;
    //
    // no need to scan for COM ports unless [Scan] button pressed
    //
    //if (!RFID_WiFi_Mode->Checked) RFIDListBox->Clear();
    //// Find all serial ports
    //RFIDListBox->Clear();
    //MainForm->DebugMessagePopup("Wait", "Scanning for COM Ports", "Please Wait");
    //(void) EnumerateComPorts(RFIDListBox);
    //WTIUListBoxClick(Sender);
    //
    } else {
	if (RFID_WiFi_Mode->Checked) {
        MainForm->ConnectedRFIDLED->Caption = "WiFi";
    	}
    MainForm->RFIDBufferLabel->Caption = "RFID Buffer " + MainForm->ConnectedRFIDLED->Caption;
    RFIDCOMPortNum->Enabled = false;
    RFIDCOMLabel->Enabled = false;
    }
Set_Comment();
}
//---------------------------------------------------------------------------

void __fastcall TSetup::RFID_WiFi_ModeClick(TObject *Sender)
{
// Setup RFID WiFi Mode
//
// none, one or both RFID modes can be selected
//
MainForm->ConnectedRFIDLED->Visible = (RFID_WiFi_Mode->Checked || RFID_COM_Mode->Checked);
if (!RFID_WiFi_Mode->Checked && !RFID_COM_Mode->Checked) {
    RFIDListBox->Clear();
    }
//
// Update labels on MainForm and Setup Form
//
if (RFID_WiFi_Mode->Checked) {
    // enable all items
    MainForm->RFIDBuffer->Enabled = true;
    MainForm->RFIDBuffer->Color = clWindow;
	//
    if (Setup) {
    HostIPPage->Enabled = true;
    RFIDListBox->Enabled = true;
    RFIDWiFiLabel->Enabled = true;
    ScanRFIDButtonClick(Sender);
        // hints
        MainForm->NumDetectors->Visible = true;
        MainForm->NumReaders->Visible = true;
        MainForm->DetLabel->Visible = true;
        MainForm->RdrLabel->Visible = true;
        }
    //
    } else {
    // disable all items
	if (RFID_COM_Mode->Checked) {
        MainForm->ConnectedRFIDLED->Caption = "COM" + String(RFIDCOMPortNum->ValueAsInt);
    	}
    MainForm->RFIDBufferLabel->Caption = "RFID Buffer " + MainForm->ConnectedRFIDLED->Caption;
    if (Setup) {
    RFIDWiFiLabel->Enabled = false;
        // hints
        MainForm->NumDetectors->Visible = false;
        MainForm->NumReaders->Visible = false;
        MainForm->DetLabel->Visible = false;
        MainForm->RdrLabel->Visible = false;
    }
    }
Set_Comment();
}
//---------------------------------------------------------------------------

void __fastcall TSetup::Set_Comment()
{
//
// Set title on some counters
//

if (Radio_COM_Mode->Checked) {
	MainForm->ConnectedWiFiRadioLED->Caption = "COM" + String(RadioCOMPortNum->ValueAsInt);
	MainForm->TIUBufferLabel->Caption = "TIU Buffer " + MainForm->ConnectedWiFiRadioLED->Caption;
    MainForm->ConnectedTIULED->Caption = "TIU";
    //MainForm->Retries->Hint = "Retries to Busy, CRC, and NAK responses";
    MainForm->BusyLabel->Caption = "Busy";
        MainForm->sendDataBusy->Hint = "SendHexStr() returned busy";
    MainForm->Label49->Caption = "NAK";
        MainForm->NAK0T->Hint = "NAK00: CC_Count == 11 && stautus == '00'";
    MainForm->Label50->Caption = "CRC";
    MainForm->Label30->Caption = "NAK Length";
        MainForm->NAKLen->Hint = "Too Few or Too Many Bytes Received";
    MainForm->Label42->Caption = "NF";
        MainForm->EngNotFound->Hint = "Count of \"Engine Not Found\" Responses from TIU";
    MainForm->Label65->Visible = false;
    MainForm->WiFiTO->Visible = false;
    MainForm->Label64->Visible = false;
    MainForm->CKSum->Visible = false;
    MainForm->WiFiTIUCount->Visible = false;
    NumWTIU->Visible = false;
    WLabel10->Visible = false;
	}
if (WTIU_WiFi_Mode->Checked) {
	MainForm->ConnectedWiFiRadioLED->Caption = "WiFi";
	MainForm->TIUBufferLabel->Caption = "TIU Buffer " + MainForm->ConnectedWiFiRadioLED->Caption;
    MainForm->ConnectedTIULED->Caption = "TIU";
    //MainForm->Retries->Hint = "WTIU responses : 'checksum error', 'input error', 'reset', 'disconnected', 'PC not available' and command echo error";
    MainForm->BusyLabel->Caption = "Failure";
        MainForm->sendDataBusy->Hint = "WTIU response : failure";
    MainForm->Label49->Caption = "Error";
        MainForm->NAK0T->Hint = "WiFi TIU response : input error";
    MainForm->Label50->Caption = "Reset";
    MainForm->Label30->Caption = "DCS Timeout";
        MainForm->NAKLen->Hint = "WiFi TIU response : DCS Timeout";
    MainForm->Label42->Caption = "Echo";
        MainForm->EngNotFound->Hint = "WiFi TIU response : 'input error'";
    MainForm->Label65->Visible = true;
    MainForm->WiFiTO->Visible = true;
    MainForm->Label64->Visible = true;
    MainForm->CKSum->Visible = true;
    MainForm->WiFiTIUCount->Visible = true;
    NumWTIU->Visible = true;
    WLabel10->Visible = true;
//    MainForm->Caption = MainForm->Caption + (" " + String(WTIUName));   // put the WTIU name in the Caption
	}

// Select a Host IP
if (RFID_WiFi_Mode->Checked || AIU_WiFi_Mode->Checked || Signals_WiFi_Mode->Checked) {
	HostIPPage->Enabled = true;
    }

if (RFID_COM_Mode->Checked && RFID_WiFi_Mode->Checked) {
	MainForm->ConnectedRFIDLED->Caption = "WiFi/COM" + String(RFIDCOMPortNum->ValueAsInt);
	MainForm->RFIDBufferLabel->Caption = "RFID Buffer " + MainForm->ConnectedRFIDLED->Caption;
	} else if (RFID_COM_Mode->Checked) {
	    MainForm->ConnectedRFIDLED->Caption = "COM" + String(RFIDCOMPortNum->ValueAsInt);
		MainForm->RFIDBufferLabel->Caption = "RFID Buffer " + MainForm->ConnectedRFIDLED->Caption;
    	} else if (RFID_WiFi_Mode->Checked) {
	        MainForm->ConnectedRFIDLED->Caption = "WiFi";
			MainForm->RFIDBufferLabel->Caption = "RFID Buffer " + MainForm->ConnectedRFIDLED->Caption;
        	}
}
//---------------------------------------------------------------------------

void __fastcall TSetup::RecordStartButtonClick(TObject *Sender)
{
// Start Recording the strings sent to the TIU
if (!MainForm->IsTIUConnected()) {
	MainForm->DebugMessagePopup("Warning", MainForm->ConnectMsg, "");
	return;
    }
if (MainForm->bPlayingBack) {
    MainForm->DebugMessage("You must stop the previous Playback before you can start a new Recording");
	return;
    }
// prepare to record
MainForm->EncodedRecordFormat = EncodedRecordFormat->Checked;
MainForm->RecordingBuffer->Clear();	// make sure the buffer is empty
MainForm->bRecording = true;
RecordingLED->Checked = true;
RecordingLED->Visible = true;
// set buttons to recording state
RecordStartButton->Enabled = false;
RecordStopButton->Enabled = true;
PlaybackStartButton->Enabled = false;
RecordingFileName = "";
// WTIU needs to be told which engine is selected by RTC sending a 'y' command
RequestyCommand = true;
//
if (DEBUGGING) DB->Debug_Print("Recording Started");
}
//---------------------------------------------------------------------------

void __fastcall TSetup::RecordStopButtonClick(TObject *Sender)
{
assert(MainForm->bRecording); 	// we must be recording

// recording complete, turn off LED
RecordingLED->Visible = false;

RecordSaveDialog->InitialDir = MainForm->WorkingDir;
RecordSaveDialog->DefaultExt = String("rtc");
RecordSaveDialog->Title = "Save Recording to a File";
RecordSaveDialog->Filter = "Remote Train Control files (*.rtc)|*.rtc";
RecordSaveDialog->FileName = "*.rtc";
RecordSaveDialog->Options = RecordSaveDialog->Options >> ofOverwritePrompt << ofEnableSizing << ofPathMustExist;
                // RTC will handle Overwrite Prompt
if(RecordSaveDialog->Execute()) {
	// user pressed SAVE
	RecordingFileName = RecordSaveDialog->FileName;
  	// Change working directory to whatever was selected
   	MainForm->WorkingDir = ExtractFilePath(RecordingFileName);
   	// if file exists, confirm first
   	if (FileExists(RecordingFileName)) {
   	    // ask for confirmation
   	    int result = Application->MessageBox(TEXT("File Exists - Do you want to overwrite it?"),
   	    TEXT("File Exists"), MB_YESNOCANCEL | MB_ICONQUESTION);
   		// if No, exit
   		if (result  == IDNO) {
        	// end the recording without writing to the file
			MainForm->bRecording = false;
			RecordingLED->Checked = false;
			RecordingLED->Visible = false;
            // set buttons to normal state
			RecordStopButton->Enabled = false;
            RecordStopButton->Enabled = false;
			RecordStartButton->Enabled = true;
			PlaybackStartButton->Enabled = true;
   	        return;		// user refused to overwrite an exisiting file
   	    	}
        if (result == IDCANCEL) {
        	// cancel this dialog and let the recording continue
            RecordingLED->Visible = true;
            return;
            }
   		}
    } else {
    // RecordStopButton is still enabled in case the user wants to try again to save the file
    RecordingLED->Visible = true;
    return;	// user canceled the File Save Dialog
    }
// At this point, it's either a new file or the user has indicated overwrite
MainForm->RecordingBuffer->Lines->SaveToFile(RecordingFileName);	// PlainText is set to true in the Object Inspector
// Leave the recording in the Recording Buffer

// Stop recording
MainForm->bRecording = false;
RecordingLED->Checked = false;
RecordingLED->Visible = false;

// set buttons to normal state
RecordStopButton->Enabled = false;
PlaybackStopButton->Enabled = false;
RecordStartButton->Enabled = true;
PlaybackStartButton->Enabled = true;

//
if (DEBUGGING) DB->Debug_Print("Recording Stopped : " + RecordingFileName);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::PlaybackStartButtonClick(TObject *Sender)
{
// Start playback of the strings sent to the TIU
if (!MainForm->IsTIUConnected()) {
	MainForm->DebugMessagePopup("Warning", MainForm->ConnectMsg, "");
	MainForm->bPlayingBack = false;
	return;
    }
if (MainForm->bRecording) {
    MainForm->DebugMessage("You must stop Recording before you can Playback a previous Recording");
	return;
    }
// start playback
PlaybackDialog->InitialDir = MainForm->WorkingDir;
PlaybackDialog->DefaultExt = String("rtc");
PlaybackDialog->Title = "Select a Playback File";
PlaybackDialog->Filter = "Remote Train Control files (*.rtc)|*.rtc";
PlaybackDialog->FileName = "*.rtc";
PlaybackDialog->Options = PlaybackDialog->Options << ofEnableSizing << ofPathMustExist << ofFileMustExist;

if (PlaybackDialog->Execute()) {
	// user pressed [Open]
	MainForm->RecordingBuffer->Clear();
	RecordingFileName = PlaybackDialog->FileName;
   	// Change working directory to whatever was selected
   	MainForm->WorkingDir = ExtractFilePath(RecordingFileName);
	} else {
    // user pressed [Cancel]
    return;	// user canceled the File Open Dialog
    }
if (!RecordingFileName.IsEmpty()) {
	// start the playback thread - FreeOnTerminate is not set so we must delete the Thread
	ResetEvent(MainForm->TerminationPBEvent);	// reset any lingering events
    // CALLEDBYSETUP indicates that playback was started from the Setup window
			// Create suspended - in BCB 4.0, the thread constructor does not wait for lower level constructors itself.
		    // The Execute() routine actually runs before some lower level construction is finished.
			// Don't put constructions in the thread constructor. if you have to, start the thread suspended and then start it running
			// per Remy LeBeau (TeamB) it is a Known bug that was fixed in BCB 6.0
	PBThread =  new TPlaybackFileThread(true, this, Handle, RemoteNo, RecordingFileName, CALLEDBYSETUP, 0);
	assert(PBThread);
	#if __BORLANDC__ >= 0x720
	PBThread->Start();			// start the thread for CB10.1
	#else
	PBThread->Resume();			// start the thread for BCB4.0 - use deprecated in CB10.1, use Start() instead
	#endif
	if (DEBUGGING) DB->Debug_Print("Starting Playback Thread for : " + RecordingFileName);
    } else {
    MainForm->DebugMessage("Playback File Name is missing");
    return;
    }
MainForm->bPlayingBack = true;
// set buttons to playback state
PlaybackStartButton->Enabled = false;
PlaybackStopButton->Enabled = true;
RecordStartButton->Enabled = false;
if (DEBUGGING) DB->Debug_Print("Playback Started : " + RecordingFileName);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::CMStopPlayback(TMessage &Message)
{
// this message handler is called only when TPlayBackFile is called from TSetup
if (Message.LParam != CALLEDBYSETUP) return;
if (PBThread != NULL) {
	PBThread->Terminate();
	PBThread->WaitFor();	// do not use FreeOnTerminate
	delete PBThread;
	PBThread = NULL;	// release the pointer
	if (DEBUGGING) DB->Debug_Print("TSetup : CMStopPlayback : Playback Stopped");
	}

MainForm->bPlayingBack = false;
// set buttons to normal state
PlaybackStartButton->Enabled = true;
PlaybackStopButton->Enabled = false;
RecordStartButton->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::PlaybackStopButtonClick(TObject *Sender)
{
// turn off playback
// send a stop message to myself
(void) PostMessage(Handle, CM_STOPPLAYBACK, NULL, CALLEDBYSETUP);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::NumRetriesChange(TObject *Sender)
{
// NumRetries is the number of times to retry after the 1st time. Therefore, setting
// it to 2 means the command will be sent a total of 3 times.
if (NumRetries->ValueAsInt == 10) {
    MainForm->DebugMessage(" Setting '# Retries' to 10 has a special Debug meaning. Be sure you want to do this.");
	}
if (DEBUGGING) DB->Debug_Print("# Retries changed to " + String(NumRetries->ValueAsInt));
}
//---------------------------------------------------------------------------

void __fastcall TSetup::MaxSpeedChange(TObject *Sender)
{
if (DEBUGGING) DB->Debug_Print("Overall Maximum Speed changed to " + String(MaxSpeed->ValueAsInt));
}
//---------------------------------------------------------------------------

#include <setupapi.h>

#define MAX_PORT_NUM      (256)
#define MAX_STR_LEN       (256 * sizeof(TCHAR))

// see http://blog.csdn.net/u013606170/article/details/46903713
// and
// http://www.naughter.com/enumser.html
/*
Copyright (c) 1998 - 2013 by PJ Naughter (Web: www.naughter.com, Email: pjna@naughter.com)

All rights reserved.

Copyright / Usage Details:

You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
when your product is released in binary form. You are allowed to modify the source code in any way you want
except you cannot modify the copyright details at the top of each module. If you want to distribute source
code with your application, then you are only allowed to distribute versions released by the author. This is
to maintain a single distribution point for the source code.

*/

BOOL __fastcall TSetup::EnumerateComPorts(TListBox * ListBox) {
 int ret, Number;

 TCHAR Mess[MAX_STR_LEN];
 GUID *pGuid;
 DWORD dwGuids;
 HDEVINFO hDevInfoSet;
 TCHAR portString[10];

 //ListBox->Clear();

 BOOL bMoreItems;
 SP_DEVINFO_DATA devInfo;

 ret = FALSE;

 //First need to convert the name "Ports" to a GUID using SetupDiClassGuidsFromName
 dwGuids = 0;
 SetupDiClassGuidsFromName(TEXT("Ports"), NULL, 0, &dwGuids);

 if(0 == dwGuids) return FALSE;
 
 //Allocate the needed memory
 pGuid = (GUID*)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, dwGuids * sizeof(GUID));
 if(NULL == pGuid) return FALSE;

 //Call the function again
 if (FALSE == SetupDiClassGuidsFromName(TEXT("Ports"), pGuid, dwGuids, &dwGuids)) {
  return FALSE;
  }/*if*/

 hDevInfoSet = SetupDiGetClassDevs(pGuid, NULL, NULL, DIGCF_PRESENT /*| DIGCF_DEVICEINTERFACE*/);
 if (INVALID_HANDLE_VALUE == hDevInfoSet) {
  //Set the error to report
  _sntprintf(Mess, sizeof Mess, TEXT("error SetupDiGetClassDevs, %d"), GetLastError());
  if (DEBUGGING) DB->Debug_Print(Mess);
  return FALSE;
  }/*if */

 devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
 unsigned int i = 0;
 unsigned int jj = 0;

 do {
  HKEY hDeviceKey;
  BOOL isFound;

  isFound = FALSE;
  bMoreItems = SetupDiEnumDeviceInfo(hDevInfoSet, i, &devInfo);
  if(FALSE == bMoreItems) break;

  i++;

  hDeviceKey = SetupDiOpenDevRegKey(hDevInfoSet, &devInfo, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);

  if (INVALID_HANDLE_VALUE != hDeviceKey) {
   size_t nLen;
   LPTSTR pszPortName;

   {
    //First query for the size of the registry value
    DWORD dwType;
    DWORD dwDataSize;
    LONG err;
    DWORD dwAllocatedSize;
    DWORD dwReturnedSize;
    dwType = 0; dwDataSize = 0;

    err = RegQueryValueEx(hDeviceKey, TEXT("PortName"), NULL, &dwType, NULL, &dwDataSize);
    if (ERROR_SUCCESS != err) continue;
   
    //Ensure the value is a string
    if (dwType != REG_SZ) continue;
   
    //Allocate enough bytes for the return value
	dwAllocatedSize = dwDataSize + sizeof(TCHAR);
	// "+ sizeof(TCHAR)" is to allow us to NULL terminate
    // the data if it is not null terminated in the registry

    pszPortName = (LPTSTR)LocalAlloc(LMEM_FIXED, dwAllocatedSize);
    if (pszPortName == NULL) continue;

    //Recall RegQueryValueEx to return the data
    pszPortName[0] = '\0';
    dwReturnedSize = dwAllocatedSize;
    err = RegQueryValueEx(hDeviceKey, TEXT("PortName"), NULL, &dwType, (LPBYTE)pszPortName, &dwReturnedSize);
    if (ERROR_SUCCESS != err) {
     LocalFree(pszPortName);
     continue;
     }

    //Handle the case where the data just returned is the same size as the allocated size. This could occur where the data
    //has been updated in the registry with a non null terminator between the two calls to ReqQueryValueEx above. Rather than
    //return a potentially non-null terminated block of data, just fail the method call
    if (dwReturnedSize >= dwAllocatedSize) continue;

    //NULL terminate the data if it was not returned NULL terminated because it is not stored null terminated in the registry
    if (pszPortName[dwReturnedSize/sizeof(TCHAR) - 1] != '\0') pszPortName[dwReturnedSize/sizeof(TCHAR)] = '\0';
   }/*local varable*/

   //If it looks like "COMX" then
   //add it to the array which will be returned
   nLen = _tcsclen(pszPortName);

   if (3 < nLen){
   	if (0 == _tcsnicmp(pszPortName, TEXT("COM"), 3)) {
      if(FALSE == _istdigit(pszPortName[3]) ) continue;
      //Work out the port number
      _sntprintf(Mess, sizeof Mess, TEXT("Port %s"), pszPortName);
 	  if (DEBUGGINGX(7)) DB->Debug_Print(Mess);
      _tcsnccpy(portString, pszPortName, sizeof(portString));
      } else {
      continue;
      }/*if 0 == _tcsnicmp(pszPortName, TEXT("COM"), 3)*/
	}/*if 3 < nLen*/

   LocalFree(pszPortName);    
   isFound = TRUE;  

   //Close the key now that we are finished with it
   RegCloseKey(hDeviceKey);
  }/*INVALID_HANDLE_VALUE != hDeviceKey*/

  if(FALSE == isFound)
   continue;

  //If the port was a serial port, then also try to get its friendly name  
  {
   TCHAR szFriendlyName[1024];     
   DWORD dwSize;
   DWORD dwType;
   szFriendlyName[0] = '\0';
   dwSize = sizeof(szFriendlyName);
   dwType = 0;

   if((TRUE == SetupDiGetDeviceRegistryProperty(hDevInfoSet, &devInfo, SPDRP_DEVICEDESC, &dwType, (PBYTE)(szFriendlyName), dwSize, &dwSize) ) && (REG_SZ == dwType)) {
    _sntprintf(Mess, sizeof Mess, TEXT("%s %s"), portString, szFriendlyName);
 	if (DEBUGGINGX(7)) DB->Debug_Print(Mess);
    ListBox->Items->Add(Mess);
    } else {
 	_sntprintf(Mess, sizeof Mess, TEXT("%s"), portString);
 	if (DEBUGGINGX(7)) DB->Debug_Print(Mess);
    ListBox->Items->Add(Mess);
    }/*if SetupDiGetDeviceRegistryProperty */
  }/*local variable */

  jj++;
  } while(1);

 HeapFree(GetProcessHeap(), 0, pGuid);
 Number = jj;
 _sntprintf(Mess, sizeof Mess, TEXT("Found %d Ports"), Number);
 if (DEBUGGINGX(7)) DB->Debug_Print(Mess);
 //
 // if one of the ports is the port that is already selected, then highlight it.
 //
 ListBox->ItemIndex = -1;
 for (int cc = 0 ; cc < Number ; cc++) {
    int nPort;
	_stscanf(ListBox->Items->Strings[cc].c_str(),TEXT("COM%d"), &nPort);
    if (nPort == RadioCOMPortNum->ValueAsInt) {
        ListBox->ItemIndex = cc;
    	break;
    	}
 	}

 if(0 < jj) ret = TRUE;
 return ret;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::EnumerateSerialPorts1Click(TObject *Sender)
{
// SetupPopupMenu Item
WTIUListBox->Clear();
EnumerateComPorts(WTIUListBox);
WTIUListBoxClick(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::WTIUListBoxClick(TObject *Sender)
{
//
// Print the entries in the WTIUListBox
//
if (WTIU_WiFi_Mode->Checked) {
    if (WTIUListBox->Items->Count == 0) {
        if (DEBUGGING) DB->Debug_Print("No WTIU over WiFi Found");
        return;
        } else {
        TCHAR IP[50], WTIUName[50];
        int Port;
        for (int idx = 0 ; idx < WTIUListBox->Items->Count ; idx++) {
            int retv = _stscanf(WTIUListBox->Items->Strings[idx].c_str(), TEXT("%s %d %s"), IP, &Port, WTIUName);
            // Parse out the WTIU Name, IP and Port
            if (retv == 3) {
                if (DEBUGGING) DB->Debug_Print("WTIU Found : " + String(WTIUName) + " at " + String(IP) + " : Port : " + String(Port));
                }
            }
        }
    NumWTIU->Value = WTIUListBox->Items->Count;
    }

if (Radio_COM_Mode->Checked) {
    const int SelectedCOMPort = WTIUListBox->ItemIndex;
    if (WTIUListBox->Items->Count == 0) {
        RadioCOMPortNum->Value = 1;
        if (DEBUGGING) DB->Debug_Print("No Radio COM Ports Found");
        return;
        } else {
        for (int idx = 0 ; idx < WTIUListBox->Items->Count ; idx++) {
            if (idx == SelectedCOMPort) {
                int nPort;
                int retv = _stscanf(WTIUListBox->Items->Strings[SelectedCOMPort].c_str(),TEXT("COM%d"), &nPort);
                if (retv == 1) {
                    RadioCOMPortNum->Value = nPort;
                    if (DEBUGGING) DB->Debug_Print("Radio COM" + String(nPort) + " Selected");
                    } else {
                    RadioCOMPortNum->Value = 1;
                    }
                }
            if (DEBUGGING) DB->Debug_Print("Radio COM Found : " + WTIUListBox->Items->Strings[idx]);
            }
        }

    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::RadioCOMPortNumValueChanged(TObject *Sender)
{
//
// if one of the ports is the port that is selected, then highlight it.
//
if (WTIUListBox->Items->Count != 0) {	// for non empty list
	WTIUListBox->ItemIndex = -1;
	for (int cc = 0 ; cc < WTIUListBox->Items->Count ; cc++) {
    	int nPort;
		_stscanf (WTIUListBox->Items->Strings[cc].c_str(),TEXT("COM%d"), &nPort);
    	if (nPort == RadioCOMPortNum->ValueAsInt) {
    	    WTIUListBox->ItemIndex = cc;
    		break;
    		}
 		}
    }

// Update labels on MainForm
if (Radio_COM_Mode) {
    char PortName[10];
    snprintf(PortName, sizeof PortName, "COM%d", RadioCOMPortNum->ValueAsInt);
    MainForm->ConnectedWiFiRadioLED->Caption = PortName;
    //Radio_COM_Mode->Checked = true;
    //RFID_WiFi_Mode->Checked = false;
    MainForm->TIUBufferLabel->Caption = "TIU Buffer " + MainForm->ConnectedWiFiRadioLED->Caption;
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::RFIDCOMPortNumValueChanged(TObject *Sender)
{
//
//RFID_COM_Mode->Checked = true;
//Radio_COM_Mode->Checked = false;

// Update labels on MainForm
char RFIDName2[10];
snprintf(RFIDName2, sizeof RFIDName2, "COM%d", RFIDCOMPortNum->ValueAsInt);
MainForm->ConnectedRFIDLED->Caption = RFIDName2;
MainForm->RFIDBufferLabel->Caption = "RFID Buffer " + MainForm->ConnectedRFIDLED->Caption;
MainForm->RFIDBuffer->Enabled = true;
MainForm->RFIDBuffer->Color = clWindow;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::FormShow(TObject *Sender)
{
// in debugging mode, make a few more controls visible
if (DEBUGGING) {
	AIU_WiFi_Multicast->Visible = true;
    } else {
	AIU_WiFi_Multicast->Visible = false;
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::WMDropFiles(TWMDropFiles &message)
{
// Not supported yet under WTIU
if (WTIU_WiFi_Mode->Checked) {
    MainForm->DebugMessagePopup("Warning", MainForm->WTIUMsg, "");
    return;
    }
if (!MainForm->IsTIUConnected()) {
	MainForm->DebugMessagePopup("Warning", MainForm->ConnectMsg, "");
	MainForm->bPlayingBack = false;
	return;
    }
if (MainForm->bRecording) {
    MainForm->DebugMessage("You must stop Recording before you can Playback a previous Recording");
	return;
    }

// Process first valid filename found
UINT filecount = DragQueryFile((HDROP) message.Drop, 0xFFFFFFFF, NULL, 0);
if ((PBThread == NULL) && (filecount > 0)) {
	String FullFileName;
	for (UINT ii = 0 ; ii < filecount ; ++ii){
    	Application->ProcessMessages();		// ok to use this during DragQueryFile() processing
		// Get the file name
		char FileName[MAX_PATH];
		DragQueryFileA ((HDROP) message.Drop, ii, FileName, MAX_PATH);
		FullFileName = FileName;
		//Application->MessageBox(FullFileName.c_str(), TEXT("Result of DragQueryFileA()"), MB_OK | MB_DEFBUTTON1);
		if (FileExists(FullFileName)) {
        	String Extension = LowerCase(ExtractFileExt(FullFileName));
            if (Extension == ".rtc") {
				// FIXME do something for each file
    	        //DebugBuffer->Lines->Append("Dropped file " + FullFileName);
                // Change working directory to whatever was selected
				MainForm->WorkingDir = ExtractFilePath(FullFileName);
				MainForm->RecordingBuffer->Lines->LoadFromFile(FullFileName);
				if (DEBUGGING) DB->Debug_Print("ReadFromDisk (Playback): " + FullFileName);
				if (!FullFileName.IsEmpty()) {
					// start the playback thread - FreeOnTerminate is not set so we must delete the Thread
				    // worry about deleting the Thread
					ResetEvent(MainForm->TerminationPBEvent);	// reset any lingering events
					// Create suspended - in BCB 4.0, the thread constructor does not wait for lower level constructors itself.
				    // The Execute() routine actually runs before some lower level construction is finished.
				    // Don't put constructions in the thread constructor. if you have to, start the thread suspended and then start it running
				    // per Remy LeBeau (TeamB) it is a Known bug that was fixed in BCB 6.0
					PBThread = new TPlaybackFileThread(true, this, Handle, RemoteNo, FullFileName, CALLEDBYSETUP, 0);
					assert(PBThread);
					#if __BORLANDC__ >= 0x720
					PBThread->Start();			// start the thread for CB10.1
					#else
					PBThread->Resume();			// start the thread for BCB4.0 - use deprecated in CB10.1, use Start() instead
					#endif
                    if (DEBUGGING) DB->Debug_Print("Starting Playback Thread for : " + FullFileName);

                    } else {
                    MainForm->DebugMessage("Playback File Name is missing");
                    }
				MainForm->bPlayingBack = true;
				// set buttons to playback state
				PlaybackStartButton->Enabled = false;
				PlaybackStopButton->Enabled = true;
				RecordStartButton->Enabled = false;
				if (DEBUGGING) DB->Debug_Print("Playback Started : " + FullFileName);
                break;
				}
            if (DEBUGGING) DB->Debug_Print("Not a Recording File : " + FullFileName);
			continue;
			} else {
			continue;
			}
		}
	//String FileName = LowerCase(ExtractFileName(FullFileName));
	// use last dropped filename
	//FileEdit->Text = FullFileName;
	}
DragFinish ((HDROP) message.Drop);
return;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ManuallysetSpeed1Click(TObject *Sender)
{
// enable the baud rate selection radio buttons
TIUPortListGroup->Visible = false;
BaudRateSel->Visible = true;
BitsSel->Visible = true;
ParitySel->Visible = true;
StopSel->Visible = true;
BaudRateSel->Enabled = true;
BitsSel->Enabled = true;
ParitySel->Enabled = true;
StopSel->Enabled = true;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::AutomaticallysetSpeed1Click(TObject *Sender)
{
// disable the baud rate selection radio buttons and return rates to default values
TIUPortListGroup->Visible = true;
BaudRateSel->ItemIndex = 2;
BitsSel->ItemIndex = 1;
ParitySel->ItemIndex = 0;
StopSel->ItemIndex = 0;
BaudRateSel->Visible = false;
BitsSel->Visible = false;
ParitySel->Visible = false;
StopSel->Visible = false;
BaudRateSel->Enabled = false;
BitsSel->Enabled = false;
ParitySel->Enabled = false;
StopSel->Enabled = false;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::FormKeyDown(TObject *Sender, WORD &Key,
      TShiftState Shift)
{
// Make sure KeyPreview is true for this form
assert(KeyPreview);
// Pass function keys to the MainForm, handle rest of the keys here.
switch (Key) {
    case VK_F1:
    case VK_F2:
    case VK_F3:
    case VK_F4:
    case VK_F5:
    case VK_F6:
    case VK_F7:
    case VK_F8:
    case VK_F9:
    case VK_F10:
    case VK_F11:
    case VK_F12:
		MainForm->FormKeyDown(Sender, Key, Shift);
        Key = 0;	// handled
		break;
	}	
}
//---------------------------------------------------------------------------

void __fastcall TSetup::DisableEmergencyStopButtonClick(TObject *Sender)
{
// This OnClick handler was called in BCB4.0 when the setting
// was read from the Registry. That did not happen in B10.1. I had
// to change the code to use the OnMouseDown event
//ShowMessage("Restart required for new setting to take effect");
}
//---------------------------------------------------------------------------

void __fastcall TSetup::DisableEmergencyStopButtonMouseDown(TObject *Sender, TMouseButton Button,
		  TShiftState Shift, int X, int Y)
{
DisableEmergencyStopButton->Checked = !DisableEmergencyStopButton->Checked;
ShowMessage("Restart required for new setting to take effect");
}
//---------------------------------------------------------------------------

void __fastcall TSetup::SuperModeSetupButtonClick(TObject *Sender)
{
// create the Super TIU window
// This code should work with auto create on OR off.
// ------------ With programmed create using C++ Builder's generated pointer
// Super TIU Form should be manually created
if (!SuperTIU) {	// since I used the C++ pointer, it will get automatically deleted at close
	SuperTIU = new TSuperTIU(this);     // Pass "this" as the owner
	assert(SuperTIU != NULL);			// make sure that construction worked
	}
if (SuperTIU) {
    // SuperTIUMode change requires that we are connected to the TIU
    if (!MainForm->IsTIUConnected()) {
        SuperTIU->SuperPanel->Enabled = false;
        MainForm->DebugMessagePopup("Information", "Connect to the TIU before changing SuperTIUMode", "");
        } else {
        SuperTIU->SuperPanel->Enabled = true;
        }
    //
    SuperTIU->Show();
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::TIUSelectionButtonClick(TObject *Sender)
{
// create the Active TIU Selection window
// This code should work with auto create on OR off.
// ------------ With programmed create using C++ Builder's generated pointer
// Active TIU Selection Form should be manually created
if (!ActiveTIU) {	// since I used the C++ pointer, it will get automatically deleted at close
	ActiveTIU = new TActiveTIU(this);     // Pass "this" as the owner
	assert(ActiveTIU != NULL);			// make sure that construction worked
	}
if (ActiveTIU) {
    if (MainForm->IsTIUConnected()) {
        ActiveTIU->ActivePanel->Enabled = false;
        MainForm->DebugMessagePopup("Information", "Disconnect from TIU before changing Active TIU Selection", "");
        } else {
        ActiveTIU->ActivePanel->Enabled = true;
        }
    ActiveTIU->Show();
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::TransparentSpinChange(TObject *Sender)
{
if (DEBUGGING) DB->Debug_Print("Tranparency changed to " + String(TransparentSpin->ValueAsInt));
}
//---------------------------------------------------------------------------

void __fastcall TSetup::Ignore_FFClick(TObject *Sender)
{
Ignore_FF_Char = Ignore_FF->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::EncodedRecordFormatClick(TObject *Sender)
{
MainForm->EncodedRecordFormat = EncodedRecordFormat->Checked;	// put format switch into global variable
}
//---------------------------------------------------------------------------

void __fastcall TSetup::PlaybackDialogShow(TObject *Sender)
{
// change Open button to "Playback"
// http://www.bcbjournal.org/articles/vol3/9912/Changing_common_dialog_button_captions.htm
HWND hWndDlg = GetParent(PlaybackDialog->Handle);
if (hWndDlg == NULL) {
	if (DEBUGGING) DB->Debug_Print("GetParent() returned NULL");
    LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        GetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR) &lpMsgBuf,
        0,
        NULL);

    // Display the string.
	if (DEBUGGING) DB->Debug_Print(String((char *)lpMsgBuf));
    // Free the buffer.
    LocalFree( lpMsgBuf );
	} else {
	HWND hWndBtn = GetDlgItem(hWndDlg, IDOK); //1);
	if (hWndBtn == NULL) {
		if (DEBUGGING) DB->Debug_Print("Control does not exist");
		} else {
		SetWindowText(hWndBtn, TEXT("Playback"));
    	}
#ifdef CANCELBUT
	hWndBtn = GetDlgItem(hWndDlg, IDCANCEL); //2);
	if (hWndBtn == NULL) {
		if (DEBUGGING) DB->Debug_Print("Control does not exist");
		} else {
		SetWindowText(hWndBtn, TEXT("Cancel"));
    	}
#endif
    }
}
//---------------------------------------------------------------------------
#ifdef USEFULINFO
#define IDOK                1
#define IDCANCEL            2
#define IDABORT             3
#define IDRETRY             4
#define IDIGNORE            5
#define IDYES               6
#define IDNO                7
#if(WINVER >= 0x0400)
#define IDCLOSE         8
#define IDHELP          9
#endif /* WINVER >= 0x0400 */
#endif
//---------------------------------------------------------------------------

void __fastcall TSetup::MPHScalingChange(TObject *Sender)
{
MainForm->GlobalMPHScaling = MPHScaling->Value;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::CopyrightClick(TObject *Sender)
{
// Copy the Form to the clipboard.
// In BCB4.0, there is no SetSize method associated with TBitmap
// so we have to use Width and Height separately.
//
// see:
// https://stackoverflow.com/questions/3190777/how-do-i-copy-a-form-as-an-image-to-the-clipboard
//
Graphics::TBitmap * bm;
bm = new Graphics::TBitmap;
try
	{
    #if __BORLANDC__ >= 0x720
	// Defined for CB10.1 C++ programs that use the VCL.
	bm->SetSize(ClientWidth, ClientHeight);
    #else
    bm->Width = ClientWidth;
    bm->Height = ClientHeight;
    #endif
	BitBlt(bm->Canvas->Handle, 0, 0, ClientWidth, ClientHeight, Canvas->Handle, 0, 0, SRCCOPY);
    Clipboard()->Assign(bm);
    }
__finally
	{
	delete bm;
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::DTRAlwaysOnClick(TObject *Sender)
{
//MainForm->DTRSwitch->Checked = DTRAlwaysOn->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::Scan(String Service, TListBox * MyListBox)
{
// Scan for devices with a given Service. Use either "All" or selected interface.
//
// Start an mDNSThread for either each of the interfaces found and listed in the IPComboBox
// or for the one interface selected using the IPComboBox->Text property
//
// Set USEmDNSThread to true to use mDNSThread, set to false to use mDNSSServices
// [mDNSServices get some kind of memory corruption problem in open_client_sockets()
// during the call to GetAdaptersAddresses when using the new code and a failure
// in the OLD code around the call to ipv4_address_to_string() - do not use mDNSServices
// for Scan(). OK to use it for announcing and responding to service inqueries.]
//
#define USEmDNSThread true
//
#if USEmDNSThread

if (IPComboBox->Text == "All" && IPComboBox->Items->Count > 0) {
    //
    // Do an mDNS scan on every interface found
    //
    for (int idx = 0 ; idx < IPComboBox->Items->Count ; idx++) {
        // Create (but don't run) the MultiDNS Thread
        // Create suspended - in BCB 4.0, the thread constructor does not wait for lower level constructors itself.
        // The Execute() routine actually runs before some lower level construction is finished.
        // Don't put constructions in the thread constructor. if you have to, start the thread suspended and then start it running
        // per Remy LeBeau (TeamB) it is a Known bug that was fixed in BCB 6.0

		ptrMultiDNSThread = new TMultiDNS(true, this, Handle, IPComboBox->Items->Strings[idx], MyListBox->Items);
        assert(ptrMultiDNSThread);	// Check that constructor worked

        // Set variables used by the mDNS thread
        ptrMultiDNSThread->query_arg =  Service;

        // Successful Open
        #if __BORLANDC__ >= 0x720
        ptrMultiDNSThread->Start();		// start the thread for CB10.1
        #else
        ptrMultiDNSThread->Resume();	// start the thread for BCB4.0 - use deprecated in CB10.1, use Start() instead
        #endif
        ptrMultiDNSThread->WaitFor();
        delete ptrMultiDNSThread;
        ptrMultiDNSThread = NULL;
        }
    } else {
    //
    // Do a service scan on the selected interface
    //
    // Create (but don't run) the MultiDNS Thread
    // Create suspended - in BCB 4.0, the thread constructor does not wait for lower level constructors itself.
    // The Execute() routine actually runs before some lower level construction is finished.
    // Don't put constructions in the thread constructor. if you have to, start the thread suspended and then start it running
    // per Remy LeBeau (TeamB) it is a Known bug that was fixed in BCB 6.0

    ptrMultiDNSThread = new TMultiDNS(true, this, Handle, IPComboBox->Text, MyListBox->Items);
    assert(ptrMultiDNSThread);	// Check that constructor worked

    // Set variables used by the mDNS thread
    ptrMultiDNSThread->query_arg =  Service;

    // Successful Open
    #if __BORLANDC__ >= 0x720
    ptrMultiDNSThread->Start();		// start the thread for CB10.1
    #else
    ptrMultiDNSThread->Resume();	// start the thread for BCB4.0 - use deprecated in CB10.1, use Start() instead
    #endif
    ptrMultiDNSThread->WaitFor();
    delete ptrMultiDNSThread;
    ptrMultiDNSThread = NULL;
    }
#endif
}
//---------------------------------------------------------------------------

void __fastcall TSetup::RFIDListBoxClick(TObject *Sender)
{
//
// Print the entries in the RFIDListBox
//
if (RFID_WiFi_Mode->Checked) {
    if (RFIDListBox->Items->Count == 0) {
        if (DEBUGGING) DB->Debug_Print("No RFID Detectors over WiFi Found");
        return;
        } else {
        TCHAR IP[50], RFIDName[50];
        int Port;
        for (int idx = 0 ; idx < RFIDListBox->Items->Count ; idx++) {
            int retv = _stscanf(RFIDListBox->Items->Strings[idx].c_str(), TEXT("%s %d %s"), IP, &Port, RFIDName);
            // Parse out the RFID Name, IP and Port
            if (retv == 3) {
                if (DEBUGGING) DB->Debug_Print("RFID Detector Found : " + String(RFIDName) + " at " + String(IP) + " : Port : " + String(Port));
                }
            }
        }
    }
if (RFID_COM_Mode->Checked) {
    const int SelectedCOMPort = RFIDListBox->ItemIndex;
    int nPort;
    int retv = _stscanf(RFIDListBox->Items->Strings[SelectedCOMPort].c_str(),TEXT("COM%d"), &nPort);
    if (retv == 1) {
        RFIDCOMPortNum->Value = nPort;
        if (DEBUGGING) DB->Debug_Print("Radio COM" + String(nPort) + " Selected");
        } else {
        RFIDCOMPortNum->Value = 1;
        if (DEBUGGING) DB->Debug_Print("No RFID COM Port Found");
        }
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::AIUListBoxClick(TObject *Sender)
{
//
// Note that I have found that Multicast mode gives much slower response times
// than Unicast. Multicast is not needed with the Radio since only one
// radio is supported. The check box is not visible and cannot be changed.
//
// This is different than the AIU devices. There can be an almost unlimited number of
// AIU devices so that Multicast is required. The check box is not visible and cannot be
// changed.
//
    AIUIP->Text = "239.255.200.3";
	AIUPort->Text = "8890";
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanRFIDButtonClick(TObject *Sender)
{
//MainForm->ConnectedRFIDLED->Flashing = false;
if (RFID_WiFi_Mode->Checked) {
    if (!RFID_WiFi_Mode->Checked) {
    	MainForm->DebugMessagePopup("Warning", MainForm->RFIDWiFiMsg);
        return;
    	}
    RFIDListBox->Clear();
    // clear boolean flags
    for (int iRFID = 0; iRFID < RFIDMAX ; iRFID++) {
        Detector[iRFID].Found = false;
        }
    // Scan for RFID tcp Detector capable devices
    MainForm->DebugMessagePopup(Caption, "Scanning for RFID WiFi Devices", "Please Wait");
    // Set variables used by the mDNS thread
    Scan("_RTCRFID._tcp.local", RFIDListBox);

    // parse the results of the mDNS scan to find all Detectors
    TCHAR IP[50], RFIDName[50];
    int Port, TotalReaders = 0;
    // Set variables used by the RFID Detection sections of RTC
    if (RFIDListBox->Items->Count > 0) {
        for (int idex = 0 ; idex < RFIDListBox->Items->Count ; idex++) {
            int retv = _stscanf(RFIDListBox->Items->Strings[idex].c_str(), TEXT("%s %d %s"), IP, &Port, RFIDName);
            if (retv == 3) {	// found three items
                // parse RFIDName   "Detector-X-Y"
                int Det, Readers;
                retv = _stscanf(RFIDName, TEXT("Detector-%d-%d"), &Det, &Readers);	// parse the Name to get detector number & number of readers
                if (retv == 2) {	// found two items
                    if (Det > 0 && Det < RFIDMAX) {
                        Detector[Det].Found = true;	// Update the Detectors boolean array flag for each Detector found
                        Detector[Det].Addr = IP;
                        Detector[Det].Port = Port;
                        Detector[Det].NumReaders = Readers;   // 1 or 2 tag readers may be present
                        if (DEBUGGINGX(5)) DB->Debug_Print("RFID Detector " + String(Det) + " Found : " + IP + " : " + String(Port) + " : " + String(Readers));
                        TotalReaders += Readers;
                        }
                    continue;
                    }
                }
            }
        }
    MainForm->NumDetectors->Value = RFIDListBox->Items->Count;
    MainForm->NumReaders->Value = TotalReaders;
    NumDetectors->Value = RFIDListBox->Items->Count;
    NumReaders->Value = TotalReaders;
    RFIDListBoxClick(Sender);   // show the detectors in the debug messages
    //
    /*
#if __BORLANDC__ >= 0x720
    if (((RFIDDetectorCount != -1) && (RFIDListBox->Items->Count < RFIDDetectorCount)) ||
        ((RFIDReaderCount != -1) && (TotalReaders < RFIDReaderCount))) {
        MainForm->ConnectedRFIDLED->Flashing = true;
        MainForm->DebugMessagePopup("Error", "Some RFID detectors not found", "(Check that RFID detectors are powered up and connected to WiFi)", 5000);
        return;
        } else {
        MainForm->DebugMessagePopup("Scanning", "RFID Scanning Complete", "Found " + String(RFIDListBox->Items->Count) + " detector(s) and " +
            String(TotalReaders) + " reader(s)", UIPOPUPTIMEOUT);
        }
    #else
    */
    // BCB 4.0
    TMessagePopup * MessagePopup = new TMessagePopup(this, Handle, (WPARAM)0, (LPARAM)0);     // Synchronize() Pass "this" as the owner
    assert(MessagePopup != NULL);		// make sure that construction worked
    MessagePopup->Show();
    if (((RFIDDetectorCount != -1) && (RFIDListBox->Items->Count < RFIDDetectorCount)) ||
        ((RFIDReaderCount != -1) && (TotalReaders < RFIDReaderCount))) {
        MainForm->ConnectedRFIDLED->Flashing = true;
        MessagePopup->StatusLine->Caption = "(Check that detectors are powered up and connected to WiFi)";
        MessagePopup->Caption = "Error";
        MessagePopup->MessageLine->Caption = "Some RFID detectors not found";
        MessagePopup->Repaint();
        MainForm->Delay(5000);
        MessagePopup->Hide();
        delete MessagePopup;
        return;     // did not find any detectors
        } else {
        MessagePopup->StatusLine->Caption = "Found " + String(RFIDListBox->Items->Count) + " detector(s) and " +
            String(TotalReaders) + " reader(s)";
        MessagePopup->Caption = "Scanning";
        MessagePopup->MessageLine->Caption = "RFID Scanning Complete";
        MessagePopup->Repaint();
        MainForm->Delay(UIPOPUPTIMEOUT);
        MessagePopup->Hide();
        delete MessagePopup;
        // found two or more detectors
        }
//#endif

    }
//
if (RFID_COM_Mode->Checked) {
    RFIDListBox->Clear();
    // Find all serial ports
    MainForm->DebugMessagePopup(Caption, "Scanning for COM Ports", "Please Wait");
    (void) EnumerateComPorts(RFIDListBox);
    RFIDListBoxClick(Sender);   // show the COM ports in the debug messages
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanAIUButtonClick(TObject *Sender)
{
/*
//MainForm->ConnectedRFIDLED->Flashing = false;
if (!AIU_WiFi_Mode->Checked) {
	MainForm->DebugMessagePopup("Warning", "AIU WiFi must be enabled before performing this operation");
    return;
	}
AIUListBox->Clear();
// clear boolean flags
for (int iTIU = 1; iTIU <= TIUMAX ; iTIU++) { // TIU 1-5
    AIUEmulator[iTIU-1].Found = false;
	}
for (int cnt = 1; cnt <= 100 ; cnt++) { // Display 1 - 100
    MessageDisplay[cnt-1].Found = false;
	}
// Scan for AIU capable devices
MainForm->DebugMessagePopup(Caption, "Scanning for RTCAIU WiFi Devices", "Please Wait");
Scan("_RTCAIU._udp.local", AIUListBox);
// Scan for Message Display Devices
MainForm->DebugMessagePopup(Caption, "Scanning for RTCMSG WiFi Devices", "Please Wait");
Scan("_RTCMSG._udp.local", AIUListBox);

// parse the results of the mDNS scan to find all TIU that have AIU Emulators
TCHAR IP[50], AIUName[50];
int Port;
// Set variables used by the mDNS thread
if (AIUListBox->Items->Count > 0) {
    for (int idex = 0 ; idex < AIUListBox->Items->Count ; idex++) {
        int retv = _stscanf(AIUListBox->Items->Strings[idex].c_str(), TEXT("%s %d %s"), IP, &Port, AIUName);
        if (retv == 3) {	// found three items
            // parse AIUName   AIU411 : 4 = TIU  1 = AIU  1 = Starting Channel
            int TIU, AIU, Chan;
            retv = _stscanf(AIUName, TEXT("AIU-%1d%1d%d"), &TIU, &AIU, &Chan);	// parse the Name to get TIU number
            if (retv == 3) {	// found three items
                // set AIUEmulator[] indexed by TIU-1
                AIUEmulator[TIU-1].Found = true;	// Update the AIUEmulator boolean array flag for each TIU found
                AIUEmulator[TIU-1].IP = IP;
                AIUEmulator[TIU-1].Port = Port;
                AIUEmulator[TIU-1].Name = Name;
				AIUEmulator[TIU-1].AIU = AIU;
                AIUEmulator[TIU-1].Chan = Chan;
                continue;
                }
            int Display;
            retv = _stscanf(AIUName, TEXT("Display-%d"), &Display);
            if (retv == 1)  {    // found one item
                // set MessageDisplay[] indexed by Display-1
                MessageDisplay[Display-1].Found = true;
                MessageDisplay[Display-1].IP = IP
                MessageDisplay[Display-1].Port = Port;
                MessageDisplay[Display-1] = Name;
                continue;
                }
            }
        }
    }
    */
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanTIUWTIUButtonClick(TObject *Sender)
{
// Based on the TIU Port Enable check boxes, scan either
// Serial COM or WTIU devices
//MainForm->ConnectedRFIDLED->Flashing = false;
if (Radio_COM_Mode->Checked) {
    // Find all serial ports
    WTIUListBox->Clear();
    MainForm->DebugMessagePopup(Caption, "Scanning for COM Ports", "Please Wait");
    (void) EnumerateComPorts(WTIUListBox);
    WTIUListBoxClick(Sender);
    }
if (WTIU_WiFi_Mode->Checked) {
    // Find all WTIU Ports
    if (Setup) {
    WTIUListBox->Clear();
    ScanTIUWIUtcpClick(Sender);
        }
    // WTIUListBoxClick(Sender);
    }
}
//---------------------------------------------------------------------------
// Not USED
void __fastcall TSetup::ScanModemClick(TObject *Sender)
{
WTIUListBox->Clear();
// Scan for Modem capable devices
MainForm->DebugMessagePopup(Caption, "Scanning for RTCModem WiFi Devices", "Please Wait");
// Set variables used by the mDNS thread
Scan("_RTCModem._udp.local", WTIUListBox);
if (WTIUListBox->Items->Count == 0) {
	MainForm->DebugMessagePopup("Error", "No RTCModem Radio WiFi Devices found.");
	}
    // Multiple WTIU mode now uses all WTIU, no selection needed
     else
    if (WTIUListBox->Items->Count > 1) {
		MainForm->DebugMessagePopup("Warning", "Click on one of the listed RTCModem Devices to use it");
    	} else
        // exactly one found
    	MainForm->DebugMessagePopup("Information", "Click on the listed RTCModem Radio WiFi Device to use it");
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanOTAClick(TObject *Sender)
{
WTIUListBox->Clear();
// Scan for OTA capable devices
MainForm->DebugMessagePopup(Caption, "Scanning for OTA Capable WiFi Devices Devices", "Please Wait");
// Set variables used by the mDNS thread
Scan("_arduino._tcp.local", WTIUListBox);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanMSGClick(TObject *Sender)
{
WTIUListBox->Clear();
// Scan for RTCMSG capable devices
MainForm->DebugMessagePopup(Caption, "Scanning for RTCMSG WiFi Devices", "Please Wait");
// Set variables used by the mDNS thread
Scan("_RTCMSG._udp.local", WTIUListBox);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanSignalClick(TObject *Sender)
{
WTIUListBox->Clear();
// Scan for RTCSignal capable devices
MainForm->DebugMessagePopup(Caption, "Scanning for Signal WiFi Devices", "Please Wait");
// Set variables used by the mDNS thread
Scan("_RTCSignal._udp.local", WTIUListBox);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanMasterClick(TObject *Sender)
{
WTIUListBox->Clear();
// Scan for RTC Master capable devices
MainForm->DebugMessagePopup(Caption, "Scanning for RTCMaster WiFi Devices", "Please Wait");
// Set variables used by the mDNS thread
Scan("_RTCMaster._udp.local", WTIUListBox);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanHostClick(TObject *Sender)
{
WTIUListBox->Clear();
// Scan for RTC Master capable devices
MainForm->DebugMessagePopup(Caption, "Scanning for RTCHost WiFi Devices", "Please Wait");
// Set variables used by the mDNS thread
Scan("_RTCHost._udp.local", WTIUListBox);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanEngineClick(TObject *Sender)
{
WTIUListBox->Clear();
// Scan for RTCEngine capable devices
MainForm->DebugMessagePopup(Caption, "Scanning for RTCEngine WiFi Devices", "Please Wait");
// Set variables used by the mDNS thread
Scan("_RTCEngine._udp.local", WTIUListBox);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanTIUWIUtcpClick(TObject *Sender)
{
WTIUListBox->Clear();
//
// Scan for mth-dcs._tcp.local services
//
MainForm->DebugMessagePopup(Caption, "Scanning for WIU/TIU and WTIU WiFi Devices", "Please Wait");
Scan("_mth-dcs._tcp.local", WTIUListBox);
//
// in BCB 4.0, the Synchronize call in the Message_Thread is not executed and the message box
// stays on the screen. I have written work around code.
//
// in CB 10.1, the message box is correctly taken down and the original code can remain
//
// BUT  MainForm->DebugMessagePopup is used in many places in Setup and works ok
//
// CB 10.1
#if __BORLANDC__ >= 0x720
if (WTIUListBox->Items->Count == 0) {
    MainForm->DebugMessagePopup("Error", "No TIU WiFi Devices found - RTC requires at least one TIU WiFi Device", "(Check that 'Setup->Select Active TIU' is set correctly)", 5000);
    MainForm->ConnectedRFIDLED->Flashing = true;
    return;
    } else {
    MainForm->DebugMessagePopup("Scanning", "TIU Scanning Complete", "Found " + String(WTIUListBox->Items->Count) + " TIU(s)", UIPOPUPTIMEOUT);
    }
#else
// BCB 4.0
TMessagePopup * MessagePopup = new TMessagePopup(this, Parent, NULL, NULL);     // Synchronize() Pass "this" as the owner
assert(MessagePopup != NULL);		// make sure that construction worked
MessagePopup->Show();
if (WTIUListBox->Items->Count == 0) {
    MainForm->ConnectedRFIDLED->Flashing = true;
    MessagePopup->StatusLine->Caption = "(Check that 'Setup->Select Active TIU' is set correctly)";
    MessagePopup->Caption = "Error";
    MessagePopup->MessageLine->Caption = "No TIU WiFi Devices found - RTC requires at least one TIU WiFi Device";
    MessagePopup->Repaint();
    MainForm->Delay(5000);
    MessagePopup->Hide();
    delete MessagePopup;
    return;     // did not find any WTIU
    } else {
    MessagePopup->StatusLine->Caption = "Found " + String(WTIUListBox->Items->Count) + " TIU(s)";
    MessagePopup->Caption = "Scanning";
    MessagePopup->MessageLine->Caption = "TIU Scanning Complete";
    MessagePopup->Repaint();
    MainForm->Delay(UIPOPUPTIMEOUT);
    MessagePopup->Hide();
    delete MessagePopup;
    // found one or more WTIU
    }
#endif
}
//---------------------------------------------------------------------------
void __fastcall TSetup::OOKRadioHelpClick(TObject *Sender)
{
HINSTANCE retv = ShellExecute(NULL, TEXT("open"), TEXT("http://www.silogic.com/trains/OOK_Radio_Support.html"), NULL, NULL, SW_SHOWNORMAL);
if ((int)retv <= 32) {
	// error
    if (DEBUGGING) DB->Debug_Print("Shell Execute error - return value = " + String((int) retv));
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::RFIDTagsHelp1Click(TObject *Sender)
{
HINSTANCE retv = ShellExecute(NULL, TEXT("open"), TEXT("http://www.silogic.com/trains/RFID.html"), NULL, NULL, SW_SHOWNORMAL);
if ((int)retv <= 32) {
	// error
    if (DEBUGGING) DB->Debug_Print("Shell Execute error - return value = " + String((int) retv));
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::RTCHelp1Click(TObject *Sender)
{
HINSTANCE retv = ShellExecute(NULL, TEXT("open"), TEXT("http://www.silogic.com/trains/RTC_Running.html"), NULL, NULL, SW_SHOWNORMAL);
if ((int)retv <= 32) {
	// error
    if (DEBUGGING) DB->Debug_Print("Shell Execute error - return value = " + String((int) retv));
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::WiFiInformation1Click(TObject *Sender)
{
HINSTANCE retv = ShellExecute(NULL, TEXT("open"), TEXT("http://www.silogic.com/trains/WiFi.html"), NULL, NULL, SW_SHOWNORMAL);
if ((int)retv <= 32) {
	// error
    if (DEBUGGING) DB->Debug_Print("Shell Execute error - return value = " + String((int) retv));
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::StartmDNSServices(bool RTCMaster, bool RTCHost)
{
//
// Start advertising the Services RTCHost and RTCMaster - both services are started, parameters not used
//
// Start an mDNSService for either each of the IP addresses found and listed in the IPComboBox
// or for the one IP address selected using the IPComboBox->Text property
//
// Note: this routine always advertises the RTCMaster and the RTCHost services. Hard coded.
//
// Create (but don't run) the MultiDNS Service Thread
// Create suspended - in BCB 4.0, the thread constructor does not wait for lower level constructors itself.
// The Execute() routine actually runs before some lower level construction is finished.
// Don't put constructions in the thread constructor. if you have to, start the thread suspended and then start it running
// per Remy LeBeau (TeamB) it is a Known bug that was fixed in BCB 6.0
// Select an interface
if (IPComboBox->Items->Count == 0) {
	// no Host IP addresses are listed in the IPComboBox
    if (DEBUGGING) DB->Debug_Print("Select a Host IP Address for WiFi Operations");
    return;
    }

if (IPComboBox->Text == "All") {
    for (int idx = 0 ; idx < IPComboBox->Items->Count ; idx++) {
        if (ptrmDNSServices[idx]) {	// already running
        	continue;
        	}
        //if (DEBUGGING) DB->Debug_Print("mDNS Server Starting on " + IPComboBox->Items->Strings[idx]);
		uint32_t S_Addr = WSocket_inet_addr(IPComboBox->Items->Strings[idx].c_str());	// Previously set to INADDR_ANY
        if (DEBUGGING) DB->Debug_Print("Starting mDNS Service (RTCMaster & RTCHost) at IP Address = " + IPComboBox->Items->Strings[idx]);
        ptrmDNSServices[idx] = new mDNSServices(true, S_Addr, RTCMaster, RTCHost);
        assert(ptrmDNSServices[idx]);	// Check that constructor worked
        MainForm->mDNSLED->Checked = true;
        //
        // Successful Open
        if (ptrmDNSServices[idx]) {
            #if __BORLANDC__ >= 0x720
            ptrmDNSServices[idx]->Start();	// start the thread for CB10.1
            #else
            ptrmDNSServices[idx]->Resume();	// start the thread for BCB4.0 - use deprecated in CB10.1, use Start() instead
            #endif
            }
        if (DEBUGGING) DB->Debug_Print("Started mDNS Service (RTCMaster & RTCHost) at IP Address " + IPComboBox->Items->Strings[idx]);
        }
    } else {
    if (ptrmDNSServices[IPComboBox->ItemIndex]) {	// already running
	    return;
    	}
    uint32_t S_Addr = WSocket_inet_addr(IPComboBox->Text.c_str());	// Previously set to INADDR_ANY
    if (DEBUGGING) DB->Debug_Print("Starting mDNS Service (RTCMaster & RTCHost) at IP Address = " + IPComboBox->Text);
	ptrmDNSServices[IPComboBox->ItemIndex] = new mDNSServices(true, S_Addr, RTCMaster, RTCHost);
    assert(ptrmDNSServices[IPComboBox->ItemIndex] );	// Check that constructor worked

	//
    // Successful Open
    if (ptrmDNSServices[IPComboBox->ItemIndex]) {
        #if __BORLANDC__ >= 0x720
        ptrmDNSServices[IPComboBox->ItemIndex] ->Start();	// start the thread for CB10.1
        #else
        ptrmDNSServices[IPComboBox->ItemIndex] ->Resume();	// start the thread for BCB4.0 - use deprecated in CB10.1, use Start() instead
        #endif
        MainForm->mDNSLED->Checked = true;
        mDNSServer->Checked = true;
        if (DEBUGGING) DB->Debug_Print("mDNS Server Started");
        }
    }
}
//---------------------------------------------------------------------------
void __fastcall TSetup::StopmDNSServices()
{
//
// Stop advertising the Services - stops all mDNSservices
//
// mDNSServices thread(s) will free on terminate
for (int idx = 0 ; idx < MAXINTERFACES ; idx++) {
	if (ptrmDNSServices[idx]) {   	    // not running
		ptrmDNSServices[idx]->KillMe(NULL);
        // https://stackoverflow.com/questions/6313645/why-do-i-get-the-handle-is-invalid-when-waiting-for-a-thread-ive-told-to-term
		//ptrmDNSServices[idx]->WaitFor();  // works BCB4.0, in CB10.1 gets Thread Error the handle in invalid (6)
		ptrmDNSServices[idx] = NULL;
        }
	}
MainForm->mDNSLED->Checked = false;
mDNSServer->Checked = false;
if (DEBUGGING) DB->Debug_Print("mDNS Server Stopped");
}
//---------------------------------------------------------------------------

void __fastcall TSetup::mDNSServerClick(TObject *Sender)
{
// This is supplied as a MenuItem selection for Debugging Only.
//
if (!RFID_WiFi_Mode->Checked) return;   // WiFi Mode only
//
if (!ptrmDNSServices[0]) {
	// Start the mDNS Server
    MainForm->DebugMessagePopup("Please Wait", "Starting the mDNS Server(s)", "");
	StartmDNSServices(RFID_WiFi_Mode->Checked, WTIU_WiFi_Mode->Checked);
    } else {
	// Stop the mDNS Server
	MainForm->DebugMessagePopup("Please Wait", "Stopping the mDNS Server(s)", "");
	StopmDNSServices();
    }
}
//---------------------------------------------------------------------------

void __fastcall TSetup::AIU_WiFi_ModeClick(TObject *Sender)
{
//
// Setup AIU Emulator WiFi Mode
//
if (!AIU_WiFi_Mode->Checked) {
    AIUListBox->Clear();
    }
//
if (AIU_WiFi_Mode->Checked) {
    AIUWiFiLabel->Enabled = true;
    AIU_WiFi_Multicast->Enabled = true;
    AIUIP->Enabled = true;
    AIUPort->Enabled = true;
    AIUListBox->Enabled = true;
    HostIPPage->Enabled = true;
	} else {
    AIUWiFiLabel->Enabled = false;
    AIU_WiFi_Multicast->Enabled = false;
    AIUIP->Enabled = false;
    AIUPort->Enabled = false;
    AIUListBox->Enabled = false;
    }
Set_Comment();
}
//---------------------------------------------------------------------------
#ifdef OLDWAY
int __fastcall TSetup::FindIPs()
{
// this routine has been replaced by LocalIPList() from OverbyteIcsWSocket.

// https://tangentsoft.net/wskfaq/examples/ipaddr.html

char ac[80];
int IPCount = 0;

WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
    return -1;
    }

if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) {
    if (DEBUGGING) DB->Debug_Print("Error " + String(WSAGetLastError()) + " when getting local host name");
	WSACleanup();
    return -1;
    }
if (DEBUGGING) DB->Debug_Print("Host name is " + String(ac));

IPComboBox->Items->Clear();
struct hostent *phe = gethostbyname(ac);
if (phe == 0) {
    if (DEBUGGING) DB->Debug_Print("Bad host lookup");
    WSACleanup();
    return -1;
    }

for (int i = 0; phe->h_addr_list[i] != 0; ++i) {
    struct in_addr addr;
    memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
    IPComboBox->Items->Append(WSocket_inet_ntoa(addr));
    if (DEBUGGING) DB->Debug_Print("Interface Found : " + String(WSocket_inet_ntoa(addr)));
    IPCount++;
	}
    
WSACleanup();
return IPCount;
}

#endif

//---------------------------------------------------------------------------

void __fastcall TSetup::IPComboBoxClick(TObject *Sender)
{
//
// restart the mDNSServer
StopmDNSServices();
StartmDNSServices(RFID_WiFi_Mode->Checked, WTIU_WiFi_Mode->Checked);	// Start the mDNS responder if in WiFi mode
return;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanHostIPButtonClick(TObject *Sender)
{
IPComboBox->Items->Clear();
TStrings *IPList;
IPList = LocalIPList();
IPComboBox->Items = IPList;

if (IPComboBox->Items->Count == 0) { // 0 based
	MainForm->DebugMessagePopup("Warning", "A Host IP Address is Required for WiFi Operations");
    IPComboBox->ItemIndex = -1;  // Deselect any IP address
    IPComboBox->Text = "None";
	return;
	}
IPComboBox->ItemIndex = -1;  // Deselect any IP address
IPComboBox->Text = "All";
}
//---------------------------------------------------------------------------

void __fastcall TSetup::NoSleepClick(TObject *Sender)
{
// Sleep
if (NoSleep->Checked) {
    // This sets the appropriate flags to prevent the system going into sleep mode; this is useful if making a screen saver that processes data in the background and can't have the computer sleep
    SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
    }
if (!NoSleep->Checked) {
	// This allows the system to sleep normally
	SetThreadExecutionState(ES_CONTINUOUS);
	}
//
}
//---------------------------------------------------------------------------

void __fastcall TSetup::FormCloseQuery(TObject *Sender, bool &CanClose)
{
// one and only one TIU/WTIU mode can be selected
if ((!WTIU_WiFi_Mode->Checked) ||
    (!Radio_COM_Mode->Checked)) {
    CanClose = true;
    return;
    }
MainForm->DebugMessagePopup("Error", "One and Only One TIU/WTIU mode can be selected");
CanClose = false;
}

//---------------------------------------------------------------------------

void __fastcall TSetup::ScanforAIUWiFiDevices1Click(TObject *Sender)
{
AIUListBox->Clear();
// Scan for AIU capable devices
MainForm->DebugMessagePopup("Wait", "Scanning for RTCAIUWiFi Devices", "Please Wait");
// Set variables used by the mDNS thread
Scan("_RTCAIU._udp.local", AIUListBox);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanforRFIDudpDevices1Click(TObject *Sender)
{
// RFID no longer uses udp but rather, uses tcp
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanforRFIDtcpDevices1Click(TObject *Sender)
{
ScanRFIDButtonClick(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::EnumerateSerialPorts10Click(TObject *Sender)
{
WTIUListBox->Clear();
MainForm->DebugMessagePopup("Wait", "Scanning for COM Ports", "Please Wait");
(void) EnumerateComPorts(WTIUListBox);
WTIUListBoxClick(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::EnumerateSerialPorts6Click(TObject *Sender)
{
RFIDListBox->Clear();
MainForm->DebugMessagePopup("Wait", "Scanning for COM Ports", "Please Wait");
(void) EnumerateComPorts(RFIDListBox);
WTIUListBoxClick(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ListBoxDrawItem(TWinControl *Control,
      int Index, TRect &Rect, TOwnerDrawState State)
{
// This owner draw method assures that even when the control is not enabled, it
// will still be readable
//
 TListBox *pListbox = dynamic_cast<TListBox*>(Control);
 TCanvas *pCanvas = pListbox->Canvas;

 if(State.Contains(odSelected))
 {
  pCanvas->Brush->Color = clBlack;
  pCanvas->Font->Color = clWhite;
 }
 else
 {
  pCanvas->Brush->Color = clWhite;
  pCanvas->Font->Color = clBlack;
 }

 pCanvas->FillRect(Rect);
 pCanvas->TextRect(Rect, Rect.Left,Rect.Top, pListbox->Items->Strings[Index]);
}
//---------------------------------------------------------------------------

void __fastcall TSetup::HiddenClick(TObject *Sender)
{
// turn on debug check box panel
Setup->SerialDebugPanel->Visible = !Setup->SerialDebugPanel->Visible;

Setup->BaudRateSel->Enabled = Setup->SerialDebugPanel->Visible;
Setup->ParitySel->Enabled = Setup->SerialDebugPanel->Visible;
Setup->BitsSel->Enabled = Setup->SerialDebugPanel->Visible;
Setup->StopSel->Enabled = Setup->SerialDebugPanel->Visible;

// turn on debug version of port control
Setup->TIUPortListGroup->Visible = !Setup->SerialDebugPanel->Visible;
Setup->BaudRateSel->Visible = Setup->SerialDebugPanel->Visible;
Setup->ParitySel->Visible = Setup->SerialDebugPanel->Visible;
Setup->StopSel->Visible = Setup->SerialDebugPanel->Visible;
Setup->ParitySel->Visible = Setup->SerialDebugPanel->Visible;
Setup->BitsSel->Visible = Setup->SerialDebugPanel->Visible;
}
//---------------------------------------------------------------------------

void __fastcall TSetup::EditthisRecording1Click(TObject *Sender)
{
if (RecordingFileName.IsEmpty()) return;    // no file name
// Attempt to run a text editor on the script
HINSTANCE retv;
String FileName = "\"" + RecordingFileName + "\"";
String DirName = "\"" + ExtractFilePath(RecordingFileName) + "\"";
// Try these in order:  Notepad++, Metapad, Notepad, Wordpad
String ProgramToRun = "notepad++";
retv = ShellExecute(Handle,
       	NULL,
        ProgramToRun.c_str(),	// Program to Run
        FileName.c_str(),		// Passed Parameter
        DirName.c_str(),		// Directory
        SW_SHOWNORMAL);
if ((int)retv > 32) return;

ProgramToRun = "metapad";
retv = ShellExecute(Handle,
       	NULL,
        ProgramToRun.c_str(),	// Program to Run
        FileName.c_str(),		// Passed Parameter
        DirName.c_str(),		// Directory
        SW_SHOWNORMAL);
if ((int)retv > 32) return;

ProgramToRun = "notepad";
retv = ShellExecute(Handle,
       	NULL,
        ProgramToRun.c_str(),	// Program to Run
        FileName.c_str(),		// Passed Parameter
        DirName.c_str(),		// Directory
        SW_SHOWNORMAL);
if ((int)retv > 32) return;

TCHAR TProgramToRun[256];
ExpandEnvironmentStrings(TEXT("%ProgramFiles%\\Windows NT\\Accessories\\wordpad.exe"), TProgramToRun, sizeof(TProgramToRun) - 2);
/*  the use of the environment variables is deprecated; see SHGetFolderPath() instead (but note that the
exact function you need depends on the versions of Windows you want to support)
*/
retv = ShellExecute(Handle,
       	NULL,
        TProgramToRun,			// Program to Run
        FileName.c_str(),		// Passed Parameter
        DirName.c_str(),		// Directory
        SW_SHOWNORMAL);
if ((int)retv > 32) return;

Application->MessageBox(TEXT("Can't Run your Editor"), TEXT("Warning"), MB_OK  | MB_ICONWARNING);    
}
//---------------------------------------------------------------------------

void __fastcall TSetup::ScanSignalsButtonClick(TObject *Sender)
{
//MainForm->ConnectedRFIDLED->Flashing = false;
if (!Signals_WiFi_Mode->Checked) {
	MainForm->DebugMessagePopup("Warning", "Signals WiFi must be enabled before performing this operation");
    return;
	}
SignalsListBox->Clear();
// clear boolean flags
for (int iSig = 0; iSig < SIGNALMAX ; iSig++) {
    Signals[iSig].Found = false;
    }
// Scan for Signals capable devices
MainForm->DebugMessagePopup(Caption, "Scanning for Signals WiFi Devices", "Please Wait");
Scan("_RTCSignal._udp.local", SignalsListBox);

// parse the results of the mDNS scan to find all Signals
TCHAR IP[50], SignalName[50];
int Port, TotalSignals = 0;
// Set variables used by Layout window
if (SignalsListBox->Items->Count > 0) {
    for (int idex = 0 ; idex < SignalsListBox->Items->Count ; idex++) {
        int retv = _stscanf(SignalsListBox->Items->Strings[idex].c_str(), TEXT("%s %d %s"), IP, &Port, SignalName);
        if (retv == 3) {	// found three items
            // parse SignalName   "Signal-X-Y"
            int Sig1, Sig2;
            retv = _stscanf(SignalName, TEXT("Signal-%d-%d"), &Sig1, &Sig2);	// parse the Name to get signal numbers
            if (retv == 2) {	// found two items
                if (Sig1 > 0 && Sig1 < SIGNALMAX) {
                    Signals[Sig1].Found = true;	// Update the Signals boolean array flag for each Signal found
                    Signals[Sig1].Addr = IP;
                    Signals[Sig1].Port = Port;
                    if (DEBUGGINGX(5)) DB->Debug_Print("Signal " + String(Sig1) + " Found : " + IP + " : " + String(Port));
                    TotalSignals++;
                    }
                if (Sig2 > 0 && Sig2 < SIGNALMAX) {
                    Signals[Sig2].Found = true;	// Update the Signals boolean array flag for each Signal found
                    Signals[Sig2].Addr = IP;
                    Signals[Sig2].Port = Port;
                    TotalSignals++;
                    if (DEBUGGINGX(5)) DB->Debug_Print("Signal " + String(Sig2) + " Found : " + IP + " : " + String(Port));
                    }
                continue;
                }
            }
        }
    }
MainForm->NumSignals->Value = TotalSignals;
NumSignals->Value = TotalSignals;
SignalsListBoxClick(Sender);    // display the list in the debug window
//
/*#if __BORLANDC__ >= 0x720
if ((SignalCount != -1) && ((SignalsListBox->Items->Count * 2) < SignalCount)) {
    MainForm->DebugMessagePopup("Error", "Some Signals not found", "(Check that Signals are powered up and connected to WiFi)", 5000);
    MainForm->ConnectedRFIDLED->Flashing = true;
    return;
    } else {
    MainForm->DebugMessagePopup("Scanning", "Signals Scanning Complete", "Found " + String(SignalsListBox->Items->Count * 2) + " signal(s)", UIPOPUPTIMEOUT);
    }
#else
// BCB 4.0
*/
TMessagePopup * MessagePopup = new TMessagePopup(this, Handle, NULL, NULL);     // Synchronize() Pass "this" as the owner
assert(MessagePopup != NULL);		// make sure that construction worked
MessagePopup->Show();
if ((SignalCount != -1) && ((SignalsListBox->Items->Count * 2) < SignalCount)) {
    MainForm->ConnectedRFIDLED->Flashing = true;
    MessagePopup->StatusLine->Caption = "(Check that Signals are powered up and connected to WiFi)";
    MessagePopup->Caption = "Error";
    MessagePopup->MessageLine->Caption = "Some Signals not found";
    MessagePopup->Repaint();
    MainForm->Delay(5000);
    MessagePopup->Hide();
    delete MessagePopup;
    // did not find any Signals
    return;
    } else {
    MessagePopup->StatusLine->Caption = "Found " + String(SignalsListBox->Items->Count * 2) + " signal(s)";
    MessagePopup->Caption = "Scanning";
    MessagePopup->MessageLine->Caption = "Signals Scanning Complete";
    MessagePopup->Repaint();
    MainForm->Delay(UIPOPUPTIMEOUT);
    MessagePopup->Hide();
    delete MessagePopup;
    // found two or more Signals
    }
//#endif

}
//---------------------------------------------------------------------------

void __fastcall TSetup::Signals_WiFi_ModeClick(TObject *Sender)
{
//
// Setup Signals WiFi Mode
//
if (!Signals_WiFi_Mode->Checked) {
    SignalsListBox->Clear();
    }
//
if (Signals_WiFi_Mode->Checked) {
    if (Setup) {
    SignalsWiFiLabel->Enabled = true;
    SignalsListBox->Enabled = true;
    HostIPPage->Enabled = true;
    ScanSignalsButtonClick(Sender);
        MainForm->NumSignals->Visible = true;
        MainForm->SigLabel->Visible = true;
        }
	} else {
    if (Setup) {
    SignalsWiFiLabel->Enabled = false;
    SignalsListBox->Enabled = false;
        MainForm->NumSignals->Visible = false;
        MainForm->SigLabel->Visible = false;
    }
    }
Set_Comment();
}
//---------------------------------------------------------------------------

void __fastcall TSetup::SignalsListBoxClick(TObject *Sender)
{
//
// Print the entries in the SignalsListBox
//
if (Signals_WiFi_Mode->Checked) {
    if (SignalsListBox->Items->Count == 0) {
        if (DEBUGGING) DB->Debug_Print("No Signals Found");
        return;
        } else {
        TCHAR IP[50], SignalName[50];
        int Port;
        for (int idx = 0 ; idx < SignalsListBox->Items->Count ; idx++) {
            int retv = _stscanf(SignalsListBox->Items->Strings[idx].c_str(), TEXT("%s %d %s"), IP, &Port, SignalName);
            // Parse out the Signal Name and Port
            if (retv == 3) {
                if (DEBUGGING) DB->Debug_Print("Signal Found : " + String(SignalName) + " at " + String(IP) + " : Port : " + String(Port));
                }
            }
        }
    }
}
//---------------------------------------------------------------------------


