void CDVAPNodeTRXThread::processNetworkHeader(CHeaderData* header)
{
	wxASSERT(header != NULL);

	wxLogMessage(wxT("Network header received - My: %s/%s  Your: %s  Rpt1: %s  Rpt2: %s  Flags: %02X %02X %02X"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3());

	// Is it for us?
	if (!header->getRptCall2().IsSameAs(m_rptCallsign)) {
		wxLogMessage(wxT("Invalid network RPT2 value, ignoring"));
		delete header;
		return;
	}

	setRepeaterState(DSRS_NETWORK);

	if (m_state == DSRS_NETWORK) {
		delete m_rxHeader;
		m_rxHeader = header;

		CHeaderData* header = new CHeaderData(*m_rxHeader);

		transmitNetworkHeader(header);
	} else {
		delete header;
	}
}
void CGMSKRepeaterTXRXThread::processNetworkHeader(CHeaderData* header)
{
	wxASSERT(header != NULL);

	// If shutdown we ignore incoming headers
	if (m_state == DSRS_SHUTDOWN) {
		delete header;
		return;
	}

	wxLogMessage(wxT("Network header received - My: %s/%s  Your: %s  Rpt1: %s  Rpt2: %s  Flags: %02X %02X %02X"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3());

	// Is it for us?
	if (!header->getRptCall2().IsSameAs(m_rptCallsign)) {
		wxLogMessage(wxT("Invalid network RPT2 value, ignoring"));
		delete header;
		return;
	}

	delete m_txHeader;
	m_txHeader = header;

	m_networkSeqNo = 0U;
	m_watchdogTimer.start();
	m_activeHangTimer.stop();

	transmitNetworkHeader(*header);
}
void CDVRPTRRepeaterTXThread::processNetworkHeader(CHeaderData* header)
{
	wxASSERT(header != NULL);

	wxLogMessage(wxT("Network header received - My: %s/%s  Your: %s  Rpt1: %s  Rpt2: %s  Flags: %02X %02X %02X"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3());

	// Is it for us?
	if (!header->getRptCall2().IsSameAs(m_rptCallsign)) {
		wxLogMessage(wxT("Invalid network RPT2 value, ignoring"));
		delete header;
		return;
	}

	m_state = DSRS_NETWORK;
	m_networkSeqNo = 0U;
	m_watchdogTimer.start();

	delete m_txHeader;
	m_txHeader = header;

	transmitNetworkHeader(new CHeaderData(*header));
}
void CDVAPNodeTRXThread::run()
{
	// Wait here until we have the essentials to run
	while (!m_killed && (m_dvap == NULL || m_rptCallsign.IsEmpty() || m_rptCallsign.IsSameAs(wxT("        "))))
		::wxMilliSleep(500UL);		// 1/2 sec

	if (m_killed)
		return;

	m_stopped = false;

	m_beaconTimer.start();
	m_dvapPollTimer.start();

	if (m_protocolHandler != NULL)
		m_pollTimer.start();

	wxLogMessage(wxT("Starting the DVAP node thread"));

	wxStopWatch stopWatch;

	while (!m_killed) {
		stopWatch.Start();

		switch (m_state) {
			case DSRS_LISTENING:
				receiveRadioHeader();
				break;
			case DSRS_NETWORK:
				break;
			case DSRS_VALID:
			case DSRS_INVALID:
			case DSRS_TIMEOUT:
				receiveRadioData();
				break;
			default:		// All the DSRS_*_WAIT values
				break;
		}

		// Listen all the time on the network for status packets at least
		receiveNetwork();

		repeaterStateMachine();

		m_tx      = m_dvap->getPTT();
		m_squelch = m_dvap->getSquelch();
		m_signal  = m_dvap->getSignal();

		// Send the network poll if needed and restart the timer
		if (m_pollTimer.hasExpired()) {
#if defined(__WINDOWS__)
			m_protocolHandler->writePoll(wxT("win_dvap-") + VERSION);
#else
			m_protocolHandler->writePoll(wxT("linux_dvap-") + VERSION);
#endif
			m_pollTimer.reset();
		}

		if (m_dvapPollTimer.hasExpired()) {
			m_dvap->writePoll();
			m_dvapPollTimer.reset();
		}

		// Send the beacon and restart the timer
		if (m_beaconTimer.isRunning() && m_beaconTimer.hasExpired()) {
			m_beacon->sendBeacon();
			m_beaconTimer.reset();
		}

		if (m_localQueue.dataReady())
			transmitLocalData();
		else if (m_networkQueue[m_readNum]->dataReady())
			transmitNetworkData();
		else if (m_localQueue.headerReady())
			transmitLocalHeader();
		else if (m_networkQueue[m_readNum]->headerReady())
			transmitNetworkHeader();

		unsigned long ms = stopWatch.Time();
		if (ms < CYCLE_TIME) {
			::wxMilliSleep(CYCLE_TIME - ms);
			clock(CYCLE_TIME);
		} else {
			clock(ms);
		}
	}

	wxLogMessage(wxT("Stopping the DVAP node thread"));

	m_dvap->close();

	if (m_protocolHandler != NULL) {
		m_protocolHandler->close();
		delete m_protocolHandler;
	}
}
void* CGMSKRepeaterTXRXThread::Entry()
{
	// Wait here until we have the essentials to run
	while (!m_killed && (m_modem == NULL  || m_controller == NULL || m_protocolHandler == NULL || m_rptCallsign.IsEmpty() || m_rptCallsign.IsSameAs(wxT("        "))))
		Sleep(500UL);		// 1/2 sec

	if (m_killed)
		return NULL;

	m_broken = m_modem->isBroken();

	m_cycleTime = m_broken ? BROKEN_CYCLE_TIME : NORMAL_CYCLE_TIME;

	m_controller->setActive(false);
	m_controller->setRadioTransmit(false);

	m_pollTimer.start();

	wxLogMessage(wxT("Starting the GMSK transmitter and receiver thread"));

	unsigned int count = 0U;

	wxStopWatch stopWatch;

	while (!m_killed) {
		stopWatch.Start();

		switch (m_state) {
			case DSRS_SHUTDOWN:
			case DSRS_LISTENING:
				// Only check for the RF header every 100ms or so
				if (m_headerReadTimer.hasExpired()) {
					bool error = receiveRadioHeader();
					if (error)
						reopenModem();

					m_headerReadTimer.reset();
				}
				break;

			case DSRS_VALID: {
					bool error = receiveRadioData();
					if (error)
						reopenModem();
				}
				break;

			default:
				break;
		}

		if (m_killed)
			break;

		// Listen all the time on the network for status packets at least
		receiveNetwork();

		repeaterStateMachine();

		// Send the network poll if needed and restart the timer
		if (m_pollTimer.hasExpired()) {
#if defined(__WINDOWS__)
			m_protocolHandler->writePoll(wxT("win_gmsk-") + VERSION);
#else
			m_protocolHandler->writePoll(wxT("linux_gmsk-") + VERSION);
#endif
			m_pollTimer.reset();
		}

		// Clock the heartbeat output every one second
		count++;
		if (count == 60U) {
			m_controller->setHeartbeat();
			count = 0U;
		}

		// Set the output state
		if (m_tx || (m_activeHangTimer.isRunning() && !m_activeHangTimer.hasExpired())) {
			m_controller->setActive(true);
		} else {
			m_controller->setActive(false);
			m_activeHangTimer.stop();
		}

		// Check the shutdown state, state changes are done here to bypass the state machine which is
		// frozen when m_disable is asserted
		m_disable = m_controller->getDisable();
		if (m_disable) {
			if (m_state != DSRS_SHUTDOWN) {
				m_watchdogTimer.stop();
				m_activeHangTimer.stop();
				for (unsigned int i = 0U; i < NETWORK_QUEUE_COUNT; i++)
					m_networkQueue[i]->reset();
				m_tx = false;
				m_controller->setActive(false);
				m_controller->setRadioTransmit(false);
				m_state = DSRS_SHUTDOWN;
			}
		} else {
			if (m_state == DSRS_SHUTDOWN) {
				m_watchdogTimer.stop();
				m_state = DSRS_LISTENING;
				m_protocolHandler->reset();
			}
		}

		if (m_networkQueue[m_readNum]->dataReady()) {
			bool ret = transmitNetworkData();
			if (!ret)
				reopenModem();
		} else if (m_networkQueue[m_readNum]->headerReady()) {
			bool ret = transmitNetworkHeader();
			if (!ret)
				reopenModem();
		}

		m_controller->setRadioTransmit(m_tx);

		unsigned long ms = stopWatch.Time();

		if (m_state != DSRS_VALID) {
			if (ms < m_cycleTime)
				Sleep(m_cycleTime - ms);

			ms = stopWatch.Time();
		}

		// Catch up with the clock
		clock(ms);
	}

	wxLogMessage(wxT("Stopping the GMSK transmitter and receiver thread"));

	if (m_modem != NULL) {
		m_modem->close();
		delete m_modem;
	}

	m_controller->setActive(false);
	m_controller->setRadioTransmit(false);
	m_controller->close();
	delete m_controller;

	m_protocolHandler->close();
	delete m_protocolHandler;

	return NULL;
}
void CDVRPTRRepeaterTXThread::run()
{
	// Wait here until we have the essentials to run
	while (!m_killed && (m_dvrptr == NULL  || m_protocolHandler == NULL || m_rptCallsign.IsEmpty() || m_rptCallsign.IsSameAs(wxT("        "))))
		::wxMilliSleep(500UL);		// 1/2 sec

	if (m_killed)
		return;

	m_stopped = false;

	m_pollTimer.start();

	wxLogMessage(wxT("Starting the DV-RPTR transmitter thread"));

	wxStopWatch stopWatch;

	while (!m_killed) {
		stopWatch.Start();

		// Remove any received data from the modem
		m_dvrptr->purgeRX();

		receiveNetwork();

		m_tx = m_dvrptr->getPTT();

		if (m_state == DSRS_NETWORK) {
			if (m_watchdogTimer.hasExpired()) {
				wxLogMessage(wxT("Network watchdog has expired"));
				// Send end of transmission data to the radio
				m_networkQueue[m_writeNum]->addData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES, true);
				endOfNetworkData();
			}
		}

		// Send the network poll if needed and restart the timer
		if (m_pollTimer.hasExpired()) {
#if defined(__WINDOWS__)
			m_protocolHandler->writePoll(wxT("win_dvrptr-") + VERSION);
#else
			m_protocolHandler->writePoll(wxT("linux_dvrptr-") + VERSION);
#endif
			m_pollTimer.reset();
		}

		if (m_networkQueue[m_readNum]->dataReady())
			transmitNetworkData();
		else if (m_networkQueue[m_readNum]->headerReady())
			transmitNetworkHeader();

		unsigned long ms = stopWatch.Time();
		if (ms < CYCLE_TIME) {
			::wxMilliSleep(CYCLE_TIME - ms);
			clock(CYCLE_TIME);
		} else {
			clock(ms);
		}
	}

	wxLogMessage(wxT("Stopping the DV-RPTR transmitter thread"));

	m_dvrptr->close();

	m_protocolHandler->close();
	delete m_protocolHandler;
}
void CDStarRepeaterTXRXThread::run()
{
    // Wait here until we have the essentials to run
    while (!m_killed && (m_modem == NULL  || m_controller == NULL || m_protocolHandler == NULL || m_rptCallsign.IsEmpty() || m_rptCallsign.IsSameAs(wxT("        "))))
        ::wxMilliSleep(500UL);		// 1/2 sec

    if (m_killed)
        return;

    m_controller->setActive(false);
    m_controller->setRadioTransmit(false);

    m_heartbeatTimer.start();
    m_statusTimer.start();
    m_registerTimer.start(10U);

    wxString hardware = m_type;
    int n = hardware.Find(wxT(' '));
    if (n != wxNOT_FOUND)
        hardware = m_type.Left(n);

    wxLogMessage(wxT("Starting the D-Star transmitter and receiver thread"));

    wxStopWatch stopWatch;

    try {
        while (!m_killed) {
            stopWatch.Start();

            if (m_statusTimer.hasExpired() || m_space == 0U) {
                m_space = m_modem->getSpace();
                m_tx    = m_modem->isTX();
                m_statusTimer.start();
            }

            receiveModem();

            receiveNetwork();

            repeaterStateMachine();

            // Send the register packet if needed and restart the timer
            if (m_registerTimer.hasExpired()) {
                m_protocolHandler->writeRegister();
                m_registerTimer.start(30U);
            }

            // Clock the heartbeat output every one second
            if (m_heartbeatTimer.hasExpired()) {
                m_controller->setHeartbeat();
                m_heartbeatTimer.start();
            }

            // Set the output state
            if (m_tx || (m_activeHangTimer.isRunning() && !m_activeHangTimer.hasExpired())) {
                m_controller->setActive(true);
            } else {
                m_controller->setActive(false);
                m_activeHangTimer.stop();
            }

            // Check the shutdown state, state changes are done here to bypass the state machine which is
            // frozen when m_disable is asserted
            m_disable = m_controller->getDisable();
            if (m_disable) {
                if (m_rptState != DSRS_SHUTDOWN) {
                    m_watchdogTimer.stop();
                    m_activeHangTimer.stop();
                    for (unsigned int i = 0U; i < NETWORK_QUEUE_COUNT; i++)
                        m_networkQueue[i]->reset();
                    m_controller->setActive(false);
                    m_controller->setRadioTransmit(false);
                    m_rptState = DSRS_SHUTDOWN;
                    m_transmitting = false;
                }
            } else {
                if (m_rptState == DSRS_SHUTDOWN) {
                    m_watchdogTimer.stop();
                    m_rptState = DSRS_LISTENING;
                    m_protocolHandler->reset();
                    m_transmitting = false;
                }
            }

            if (m_networkQueue[m_readNum]->dataReady())
                transmitNetworkData();
            else if (m_networkQueue[m_readNum]->headerReady())
                transmitNetworkHeader();

            m_controller->setRadioTransmit(m_tx);

            unsigned long ms = stopWatch.Time();
            if (ms < CYCLE_TIME) {
                ::wxMilliSleep(CYCLE_TIME - ms);
                clock(CYCLE_TIME);
            } else {
                clock(ms);
            }
        }
    }
    catch (std::exception& e) {
        wxString message(e.what(), wxConvLocal);
        wxLogError(wxT("Exception raised - \"%s\""), message.c_str());
    }
    catch (...) {
        wxLogError(wxT("Unknown exception raised"));
    }

    wxLogMessage(wxT("Stopping the D-Star transmitter and receiver thread"));

    m_modem->stop();

    m_controller->setActive(false);
    m_controller->setRadioTransmit(false);
    m_controller->close();
    delete m_controller;

    m_protocolHandler->close();
    delete m_protocolHandler;
}
void CGMSKRepeaterTXThread::run()
{
	// Wait here until we have the essentials to run
	while (!m_killed && (m_modem == NULL || m_protocolHandler == NULL || m_rptCallsign.IsEmpty() || m_rptCallsign.IsSameAs(wxT("        "))))
		::wxMilliSleep(500UL);		// 1/2 sec

	if (m_killed)
		return;

	m_stopped = false;

	m_pollTimer.start();

	wxLogMessage(wxT("Starting the GMSK transmitter thread"));

	wxStopWatch stopWatch;

	while (!m_killed) {
		stopWatch.Start();

		// Listen all the time on the network for status packets at least
		receiveNetwork();

		if (m_state == DSRS_NETWORK) {
			if (m_watchdogTimer.hasExpired()) {
				wxLogMessage(wxT("Network watchdog has expired"));
				// Send end of transmission data to the radio
				m_networkQueue[m_writeNum]->addData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES, true);
				endOfNetworkData();
				m_tx = false;
			}
		}

		// Send the network poll if needed and restart the timer
		if (m_pollTimer.hasExpired()) {
#if defined(__WINDOWS__)
			m_protocolHandler->writePoll(wxT("win_gmsk-") + VERSION);
#else
			m_protocolHandler->writePoll(wxT("linux_gmsk-") + VERSION);
#endif
			m_pollTimer.reset();
		}

		if (m_networkQueue[m_readNum]->dataReady()) {
			bool ret = transmitNetworkData();
			if (!ret)
				reopenModem();
		} else if (m_networkQueue[m_readNum]->headerReady()) {
			bool ret = transmitNetworkHeader();
			if (!ret)
				reopenModem();
		}

		unsigned long ms = stopWatch.Time();

		if (ms < CYCLE_TIME) {
			::wxMilliSleep(CYCLE_TIME - ms);

			ms = stopWatch.Time();
		}

		// Catch up with the clock
		clock(ms);
	}

	wxLogMessage(wxT("Stopping the GMSK transmitter thread"));

	if (m_modem != NULL) {
		m_modem->close();
		delete m_modem;
	}

	m_protocolHandler->close();
	delete m_protocolHandler;
}