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)
		return false;

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

	m_txData.addData(buffer, DVAP_HEADER_LEN);

	return true;
}
bool CGatewayProtocolHandler::writeHeader(const unsigned char* header, wxUint16 id, const in_addr& address, unsigned int port)
{
	unsigned char buffer[50U];

	buffer[0] = 'D';
	buffer[1] = 'S';
	buffer[2] = 'R';
	buffer[3] = 'P';

	buffer[4] = 0x20U;

	buffer[5] = id / 256U;	// Unique session id
	buffer[6] = id % 256U;

	buffer[7] = 0U;

	::memcpy(buffer + 8U, header + 0U, RADIO_HEADER_LENGTH_BYTES - 2U);

	// Get the checksum for the header
	CCCITTChecksumReverse csum;
	csum.update(buffer + 8U, RADIO_HEADER_LENGTH_BYTES - 2U);
	csum.result(buffer + 8U + RADIO_HEADER_LENGTH_BYTES - 2U);

#if defined(DUMP_TX)
	CUtils::dump(wxT("Sending Header"), buffer, 49U);
#endif

	for (unsigned int i = 0U; i < 4U; i++) {
		bool ret = m_socket.write(buffer, 49U, address, port);
		if (!ret)
			return false;
	}

	return true;
}
bool CRepeaterProtocolHandler::writeHeader(const CHeaderData& header)
{
	unsigned char buffer[50U];

	buffer[0] = 'D';
	buffer[1] = 'S';
	buffer[2] = 'R';
	buffer[3] = 'P';

	buffer[4] = 0x20U;

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

	buffer[5] = m_outId / 256U;	// Unique session id
	buffer[6] = m_outId % 256U;

	buffer[7] = 0U;

	buffer[8]  = header.getFlag1();
	buffer[9]  = header.getFlag2();
	buffer[10] = header.getFlag3();

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

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

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

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

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

	// Get the checksum for the header
	CCCITTChecksumReverse csum;
	csum.update(buffer + 8U, 4U * LONG_CALLSIGN_LENGTH + SHORT_CALLSIGN_LENGTH + 3U);
	csum.result(buffer + 47U);

	m_outSeq = 0U;

#if defined(DUMP_TX)
	CUtils::dump(wxT("Sending Header"), buffer, 49U);
	return true;
#else
	for (unsigned int i = 0U; i < 2U; i++) {
		bool ret = m_socket.write(buffer, 49U);
		if (!ret)
			return false;
	}

	return true;
#endif
}
unsigned int CSplitRepeaterHeaderData::getData(unsigned char *data, unsigned int length) const
{
	wxASSERT(data != NULL);
	wxASSERT(length >= RADIO_HEADER_LENGTH_BYTES);

	data[0] = m_flag1;				// Flags 1, 2, and 3
	data[1] = m_flag2;
	data[2] = m_flag3;

	::memcpy(data + 3U,  m_rptCall2, LONG_CALLSIGN_LENGTH);
	::memcpy(data + 11U, m_rptCall1, LONG_CALLSIGN_LENGTH);
	::memcpy(data + 19U, m_yourCall, LONG_CALLSIGN_LENGTH);
	::memcpy(data + 27U, m_myCall1,  LONG_CALLSIGN_LENGTH);
	::memcpy(data + 35U, m_myCall2,  SHORT_CALLSIGN_LENGTH);

	CCCITTChecksumReverse csum;
	csum.update(data, RADIO_HEADER_LENGTH_BYTES - 2U);
	csum.result(data + RADIO_HEADER_LENGTH_BYTES - 2U);

	return RADIO_HEADER_LENGTH_BYTES;
}
unsigned int CSplitRepeaterHeaderData::getRepeaterData(unsigned char *data, unsigned int length, bool check) const
{
	wxASSERT(data != NULL);
	wxASSERT(length >= 49U);

	data[0] = 'D';
	data[1] = 'S';
	data[2] = 'R';
	data[3] = 'P';

	data[4] = 0x20U;

	data[5] = m_id / 256U;			// Unique session id
	data[6] = m_id % 256U;

	data[7] = 0U;

	data[8]  = m_flag1;				// Flags 1, 2, and 3
	data[9]  = m_flag2;
	data[10] = m_flag3;

	::memcpy(data + 11U, m_rptCall2, LONG_CALLSIGN_LENGTH);
	::memcpy(data + 19U, m_rptCall1, LONG_CALLSIGN_LENGTH);
	::memcpy(data + 27U, m_yourCall, LONG_CALLSIGN_LENGTH);
	::memcpy(data + 35U, m_myCall1,  LONG_CALLSIGN_LENGTH);
	::memcpy(data + 43U, m_myCall2,  SHORT_CALLSIGN_LENGTH);

	if (check) {
		CCCITTChecksumReverse csum;
		csum.update(data + 8U, 4U * LONG_CALLSIGN_LENGTH + SHORT_CALLSIGN_LENGTH + 3U);
		csum.result(data + 47U);
	} else {
		data[47] = 0xFF;
		data[48] = 0xFF;
	}

	return 49U;
}
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;
}