Пример #1
0
void CDummyRepeaterApp::createThread()
{
	m_thread = new CDummyRepeaterThread;
	m_thread->Create();
	m_thread->Run();

	wxString callsign1, callsign2;
	getCallsign(callsign1, callsign2);
	m_thread->setCallsign(callsign1, callsign2);

	wxString call;
	wxSortedArrayString list;

	getYourCalls(call, list);
	m_thread->setYour(call);

	getRpt1Calls(call, list);
	m_thread->setRpt1(call);

	getRpt2Calls(call, list);
	m_thread->setRpt2(call);

	wxString message;
	getMessage(message);
	m_thread->setMessage(message);

	DONGLE_TYPE dongleType;
	wxString dongleDevice, dongleAddress;
	unsigned int donglePort;
	getDongle(dongleType, dongleDevice, dongleAddress, donglePort);

	CDongleThread* dongle = NULL;

	switch (dongleType) {
		case DT_DVDONGLE:
			if (!dongleDevice.IsEmpty())
				dongle = new CDVDongleThread(new CDVDongleController(dongleDevice));
			break;
		case DT_DV3000:
			if (!dongleAddress.IsEmpty() && donglePort > 0U)
				dongle = new CAMBE3000Thread(new CDV3000Controller(dongleAddress, donglePort));
			break;
		default:
			wxLogError(wxT("Invalid Dongle type specified - %d"), int(dongleType));
			error(_("Invalid Dongle type specified"));
			break;
	}

	if (dongle != NULL) {
		dongle->setEncodeCallback(m_thread);
		dongle->setDecodeCallback(m_thread);

		bool res = dongle->open();
		if (!res) {
			wxLogError(wxT("Can't find the AMBE Dongle on the port specified"));
			error(_("Can't find the AMBE Dongle on the port specified"));
		} else {
			m_thread->setDongle(dongle);
		}
	}

	wxString readDevice, writeDevice;
	getSoundcard(readDevice, writeDevice);

	if (!readDevice.IsEmpty() && !writeDevice.IsEmpty()) {
#if defined(__WINDOWS__)
		CSoundCardReaderWriter* soundcard = new CSoundCardReaderWriter(readDevice, writeDevice, DSTAR_RADIO_SAMPLE_RATE, DSTAR_RADIO_BLOCK_SIZE);
#else
		CSoundCardReaderWriter* soundcard = new CSoundCardReaderWriter(readDevice, writeDevice, DSTAR_RADIO_SAMPLE_RATE, 64U);
#endif
		soundcard->setCallback(m_thread, 0);

		bool res = soundcard->open();
		if (!res) {
			wxLogError(wxT("Cannot open the sound card"));
			error(_("Cannot open the sound card"));
		} else {
			m_thread->setSoundCard(soundcard);
		}
	}

	wxString gwyAddress, localAddress;
	unsigned int gwyPort, localPort;
	getNetwork(gwyAddress, gwyPort, localAddress, localPort);

	if (!gwyAddress.IsEmpty()) {
		CRepeaterProtocolHandler* protocol = new CRepeaterProtocolHandler(gwyAddress, gwyPort, localAddress, localPort);

		bool res = protocol->open();
		if (!res) {
			wxLogError(wxT("Cannot open the protocol handler"));
			error(_("Cannot open the protocol handler"));
		} else {
			m_thread->setProtocol(protocol);
		}
	}

	wxString type;
	unsigned int config;
	bool pttInvert, squelchInvert;
	getController(type, config, pttInvert, squelchInvert);

	CExternalController* controller = NULL;

	wxString port;
	if (type.StartsWith(wxT("Velleman K8055 - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CK8055Controller(num), pttInvert, squelchInvert);
	} else if (type.StartsWith(wxT("URI USB - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CURIUSBController(num, true), pttInvert, squelchInvert);
	} else if (type.StartsWith(wxT("Serial - "), &port)) {
		controller = new CExternalController(new CSerialLineController(port, config), pttInvert, squelchInvert);
	} else if (type.StartsWith(wxT("Arduino - "), &port)) {
		controller = new CExternalController(new CArduinoController(port), pttInvert, squelchInvert);
#if defined(RASPBERRY_PI)
	} else if (type.IsSameAs(wxT("Raspberry Pi"))) {
		controller = new CExternalController(new CRaspberryController, pttInvert, squelchInvert);
#endif
	} else {
		controller = new CExternalController(new CDummyController, pttInvert, squelchInvert);
	}

	bool res = controller->open();
	if (!res) {
		wxLogError(wxT("Cannot open the hardware interface - %s"), type.c_str());
		error(_("Cannot open the hardware interface"));
	} else {
		m_thread->setController(controller);
	}

	bool bleep;
	getBleep(bleep);
	m_thread->setBleep(bleep);
}
Пример #2
0
void CAnalogueRepeaterApp::createThread()
{
	CAnalogueRepeaterThread* thread = new CAnalogueRepeaterThread;

	wxString openId, closeId, beacon1, beacon2;
	unsigned int speed, freq;
	wxFloat32 level1, level2;
	AUDIO_SOURCE openIdSource, closeIdSource, beacon1Source, beacon2Source;
	getCallsign(openIdSource, openId, closeIdSource, closeId, beacon1Source, beacon1, beacon2Source, beacon2, speed, freq, level1, level2);
	wxLogInfo(wxT("Open ID source: %d, value: \"%s\", close ID source: %d, value: \"%s\", beacon 1 source: %d, value: \"%s\", beacon 2 source: %d, value: \"%s\", speed: %u WPM, freq: %u Hz, level1: %.3f, level2: %.3f"), int(openIdSource), openId.c_str(), int(closeIdSource), closeId.c_str(), int(beacon1Source), beacon1.c_str(), int(beacon2Source), beacon2.c_str(), speed, freq, level1, level2);

	IFixedAudioSource* openIdAudio  = NULL;
	IFixedAudioSource* closeIdAudio = NULL;
	IFixedAudioSource* beacon1Audio = NULL;
	IFixedAudioSource* beacon2Audio = NULL;

	switch (openIdSource) {
		case AS_CW_KEYER:
			openIdAudio = new CCWKeyer(openId, speed, freq, ANALOGUE_RADIO_SAMPLE_RATE);
			break;
		case AS_WAV_FILE: {
				CWAVFileStore* audio = new CWAVFileStore;
				bool res = audio->load(openId, ANALOGUE_RADIO_SAMPLE_RATE);
				if (!res)
					delete audio;
				else
					openIdAudio = audio;
			}
			break;
	}

	switch (closeIdSource) {
		case AS_CW_KEYER:
			closeIdAudio = new CCWKeyer(closeId, speed, freq, ANALOGUE_RADIO_SAMPLE_RATE);
			break;
		case AS_WAV_FILE: {
				CWAVFileStore* audio = new CWAVFileStore;
				bool res = audio->load(closeId, ANALOGUE_RADIO_SAMPLE_RATE);
				if (!res)
					delete audio;
				else
					closeIdAudio = audio;
			}
			break;
	}

	switch (beacon1Source) {
		case AS_CW_KEYER:
			beacon1Audio = new CCWKeyer(beacon1, speed, freq, ANALOGUE_RADIO_SAMPLE_RATE);
			break;
		case AS_WAV_FILE: {
				CWAVFileStore* audio = new CWAVFileStore;
				bool res = audio->load(beacon1, ANALOGUE_RADIO_SAMPLE_RATE);
				if (!res)
					delete audio;
				else
					beacon1Audio = audio;
			}
			break;
	}

	switch (beacon2Source) {
		case AS_CW_KEYER:
			beacon2Audio = new CCWKeyer(beacon2, speed, freq, ANALOGUE_RADIO_SAMPLE_RATE);
			break;
		case AS_WAV_FILE: {
				CWAVFileStore* audio = new CWAVFileStore;
				bool res = audio->load(beacon2, ANALOGUE_RADIO_SAMPLE_RATE);
				if (!res)
					delete audio;
				else
					beacon2Audio = audio;
			}
			break;
	}

	thread->setCallsign(openIdAudio, closeIdAudio, beacon1Audio, beacon2Audio, level1, level2);

	wxString radioAck, extAck, batteryAck;
	unsigned int ack, minimum;
	wxFloat32 level;
	AUDIO_SOURCE radioAckSource, extAckSource, batteryAckSource;
	getAck(radioAckSource, radioAck, extAckSource, extAck, batteryAckSource, batteryAck, speed, freq, level, ack, minimum);
	wxLogInfo(wxT("Radio ack source: %d, radio ack: \"%s\", network ack source: %d, network ack: \"%s\", battery ack source: %d, battery ack: \"%s\", speed: %u WPM, freq: %u Hz, level: %.3f, ack: %u ms, minimum: %u ms"), int(radioAckSource), radioAck.c_str(), int(extAckSource), extAck.c_str(), int(batteryAckSource), batteryAck.c_str(), speed, freq, level, ack, minimum);

	IFixedAudioSource* radioAckAudio   = NULL;
	IFixedAudioSource* extAckAudio     = NULL;
	IFixedAudioSource* batteryAckAudio = NULL;

	switch (radioAckSource) {
		case AS_CW_KEYER:
			radioAckAudio = new CCWKeyer(radioAck, speed, freq, ANALOGUE_RADIO_SAMPLE_RATE);
			break;
		case AS_WAV_FILE: {
				CWAVFileStore* audio = new CWAVFileStore;
				bool res = audio->load(radioAck, ANALOGUE_RADIO_SAMPLE_RATE);
				if (!res)
					delete audio;
				else
					radioAckAudio = audio;
			}
			break;
	}

	switch (extAckSource) {
		case AS_CW_KEYER:
			extAckAudio = new CCWKeyer(extAck, speed, freq, ANALOGUE_RADIO_SAMPLE_RATE);
			break;
		case AS_WAV_FILE: {
				CWAVFileStore* audio = new CWAVFileStore;
				bool res = audio->load(extAck, ANALOGUE_RADIO_SAMPLE_RATE);
				if (!res)
					delete audio;
				else
					extAckAudio = audio;
			}
			break;
	}

	switch (batteryAckSource) {
		case AS_CW_KEYER:
			batteryAckAudio = new CCWKeyer(batteryAck, speed, freq, ANALOGUE_RADIO_SAMPLE_RATE);
			break;
		case AS_WAV_FILE: {
				CWAVFileStore* audio = new CWAVFileStore;
				bool res = audio->load(extAck, ANALOGUE_RADIO_SAMPLE_RATE);
				if (!res)
					delete audio;
				else
					batteryAckAudio = audio;
			}
			break;
	}

	thread->setAck(radioAckAudio, extAckAudio, batteryAckAudio, level, ack, minimum);

	unsigned int callsignTime, timeout, lockoutTime, hangTime, latchTime;
	getTimes(callsignTime, timeout, lockoutTime, hangTime, latchTime);
	thread->setTimes(callsignTime, timeout, lockoutTime, hangTime, latchTime);
	wxLogInfo(wxT("Times set to: callsign time: %u secs, timeout: %u secs, lockout time: %u secs, hang time: %u secs, latch time: %u secs"), callsignTime, timeout, lockoutTime, hangTime, latchTime);

	bool tbEnable, ctcssInternal;
	wxFloat32 tbThreshold, ctcssFreq, ctcssThresh, ctcssLevel;
	unsigned int ctcssHangTime;
	ANALOGUE_CTCSS_OUTPUT ctcssOutput;
	getTones(tbEnable, tbThreshold, ctcssFreq, ctcssInternal, ctcssThresh, ctcssLevel, ctcssHangTime, ctcssOutput);
	thread->setTones(tbEnable, tbThreshold, ctcssFreq, ctcssInternal, ctcssThresh, ctcssLevel, ctcssHangTime, ctcssOutput);
	wxLogInfo(wxT("Tones set to: toneburst enable: %u, threshold: %.3f, CTCSS freq: %.1f Hz, internal: %u, threshold: %.3f, level: %.3f, hang time: %u ms, output: %d"), tbEnable, tbThreshold, ctcssFreq, ctcssInternal, ctcssThresh, ctcssLevel, ctcssHangTime * 20U, ctcssOutput);

	ANALOGUE_CALLSIGN_START callsignAtStart;
	unsigned int callsignStartDelay;
	bool callsignAtEnd;
	ANALOGUE_TIMEOUT_TYPE timeoutType;
	ANALOGUE_CALLSIGN_HOLDOFF callsignHoldoff;
	getFeel(callsignAtStart, callsignStartDelay, callsignAtEnd, timeoutType, callsignHoldoff);
	thread->setFeel(callsignAtStart, callsignStartDelay, callsignAtEnd, timeoutType, callsignHoldoff);
	wxLogInfo(wxT("Feel set to: callsignAtStart: %d, callsignStartDelay: %u s, callsignAtEnd: %u, timeoutType: %d, callsignHoldoff: %d"), callsignAtStart, callsignStartDelay, callsignAtEnd, timeoutType, callsignHoldoff);

	wxString readDevice, writeDevice;
	unsigned int audioDelay;
	bool deEmphasis, preEmphasis, vogad;
	getRadio(readDevice, writeDevice, audioDelay, deEmphasis, preEmphasis, vogad);
	wxLogInfo(wxT("Radio soundcard set to %s:%s, delay: %u ms, de-emphasis: %d, pre-emphasis %d, vogad: %d"), readDevice.c_str(), writeDevice.c_str(), audioDelay * 20U, int(deEmphasis), int(preEmphasis), int(vogad));

	if (!readDevice.IsEmpty() && !writeDevice.IsEmpty()) {
		CSoundCardReaderWriter* soundcard = new CSoundCardReaderWriter(readDevice, writeDevice, ANALOGUE_RADIO_SAMPLE_RATE, ANALOGUE_RADIO_BLOCK_SIZE);
		soundcard->setCallback(thread, SOUNDCARD_RADIO);

		bool res = soundcard->open();
		if (!res)
			wxLogError(wxT("Cannot open the radio sound card"));
		else
			thread->setRadio(soundcard, audioDelay, deEmphasis, preEmphasis, vogad);
	}

	wxString type;
	unsigned int pttDelay, squelchDelay, cfg;
	bool pttInvert, squelchInvert;
	getController(type, cfg, pttDelay, squelchDelay, pttInvert, squelchInvert);
	wxLogInfo(wxT("Controller set to %s, config: %u, ptt delay: %u ms, squelch delay: %u ms, ptt invert: %d, squelch invert: %d"), type.c_str(), cfg, pttDelay * 20U, squelchInvert * 20U, pttInvert, squelchInvert);

	CExternalController* controller = NULL;

	wxString port;
	if (type.StartsWith(wxT("Velleman K8055 - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CK8055Controller(num), pttInvert, squelchInvert);
	} else if (type.StartsWith(wxT("Serial - "), &port)) {
		controller = new CExternalController(new CSerialLineController(port, cfg), pttInvert, squelchInvert);
	} else if (type.StartsWith(wxT("Arduino - "), &port)) {
		controller = new CExternalController(new CArduinoController(port), pttInvert, squelchInvert);
#if defined(GPIO)
	} else if (type.IsSameAs(wxT("GPIO"))) {
		controller = new CExternalController(new CGPIOController(cfg), pttInvert, squelchInvert);
#endif
	} else {
		controller = new CExternalController(new CDummyController, pttInvert, squelchInvert);
	}

	bool res = controller->open();
	if (!res)
		wxLogError(wxT("Cannot open the hardware interface - %s"), type.c_str());
	else
		thread->setController(controller, pttDelay, squelchDelay);

	ANALOGUE_EXTERNAL_MODE mode;
	wxString device;
	SERIALPIN txPin, rxPin;
	bool background;
	getExternal(mode, readDevice, writeDevice, audioDelay, deEmphasis, preEmphasis, vogad, device, txPin, rxPin, background);
	wxLogInfo(wxT("External mode: %d, soundcard set to %s:%s, delay: %u ms, de-emphasis: %d, pre-emphasis %d, vogad: %u, interface set to %s, tx %d, rx %d, background: %d"), mode, readDevice.c_str(), writeDevice.c_str(), audioDelay * 20U, int(deEmphasis), int(preEmphasis), int(vogad), device.c_str(), txPin, rxPin, int(background));

	if (mode != AEM_DISABLED) {
		CSoundCardReaderWriter* soundcard = new CSoundCardReaderWriter(readDevice, writeDevice, ANALOGUE_RADIO_SAMPLE_RATE, ANALOGUE_RADIO_BLOCK_SIZE);
		soundcard->setCallback(thread, SOUNDCARD_EXTERNAL);

		bool res = soundcard->open();
		if (!res) {
			wxLogError(wxT("Cannot open the external sound card"));
		} else {
			// This works even for an empty device name
			CNetworkController* controller = new CNetworkController(device, txPin, rxPin);

			res = controller->open();
			if (!res)
				wxLogError(wxT("Cannot open serial port - %s"), device.c_str());
			else
				thread->setExternal(mode, soundcard, audioDelay, deEmphasis, preEmphasis, vogad, controller, background);
		}
	}

	bool out1, out2, out3, out4;
	getOutputs(out1, out2, out3, out4);
	thread->setOutputs(out1, out2, out3, out4);
	m_frame->setOutputs(out1, out2, out3, out4);
	wxLogInfo(wxT("Output 1: %d, output 2: %d, output 3: %d, output 4: %d"), out1, out2, out3, out4);

	bool dtmfRadio, dtmfExternal;
	wxString dtmfShutdown, dtmfStartup, dtmfTimeout, dtmfTimeReset, dtmfOutput1, dtmfOutput2, dtmfOutput3, dtmfOutput4;
	wxString dtmfCommand1, dtmfCommand1Line, dtmfCommand2, dtmfCommand2Line;
	wxFloat32 dtmfThreshold;
	getDTMF(dtmfRadio, dtmfExternal, dtmfShutdown, dtmfStartup, dtmfTimeout, dtmfTimeReset, dtmfCommand1, dtmfCommand1Line, dtmfCommand2, dtmfCommand2Line, dtmfOutput1, dtmfOutput2, dtmfOutput3, dtmfOutput4, dtmfThreshold);
	thread->setDTMF(dtmfRadio, dtmfExternal, dtmfShutdown, dtmfStartup, dtmfTimeout, dtmfTimeReset, dtmfCommand1, dtmfCommand1Line, dtmfCommand2, dtmfCommand2Line, dtmfOutput1, dtmfOutput2, dtmfOutput3, dtmfOutput4, dtmfThreshold);
	wxLogInfo(wxT("DTMF: Radio: %d, External: %d, Shutdown: %s, Startup: %s, Timeout: %s, Time Reset: %s, Command1: %s = %s, Command2: %s = %s, Output1: %s, Output2: %s, Output3: %s, Output4: %s, Threshold: %f"), dtmfRadio, dtmfExternal, dtmfShutdown.c_str(), dtmfStartup.c_str(), dtmfTimeout.c_str(), dtmfTimeReset.c_str(), dtmfCommand1.c_str(), dtmfCommand1Line.c_str(), dtmfCommand2.c_str(), dtmfCommand2Line.c_str(), dtmfOutput1.c_str(), dtmfOutput2.c_str(), dtmfOutput3.c_str(), dtmfOutput4.c_str(), dtmfThreshold);

	unsigned int activeHangTime;
	getActiveHang(activeHangTime);
	thread->setActiveHang(activeHangTime);
	wxLogInfo(wxT("Active Hang: time: %u"), activeHangTime);

	// Convert the worker class into a thread
	m_thread = new CAnalogueRepeaterThreadHelper(thread);
	m_thread->start();
}
Пример #3
0
bool CDStarRepeaterD::createThread()
{
	CDStarRepeaterConfig config(m_confDir, CONFIG_FILE_NAME, m_name);

	wxString callsign, gateway;
	DSTAR_MODE mode;
	ACK_TYPE ack;
	bool restriction, rpt1Validation, dtmfBlanking, errorReply;
	config.getCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation, dtmfBlanking, errorReply);

	wxString modemType;
	config.getModem(modemType);

	// DVAP can only do simplex, force the mode accordingly
	if (modemType.IsSameAs(wxT("DVAP"))) {
		if (mode == MODE_DUPLEX) {
			wxLogInfo(wxT("DVAP: changing mode from DUPLEX to SIMPLEX"));
			mode = MODE_SIMPLEX;
		} else if (mode == MODE_TXANDRX) {
			wxLogInfo(wxT("DVAP: changing mode from TX_AND_RX to RX_ONLY"));
			mode = MODE_RXONLY;
		}
	}

	switch (mode) {
		case MODE_RXONLY:
			m_thread = new CDStarRepeaterRXThread(modemType);
			break;
		case MODE_TXONLY:
			m_thread = new CDStarRepeaterTXThread(modemType);
			break;
		case MODE_TXANDRX:
			m_thread = new CDStarRepeaterTXRXThread(modemType);
			break;
		default:
			m_thread = new CDStarRepeaterTRXThread(modemType);
			break;
	}

	m_thread->setCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation, dtmfBlanking, errorReply);
	wxLogInfo(wxT("Callsign set to \"%s\", gateway set to \"%s\", mode: %d, ack: %d, restriction: %d, RPT1 validation: %d, DTMF blanking: %d, Error reply: %d"), callsign.c_str(), gateway.c_str(), int(mode), int(ack), int(restriction), int(rpt1Validation), int(dtmfBlanking), int(errorReply));

	wxString gatewayAddress, localAddress, name;
	unsigned int gatewayPort, localPort;
	config.getNetwork(gatewayAddress, gatewayPort, localAddress, localPort, name);
	wxLogInfo(wxT("Gateway set to %s:%u, local set to %s:%u, name set to \"%s\""), gatewayAddress.c_str(), gatewayPort, localAddress.c_str(), localPort, name.c_str());

	if (!gatewayAddress.IsEmpty()) {
		bool local = gatewayAddress.IsSameAs(wxT("127.0.0.1"));

		CRepeaterProtocolHandler* handler = new CRepeaterProtocolHandler(gatewayAddress, gatewayPort, localAddress, localPort, name);

		bool res = handler->open();
		if (!res) {
			wxLogError(wxT("Cannot open the protocol handler"));
			return false;
		}

		m_thread->setProtocolHandler(handler, local);
	}

	unsigned int timeout, ackTime;
	config.getTimes(timeout, ackTime);
	m_thread->setTimes(timeout, ackTime);
	wxLogInfo(wxT("Timeout set to %u secs, ack time set to %u ms"), timeout, ackTime);

	unsigned int beaconTime;
	wxString beaconText;
	bool beaconVoice;
	TEXT_LANG language;
	config.getBeacon(beaconTime, beaconText, beaconVoice, language);
	if (mode == MODE_GATEWAY)
		beaconTime = 0U;
	m_thread->setBeacon(beaconTime, beaconText, beaconVoice, language);
	wxLogInfo(wxT("Beacon set to %u mins, text set to \"%s\", voice set to %d, language set to %d"), beaconTime / 60U, beaconText.c_str(), int(beaconVoice), int(language));

	bool announcementEnabled;
	unsigned int announcementTime;
	wxString announcementRecordRPT1, announcementRecordRPT2;
	wxString announcementDeleteRPT1, announcementDeleteRPT2;
	config.getAnnouncement(announcementEnabled, announcementTime, announcementRecordRPT1, announcementRecordRPT2, announcementDeleteRPT1, announcementDeleteRPT2);
	if (mode == MODE_GATEWAY)
		announcementEnabled = false;
	m_thread->setAnnouncement(announcementEnabled, announcementTime, announcementRecordRPT1, announcementRecordRPT2, announcementDeleteRPT1, announcementDeleteRPT2);
	wxLogInfo(wxT("Announcement enabled: %d, time: %u mins, record RPT1: \"%s\", record RPT2: \"%s\", delete RPT1: \"%s\", delete RPT2: \"%s\""), int(announcementEnabled), announcementTime / 60U, announcementRecordRPT1.c_str(), announcementRecordRPT2.c_str(), announcementDeleteRPT1.c_str(), announcementDeleteRPT2.c_str());

	wxLogInfo(wxT("Modem type set to \"%s\""), modemType.c_str());

	CModem* modem = NULL;
	if (modemType.IsSameAs(wxT("DVAP"))) {
		wxString port;
		unsigned int frequency;
		int power, squelch;
		config.getDVAP(port, frequency, power, squelch);
		wxLogInfo(wxT("DVAP: port: %s, frequency: %u Hz, power: %d dBm, squelch: %d dBm"), port.c_str(), frequency, power, squelch);
		modem = new CDVAPController(port, frequency, power, squelch);
	} else if (modemType.IsSameAs(wxT("DV-RPTR V1"))) {
		wxString port;
		bool rxInvert, txInvert, channel;
		unsigned int modLevel, txDelay;
		config.getDVRPTR1(port, rxInvert, txInvert, channel, modLevel, txDelay);
		wxLogInfo(wxT("DV-RPTR V1, port: %s, RX invert: %d, TX invert: %d, channel: %s, mod level: %u%%, TX delay: %u ms"), port.c_str(), int(rxInvert), int(txInvert), channel ? wxT("B") : wxT("A"), modLevel, txDelay);
		modem = new CDVRPTRV1Controller(port, wxEmptyString, rxInvert, txInvert, channel, modLevel, txDelay);
	} else if (modemType.IsSameAs(wxT("DV-RPTR V2"))) {
		CONNECTION_TYPE connType;
		wxString usbPort, address;
		bool txInvert;
		unsigned int port, modLevel, txDelay;
		config.getDVRPTR2(connType, usbPort, address, port, txInvert, modLevel, txDelay);
		wxLogInfo(wxT("DV-RPTR V2, type: %d, address: %s:%u, TX invert: %d, mod level: %u%%, TX delay: %u ms"), int(connType), address.c_str(), port, int(txInvert), modLevel, txDelay);
		switch (connType) {
			case CT_USB:
				modem = new CDVRPTRV2Controller(usbPort, wxEmptyString, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign, txDelay);
				break;
			case CT_NETWORK:
				modem = new CDVRPTRV2Controller(address, port, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign, txDelay);
				break;
		}
	} else if (modemType.IsSameAs(wxT("DV-RPTR V3"))) {
		CONNECTION_TYPE connType;
		wxString usbPort, address;
		bool txInvert;
		unsigned int port, modLevel, txDelay;
		config.getDVRPTR3(connType, usbPort, address, port, txInvert, modLevel, txDelay);
		wxLogInfo(wxT("DV-RPTR V3, type: %d, address: %s:%u, TX invert: %d, mod level: %u%%, TX delay: %u ms"), int(connType), address.c_str(), port, int(txInvert), modLevel, txDelay);
		switch (connType) {
			case CT_USB:
				modem = new CDVRPTRV3Controller(usbPort, wxEmptyString, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign, txDelay);
				break;
			case CT_NETWORK:
				modem = new CDVRPTRV3Controller(address, port, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign, txDelay);
				break;
		}
	} else if (modemType.IsSameAs(wxT("DVMEGA"))) {
		wxString port;
		DVMEGA_VARIANT variant;
		bool rxInvert, txInvert;
		unsigned int txDelay, rxFrequency, txFrequency, power;
		config.getDVMEGA(port, variant, rxInvert, txInvert, txDelay, rxFrequency, txFrequency, power);
		wxLogInfo(wxT("DVMEGA, port: %s, variant: %d, RX invert: %d, TX invert: %d, TX delay: %u ms, rx frequency: %u Hz, tx frequency: %u Hz, power: %u %%"), port.c_str(), int(variant), int(rxInvert), int(txInvert), txDelay, rxFrequency, txFrequency, power);
		switch (variant) {
			case DVMV_MODEM:
				modem = new CDVMegaController(port, wxEmptyString, rxInvert, txInvert, txDelay);
				break;
			case DVMV_RADIO_2M:
			case DVMV_RADIO_70CM:
			case DVMV_RADIO_2M_70CM:
				modem = new CDVMegaController(port, wxEmptyString, txDelay, rxFrequency, txFrequency, power);
				break;
			default:
				wxLogError(wxT("Unknown DVMEGA variant - %d"), int(variant));
				break;
		}
	} else if (modemType.IsSameAs(wxT("GMSK Modem"))) {
		USB_INTERFACE iface;
		unsigned int address;
		config.getGMSK(iface, address);
		wxLogInfo(wxT("GMSK, interface: %d, address: %04X"), int(iface), address);
		modem = new CGMSKController(iface, address, mode == MODE_DUPLEX || mode == MODE_TXANDRX);
	} else if (modemType.IsSameAs(wxT("Sound Card"))) {
		wxString rxDevice, txDevice;
		bool rxInvert, txInvert;
		wxFloat32 rxLevel, txLevel;
		unsigned int txDelay, txTail;
		config.getSoundCard(rxDevice, txDevice, rxInvert, txInvert, rxLevel, txLevel, txDelay, txTail);
		wxLogInfo(wxT("Sound Card, devices: %s:%s, invert: %d:%d, levels: %.2f:%.2f, tx delay: %u ms, tx tail: %u ms"), rxDevice.c_str(), txDevice.c_str(), int(rxInvert), int(txInvert), rxLevel, txLevel, txDelay, txTail);
		modem = new CSoundCardController(rxDevice, txDevice, rxInvert, txInvert, rxLevel, txLevel, txDelay, txTail);
	} else if (modemType.IsSameAs(wxT("MMDVM"))) {
		wxString port;
		bool rxInvert, txInvert, pttInvert;
		unsigned int txDelay, rxLevel, txLevel;
		config.getMMDVM(port, rxInvert, txInvert, pttInvert, txDelay, rxLevel, txLevel);
		wxLogInfo(wxT("MMDVM, port: %s, RX invert: %d, TX invert: %d, PTT invert: %d, TX delay: %u ms, RX level: %u%%, TX level: %u%%"), port.c_str(), int(rxInvert), int(txInvert), int(pttInvert), txDelay, rxLevel, txLevel);
		modem = new CMMDVMController(port, wxEmptyString, rxInvert, txInvert, pttInvert, txDelay, rxLevel, txLevel);
	} else if (modemType.IsSameAs(wxT("Split"))) {
		wxString localAddress;
		unsigned int localPort;
		wxArrayString transmitterNames, receiverNames;
		unsigned int timeout;
		config.getSplit(localAddress, localPort, transmitterNames, receiverNames, timeout);
		wxLogInfo(wxT("Split, local: %s:%u, timeout: %u ms"), localAddress.c_str(), localPort, timeout);
		for (unsigned int i = 0U; i < transmitterNames.GetCount(); i++) {
			wxString name = transmitterNames.Item(i);
			if (!name.IsEmpty())
				wxLogInfo(wxT("\tTX %u name: %s"), i + 1U, name.c_str());
		}
		for (unsigned int i = 0U; i < receiverNames.GetCount(); i++) {
			wxString name = receiverNames.Item(i);
			if (!name.IsEmpty())
				wxLogInfo(wxT("\tRX %u name: %s"), i + 1U, name.c_str());
		}
		modem = new CSplitController(localAddress, localPort, transmitterNames, receiverNames, timeout);
	} else {
		wxLogError(wxT("Unknown modem type: %s"), modemType.c_str());
	}

	if (modem != NULL) {
		bool res = modem->start();
		if (!res)
			wxLogError(wxT("Cannot open the D-Star modem"));
		else
			m_thread->setModem(modem);
	}

	wxString controllerType;
	unsigned int portConfig, activeHangTime;
	bool pttInvert;
	config.getController(controllerType, portConfig, pttInvert, activeHangTime);
	wxLogInfo(wxT("Controller set to %s, config: %u, PTT invert: %d, active hang time: %u ms"), controllerType.c_str(), portConfig, int(pttInvert), activeHangTime);

	CExternalController* controller = NULL;

	wxString port;
	if (controllerType.StartsWith(wxT("Velleman K8055 - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CK8055Controller(num), pttInvert);
	} else if (controllerType.StartsWith(wxT("Serial - "), &port)) {
		controller = new CExternalController(new CSerialLineController(port, portConfig), pttInvert);
	} else if (controllerType.StartsWith(wxT("Arduino - "), &port)) {
		controller = new CExternalController(new CArduinoController(port), pttInvert);
#if defined(GPIO)
	} else if (controllerType.IsSameAs(wxT("GPIO"))) {
		controller = new CExternalController(new CGPIOController(portConfig), pttInvert);
#endif
	} else {
		controller = new CExternalController(new CDummyController, pttInvert);
	}

	bool res = controller->open();
	if (!res)
		wxLogError(wxT("Cannot open the hardware interface - %s"), controllerType.c_str());
	else
		m_thread->setController(controller, activeHangTime);

	bool out1, out2, out3, out4;
	config.getOutputs(out1, out2, out3, out4);
	m_thread->setOutputs(out1, out2, out3, out4);
	wxLogInfo(wxT("Output 1 = %d, output 2 = %d, output 3 = %d, output 4 = %d"), out1, out2, out3, out4);

	bool enabled;
	wxString rpt1Callsign, rpt2Callsign;
	wxString shutdown, startup;
	wxString status1, status2, status3, status4, status5;
	wxString command1, command1Line, command2, command2Line;
	wxString command3, command3Line, command4, command4Line;
	wxString command5, command5Line, command6, command6Line;
	wxString output1, output2, output3, output4;
	config.getControl(enabled, rpt1Callsign, rpt2Callsign, shutdown, startup, status1, status2, status3, status4, status5, command1, command1Line, command2, command2Line, command3, command3Line, command4, command4Line, command5, command5Line, command6, command6Line, output1, output2, output3, output4);
	m_thread->setControl(enabled, rpt1Callsign, rpt2Callsign, shutdown, startup, status1, status2, status3, status4, status5, command1, command1Line, command2, command2Line, command3, command3Line, command4, command4Line, command5, command5Line, command6, command6Line, output1, output2, output3, output4);
	wxLogInfo(wxT("Control: enabled: %d, RPT1: %s, RPT2: %s, shutdown: %s, startup: %s, status1: %s, status2: %s, status3: %s, status4: %s, status5: %s, command1: %s = %s, command2: %s = %s, command3: %s = %s, command4: %s = %s, command5: %s = %s, command6: %s = %s, output1: %s, output2: %s, output3: %s, output4: %s"), enabled, rpt1Callsign.c_str(), rpt2Callsign.c_str(), shutdown.c_str(), startup.c_str(), status1.c_str(), status2.c_str(), status3.c_str(), status4.c_str(), status5.c_str(), command1.c_str(), command1Line.c_str(), command2.c_str(), command2Line.c_str(), command3.c_str(), command3Line.c_str(), command4.c_str(), command4Line.c_str(), command5.c_str(), command5Line.c_str(), command6.c_str(), command6Line.c_str(), output1.c_str(), output2.c_str(), output3.c_str(), output4.c_str());

	bool logging;
	config.getLogging(logging);
	m_thread->setLogging(logging, m_audioDir);
	wxLogInfo(wxT("Frame logging set to %d, in %s"), int(logging), m_audioDir.c_str());

	wxFileName wlFilename(wxFileName::GetHomeDir(), WHITELIST_FILE_NAME);
	bool exists = wlFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(wlFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError(wxT("Unable to open white list file - %s"), wlFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo(wxT("%u callsigns loaded into the white list"), list->getCount());
			m_thread->setWhiteList(list);
		}
	}

	wxFileName blFilename(wxFileName::GetHomeDir(), BLACKLIST_FILE_NAME);
	exists = blFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(blFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError(wxT("Unable to open black list file - %s"), blFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo(wxT("%u callsigns loaded into the black list"), list->getCount());
			m_thread->setBlackList(list);
		}
	}

	wxFileName glFilename(wxFileName::GetHomeDir(), GREYLIST_FILE_NAME);
	exists = glFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(glFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError(wxT("Unable to open grey list file - %s"), glFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo(wxT("%u callsigns loaded into the grey list"), list->getCount());
			m_thread->setGreyList(list);
		}
	}

	return true;
}
void CDummyRepeaterApp::createThread()
{
	m_thread = new CDummyRepeaterThread;
	m_thread->Create();
	m_thread->Run();

	wxString callsign1, callsign2;
	getCallsign(callsign1, callsign2);
	m_thread->setCallsign(callsign1, callsign2);

	wxString call;
	wxSortedArrayString list;

	getYourCalls(call, list);
	m_thread->setYour(call);

	getRpt1Calls(call, list);
	m_thread->setRpt1(call);

	getRpt2Calls(call, list);
	m_thread->setRpt2(call);

	wxString message;
	getMessage(message);
	m_thread->setMessage(message);

	wxString device;
	getDVDongle(device);

	if (!device.IsEmpty()) {
		CDVDongleController* dongle = new CDVDongleController(new CSerialDataController(device, SERIAL_230400));

		bool res = dongle->open();
		if (!res) {
			wxLogError(wxT("Can't find the DV-Dongle on the port specified"));
			error(_("Can't find the DV-Dongle on the port specified"));
		} else {
			m_thread->setDVDongle(dongle);
		}
	}

	wxString readDevice, writeDevice;
	getSoundcard(readDevice, writeDevice);

	if (!readDevice.IsEmpty() && !writeDevice.IsEmpty()) {
#if defined(__WINDOWS__)
		CSoundCardReaderWriter* soundcard = new CSoundCardReaderWriter(readDevice, writeDevice, DSTAR_RADIO_SAMPLE_RATE, DSTAR_RADIO_BLOCK_SIZE);
#else
		CSoundCardReaderWriter* soundcard = new CSoundCardReaderWriter(readDevice, writeDevice, DSTAR_RADIO_SAMPLE_RATE, 64U);
#endif
		soundcard->setCallback(m_thread, 0);

		bool res = soundcard->open();
		if (!res) {
			wxLogError(wxT("Cannot open the sound card"));
			error(_("Cannot open the sound card"));
		} else {
			m_thread->setSoundCard(soundcard);
		}
	}

	wxString gwyAddress, localAddress;
	unsigned int gwyPort, localPort;
	getNetwork(gwyAddress, gwyPort, localAddress, localPort);

	if (!gwyAddress.IsEmpty()) {
		CRepeaterProtocolHandler* protocol = new CRepeaterProtocolHandler(gwyAddress, gwyPort, localAddress, localPort);

		bool res = protocol->open();
		if (!res) {
			wxLogError(wxT("Cannot open the protocol handler"));
			error(_("Cannot open the protocol handler"));
		} else {
			m_thread->setProtocol(protocol);
		}
	}

	wxString type;
	unsigned int config;
	bool pttInvert, squelchInvert;
	getController(type, config, pttInvert, squelchInvert);

	CExternalController* controller = NULL;

	wxString port;
	if (type.StartsWith(wxT("Velleman K8055 - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CK8055Controller(num), pttInvert, squelchInvert);
	} else if (type.StartsWith(wxT("URI USB - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CURIUSBController(num, true), pttInvert, squelchInvert);
	} else if (type.StartsWith(wxT("Serial - "), &port)) {
		controller = new CExternalController(new CSerialController(port, config), pttInvert, squelchInvert);
	} else {
		controller = new CExternalController(new CDummyController, pttInvert, squelchInvert);
	}

	bool res = controller->open();
	if (!res) {
		wxLogError(wxT("Cannot open the hardware interface - %s"), type.c_str());
		error(_("Cannot open the hardware interface"));
	} else {
		m_thread->setController(controller);
	}

	bool bleep;
	getBleep(bleep);
	m_thread->setBleep(bleep);
}
void CGMSKRepeaterApp::createThread()
{
	wxString callsign, gateway;
	DSTAR_MODE mode;
	ACK_TYPE ack;
	bool restriction, rpt1Validation;
	getCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation);

	IGMSKRepeaterThread* thread = NULL;
	switch (mode) {
		case MODE_RXONLY:
			thread = new CGMSKRepeaterRXThread;
			break;
		case MODE_TXONLY:
			thread = new CGMSKRepeaterTXThread;
			break;
		case MODE_TXANDRX:
			thread = new CGMSKRepeaterTXRXThread;
			break;
		default:
			thread = new CGMSKRepeaterTRXThread;
			break;
	}

	thread->setCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation);
	wxLogInfo(wxT("Callsign set to \"%s\", gateway set to \"%s\", mode: %d, ack: %d, restriction: %d, RPT1 validation: %d"), callsign.c_str(), gateway.c_str(), int(mode), int(ack), restriction, rpt1Validation);

	wxString gatewayAddress, localAddress;
	unsigned int gatewayPort, localPort;
	getNetwork(gatewayAddress, gatewayPort, localAddress, localPort);
	wxLogInfo(wxT("Gateway set to %s:%u, local set to %s:%u"), gatewayAddress.c_str(), gatewayPort, localAddress.c_str(), localPort);

	if (!gatewayAddress.IsEmpty()) {
		CRepeaterProtocolHandler* handler = new CRepeaterProtocolHandler(gatewayAddress, gatewayPort, localAddress, localPort);

		bool res = handler->open();
		if (!res)
			wxLogError(wxT("Cannot open the protocol handler"));
		else
			thread->setProtocolHandler(handler);
	}

	unsigned int timeout, ackTime;
	getTimes(timeout, ackTime);
	thread->setTimes(timeout, ackTime);
	wxLogInfo(wxT("Timeout set to %u secs, ack time set to %u ms"), timeout, ackTime);

	unsigned int beaconTime;
	wxString beaconText;
	bool beaconVoice;
	TEXT_LANG language;
	getBeacon(beaconTime, beaconText, beaconVoice, language);
	if (mode == MODE_GATEWAY)
		beaconTime = 0U;
	thread->setBeacon(beaconTime, beaconText, beaconVoice, language);
	wxLogInfo(wxT("Beacon set to %u mins, text set to \"%s\", voice set to %d, language set to %d"), beaconTime / 60U, beaconText.c_str(), int(beaconVoice), int(language));

	GMSK_MODEM_TYPE modemType;
	unsigned int modemAddress;
	getModem(modemType, modemAddress);

#if defined(WIN32)
	IGMSKModem* modem = NULL;
	switch (modemType) {
		case GMT_LIBUSB:
			wxLogInfo(wxT("GMSK modem: type: LibUsb, address: 0x%04X"), modemAddress);
			modem =	new CGMSKModemLibUsb(modemAddress);
			break;
		case GMT_WINUSB:
			wxLogInfo(wxT("GMSK modem: type: WinUSB, address: 0x%04X"), modemAddress);
			modem =	new CGMSKModemWinUSB(modemAddress);
			break;
		default:
			wxLogError(wxT("Unknown GMSK Modem type - %d"), int(modemType));
			break;
	}
#else
	wxLogInfo(wxT("GMSK modem: type: LibUsb, address: 0x%04X"), modemAddress);
	IGMSKModem* modem =	new CGMSKModemLibUsb(modemAddress);
#endif

	if (modem != NULL) {
		bool res = modem->open();
		if (!res)
			wxLogError(wxT("Cannot open the GMSK modem"));
		else
			thread->setModem(modem);
	}

	wxString controllerType;
	unsigned int activeHangTime;
	getController(controllerType, activeHangTime);
	wxLogInfo(wxT("Controller set to %s, active hang time: %u ms"), controllerType.c_str(), activeHangTime);

	CExternalController* controller = NULL;

	wxString port;
	if (controllerType.StartsWith(wxT("Velleman K8055 - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CK8055Controller(num), false, false);
	} else if (controllerType.IsSameAs(wxT("Raspberry Pi"))) {
		controller = new CExternalController(new CRaspberryController, false, false);
	} else {
		controller = new CExternalController(new CDummyController, false, false);
	}

	bool res = controller->open();
	if (!res)
		wxLogError(wxT("Cannot open the hardware interface - %s"), controllerType.c_str());
	else
		thread->setController(controller, activeHangTime);

	bool out1, out2, out3, out4;
	getOutputs(out1, out2, out3, out4);
	thread->setOutputs(out1, out2, out3, out4);
	m_frame->setOutputs(out1, out2, out3, out4);
	wxLogInfo(wxT("Output 1 = %d, output 2 = %d, output 3 = %d, output 4 = %d"), out1, out2, out3, out4);

	bool enabled;
	wxString rpt1Callsign, rpt2Callsign;
	wxString shutdown, startup;
	wxString status1, status2, status3, status4, status5;
	wxString command1, command1Line, command2, command2Line;
	wxString command3, command3Line, command4, command4Line;
	wxString output1, output2, output3, output4;
	getControl(enabled, rpt1Callsign, rpt2Callsign, shutdown, startup, status1, status2, status3, status4, status5, command1, command1Line, command2, command2Line, command3, command3Line, command4, command4Line, output1, output2, output3, output4);
	thread->setControl(enabled, rpt1Callsign, rpt2Callsign, shutdown, startup, status1, status2, status3, status4, status5, command1, command1Line, command2, command2Line, command3, command3Line, command4, command4Line, output1, output2, output3, output4);
	wxLogInfo(wxT("Control: enabled: %d, RPT1: %s, RPT2: %s, shutdown: %s, startup: %s, status1: %s, status2: %s, status3: %s, status4: %s, status5: %s, command1: %s = %s, command2: %s = %s, command3: %s = %s, command4: %s = %s, output1: %s, output2: %s, output3: %s, output4: %s"), enabled, rpt1Callsign.c_str(), rpt2Callsign.c_str(), shutdown.c_str(), startup.c_str(), status1.c_str(), status2.c_str(), status3.c_str(), status4.c_str(), status5.c_str(), command1.c_str(), command1Line.c_str(), command2.c_str(), command2Line.c_str(), command3.c_str(), command3Line.c_str(), command4.c_str(), command4Line.c_str(), output1.c_str(), output2.c_str(), output3.c_str(), output4.c_str());

	bool logging;
	getLogging(logging);
	thread->setLogging(logging, m_audioDir);
	m_frame->setLogging(logging);
	wxLogInfo(wxT("Frame logging set to %d, in %s"), int(logging), m_audioDir.c_str());

	wxFileName wlFilename(wxFileName::GetHomeDir(), WHITELIST_FILE_NAME);
	bool exists = wlFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(wlFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError(wxT("Unable to open white list file - %s"), wlFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo(wxT("%u callsigns loaded into the white list"), list->getCount());
			thread->setWhiteList(list);
		}
	}

	wxFileName blFilename(wxFileName::GetHomeDir(), BLACKLIST_FILE_NAME);
	exists = blFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(blFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError(wxT("Unable to open black list file - %s"), blFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo(wxT("%u callsigns loaded into the black list"), list->getCount());
			thread->setBlackList(list);
		}
	}

	// Convert the worker class into a thread
	m_thread = new CGMSKRepeaterThreadHelper(thread);
	m_thread->start();
}
void CDVRPTRRepeaterApp::createThread()
{
	wxString callsign, gateway;
	DSTAR_MODE mode;
	ACK_TYPE ack;
	bool restriction, rpt1Validation;
	getCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation);

	IDVRPTRRepeaterThread* thread = NULL;
	switch (mode) {
		case MODE_RXONLY:
			thread = new CDVRPTRRepeaterRXThread;
			break;
		case MODE_TXONLY:
			thread = new CDVRPTRRepeaterTXThread;
			break;
		case MODE_TXANDRX:
			thread = new CDVRPTRRepeaterTXRXThread;
			break;
		default:
			thread = new CDVRPTRRepeaterTRXThread;
			break;
	}

	thread->setCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation);
	wxLogInfo(wxT("Callsign set to \"%s\", gateway set to \"%s\", mode: %d, ack: %d, restriction: %d, RPT1 validation: %d"), callsign.c_str(), gateway.c_str(), int(mode), int(ack), restriction, rpt1Validation);

	wxString gatewayAddress, localAddress;
	unsigned int gatewayPort, localPort;
	getNetwork(gatewayAddress, gatewayPort, localAddress, localPort);
	wxLogInfo(wxT("Gateway set to %s:%u, local set to %s:%u"), gatewayAddress.c_str(), gatewayPort, localAddress.c_str(), localPort);

	if (!gatewayAddress.IsEmpty()) {
		CRepeaterProtocolHandler* handler = new CRepeaterProtocolHandler(gatewayAddress, gatewayPort, localAddress, localPort);

		bool res = handler->open();
		if (!res)
			wxLogError(wxT("Cannot open the protocol handler"));
		else
			thread->setProtocolHandler(handler);
	}

	unsigned int timeout, ackTime;
	getTimes(timeout, ackTime);
	thread->setTimes(timeout, ackTime);
	wxLogInfo(wxT("Timeout set to %u secs, ack time set to %u ms"), timeout, ackTime);

	unsigned int beaconTime;
	wxString beaconText;
	bool beaconVoice;
	TEXT_LANG language;
	getBeacon(beaconTime, beaconText, beaconVoice, language);
	if (mode == MODE_GATEWAY)
		beaconTime = 0U;
	thread->setBeacon(beaconTime, beaconText, beaconVoice, language);
	wxLogInfo(wxT("Beacon set to %u mins, text set to \"%s\", voice set to %d, language set to %d"), beaconTime / 60U, beaconText.c_str(), int(beaconVoice), int(language));

	DVRPTR_VERSION modemVersion;
	CONNECTION_TYPE modemType;
	wxString modemUSBPort, modemAddress, modemUSBPath;
	bool rxInvert, txInvert, channel;
	unsigned int modemPort, modLevel, txDelay;
	getModem(modemVersion, modemType, modemUSBPort, modemAddress, modemPort, rxInvert, txInvert, channel, modLevel, txDelay);
	wxLogInfo(wxT("DV-RPTR modem: version: %d, type: %d, USB port: %s, address: %s:%u, RX invert: %d, TX invert: %d, channel: %s, mod level: %u%%, TX delay: %u ms"), int(modemVersion), int(modemType), modemUSBPort.c_str(), modemAddress.c_str(), modemPort, int(rxInvert), int(txInvert), channel ? wxT("B") : wxT("A"), modLevel, txDelay);

	if (modemType == CT_USB) {
		if (!modemUSBPort.IsEmpty()) {
			getModem(modemUSBPath);
			if (!modemUSBPath.IsEmpty())
				wxLogInfo(wxT("DV-RPTR modem: path: %s"), modemUSBPath.c_str());

			IDVRPTRController* controller = NULL;
			switch (modemVersion) {
				case DVRPTR_V1:
					controller = new CDVRPTRControllerV1(modemUSBPort, modemUSBPath, rxInvert, txInvert, channel, modLevel, txDelay);
					break;
				case DVRPTR_V2:
					controller = new CDVRPTRControllerV2(modemUSBPort, modemUSBPath, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign);
					break;
				default:
					wxLogError(wxT("Unknown DV-RPTR modem version - %d"), int(modemVersion));
					break;
			}

			if (controller != NULL) {
				bool res = controller->open();
				if (!res) {
					wxLogError(wxT("Cannot open the DV-RPTR modem"));
				} else {
					thread->setModem(controller);
					setModem(controller->getPath());
				}
			}
		}
	} else if (modemType == CT_NETWORK) {
		if (!modemAddress.IsEmpty()) {
			CDVRPTRControllerV2* controller = new CDVRPTRControllerV2(modemAddress, modemPort, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign);
			bool res = controller->open();
			if (!res)
				wxLogError(wxT("Cannot open the DV-RPTR modem"));
			else
				thread->setModem(controller);
		}
	}

	wxString controllerType;
	unsigned int activeHangTime;
	getController(controllerType, activeHangTime);
	wxLogInfo(wxT("Controller set to %s, active hang time: %u ms"), controllerType.c_str(), activeHangTime);

	CExternalController* controller = NULL;

	wxString port;
	if (controllerType.StartsWith(wxT("Velleman K8055 - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CK8055Controller(num), false, false);
	} else if (controllerType.IsSameAs(wxT("Raspberry Pi"))) {
		controller = new CExternalController(new CRaspberryController, false, false);
	} else {
		controller = new CExternalController(new CDummyController, false, false);
	}

	bool res = controller->open();
	if (!res)
		wxLogError(wxT("Cannot open the hardware interface - %s"), controllerType.c_str());
	else
		thread->setController(controller, activeHangTime);

	bool out1, out2, out3, out4;
	getOutputs(out1, out2, out3, out4);
	thread->setOutputs(out1, out2, out3, out4);
	m_frame->setOutputs(out1, out2, out3, out4);
	wxLogInfo(wxT("Output 1 = %d, output 2 = %d, output 3 = %d, output 4 = %d"), out1, out2, out3, out4);

	bool enabled;
	wxString rpt1Callsign, rpt2Callsign;
	wxString shutdown, startup;
	wxString status1, status2, status3, status4, status5;
	wxString command1, command1Line, command2, command2Line;
	wxString command3, command3Line, command4, command4Line;
	wxString output1, output2, output3, output4;
	getControl(enabled, rpt1Callsign, rpt2Callsign, shutdown, startup, status1, status2, status3, status4, status5, command1, command1Line, command2, command2Line, command3, command3Line, command4, command4Line, output1, output2, output3, output4);
	thread->setControl(enabled, rpt1Callsign, rpt2Callsign, shutdown, startup, status1, status2, status3, status4, status5, command1, command1Line, command2, command2Line, command3, command3Line, command4, command4Line, output1, output2, output3, output4);
	wxLogInfo(wxT("Control: enabled: %d, RPT1: %s, RPT2: %s, shutdown: %s, startup: %s, status1: %s, status2: %s, status3: %s, status4: %s, status5: %s, command1: %s = %s, command2: %s = %s, command3: %s = %s, command4: %s = %s, output1: %s, output2: %s, output3: %s, output4: %s"), enabled, rpt1Callsign.c_str(), rpt2Callsign.c_str(), shutdown.c_str(), startup.c_str(), status1.c_str(), status2.c_str(), status3.c_str(), status4.c_str(), status5.c_str(), command1.c_str(), command1Line.c_str(), command2.c_str(), command2Line.c_str(), command3.c_str(), command3Line.c_str(), command4.c_str(), command4Line.c_str(), output1.c_str(), output2.c_str(), output3.c_str(), output4.c_str());

	bool logging;
	getLogging(logging);
	thread->setLogging(logging, m_audioDir);
	m_frame->setLogging(logging);
	wxLogInfo(wxT("Frame logging set to %d, in %s"), int(logging), m_audioDir.c_str());

	wxFileName wlFilename(wxFileName::GetHomeDir(), WHITELIST_FILE_NAME);
	bool exists = wlFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(wlFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError(wxT("Unable to open white list file - %s"), wlFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo(wxT("%u callsigns loaded into the white list"), list->getCount());
			thread->setWhiteList(list);
		}
	}

	wxFileName blFilename(wxFileName::GetHomeDir(), BLACKLIST_FILE_NAME);
	exists = blFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(blFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError(wxT("Unable to open black list file - %s"), blFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo(wxT("%u callsigns loaded into the black list"), list->getCount());
			thread->setBlackList(list);
		}
	}

	// Convert the worker class into a thread
	m_thread = new CDVRPTRRepeaterThreadHelper(thread);
	m_thread->start();
}
Пример #7
0
void CDStarRepeaterApp::createThread()
{
	wxASSERT(m_config != NULL);

	wxString callsign, gateway;
	DSTAR_MODE mode;
	ACK_TYPE ack;
	bool restriction, rpt1Validation, dtmfBlanking, errorReply;
	m_config->getCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation, dtmfBlanking, errorReply);

	wxString modemType;
	m_config->getModem(modemType);

	// DVAP can only do simplex, force the mode accordingly
	if (modemType.IsSameAs("DVAP")) {
		if (mode == MODE_DUPLEX) {
			wxLogInfo("DVAP: changing mode from DUPLEX to SIMPLEX");
			mode = MODE_SIMPLEX;
		} else if (mode == MODE_TXANDRX) {
			wxLogInfo("DVAP: changing mode from TX_AND_RX to RX_ONLY");
			mode = MODE_RXONLY;
		}
	}

	//  XXX This should be m_thread eventually.
	switch (mode) {
		case MODE_RXONLY:
			m_thread = new CDStarRepeaterRXThread(modemType);
			break;
		case MODE_TXONLY:
			m_thread = new CDStarRepeaterTXThread(modemType);
			break;
		case MODE_TXANDRX:
			m_thread = new CDStarRepeaterTXRXThread(modemType);
			break;
		default:
			m_thread = new CDStarRepeaterTRXThread(modemType);
			break;
	}

	m_thread->setCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation, dtmfBlanking, errorReply);
	wxLogInfo("Callsign set to \"%s\", gateway set to \"%s\", mode: %d, ack: %d, restriction: %d, RPT1 validation: %d, DTMF blanking: %d, Error reply: %d", callsign.c_str(), gateway.c_str(), int(mode), int(ack), int(restriction), int(rpt1Validation), int(dtmfBlanking), int(errorReply));

	wxString gatewayAddress, localAddress, name;
	unsigned int gatewayPort, localPort;
	m_config->getNetwork(gatewayAddress, gatewayPort, localAddress, localPort, name);
	wxLogInfo("Gateway set to %s:%u, local set to %s:%u, name set to \"%s\"", gatewayAddress.c_str(), gatewayPort, localAddress.c_str(), localPort, name.c_str());

	if (!gatewayAddress.IsEmpty()) {
		bool local = gatewayAddress.IsSameAs("127.0.0.1");

		CRepeaterProtocolHandler* handler = new CRepeaterProtocolHandler(gatewayAddress, gatewayPort, localAddress, localPort, name);

		bool res = handler->open();
		if (!res)
			wxLogError("Cannot open the protocol handler");
		else
			m_thread->setProtocolHandler(handler, local);
	}

	unsigned int timeout, ackTime;
	m_config->getTimes(timeout, ackTime);
	m_thread->setTimes(timeout, ackTime);
	wxLogInfo("Timeout set to %u secs, ack time set to %u ms", timeout, ackTime);

	unsigned int beaconTime;
	wxString beaconText;
	bool beaconVoice;
	TEXT_LANG language;
	m_config->getBeacon(beaconTime, beaconText, beaconVoice, language);
	if (mode == MODE_GATEWAY)
		beaconTime = 0U;
	m_thread->setBeacon(beaconTime, beaconText, beaconVoice, language);
	wxLogInfo("Beacon set to %u mins, text set to \"%s\", voice set to %d, language set to %d", beaconTime / 60U, beaconText.c_str(), int(beaconVoice), int(language));

	bool announcementEnabled;
	unsigned int announcementTime;
	wxString announcementRecordRPT1, announcementRecordRPT2;
	wxString announcementDeleteRPT1, announcementDeleteRPT2;
	m_config->getAnnouncement(announcementEnabled, announcementTime, announcementRecordRPT1, announcementRecordRPT2, announcementDeleteRPT1, announcementDeleteRPT2);
	if (mode == MODE_GATEWAY)
		announcementEnabled = false;
	m_thread->setAnnouncement(announcementEnabled, announcementTime, announcementRecordRPT1, announcementRecordRPT2, announcementDeleteRPT1, announcementDeleteRPT2);
	wxLogInfo("Announcement enabled: %d, time: %u mins, record RPT1: \"%s\", record RPT2: \"%s\", delete RPT1: \"%s\", delete RPT2: \"%s\"", int(announcementEnabled), announcementTime / 60U, announcementRecordRPT1.c_str(), announcementRecordRPT2.c_str(), announcementDeleteRPT1.c_str(), announcementDeleteRPT2.c_str());

	wxLogInfo("Modem type set to \"%s\"", modemType.c_str());

	CModem* modem = NULL;
	if (modemType.IsSameAs("DVAP")) {
		wxString port;
		unsigned int frequency;
		int power, squelch;
		m_config->getDVAP(port, frequency, power, squelch);
		wxLogInfo("DVAP: port: %s, frequency: %u Hz, power: %d dBm, squelch: %d dBm", port.c_str(), frequency, power, squelch);
		modem = new CDVAPController(port, frequency, power, squelch);
	} else if (modemType.IsSameAs("DV-RPTR V1")) {
		wxString port;
		bool rxInvert, txInvert, channel;
		unsigned int modLevel, txDelay;
		m_config->getDVRPTR1(port, rxInvert, txInvert, channel, modLevel, txDelay);
		wxLogInfo("DV-RPTR V1, port: %s, RX invert: %d, TX invert: %d, channel: %s, mod level: %u%%, TX delay: %u ms", port.c_str(), int(rxInvert), int(txInvert), channel ? "B" : "A", modLevel, txDelay);
		modem = new CDVRPTRV1Controller(port, wxEmptyString, rxInvert, txInvert, channel, modLevel, txDelay);
	} else if (modemType.IsSameAs("DV-RPTR V2")) {
		CONNECTION_TYPE connType;
		wxString usbPort, address;
		bool txInvert;
		unsigned int port, modLevel, txDelay;
		m_config->getDVRPTR2(connType, usbPort, address, port, txInvert, modLevel, txDelay);
		wxLogInfo("DV-RPTR V2, type: %d, address: %s:%u, TX invert: %d, mod level: %u%%, TX delay: %u ms", int(connType), address.c_str(), port, int(txInvert), modLevel, txDelay);
		switch (connType) {
			case CT_USB:
				modem = new CDVRPTRV2Controller(usbPort, wxEmptyString, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign, txDelay);
				break;
			case CT_NETWORK:
				modem = new CDVRPTRV2Controller(address, port, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign, txDelay);
				break;
		}
	} else if (modemType.IsSameAs("DV-RPTR V3")) {
		CONNECTION_TYPE connType;
		wxString usbPort, address;
		bool txInvert;
		unsigned int port, modLevel, txDelay;
		m_config->getDVRPTR3(connType, usbPort, address, port, txInvert, modLevel, txDelay);
		wxLogInfo("DV-RPTR V3, type: %d, address: %s:%u, TX invert: %d, mod level: %u%%, TX delay: %u ms", int(connType), address.c_str(), port, int(txInvert), modLevel, txDelay);
		switch (connType) {
			case CT_USB:
				modem = new CDVRPTRV3Controller(usbPort, wxEmptyString, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign, txDelay);
				break;
			case CT_NETWORK:
				modem = new CDVRPTRV3Controller(address, port, txInvert, modLevel, mode == MODE_DUPLEX || mode == MODE_TXANDRX, callsign, txDelay);
				break;
		}
	} else if (modemType.IsSameAs("DVMEGA")) {
		wxString port;
		DVMEGA_VARIANT variant;
		bool rxInvert, txInvert;
		unsigned int txDelay, rxFrequency, txFrequency, power;
		m_config->getDVMEGA(port, variant, rxInvert, txInvert, txDelay, rxFrequency, txFrequency, power);
		wxLogInfo("DVMEGA, port: %s, variant: %d, RX invert: %d, TX invert: %d, TX delay: %u ms, rx frequency: %u Hz, tx frequency: %u Hz, power: %u %%", port.c_str(), int(variant), int(rxInvert), int(txInvert), txDelay, rxFrequency, txFrequency, power);
		switch (variant) {
			case DVMV_MODEM:
				modem = new CDVMegaController(port, wxEmptyString, rxInvert, txInvert, txDelay);
				break;
			case DVMV_RADIO_2M:
			case DVMV_RADIO_70CM:
			case DVMV_RADIO_2M_70CM:
				modem = new CDVMegaController(port, wxEmptyString, txDelay, rxFrequency, txFrequency, power);
				break;
			default:
				wxLogError("Unknown DVMEGA variant - %d"), int(variant);
				break;
		}
	} else if (modemType.IsSameAs("GMSK Modem")) {
		USB_INTERFACE iface;
		unsigned int address;
		m_config->getGMSK(iface, address);
		wxLogInfo("GMSK, interface: %d, address: %04X", int(iface), address);
		modem = new CGMSKController(iface, address, mode == MODE_DUPLEX || mode == MODE_TXANDRX);
	} else if (modemType.IsSameAs("Sound Card")) {
		wxString rxDevice, txDevice;
		bool rxInvert, txInvert;
		wxFloat32 rxLevel, txLevel;
		unsigned int txDelay, txTail;
		m_config->getSoundCard(rxDevice, txDevice, rxInvert, txInvert, rxLevel, txLevel, txDelay, txTail);
		wxLogInfo("Sound Card, devices: %s:%s, invert: %d:%d, levels: %.2f:%.2f, tx delay: %u ms, tx tail: %u ms", rxDevice.c_str(), txDevice.c_str(), int(rxInvert), int(txInvert), rxLevel, txLevel, txDelay, txTail);
		modem = new CSoundCardController(rxDevice, txDevice, rxInvert, txInvert, rxLevel, txLevel, txDelay, txTail);
	} else if (modemType.IsSameAs("MMDVM")) {
		wxString port;
		bool rxInvert, txInvert, pttInvert;
		unsigned int txDelay, rxLevel, txLevel;
		m_config->getMMDVM(port, rxInvert, txInvert, pttInvert, txDelay, rxLevel, txLevel);
		wxLogInfo("MMDVM, port: %s, RX invert: %d, TX invert: %d, PTT invert: %d, TX delay: %u ms, RX level: %u%%, TX level: %u%%", port.c_str(), int(rxInvert), int(txInvert), int(pttInvert), txDelay, rxLevel, txLevel);
		modem = new CMMDVMController(port, wxEmptyString, rxInvert, txInvert, pttInvert, txDelay, rxLevel, txLevel);
	} else if (modemType.IsSameAs("Split")) {
		wxString localAddress;
		unsigned int localPort;
		wxArrayString transmitterNames, receiverNames;
		unsigned int timeout;
		m_config->getSplit(localAddress, localPort, transmitterNames, receiverNames, timeout);
		wxLogInfo("Split, local: %s:%u, timeout: %u ms", localAddress.c_str(), localPort, timeout);
		for (unsigned int i = 0U; i < transmitterNames.GetCount(); i++) {
			wxString name = transmitterNames.Item(i);
			if (!name.IsEmpty())
				wxLogInfo("\tTX %u name: %s", i + 1U, name.c_str());
		}
		for (unsigned int i = 0U; i < receiverNames.GetCount(); i++) {
			wxString name = receiverNames.Item(i);
			if (!name.IsEmpty())
				wxLogInfo("\tRX %u name: %s", i + 1U, name.c_str());
		}
		modem = new CSplitController(localAddress, localPort, transmitterNames, receiverNames, timeout);
	} else {
		wxLogError("Unknown modem type: %s", modemType.c_str());
	}

	if (modem != NULL) {
		bool res = modem->start();
		if (!res)
			wxLogError("Cannot open the D-Star modem");
		else
			m_thread->setModem(modem);
	}

	wxString controllerType;
	unsigned int portConfig, activeHangTime;
	bool pttInvert;
	m_config->getController(controllerType, portConfig, pttInvert, activeHangTime);
	wxLogInfo("Controller set to %s, config: %u, PTT invert: %d, active hang time: %u ms", controllerType.c_str(), portConfig, int(pttInvert), activeHangTime);

	CExternalController* controller = NULL;

	wxString port;
	if (controllerType.StartsWith("Velleman K8055 - ", &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CK8055Controller(num), pttInvert);
	} else if (controllerType.StartsWith("URI USB - ", &port)) {
                unsigned long num;
                port.ToULong(&num);
                controller = new CExternalController(new CURIUSBController(num, true), pttInvert);
	} else if (controllerType.StartsWith("Serial - ", &port)) {
		controller = new CExternalController(new CSerialLineController(port, portConfig), pttInvert);
	} else if (controllerType.StartsWith("Arduino - ", &port)) {
		controller = new CExternalController(new CArduinoController(port), pttInvert);
#if defined(GPIO)
	} else if (controllerType.IsSameAs("GPIO")) {
		controller = new CExternalController(new CGPIOController(portConfig), pttInvert);
	} else if (controllerType.IsSameAs(wxT("UDRC"))) {
		switch(portConfig) {
			case 1:
				controller = new CUDRCController(AUTO_FM);
				break;
			case 3:
				controller = new CUDRCController(DIGITAL_DIGITAL);
				break;
			case 4:
				controller = new CUDRCController(FM_FM);
				break;
			case 5:
				controller = new CUDRCController(HOTSPOT);
				break;
			default:
			case 2:
				controller = new CUDRCController(AUTO_AUTO);
				break;

			}
#endif
	} else {
		wxLogError("Unrecognized controller %s, using dummy controller", controllerType);
		controller = new CExternalController(new CDummyController, pttInvert);
	}

	bool res = controller->open();
	if (!res)
		wxLogError("Cannot open the hardware interface - %s", controllerType.c_str());
	else
		m_thread->setController(controller, activeHangTime);

	bool out1, out2, out3, out4;
	m_config->getOutputs(out1, out2, out3, out4);
	m_thread->setOutputs(out1, out2, out3, out4);
#if (wxUSE_GUI == 1)
	m_frame->setOutputs(out1, out2, out3, out4);
#endif
	wxLogInfo("Output 1 = %d, output 2 = %d, output 3 = %d, output 4 = %d", int(out1), int(out2), int(out3), int(out4));

	bool enabled;
	wxString rpt1Callsign, rpt2Callsign;
	wxString shutdown, startup;

	//  XXX Initialization should be temporary until we get them coming
	//  from m_config->getControl
	wxArrayString status;
	status.Add("", 5);
	wxArrayString command;
	command.Add("", 6);
	wxArrayString output;
	output.Add("", 4);

	m_config->getControl(enabled, rpt1Callsign, rpt2Callsign, shutdown, startup, status[0], status[1], status[2], status[3], status[4], command[0], m_commandLine[0], command[1], m_commandLine[1], command[2], m_commandLine[2], command[3], m_commandLine[3], command[4], m_commandLine[4], command[5], m_commandLine[5], output[0], output[1], output[2], output[3]);

	m_thread->setControl(enabled, rpt1Callsign, rpt2Callsign, shutdown,
		startup, command, status, output);

	wxLogInfo(wxT("Control: enabled: %d, RPT1: %s, RPT2: %s, shutdown: %s, startup: %s, status1: %s, status2: %s, status3: %s, status4: %s, status5: %s, command1: %s = %s, command2: %s = %s, command3: %s = %s, command4: %s = %s, command5: %s = %s, command6: %s = %s, output1: %s, output2: %s, output3: %s, output4: %s"), enabled, rpt1Callsign.c_str(), rpt2Callsign.c_str(), shutdown.c_str(), startup.c_str(), status[0].c_str(), status[1].c_str(), status[2].c_str(), status[3].c_str(), status[4].c_str(), command[0].c_str(), m_commandLine[0].c_str(), command[1].c_str(), m_commandLine[1].c_str(), command[2].c_str(), m_commandLine[2].c_str(), command[3].c_str(), m_commandLine[3].c_str(), command[4].c_str(), m_commandLine[4].c_str(), command[5].c_str(), m_commandLine[5].c_str(), output[0].c_str(), output[1].c_str(), output[2].c_str(), output[3].c_str());

	bool logging;
	m_config->getLogging(logging);
	m_thread->setLogging(logging, m_audioDir);
#if (wxUSE_GUI == 1)
	m_frame->setLogging(logging);
#endif
	wxLogInfo("Frame logging set to %d, in %s", int(logging), m_audioDir.c_str());

#if defined(__WINDOWS__)
	wxFileName wlFilename(wxFileName::GetHomeDir(), PRIMARY_WHITELIST_FILE_NAME);
#else
	wxFileName wlFilename(CONF_DIR, PRIMARY_WHITELIST_FILE_NAME);
#endif
	bool exists = wlFilename.FileExists();

	if (!exists) {
#if defined(__WINDOWS__)
		wlFilename.Assign(wxFileName::GetHomeDir(), SECONDARY_WHITELIST_FILE_NAME);
#else
		wlFilename.Assign(CONF_DIR, SECONDARY_WHITELIST_FILE_NAME);
#endif
		exists = wlFilename.FileExists();
	}

	if (exists) {
		CCallsignList* list = new CCallsignList(wlFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError("Unable to open white list file - %s", wlFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo("%u callsigns loaded into the white list", list->getCount());
			m_thread->setWhiteList(list);
		}
	}
#if defined(__WINDOWS__)
	wxFileName blFilename(wxFileName::GetHomeDir(), PRIMARY_BLACKLIST_FILE_NAME);
#else
		wxFileName blFilename(CONF_DIR, PRIMARY_BLACKLIST_FILE_NAME);
#endif
	exists = blFilename.FileExists();

	if (!exists) {
#if defined(__WINDOWS__)
		blFilename.Assign(wxFileName::GetHomeDir(), SECONDARY_BLACKLIST_FILE_NAME);
#else
		blFilename.Assign(CONF_DIR, SECONDARY_BLACKLIST_FILE_NAME);
#endif
		exists = blFilename.FileExists();
	}

	if (exists) {
		CCallsignList* list = new CCallsignList(blFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError("Unable to open black list file - %s", blFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo("%u callsigns loaded into the black list", list->getCount());
			m_thread->setBlackList(list);
		}
	}
#if defined(__WINDOWS__)
	wxFileName glFilename(wxFileName::GetHomeDir(), GREYLIST_FILE_NAME);
#else
		wxFileName glFilename(CONF_DIR, GREYLIST_FILE_NAME);
#endif
	exists = glFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(glFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError("Unable to open grey list file - %s", glFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo("%u callsigns loaded into the grey list", list->getCount());
			m_thread->setGreyList(list);
		}
	}

	m_thread->Create();
	m_thread->SetPriority(wxPRIORITY_MAX);
	m_thread->Run();
}
void CSoundCardRepeaterApp::createThread()
{
	wxString callsign, gateway;
	DSTAR_MODE mode;
	ACK_TYPE ack;
	bool restriction, rpt1Validation;
	getCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation);

	switch (mode) {
		case MODE_RXONLY:
			m_thread = new CSoundCardRepeaterRXThread;
			break;
		case MODE_TXONLY:
			m_thread = new CSoundCardRepeaterTXThread;
			break;
		case MODE_TXANDRX:
			m_thread = new CSoundCardRepeaterTXRXThread;
			break;
		default:
			m_thread = new CSoundCardRepeaterTRXThread;
			break;
	}

	m_thread->setCallsign(callsign, gateway, mode, ack, restriction, rpt1Validation);
	wxLogInfo(wxT("Callsign set to \"%s\", gateway set to \"%s\", mode: %d, ack: %d, restriction: %d, RPT1 validation: %d"), callsign.c_str(), gateway.c_str(), int(mode), int(ack), restriction, rpt1Validation);

	wxString gatewayAddress, localAddress;
	unsigned int gatewayPort, localPort;
	getNetwork(gatewayAddress, gatewayPort, localAddress, localPort);
	wxLogInfo(wxT("Gateway set to %s:%u, local set to %s:%u"), gatewayAddress.c_str(), gatewayPort, localAddress.c_str(), localPort);

	if (!gatewayAddress.IsEmpty()) {
		CRepeaterProtocolHandler* handler = new CRepeaterProtocolHandler(gatewayAddress, gatewayPort, localAddress, localPort);

		bool res = handler->open();
		if (!res)
			wxLogError(wxT("Cannot open the protocol handler"));
		else
			m_thread->setProtocolHandler(handler);
	}

	unsigned int timeout, ackTime, hangTime;
	getTimes(timeout, ackTime, hangTime);
	m_thread->setTimes(timeout, ackTime, hangTime);
	wxLogInfo(wxT("Timeout set to %u secs, Ack time set to %u ms, Hang time set to %u ms"), timeout, ackTime, hangTime);

	unsigned int beaconTime;
	wxString beaconText;
	bool beaconVoice;
	TEXT_LANG language;
	getBeacon(beaconTime, beaconText, beaconVoice, language);
	m_thread->setBeacon(beaconTime, beaconText, beaconVoice, language);
	wxLogInfo(wxT("Beacon set to %u mins, text set to \"%s\", voice set to %d, language set to %d"), beaconTime / 60U, beaconText.c_str(), int(beaconVoice), int(language));

	wxString readDevice, writeDevice;
	bool rxInvert, txInvert;
	wxFloat32 rxLevel, txLevel, squelchLevel;
	SQUELCH_MODE squelchMode;
	getRadio(readDevice, writeDevice, rxLevel, txLevel, squelchMode, squelchLevel, rxInvert, txInvert);
	wxLogInfo(wxT("Soundcard set to %s:%s, levels: %.2f:%.2f, GMSK Inversion set to %d:%d, squelch: mode: %d level: %.2f"), readDevice.c_str(), writeDevice.c_str(), rxLevel, txLevel, rxInvert, txInvert, int(squelchMode), squelchLevel);

	if (!readDevice.IsEmpty() && !writeDevice.IsEmpty()) {
#if defined(__WINDOWS__)
		CSoundCardReaderWriter* soundcard = new CSoundCardReaderWriter(readDevice, writeDevice, DSTAR_RADIO_SAMPLE_RATE, DSTAR_RADIO_BLOCK_SIZE);
#else
		CSoundCardReaderWriter* soundcard = new CSoundCardReaderWriter(readDevice, writeDevice, DSTAR_RADIO_SAMPLE_RATE, 64U);
#endif
		soundcard->setCallback(m_thread, 0U);

		bool res = soundcard->open();
		if (!res)
			wxLogError(wxT("Cannot open the sound card"));
		else
			m_thread->setSoundCard(soundcard, rxLevel, txLevel, squelchMode, squelchLevel, rxInvert, txInvert);
	}

	wxString type;
	unsigned int cfg;
	int pttDelay;
	bool pttInvert;
	getController(type, cfg, pttDelay, pttInvert);
	wxLogInfo(wxT("Controller set to %s, config: %u, ptt delay: %d ms, PTT Inversion set to %d"), type.c_str(), cfg, pttDelay * 20, pttInvert);

	CExternalController* controller = NULL;

	wxString port;
	if (type.StartsWith(wxT("Velleman K8055 - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CK8055Controller(num), pttInvert, false);
	} else if (type.StartsWith(wxT("URI USB - "), &port)) {
		unsigned long num;
		port.ToULong(&num);
		controller = new CExternalController(new CURIUSBController(num, false), pttInvert, false);
	} else if (type.StartsWith(wxT("Serial - "), &port)) {
		controller = new CExternalController(new CSerialController(port, cfg), pttInvert, false);
	} else {
		controller = new CExternalController(new CDummyController, pttInvert, false);
	}

	bool res = controller->open();
	if (!res)
		wxLogError(wxT("Cannot open the hardware interface - %s"), type.c_str());
	else
		m_thread->setController(controller, pttDelay);

	bool out1, out2, out3, out4;
	getOutputs(out1, out2, out3, out4);
	m_thread->setOutputs(out1, out2, out3, out4);
	m_frame->setOutputs(out1, out2, out3, out4);
	wxLogInfo(wxT("Output 1 = %d, output 2 = %d, output 3 = %d, output 4 = %d"), out1, out2, out3, out4);

	bool enabled;
	wxString rpt1Callsign, rpt2Callsign;
	wxString shutdown, startup;
	wxString status1, status2, status3, status4, status5;
	wxString command1, command1Line, command2, command2Line;
	wxString command3, command3Line, command4, command4Line;
	wxString output1, output2, output3, output4;
	getControl(enabled, rpt1Callsign, rpt2Callsign, shutdown, startup, status1, status2, status3, status4, status5, command1, command1Line, command2, command2Line, command3, command3Line, command4, command4Line, output1, output2, output3, output4);
	m_thread->setControl(enabled, rpt1Callsign, rpt2Callsign, shutdown, startup, status1, status2, status3, status4, status5, command1, command1Line, command2, command2Line, command3, command3Line, command4, command4Line, output1, output2, output3, output4);
	wxLogInfo(wxT("Control: enabled: %d, RPT1: %s, RPT2: %s, shutdown: %s, startup: %s, status1: %s, status2: %s, status3: %s, status4: %s, status5: %s, command1: %s = %s, command2: %s = %s, command3: %s = %s, command4: %s = %s, output1: %s, output2: %s, output3: %s, output4: %s"), enabled, rpt1Callsign.c_str(), rpt2Callsign.c_str(), shutdown.c_str(), startup.c_str(), status1.c_str(), status2.c_str(), status3.c_str(), status4.c_str(), status5.c_str(), command1.c_str(), command1Line.c_str(), command2.c_str(), command2Line.c_str(), command1.c_str(), command1Line.c_str(), command2.c_str(), command2Line.c_str(), command3.c_str(), command3Line.c_str(), command4.c_str(), command4Line.c_str(), output1.c_str(), output2.c_str(), output3.c_str(), output4.c_str());

	unsigned int activeHangTime;
	getActiveHang(activeHangTime);
	m_thread->setActiveHang(activeHangTime);
	wxLogInfo(wxT("Active Hang: time: %u"), activeHangTime);

	bool logging;
	getLogging(logging);
	m_thread->setLogging(logging, ::wxGetHomeDir());
	m_frame->setLogging(logging);
	wxLogInfo(wxT("Frame logging set to %d, in %s"), int(logging), ::wxGetHomeDir().c_str());

	wxFileName wlFilename(wxFileName::GetHomeDir(), WHITELIST_FILE_NAME);
	bool exists = wlFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(wlFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError(wxT("Unable to open white list file - %s"), wlFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo(wxT("%u callsigns loaded into the white list"), list->getCount());
			m_thread->setWhiteList(list);
		}
	}

	wxFileName blFilename(wxFileName::GetHomeDir(), BLACKLIST_FILE_NAME);
	exists = blFilename.FileExists();
	if (exists) {
		CCallsignList* list = new CCallsignList(blFilename.GetFullPath());
		bool res = list->load();
		if (!res) {
			wxLogError(wxT("Unable to open black list file - %s"), blFilename.GetFullPath().c_str());
			delete list;
		} else {
			wxLogInfo(wxT("%u callsigns loaded into the black list"), list->getCount());
			m_thread->setBlackList(list);
		}
	}

	m_thread->start();
}