void CDStarRepeaterRXThread::receiveSlowData(unsigned char* data, unsigned int)
{
    unsigned int errs;
    errs  = countBits(data[VOICE_FRAME_LENGTH_BYTES + 0U] ^ DATA_SYNC_BYTES[0U]);
    errs += countBits(data[VOICE_FRAME_LENGTH_BYTES + 1U] ^ DATA_SYNC_BYTES[1U]);
    errs += countBits(data[VOICE_FRAME_LENGTH_BYTES + 2U] ^ DATA_SYNC_BYTES[2U]);

    // The data sync has been seen, a fuzzy match is used, two bit errors or less
    if (errs <= MAX_DATA_SYNC_BIT_ERRS) {
        // wxLogMessage(wxT("Found data sync at frame %u, errs: %u"), m_radioSeqNo, errs);
        m_radioSeqNo     = 0U;
        m_slowDataDecoder.sync();
    } else if (m_radioSeqNo == 20U) {
        // wxLogMessage(wxT("Assuming data sync"));
        m_radioSeqNo = 0U;
        m_slowDataDecoder.sync();
    } else {
        m_radioSeqNo++;
        m_slowDataDecoder.addData(data + VOICE_FRAME_LENGTH_BYTES);

        CHeaderData* header = m_slowDataDecoder.getHeaderData();
        if (header == NULL)
            return;

        wxLogMessage(wxT("Radio header from slow data - My: %s/%s  Your: %s  Rpt1: %s  Rpt2: %s  Flags: %02X %02X %02X  BER: 0%%"), 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());

        if (header != NULL) {
            bool res = processRadioHeader(header);
            if (res) {
                // A valid header and is a DV packet, go to normal data relaying
                setRadioState(DSRXS_PROCESS_DATA);
            } else {
                // This is a DD packet or some other problem
                // wxLogMessage(wxT("Invalid header"));
            }
        }
    }
}
void CDStarRepeaterTXRXThread::transmitNetworkHeader(const CHeaderData& header)
{
    wxLogMessage(wxT("Transmitting to - 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());

    bool empty = m_networkQueue[m_readNum]->isEmpty();
    if (!empty) {
        bool headerReady = m_networkQueue[m_readNum]->headerReady();
        if (headerReady) {
            // Transmission has never started, so just purge the queue
            m_networkQueue[m_readNum]->reset();

            m_readNum++;
            if (m_readNum >= NETWORK_QUEUE_COUNT)
                m_readNum = 0U;
        } else {
            // Append an end of stream
            m_networkQueue[m_readNum]->reset();
            m_networkQueue[m_readNum]->addData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES, true);
        }
    }

    m_networkQueue[m_writeNum]->reset();
    m_networkQueue[m_writeNum]->setHeader(new CHeaderData(header));
}
void CDVAPNodeRXThread::receiveRadioHeader()
{
	CHeaderData* header = m_dvap->readHeader();
	if (header == NULL)
		return;

	wxLogMessage(wxT("Header decoded - 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());

	bool res = processRadioHeader(header);
	if (res) {
		// A valid header and is a DV packet
		m_radioSeqNo     = 20U;
		m_ambeFrames     = 0U;
		m_ambeSilence    = 0U;
		m_ambeBits       = 1U;
		m_ambeErrors     = 0U;
		m_lastAMBEBits   = 0U;
		m_lastAMBEErrors = 0U;
	} else {
		// This is a DD packet or some other problem
		// wxLogMessage(wxT("Invalid header"));
	}
}
void CDVToolReaderThread::processHeader(const unsigned char* buffer)
{
	// Tell the GUI about the header, we assume that it's valid
	CHeaderData* header = new CHeaderData(buffer, RADIO_HEADER_LENGTH_BYTES, false);

	wxLogMessage(wxT("Header decoded - 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());

	::wxGetApp().showHeader(header);
}
void CSoundCardRepeaterTXThread::transmitNetworkHeader(CHeaderData& header)
{
	wxLogMessage(wxT("Transmitting to - 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());

	// Send the bit sync, 700 bits in 4 bit chunks
	for (unsigned int i = 0U; i < 175U; i++)
		m_networkBuffer.addData(BIT_SYNC_BITS, BIT_SYNC_LENGTH_BITS);

	// Send the frame sync
	m_networkBuffer.addData(FRAME_SYNC_BITS, FRAME_SYNC_LENGTH_BITS);

	// Send the header
	bool headerBits[FEC_SECTION_LENGTH_BITS];
	CRadioHeaderEncoder encoder(header);
	encoder.getRadioData(headerBits, FEC_SECTION_LENGTH_BITS);
	m_networkBuffer.addData(headerBits, FEC_SECTION_LENGTH_BITS);

	m_networkStarted = false;
	m_networkRun = 0U;
}
bool CDVAPController::writeHeader(const CHeaderData& header)
{
	m_streamId++;

	unsigned char buffer[50U];

	::memcpy(buffer, DVAP_HEADER, DVAP_HEADER_LEN);

	wxUint16 sid = wxUINT16_SWAP_ON_BE(m_streamId);
	::memcpy(buffer + 2U, &sid, sizeof(wxUint16));

	buffer[4U] = 0x80U;
	buffer[5U] = 0U;

	::memset(buffer + 6U, ' ', RADIO_HEADER_LENGTH_BYTES);

	buffer[6U] = header.getFlag1();
	buffer[7U] = header.getFlag2();
	buffer[8U] = header.getFlag3();

	wxString rpt2 = header.getRptCall2();
	for (unsigned int i = 0U; i < rpt2.Len() && i < LONG_CALLSIGN_LENGTH; i++)
		buffer[i + 9U]  = rpt2.GetChar(i);

	wxString rpt1 = header.getRptCall1();
	for (unsigned int i = 0U; i < rpt1.Len() && i < LONG_CALLSIGN_LENGTH; i++)
		buffer[i + 17U] = rpt1.GetChar(i);

	wxString your = header.getYourCall();
	for (unsigned int i = 0U; i < your.Len() && i < LONG_CALLSIGN_LENGTH; i++)
		buffer[i + 25U] = your.GetChar(i);

	wxString my1 = header.getMyCall1();
	for (unsigned int i = 0U; i < my1.Len() && i < LONG_CALLSIGN_LENGTH; i++)
		buffer[i + 33U] = my1.GetChar(i);

	wxString my2 = header.getMyCall2();
	for (unsigned int i = 0U; i < my2.Len() && i < SHORT_CALLSIGN_LENGTH; i++)
		buffer[i + 41U] = my2.GetChar(i);

	CCCITTChecksumReverse cksum;
	cksum.update(buffer + 6U, RADIO_HEADER_LENGTH_BYTES - 2U);
	cksum.result(buffer + 45U);

	m_framePos = 0U;
	m_seq = 0U;

	wxMutexLocker locker(m_mutex);

	unsigned int space = m_txData.freeSpace();
	if (space < 48U) {
		wxLogMessage(wxT("Out of space in the DVAP TX queue"));
		return false;
	}

	unsigned char len = DVAP_HEADER_LEN;
	m_txData.addData(&len, 1U);

	m_txData.addData(buffer, DVAP_HEADER_LEN);

	return true;
}
bool CGMSKModemLibUsb::writeHeader(const CHeaderData& header)
{
	wxASSERT(m_handle != NULL);

	unsigned char myCall1[LONG_CALLSIGN_LENGTH];
	unsigned char myCall2[SHORT_CALLSIGN_LENGTH];
	unsigned char yourCall[LONG_CALLSIGN_LENGTH];
	unsigned char rptCall1[LONG_CALLSIGN_LENGTH];
	unsigned char rptCall2[LONG_CALLSIGN_LENGTH];

	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		myCall1[i] = header.getMyCall1().GetChar(i);
	for (unsigned int i = 0U; i < SHORT_CALLSIGN_LENGTH; i++)
		myCall2[i] = header.getMyCall2().GetChar(i);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		yourCall[i] = header.getYourCall().GetChar(i);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		rptCall1[i] = header.getRptCall1().GetChar(i);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		rptCall2[i] = header.getRptCall2().GetChar(i);

	int ret = ::libusb_control_transfer(m_handle, 0x40, SET_MyCALL2, 0, 0, myCall2, SHORT_CALLSIGN_LENGTH, USB_TIMEOUT);
	if (ret < 0) {
		wxLogMessage(wxT("SET_MyCALL2, err=%d"), ret);
		return false;
	}

	ret = ::libusb_control_transfer(m_handle, 0x40, SET_MyCALL, 0, 0, myCall1, LONG_CALLSIGN_LENGTH,  USB_TIMEOUT);
	if (ret < 0) {
		wxLogMessage(wxT("SET_MyCALL, err=%d"), ret);
		return false;
	}

	ret = ::libusb_control_transfer(m_handle, 0x40, SET_YourCALL, 0, 0, yourCall, LONG_CALLSIGN_LENGTH,  USB_TIMEOUT);
	if (ret < 0) {
		wxLogMessage(wxT("SET_YourCALL, err=%d"), ret);
		return false;
	}

	ret = ::libusb_control_transfer(m_handle, 0x40, SET_RPT1CALL, 0, 0, rptCall1, LONG_CALLSIGN_LENGTH,  USB_TIMEOUT);
	if (ret < 0) {
		wxLogMessage(wxT("SET_RPT1CALL, err=%d"), ret);
		return false;
	}

	ret = ::libusb_control_transfer(m_handle, 0x40, SET_RPT2CALL, 0, 0, rptCall2, LONG_CALLSIGN_LENGTH,  USB_TIMEOUT);
	if (ret < 0) {
		wxLogMessage(wxT("SET_RPT2CALL, err=%d"), ret);
		return false;
	}

	unsigned char flags[3U];
	flags[0U] = header.getFlag1();
	flags[1U] = header.getFlag2();
	flags[2U] = header.getFlag3();

	ret = ::libusb_control_transfer(m_handle, 0x40, SET_FLAGS, 0, 0, flags, 3, USB_TIMEOUT);
	if (ret < 0) {
		wxLogMessage(wxT("SET_FLAGS, err=%d"), ret);
		return false;
	}

	return true;
}
CHeaderData* CSoundCardRepeaterTXRXThread::processSlowData(bool sync)
{
	bool bits[DV_FRAME_LENGTH_BITS];
	m_bitBuffer.getData(bits, DV_FRAME_LENGTH_BITS);

	if (sync) {
		m_slowDataDecoder.sync();
		return NULL;
	}

	unsigned char bytes[DATA_FRAME_LENGTH_BYTES];

	// Convert the bits to bytes
	unsigned int n = 0U;
	for (unsigned int i = 0U; i < DATA_FRAME_LENGTH_BYTES; i++, n += 8U)
		bytes[i] = CUtils::bitsToByteRev(bits + VOICE_FRAME_LENGTH_BITS + n);

	m_slowDataDecoder.addData(bytes);

	CHeaderData* header = m_slowDataDecoder.getHeaderData();
	if (header == NULL)
		return NULL;

	wxLogMessage(wxT("Radio header from slow data - My: %s/%s  Your: %s  Rpt1: %s  Rpt2: %s  Flags: %02X %02X %02X  BER: 0%%"), 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());

	m_headerBER = 0U;

	return header;
}
CHeaderData* CSoundCardRepeaterTXRXThread::processFECHeader()
{
	bool buffer[FEC_SECTION_LENGTH_BITS];
	m_bitBuffer.getData(buffer, FEC_SECTION_LENGTH_BITS);

	CRadioHeaderDecoder decoder(buffer, FEC_SECTION_LENGTH_BITS);

	CHeaderData* header = decoder.getHeaderData();
	if (header == NULL)
		return NULL;

	m_headerBER = decoder.getBER();

	wxLogMessage(wxT("Radio header decoded - My: %s/%s  Your: %s  Rpt1: %s  Rpt2: %s  Flags: %02X %02X %02X  BER: %u%%"), 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(), m_headerBER);

	return header;
}
void CDummyRepeaterThread::transmit()
{
	m_encodeData.clear();
	m_dongle->setMode(DVDMODE_ENCODE);

	// Pause until all the silence data has been processed by the AMBE2020
	for (unsigned int startCount = 30U; startCount > 0U; startCount--) {
		unsigned char frame[DV_FRAME_LENGTH_BYTES];
		unsigned int n = 0U;
		do {
			n += m_encodeData.getData(frame + n, VOICE_FRAME_LENGTH_BYTES - n);

			if (n < VOICE_FRAME_LENGTH_BYTES)
				Sleep(DSTAR_FRAME_TIME_MS / 4UL);
		} while (n < VOICE_FRAME_LENGTH_BYTES);

		serviceNetwork();
		checkController();
	}

	CHeaderData* header = new CHeaderData(m_callsign1, m_callsign2, m_your, m_rpt2, m_rpt1);

	wxLogMessage(wxT("Transmitting to - My: %s/%s  Your: %s  Rpt1: %s  Rpt2: %s"), header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str());

	m_slowDataEncoder.reset();
	m_slowDataEncoder.setHeaderData(*header);

	serviceNetwork();
	checkController();

	if (!m_message.IsEmpty())
		m_slowDataEncoder.setMessageData(m_message);

	m_protocol->writeHeader(*header);
	delete header;

	serviceNetwork();
	checkController();

	m_frameCount = 20U;

	unsigned int endCount = 30U;

	// While transmitting and not exiting
	for (;;) {
		unsigned char frame[DV_FRAME_LENGTH_BYTES];
		unsigned int n = 0U;
		do {
			n += m_encodeData.getData(frame + n, VOICE_FRAME_LENGTH_BYTES - n);

			if (n < VOICE_FRAME_LENGTH_BYTES)
				Sleep(DSTAR_FRAME_TIME_MS / 4UL);
		} while (n < VOICE_FRAME_LENGTH_BYTES);

		serviceNetwork();
		checkController();

		if (m_frameCount == 20U) {
			// Put in the data resync pattern
			::memcpy(frame + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES);
			m_frameCount = 0U;
		} else {
			// Tack the slow data on the end
			m_slowDataEncoder.getData(frame + VOICE_FRAME_LENGTH_BYTES);
			m_frameCount++;
		}

		if (m_transmit != CLIENT_TRANSMIT)
			endCount--;

		// Send the AMBE and slow data frame
		if (endCount == 0U || m_killed) {
			m_protocol->writeData(frame, DV_FRAME_LENGTH_BYTES, 0U, true);
			break;
		} else {
			m_protocol->writeData(frame, DV_FRAME_LENGTH_BYTES, 0U, false);
		}

		serviceNetwork();
		checkController();
	}

	m_dongle->setMode(DVDMODE_IDLE);

	resetReceiver();

	m_transmit = CLIENT_RECEIVE;

	serviceNetwork();
	checkController();
}
bool CGMSKModemWinUSB::writeHeader(const CHeaderData& header)
{
	unsigned char myCall1[LONG_CALLSIGN_LENGTH];
	unsigned char myCall2[SHORT_CALLSIGN_LENGTH];
	unsigned char yourCall[LONG_CALLSIGN_LENGTH];
	unsigned char rptCall1[LONG_CALLSIGN_LENGTH];
	unsigned char rptCall2[LONG_CALLSIGN_LENGTH];

	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		myCall1[i] = header.getMyCall1().GetChar(i);
	for (unsigned int i = 0U; i < SHORT_CALLSIGN_LENGTH; i++)
		myCall2[i] = header.getMyCall2().GetChar(i);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		yourCall[i] = header.getYourCall().GetChar(i);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		rptCall1[i] = header.getRptCall1().GetChar(i);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		rptCall2[i] = header.getRptCall2().GetChar(i);

	int ret = io(SET_MyCALL2, 0x40U, 0U, myCall2, SHORT_CALLSIGN_LENGTH);
	if (ret < 0) {
		wxLogError(wxT("SET_MyCALL2 returned %d"), -ret);
		return false;
	}

	ret = io(SET_MyCALL, 0x40U, 0U, myCall1, LONG_CALLSIGN_LENGTH);
	if (ret < 0) {
		wxLogError(wxT("SET_MyCALL returned %d"), -ret);
		return false;
	}

	ret = io(SET_YourCALL, 0x40U, 0U, yourCall, LONG_CALLSIGN_LENGTH);
	if (ret < 0) {
		wxLogError(wxT("SET_YourCALL returned %d"), -ret);
		return false;
	}

	ret = io(SET_RPT1CALL, 0x40U, 0U, rptCall1, LONG_CALLSIGN_LENGTH);
	if (ret < 0) {
		wxLogError(wxT("SET_RPT1CALL returned %d"), -ret);
		return false;
	}

	ret = io(SET_RPT2CALL, 0x40U, 0U, rptCall2, LONG_CALLSIGN_LENGTH);
	if (ret < 0) {
		wxLogError(wxT("SET_RPT2CALL returned %d"), -ret);
		return false;
	}

	unsigned char flags[3U];
	flags[0U] = header.getFlag1();
	flags[1U] = header.getFlag2();
	flags[2U] = header.getFlag3();

	ret = io(SET_FLAGS, 0x40U, 0U, flags, 3U);
	if (ret < 0) {
		wxLogError(wxT("SET_FLAGS returned %d"), -ret);
		return false;
	}

	return setPTT(true);
}
void CDVRPTRRepeaterRXThread::receiveHeader(unsigned char* data, unsigned int length)
{
	CHeaderData* header = new CHeaderData(data, length, false);

	wxLogMessage(wxT("Radio header decoded - 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());

	bool res = processRadioHeader(header);
	if (res) {
		// A valid header and is a DV packet
		m_radioSeqNo = 20U;
		setRadioState(DSRXS_PROCESS_DATA);
	} else {
		// This is a DD packet or some other problem
		// wxLogMessage(wxT("Invalid header"));
	}
}
bool CGMSKModemLibUsb::writeHeader(const CHeaderData& header)
{
	char myCall1[LONG_CALLSIGN_LENGTH];
	char myCall2[SHORT_CALLSIGN_LENGTH];
	char yourCall[LONG_CALLSIGN_LENGTH];
	char rptCall1[LONG_CALLSIGN_LENGTH];
	char rptCall2[LONG_CALLSIGN_LENGTH];

	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		myCall1[i] = header.getMyCall1().GetChar(i);
	for (unsigned int i = 0U; i < SHORT_CALLSIGN_LENGTH; i++)
		myCall2[i] = header.getMyCall2().GetChar(i);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		yourCall[i] = header.getYourCall().GetChar(i);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		rptCall1[i] = header.getRptCall1().GetChar(i);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		rptCall2[i] = header.getRptCall2().GetChar(i);

	int ret = io(0x40, SET_MyCALL2, 0, 0, myCall2, SHORT_CALLSIGN_LENGTH, USB_TIMEOUT);
	if (ret < 0) {
		wxString errorText(m_usbStrerror(), wxConvLocal);
		wxLogMessage(wxT("SET_MyCALL2, ret: %d, err=%s"), ret, errorText.c_str());
		return false;
	}

	ret = io(0x40, SET_MyCALL, 0, 0, myCall1, LONG_CALLSIGN_LENGTH, USB_TIMEOUT);
	if (ret < 0) {
		wxString errorText(m_usbStrerror(), wxConvLocal);
		wxLogMessage(wxT("SET_MyCALL, ret: %d, err=%s"), ret, errorText.c_str());
		return false;
	}

	ret = io(0x40, SET_YourCALL, 0, 0, yourCall, LONG_CALLSIGN_LENGTH, USB_TIMEOUT);
	if (ret < 0) {
		wxString errorText(m_usbStrerror(), wxConvLocal);
		wxLogMessage(wxT("SET_YourCALL, ret: %d, err=%s"), ret, errorText.c_str());
		return false;
	}

	ret = io(0x40, SET_RPT1CALL, 0, 0, rptCall1, LONG_CALLSIGN_LENGTH, USB_TIMEOUT);
	if (ret < 0) {
		wxString errorText(m_usbStrerror(), wxConvLocal);
		wxLogMessage(wxT("SET_RPT1CALL, ret: %d, err=%s"), ret, errorText.c_str());
		return false;
	}

	ret = io(0x40, SET_RPT2CALL, 0, 0, rptCall2, LONG_CALLSIGN_LENGTH, USB_TIMEOUT);
	if (ret < 0) {
		wxString errorText(m_usbStrerror(), wxConvLocal);
		wxLogMessage(wxT("SET_RPT2CALL, ret: %d, err=%s"), ret, errorText.c_str());
		return false;
	}

	char flags[3U];
	flags[0U] = header.getFlag1();
	flags[1U] = header.getFlag2();
	flags[2U] = header.getFlag3();

	ret = io(0x40, SET_FLAGS, 0, 0, flags, 3, USB_TIMEOUT);
	if (ret < 0) {
		wxString errorText(m_usbStrerror(), wxConvLocal);
		wxLogMessage(wxT("SET_FLAGS, ret: %d, err=%s"), ret, errorText.c_str());
		return false;
	}

	return true;
}
void CStarNetHandler::process(CHeaderData &header)
{
	wxString my   = header.getMyCall1();
	wxString your = header.getYourCall();

	unsigned int id = header.getId();

	CStarNetUser* user = m_users[my];

	// Ensure that this user is in the cache
	CUserData* userData = m_cache->findUser(my);
	if (userData == NULL)
		m_irc->findUser(my);

	if (your.IsSameAs(m_groupCallsign)) {
		// This is a normal message for logging in/relaying
		if (user == NULL) {
			// This is a new user, add them to the list
			if (m_logFile != NULL) {
				time_t timeNow = ::time(NULL);
				struct tm* tm = ::gmtime(&timeNow);

				wxString text;
				text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: Adding %s to StarNet group %s\n"),
					tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
					my.c_str(), m_groupCallsign.c_str());

				m_logFile->Write(text);
				m_logFile->Flush();
			}

			// Start the StarNet group timer if not already running
			if (!m_groupTimer.isRunning())
				m_groupTimer.start();

			user = new CStarNetUser(my, m_userTimeout * 60U);
			m_users[my] = user;

			CStarNetId* tx = new CStarNetId(id, MESSAGE_DELAY, user);
			tx->setLogin();
			m_ids[id] = tx;
		} else {
			user->reset();

			// Check that it isn't a duplicate header
			CStarNetId* tx = m_ids[id];
			if (tx != NULL) {
				delete userData;
				return;
			}

			m_ids[id] = new CStarNetId(id, MESSAGE_DELAY, user);
		}
	} else {
		delete userData;
		userData = NULL;

		// This is a logoff message
		if (user == NULL)				// Not a known user, ignore
			return;

		if (m_logFile != NULL) {
			time_t timeNow = ::time(NULL);
			struct tm* tm = ::gmtime(&timeNow);

			wxString text;
			text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: Removing %s from StarNet group %s, logged off\n"),
				tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
				user->getCallsign().c_str(), m_groupCallsign.c_str());

			m_logFile->Write(text);
			m_logFile->Flush();
		}

		// Remove the user from the user list
		m_users.erase(my);

		CStarNetId* tx = new CStarNetId(id, MESSAGE_DELAY, user);
		tx->setLogoff();
		m_ids[id] = tx;

		return;
	}

	m_groupTimer.reset();

	if (m_id != 0x00U) {
		delete userData;
		return;
	}

	m_id = id;

	// Change the Your callsign to CQCQCQ
	header.setCQCQCQ();

	header.setFlag1(0x00);
	header.setFlag2(0x00);
	header.setFlag3(0x00);

#if defined(DEXTRA_LINK)
	header.setRepeaters(m_linkGateway, m_linkReflector);
	CDExtraHandler::writeHeader(m_repeater, header, DIR_OUTGOING);
#endif
#if defined(DCS_LINK)
	header.setRepeaters(m_linkGateway, m_linkReflector);
	CDCSHandler::writeHeader(m_repeater, header, DIR_OUTGOING);
#endif

	// Get the home repeater of the user
	wxString exclude;
	if (userData != NULL) {
		exclude = userData->getRepeater();
		delete userData;
		userData = NULL;
	}

	// Build new repeater list
	for (CStarNetUsersHashMap::const_iterator it = m_users.begin(); it != m_users.end(); ++it) {
		CStarNetUser* user = it->second;
		if (user != NULL) {
			// Find the user in the cache
			CUserData* userData = m_cache->findUser(user->getCallsign());

			if (userData != NULL) {
				// Check for the excluded repeater
				if (!userData->getRepeater().IsSameAs(exclude)) {
					// Find the users repeater in the repeater list, add it otherwise
					CStarNetRepeater* repeater = m_repeaters[userData->getRepeater()];
					if (repeater == NULL) {
						// Add a new repeater entry
						repeater = new CStarNetRepeater;
						repeater->m_destination = wxT("/") + userData->getRepeater().Left(6U) + userData->getRepeater().Right(1U);
						repeater->m_repeater    = userData->getRepeater();
						repeater->m_gateway     = userData->getGateway();
						repeater->m_address     = userData->getAddress();
						repeater->m_local       = CRepeaterHandler::findDVRepeater(userData->getRepeater());
						m_repeaters[userData->getRepeater()] = repeater;
					}
				}

				delete userData;
				userData = NULL;
			}
		}
	}

	switch (m_callsignSwitch) {
		case SCS_GROUP_CALLSIGN:
			// Change the My Callsign 1 to be that of the StarNet group
			header.setMyCall1(m_groupCallsign);
			header.setMyCall2(wxT("SNET"));
			break;
		case SCS_USER_CALLSIGN:
			// Change the My Callsign 2 to be that of the StarNet group
			header.setMyCall1(my);
			header.setMyCall2(m_shortCallsign);
			break;
		default:
			break;
	}

	sendToRepeaters(header);

	if (m_txMsgSwitch)
		sendFromText(my);
}
Example #15
0
CRadioHeaderEncoder::CRadioHeaderEncoder(const CHeaderData& header) :
m_header(NULL)
{
	m_header = new bool[FEC_SECTION_LENGTH_BITS];

	bool* buffer1 = new bool[700U];
	bool* buffer2 = new bool[700U];

	// Clear everything
	::memset(buffer1, 0x00, 700U * sizeof(bool));

	// Flag 1
	unsigned char flag1 = header.getFlag1();
	buffer1[0]  = (flag1 & 0x80U) == 0x80U; buffer1[1]  = (flag1 & 0x40U) == 0x40U;
	buffer1[2]  = (flag1 & 0x20U) == 0x20U; buffer1[3]  = (flag1 & 0x10U) == 0x10U;
	buffer1[4]  = (flag1 & 0x08U) == 0x08U; buffer1[5]  = (flag1 & 0x04U) == 0x04U;
	buffer1[6]  = (flag1 & 0x02U) == 0x02U; buffer1[7]  = (flag1 & 0x01U) == 0x01U;

	// Flag 2
	unsigned char flag2 = header.getFlag2();
	buffer1[8]  = (flag2 & 0x80U) == 0x80U; buffer1[9]  = (flag2 & 0x40U) == 0x40U;
	buffer1[10] = (flag2 & 0x20U) == 0x20U; buffer1[11] = (flag2 & 0x10U) == 0x10U;
	buffer1[12] = (flag2 & 0x08U) == 0x08U; buffer1[13] = (flag2 & 0x04U) == 0x04U;
	buffer1[14] = (flag2 & 0x02U) == 0x02U; buffer1[15] = (flag2 & 0x01U) == 0x01U;

	// Flag 3
	unsigned char flag3 = header.getFlag3();
	buffer1[16] = (flag3 & 0x80U) == 0x80U; buffer1[17] = (flag3 & 0x40U) == 0x40U;
	buffer1[18] = (flag3 & 0x20U) == 0x20U; buffer1[19] = (flag3 & 0x10U) == 0x10U;
	buffer1[20] = (flag3 & 0x08U) == 0x08U; buffer1[21] = (flag3 & 0x04U) == 0x04U;
	buffer1[22] = (flag3 & 0x02U) == 0x02U; buffer1[23] = (flag3 & 0x01U) == 0x01U;

	unsigned int n = 24U;

	stringToBits(header.getRptCall2(), buffer1 + n, LONG_CALLSIGN_LENGTH);
	n += LONG_CALLSIGN_LENGTH * 8U;

	stringToBits(header.getRptCall1(), buffer1 + n, LONG_CALLSIGN_LENGTH);
	n += LONG_CALLSIGN_LENGTH * 8U;

	stringToBits(header.getYourCall(), buffer1 + n, LONG_CALLSIGN_LENGTH);
	n += LONG_CALLSIGN_LENGTH * 8U;

	stringToBits(header.getMyCall1(),  buffer1 + n, LONG_CALLSIGN_LENGTH);
	n += LONG_CALLSIGN_LENGTH * 8U;

	stringToBits(header.getMyCall2(),  buffer1 + n, SHORT_CALLSIGN_LENGTH);
	n += SHORT_CALLSIGN_LENGTH * 8U;

	CCCITTChecksumReverse cksum;
	for (unsigned int i = 0U; i < n; i += 8U)
		cksum.update(buffer1 + i);
	cksum.result(buffer1 + n);

	// CUtils::dump(wxT("TX Raw Data"), buffer1, n + 16U);

	unsigned int length;
	CDStarFECEncoder fec;
	fec.encode(buffer1, buffer2, RADIO_HEADER_LENGTH_BITS, length);

	// CUtils::dump(wxT("TX After FEC"), buffer2, FEC_SECTION_LENGTH_BITS);

	CDStarInterleaver interleaver;
	interleaver.interleave(buffer2, m_header, FEC_SECTION_LENGTH_BITS);

	// CUtils::dump(wxT("TX After Interleaver"), m_header, FEC_SECTION_LENGTH_BITS);

	CDStarScrambler scrambler;
	scrambler.process(m_header, FEC_SECTION_LENGTH_BITS);

	// CUtils::dump(wxT("TX After Scrambler"), m_header, FEC_SECTION_LENGTH_BITS);

	delete[] buffer1;
	delete[] buffer2;
}
bool CDExtraProtocolHandler::writeHeader(const CHeaderData& header)
{
	wxASSERT(m_socket != NULL);

	// Create a random id for this transmission
	m_outId = (::rand() % 65535U) + 1U;

	unsigned char buffer[56U];

	buffer[0]  = 'D';
	buffer[1]  = 'S';
	buffer[2]  = 'V';
	buffer[3]  = 'T';

	buffer[4]  = 0x10;
	buffer[5]  = 0x00;
	buffer[6]  = 0x00;
	buffer[7]  = 0x00;
	buffer[8]  = 0x20;
	buffer[9]  = 0x00;
	buffer[10] = 0x01;

	buffer[11] = 0x00;				// Band

	buffer[12] = m_outId % 256U;	// Unique session id
	buffer[13] = m_outId / 256U;

	buffer[14] = 0x80;

	buffer[15] = 0x00;				// Flags 1, 2 and 3
	buffer[16] = 0x00;
	buffer[17] = 0x00;

	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		buffer[18 + i] = header.getRptCall1().GetChar(i);

	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		buffer[26 + i] = header.getRptCall2().GetChar(i);

	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		buffer[34 + i] = header.getYourCall().GetChar(i);

	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH; i++)
		buffer[42 + i] = header.getMyCall1().GetChar(i);

	for (unsigned int i = 0U; i < SHORT_CALLSIGN_LENGTH; i++)
		buffer[50 + i] = header.getMyCall2().GetChar(i);

	// A dummy checksum
	buffer[54] = 0xFF;
	buffer[55] = 0xFF;

	m_outSeq = 0U;

#if defined(DUMP_TX)
	CUtils::dump(wxT("Sending Header"), buffer, 56U);
	return true;
#else
	for (unsigned int i = 0U; i < 5U; i++) {
		bool res = m_socket->write(buffer, 56U);
		if (!res)
			return false;
	}

	return true;
#endif
}