Пример #1
0
void CDMRSlot::clock(unsigned int ms)
{
	m_timeoutTimer.clock(ms);

	m_playoutTimer.clock(ms);
	if (m_playoutTimer.isRunning() && m_playoutTimer.hasExpired()) {
		m_playoutTimer.stop();

		while (!m_networkQueue.isEmpty()) {
			unsigned char len = 0U;
			m_networkQueue.getData(&len, 1U);

			unsigned char buffer[100U];
			m_networkQueue.getData(buffer, len);

			m_radioQueue.addData(&len, 1U);
			m_radioQueue.addData(buffer, len);
		}
	}

	if (m_state == SS_RELAYING_NETWORK) {
		m_networkWatchdog.clock(ms);

		if (m_networkWatchdog.hasExpired()) {
			LogMessage("DMR Slot %u, network watchdog has expired", m_slotNo);
			writeEndOfTransmission();
#if defined(DUMP_DMR)
			closeFile();
#endif
		}
	}
}
Пример #2
0
void CDStarControl::clock(unsigned int ms)
{
	if (m_network != NULL)
		writeNetwork();

	m_ackTimer.clock(ms);
	if (m_ackTimer.isRunning() && m_ackTimer.hasExpired()) {
		sendAck();
		m_ackTimer.stop();
	}

	m_holdoffTimer.clock(ms);
	if (m_holdoffTimer.isRunning() && m_holdoffTimer.hasExpired())
		m_holdoffTimer.stop();

	m_timeoutTimer.clock(ms);

	if (m_state == RS_RELAYING_NETWORK_AUDIO) {
		m_networkWatchdog.clock(ms);

		if (m_networkWatchdog.hasExpired()) {
			// We're received the header haven't we?
			m_frames += 1U;
			if (m_bits == 0U) m_bits = 1U;
			LogMessage("D-Star, network watchdog has expired, %.1f seconds,  %u%% packet loss, BER: %.1f%%", float(m_frames) / 50.0F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits));
			m_timeoutTimer.stop();
			writeEndOfTransmission();
#if defined(DUMP_DSTAR)
			closeFile();
#endif
		}
	}

	if (m_state == RS_RELAYING_NETWORK_AUDIO) {
		m_packetTimer.clock(ms);

		if (m_packetTimer.isRunning() && m_packetTimer.hasExpired()) {
			unsigned int frames = m_elapsed.elapsed() / DSTAR_FRAME_TIME;

			if (frames > m_frames) {
				unsigned int count = frames - m_frames;
				if (count > 3U) {
					LogMessage("D-Star, lost audio for 300ms filling in, %u %u", frames, m_frames);
					insertSilence(count - 1U);
				}
			}

			m_packetTimer.start();
		}
	}
}
Пример #3
0
void CDMRSlot::clock(unsigned int ms)
{
	m_timeoutTimer.clock(ms);

	if (m_state == RS_RELAYING_NETWORK_AUDIO || m_state == RS_RELAYING_NETWORK_DATA) {
		m_networkWatchdog.clock(ms);

		if (m_networkWatchdog.hasExpired()) {
			// We've received the voice header haven't we?
			m_frames += 1U;
			if (m_state == RS_RELAYING_NETWORK_AUDIO)
				LogMessage("DMR Slot %u, network watchdog has expired, %u%% packet loss, BER: %u%%", m_slotNo, (m_lost * 100U) / m_frames, (m_errs * 100U) / m_bits);
			else
				LogMessage("DMR Slot %u, network watchdog has expired", m_slotNo);
			writeEndOfTransmission();
#if defined(DUMP_DMR)
			closeFile();
#endif
		}
	}

	if (m_state == RS_RELAYING_NETWORK_AUDIO) {
		m_packetTimer.clock(ms);

		if (m_packetTimer.hasExpired()) {
			unsigned int frames = m_elapsed.elapsed() / DMR_SLOT_TIME;

			if (frames > m_frames) {
				unsigned int count = frames - m_frames;
				if (count > 3U)
					insertSilence(m_seqNo + count - 1U);
			}

			m_packetTimer.start();
		}
	}
}
Пример #4
0
void CDMRSlot::writeModem(unsigned char *data)
{
	if (data[0U] == TAG_LOST && m_state == SS_RELAYING_RF) {
		LogMessage("DMR Slot %u, transmission lost", m_slotNo);
		writeEndOfTransmission();
		return;
	}

	if (data[0U] == TAG_LOST && m_state == SS_LATE_ENTRY) {
		m_state = SS_LISTENING;
		return;
	}

	if (m_state == SS_RELAYING_NETWORK)
		return;

	bool dataSync  = (data[1U] & DMR_SYNC_DATA)  == DMR_SYNC_DATA;
	bool audioSync = (data[1U] & DMR_SYNC_AUDIO) == DMR_SYNC_AUDIO;

	if (dataSync) {
		CSlotType slotType;
		slotType.putData(data + 2U);

		unsigned char colorCode = slotType.getColorCode();
		unsigned char dataType  = slotType.getDataType();

		if (colorCode != m_colorCode)
			return;

		if (dataType == DT_VOICE_LC_HEADER) {
			if (m_state != SS_RELAYING_RF) {
				CFullLC fullLC;
				m_lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
				if (m_lc == NULL) {
					LogMessage("DMR Slot %u: unable to decode the LC", m_slotNo);
					return;
				}

				// Regenerate the LC
				fullLC.encode(*m_lc, data + 2U, DT_VOICE_LC_HEADER);

				// Regenerate the Slot Type
				slotType.getData(data + 2U);

				// Convert the Data Sync to be from the BS
				CDMRSync sync;
				sync.addSync(data + 2U, DST_BS_DATA);

				data[0U] = TAG_DATA;
				data[1U] = 0x00U;
				m_n = 0U;

				m_networkWatchdog.stop();
				m_timeoutTimer.start();

				m_seqNo = 0U;

				for (unsigned i = 0U; i < 3U; i++) {
					writeNetwork(data, DT_VOICE_LC_HEADER);
					writeRadioQueue(data);
				}

				m_state = SS_RELAYING_RF;
				setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());

				m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());

				LogMessage("DMR Slot %u, received RF header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
			}
		} else if (dataType == DT_VOICE_PI_HEADER) {
			if (m_state == SS_RELAYING_RF) {
				// Regenerate the Slot Type
				slotType.getData(data + 2U);

				// Convert the Data Sync to be from the BS
				CDMRSync sync;
				sync.addSync(data + 2U, DST_BS_DATA);

				data[0U] = TAG_DATA;
				data[1U] = 0x00U;
				m_n = 0U;

				writeNetwork(data, DT_VOICE_PI_HEADER);
				writeRadioQueue(data);

				LogMessage("DMR Slot %u, received PI header", m_slotNo);
			} else {
				// Should save the PI header for after we have a valid LC
			}
		} else {
			// Ignore wakeup CSBKs
			if (dataType == DT_CSBK) {
				CCSBK csbk(data + 2U);
				CSBKO csbko = csbk.getCSBKO();
				if (csbko == CSBKO_BSDWNACT)
					return;
			}

			if (m_state == SS_RELAYING_RF) {
				unsigned char end[DMR_FRAME_LENGTH_BYTES + 2U];

				// Generate the LC
				CFullLC fullLC;
				fullLC.encode(*m_lc, end + 2U, DT_TERMINATOR_WITH_LC);

				// Generate the Slot Type
				CSlotType slotType;
				slotType.setColorCode(m_colorCode);
				slotType.setDataType(DT_TERMINATOR_WITH_LC);
				slotType.getData(end + 2U);

				// Set the Data Sync to be from the BS
				CDMRSync sync;
				sync.addSync(end + 2U, DST_BS_DATA);

				end[0U] = TAG_EOT;
				end[1U] = 0x00U;

				writeNetwork(end, DT_TERMINATOR_WITH_LC);
				writeRadioQueue(end);

				LogMessage("DMR Slot %u, received RF end of transmission", m_slotNo);

				// 480ms of idle to space things out
				for (unsigned int i = 0U; i < 8U; i++)
					writeRadioQueue(m_idle);

				writeEndOfTransmission();

				if (dataType == DT_TERMINATOR_WITH_LC)
					return;
			}

			// Regenerate the Slot Type
			slotType.getData(data + 2U);

			// Convert the Data Sync to be from the BS
			CDMRSync sync;
			sync.addSync(data + 2U, DST_BS_DATA);

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;

			writeNetwork(data, dataType);
			writeRadioQueue(data);
		}
	} else if (audioSync) {
		if (m_state == SS_RELAYING_RF) {
			// Convert the Audio Sync to be from the BS
			CDMRSync sync;
			sync.addSync(data + 2U, DST_BS_AUDIO);

			unsigned char fid = m_lc->getFID();
			if (fid == FID_ETSI || fid == FID_DMRA)
				; // AMBE FEC

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;
			m_n = 0U;

			writeRadioQueue(data);
			writeNetwork(data, DT_VOICE_SYNC);
		} else if (m_state == SS_LISTENING) {
			m_state = SS_LATE_ENTRY;
		}
	} else {
		if (m_state == SS_RELAYING_RF) {
			// Regenerate the EMB
			CEMB emb;
			emb.putData(data + 2U);
			emb.setColorCode(m_colorCode);
			emb.getData(data + 2U);

			unsigned char fid = m_lc->getFID();
			if (fid == FID_ETSI || fid == FID_DMRA)
				; // AMBE FEC

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;
			m_n++;

			writeRadioQueue(data);
			writeNetwork(data, DT_VOICE);
		} else if (m_state == SS_LATE_ENTRY) {
			// If we haven't received an LC yet, then be strict on the color code
			CEMB emb;
			emb.putData(data + 2U);
			unsigned char colorCode = emb.getColorCode();
			if (colorCode != m_colorCode)
				return;

			m_lc = m_embeddedLC.addData(data + 2U, emb.getLCSS());
			if (m_lc != NULL) {
				// Create a dummy start frame to replace the received frame
				unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U];

				CDMRSync sync;
				sync.addSync(start + 2U, DST_BS_DATA);

				CFullLC fullLC;
				fullLC.encode(*m_lc, start + 2U, DT_VOICE_LC_HEADER);

				CSlotType slotType;
				slotType.setColorCode(m_colorCode);
				slotType.setDataType(DT_VOICE_LC_HEADER);
				slotType.getData(start + 2U);

				start[0U] = TAG_DATA;
				start[1U] = 0x00U;
				m_n = 0U;

				m_networkWatchdog.stop();
				m_timeoutTimer.start();

				m_seqNo = 0U;

				for (unsigned int i = 0U; i < 3U; i++) {
					writeNetwork(start, DT_VOICE_LC_HEADER);
					writeRadioQueue(start);
				}

				// Send the original audio frame out
				unsigned char fid = m_lc->getFID();
				if (fid == FID_ETSI || fid == FID_DMRA)
					; // AMBE FEC

				data[0U] = TAG_DATA;
				data[1U] = 0x00U;
				m_n++;

				writeRadioQueue(data);
				writeNetwork(data, DT_VOICE);

				m_state = SS_RELAYING_RF;

				setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());

				m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());

				LogMessage("DMR Slot %u, received RF late entry from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
			}
		}
	}
}
Пример #5
0
void CDMRSlot::writeNetwork(const CDMRData& dmrData)
{
	if (m_state == SS_RELAYING_RF || m_state == SS_LATE_ENTRY)
		return;

	m_networkWatchdog.start();

	unsigned char dataType = dmrData.getDataType();

	unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U];
	dmrData.getData(data + 2U);

	if (dataType == DT_VOICE_LC_HEADER) {
		if (m_state != SS_RELAYING_NETWORK) {
			CFullLC fullLC;
			m_lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
			if (m_lc == NULL) {
				LogMessage("DMR Slot %u, bad LC received from the network", m_slotNo);
				return;
			}

			// Regenerate the LC
			fullLC.encode(*m_lc, data + 2U, DT_VOICE_LC_HEADER);

			// Regenerate the Slot Type
			CSlotType slotType;
			slotType.setColorCode(m_colorCode);
			slotType.setDataType(DT_VOICE_LC_HEADER);
			slotType.getData(data + 2U);

			// Convert the Data Sync to be from the BS
			CDMRSync sync;
			sync.addSync(data + 2U, DST_BS_DATA);

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;

			m_playoutTimer.start();
			m_timeoutTimer.start();

			for (unsigned int i = 0U; i < 3U; i++)
				writeNetworkQueue(data);

			m_state = SS_RELAYING_NETWORK;

			setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());

			m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());

#if defined(DUMP_DMR)
			openFile();
			writeFile(data);
#endif
			LogMessage("DMR Slot %u, received network header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
		}
	} else if (dataType == DT_VOICE_PI_HEADER) {
		if (m_state != SS_RELAYING_NETWORK)
			return;

		// Regenerate the Slot Type
		CSlotType slotType;
		slotType.setColorCode(m_colorCode);
		slotType.setDataType(DT_VOICE_PI_HEADER);
		slotType.getData(data + 2U);

		// Convert the Data Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_DATA);

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		writeNetworkQueue(data);

#if defined(DUMP_DMR)
		writeFile(data);
#endif
	} else if (dataType == DT_TERMINATOR_WITH_LC) {
		if (m_state != SS_RELAYING_NETWORK)
			return;

		// Regenerate the LC
		CFullLC fullLC;
		fullLC.encode(*m_lc, data + 2U, DT_TERMINATOR_WITH_LC);

		// Regenerate the Slot Type
		CSlotType slotType;
		slotType.setColorCode(m_colorCode);
		slotType.setDataType(DT_TERMINATOR_WITH_LC);
		slotType.getData(data + 2U);

		// Convert the Data Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_DATA);

		data[0U] = TAG_EOT;
		data[1U] = 0x00U;

		writeNetworkQueue(data);
		writeEndOfTransmission();

#if defined(DUMP_DMR)
		writeFile(data);
		closeFile();
#endif
		LogMessage("DMR Slot %u, received network end of transmission", m_slotNo);
	} else if (dataType == DT_VOICE_SYNC) {
		if (m_state != SS_RELAYING_NETWORK)
			return;

		// Convert the Audio Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_AUDIO);

		unsigned char fid = m_lc->getFID();
		if (fid == FID_ETSI || fid == FID_DMRA)
			; // AMBE FEC

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		writeNetworkQueue(data);

#if defined(DUMP_DMR)
		writeFile(data);
#endif
	} else if (dataType == DT_VOICE) {
		if (m_state != SS_RELAYING_NETWORK)
			return;

		unsigned char fid = m_lc->getFID();
		if (fid == FID_ETSI || fid == FID_DMRA)
			; // AMBE FEC

		// Change the color code in the EMB
		CEMB emb;
		emb.putData(data + 2U);
		emb.setColorCode(m_colorCode);
		emb.getData(data + 2U);

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		writeNetworkQueue(data);

#if defined(DUMP_DMR)
		writeFile(data);
#endif
	} else {
		if (m_state != SS_RELAYING_NETWORK)
			return;

		// Change the Color Code of the Slot Type
		CSlotType slotType;
		slotType.putData(data + 2U);
		slotType.setColorCode(m_colorCode);
		slotType.getData(data + 2U);

		// Convert the Data Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_DATA);

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		writeNetworkQueue(data);

#if defined(DUMP_DMR)
		writeFile(data);
#endif
	}
}
Пример #6
0
bool CDStarControl::writeModem(unsigned char *data)
{
	unsigned char type = data[0U];

	if (type == TAG_LOST && m_state == RS_RELAYING_RF_AUDIO) {
		if (m_bits == 0U) m_bits = 1U;
		LogMessage("D-Star, transmission lost, %.1f seconds, BER: %.1f%%", float(m_frames) / 50.0F, float(m_errs * 100U) / float(m_bits));
		m_ackTimer.start();
		writeEndOfTransmission();
		return false;
	}

	if (type == TAG_LOST) {
		if (m_state == RS_LATE_ENTRY)
			m_state = RS_LISTENING;
		return false;
	}

	if (type == TAG_HEADER) {
		CDStarHeader header(data + 1U);

		// Is this a transmission destined for a repeater?
		if (!header.isRepeater()) {
			LogMessage("D-Star, non repeater RF header received");
			return false;
		}

		unsigned char callsign[DSTAR_LONG_CALLSIGN_LENGTH];
		header.getRPTCall1(callsign);

		// Is it for us?
		if (::memcmp(callsign, m_callsign, DSTAR_LONG_CALLSIGN_LENGTH) != 0) {
			LogMessage("D-Star, received RF header for wrong repeater - %8.8s", callsign);
			return false;
		}

		unsigned char gateway[DSTAR_LONG_CALLSIGN_LENGTH];
		header.getRPTCall2(gateway);

		unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH];
		header.getMyCall1(my1);

		unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH];
		header.getMyCall2(my2);

		unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
		header.getYourCall(your);

		m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0;

		if (m_state == RS_LISTENING) {
			// Only start the timeout if not already running
			if (!m_timeoutTimer.isRunning()) {
				m_timeoutTimer.start();
				m_bits = 1U;
				m_errs = 0U;
			}

			m_header = header;

			m_networkWatchdog.stop();
			m_holdoffTimer.stop();
			m_ackTimer.stop();

			m_frames = 1U;
			m_lost = 0U;

			m_n = 0U;

			if (m_duplex) {
				// Modify the header
				header.setRepeater(false);
				header.setRPTCall1(m_callsign);
				header.setRPTCall2(m_callsign);
				header.get(data + 1U);

				writeQueueHeader(data);
			}

			if (m_net) {
				// Modify the header
				header.setRepeater(false);
				header.setRPTCall1(m_callsign);
				header.setRPTCall2(m_gateway);
				header.get(data + 1U);

				for (unsigned i = 0U; i < 3U; i++)
					writeNetworkHeader(data, false);
			}

			m_state = RS_RELAYING_RF_AUDIO;

			m_display->writeDStar(std::string((char*)my1, 8U), std::string((char*)my2, 4U));

			LogMessage("D-Star, received RF header from %8.8s/%4.4s to %8.8s", my1, my2, your);
		} else if (m_state == RS_RELAYING_NETWORK_AUDIO) {
			if (m_net) {
				for (unsigned i = 0U; i < 3U; i++)
					writeNetworkHeader(data, true);
			}

			LogMessage("D-Star, received RF busy header from %8.8s/%4.4s to %8.8s", my1, my2, your);

			return false;
		}
	} else if (type == TAG_EOT) {
		if (m_state == RS_RELAYING_RF_AUDIO) {
			if (m_net) {
				for (unsigned int i = 0U; i < 2U; i++)
					writeNetworkData(DSTAR_END_PATTERN_BYTES, 0U, true, false);
			}

			if (m_duplex) {
				for (unsigned int i = 0U; i < 3U; i++)
					writeQueueData(DSTAR_END_PATTERN_BYTES);
			}

			m_ackTimer.start();

			if (m_bits == 0U) m_bits = 1U;
			LogMessage("D-Star, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_frames) / 50.0F, float(m_errs * 100U) / float(m_bits));

			writeEndOfTransmission();
		} else if (m_state == RS_RELAYING_NETWORK_AUDIO) {
			if (m_net) {
				for (unsigned int i = 0U; i < 2U; i++)
					writeNetworkData(DSTAR_END_PATTERN_BYTES, 0U, true, true);
			}
		}

		return false;
	} else if (type == TAG_DATA) {
		if (m_state == RS_LISTENING) {
			// The sync is regenerated by the modem so can do exact match
			if (::memcmp(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES) == 0) {
				m_slowData.start();
				m_state = RS_LATE_ENTRY;
			}

			return false;
		} else if (m_state == RS_RELAYING_RF_AUDIO) {
			unsigned int errors = m_fec.regenerateDStar(data + 1U);
			m_errs += errors;
			m_bits += 48U;

			m_frames++;

			// The sync is regenerated by the modem so can do exact match
			if (::memcmp(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES) == 0)
				m_n = 0U;

			// Regenerate the sync
			if (m_n == 0U)
				::memcpy(data + DSTAR_VOICE_FRAME_LENGTH_BYTES + 1U, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES);

			m_n = (m_n + 1U) % 21U;

			if (m_net)
				writeNetworkData(data, errors, false, false);

			if (m_duplex) {
				blankDTMF(data + 1U);
				writeQueueData(data);
			}
		} else if (m_state == RS_RELAYING_NETWORK_AUDIO) {
			m_fec.regenerateDStar(data + 1U);

			if (m_net)
				writeNetworkData(data, 0U, false, true);

			return false;
		} else if (m_state == RS_LATE_ENTRY) {
			// The sync is regenerated by the modem so can do exact match
			if (::memcmp(data + 1U + DSTAR_VOICE_FRAME_LENGTH_BYTES, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES) == 0) {
				m_slowData.reset();
				return false;
			}

			CDStarHeader* header = m_slowData.add(data + 1U);
			if (header == NULL)
				return false;

			// Is this a transmission destined for a repeater?
			if (!header->isRepeater()) {
				LogMessage("D-Star, non repeater RF late entry header received");
				return false;
			}

			unsigned char callsign[DSTAR_LONG_CALLSIGN_LENGTH];
			header->getRPTCall1(callsign);

			// Is it for us?
			if (::memcmp(callsign, m_callsign, DSTAR_LONG_CALLSIGN_LENGTH) != 0) {
				LogMessage("D-Star, received RF header for wrong repeater - %8.8s", callsign);
				return false;
			}

			unsigned char gateway[DSTAR_LONG_CALLSIGN_LENGTH];
			header->getRPTCall2(gateway);

			unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH];
			header->getMyCall1(my1);

			unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH];
			header->getMyCall2(my2);

			unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
			header->getYourCall(your);

			m_net = ::memcmp(gateway, m_gateway, DSTAR_LONG_CALLSIGN_LENGTH) == 0;

			// Only reset the timeout if the timeout is not running
			if (!m_timeoutTimer.isRunning()) {
				m_timeoutTimer.start();
				m_bits = 1U;
				m_errs = 0U;
			}

			// Create a dummy start frame to replace the received frame
			m_networkWatchdog.stop();
			m_ackTimer.stop();

			m_header = *header;

			m_frames = 1U;
			m_lost = 0U;

			m_n = 1U;

			if (m_duplex) {
				unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U];
				start[0U] = TAG_HEADER;

				// Modify the header
				header->setRepeater(false);
				header->setRPTCall1(m_callsign);
				header->setRPTCall2(m_callsign);
				header->get(start + 1U);

				writeQueueHeader(start);
			}

			if (m_net) {
				unsigned char start[DSTAR_HEADER_LENGTH_BYTES + 1U];
				start[0U] = TAG_HEADER;

				// Modify the header
				header->setRepeater(false);
				header->setRPTCall1(m_gateway);
				header->setRPTCall2(m_callsign);
				header->get(start + 1U);

				for (unsigned int i = 0U; i < 3U; i++)
					writeNetworkHeader(start, false);
			}

			delete header;

			unsigned int errors = m_fec.regenerateDMR(data + 1U);
			m_errs += errors;
			m_bits += 48U;

			if (m_net)
				writeNetworkData(data, errors, false, false);

			if (m_duplex) {
				blankDTMF(data + 1U);
				writeQueueData(data);
			}

			m_state = RS_RELAYING_RF_AUDIO;

			m_display->writeDStar(std::string((char*)my1, 8U), std::string((char*)my2, 4U));

			LogMessage("D-Star, received RF late entry from %8.8s/%4.4s to %8.8s", my1, my2, your);
		}
	} else {
		CUtils::dump("D-Star, unknown data from modem", data, DSTAR_FRAME_LENGTH_BYTES + 1U);
	}

	return true;
}
Пример #7
0
void CDStarControl::writeNetwork()
{
	assert(m_network != NULL);

	unsigned char data[DSTAR_HEADER_LENGTH_BYTES + 2U];
	unsigned int length = m_network->read(data, DSTAR_HEADER_LENGTH_BYTES + 2U);
	if (length == 0U)
		return;

	if (m_state == RS_RELAYING_RF_AUDIO || m_state == RS_LATE_ENTRY)
		return;

	m_networkWatchdog.start();

	unsigned char type = data[0U];

	if (type == TAG_HEADER) {
		if (m_state != RS_LISTENING)
			return;

		CDStarHeader header(data + 1U);

		unsigned char my1[DSTAR_LONG_CALLSIGN_LENGTH];
		header.getMyCall1(my1);

		unsigned char my2[DSTAR_SHORT_CALLSIGN_LENGTH];
		header.getMyCall2(my2);

		unsigned char your[DSTAR_LONG_CALLSIGN_LENGTH];
		header.getYourCall(your);

		m_header = header;

		m_timeoutTimer.start();
		m_elapsed.start();
		m_ackTimer.stop();

		m_frames = 0U;
		m_lost = 0U;

		m_n = 0U;

		m_bits = 1U;
		m_errs = 0U;

		writeQueueHeader(data);

#if defined(DUMP_DSTAR)
		openFile();
		writeFile(data + 1U, length - 1U);
#endif
		m_state = RS_RELAYING_NETWORK_AUDIO;

		m_display->writeDStar(std::string((char*)my1, 8U), std::string((char*)my2, 4U));

		LogMessage("D-Star, received network header from %8.8s/%4.4s to %8.8s", my1, my2, your);
	} else if (type == TAG_EOT) {
		if (m_state != RS_RELAYING_NETWORK_AUDIO)
			return;

		m_timeoutTimer.stop();

		data[1U] = TAG_EOT;
		for (unsigned int i = 0U; i < 3U; i++)
			writeQueueData(data + 1U);

#if defined(DUMP_DSTAR)
		writeFile(data + 1U, length - 1U);
		closeFile();
#endif
		// We've received the header and EOT haven't we?
		m_frames += 2U;
		if (m_bits == 0U) m_bits = 1U;
		LogMessage("D-Star, received network end of transmission, %.1f seconds, %u%% packet loss, BER: %.1f%%", float(m_frames) / 50.0F, (m_lost * 100U) / m_frames, float(m_errs * 100U) / float(m_bits));

		writeEndOfTransmission();
	} else if (type == TAG_DATA) {
		if (m_state != RS_RELAYING_NETWORK_AUDIO)
			return;

		unsigned char n = data[1U];

		insertSilence(data + 2U, n);

		m_errs += m_fec.regenerateDStar(data + 2U);
		m_bits += 48U;

		blankDTMF(data + 2U);

		// Regenerate the sync
		if (n == 0U)
			::memcpy(data + DSTAR_VOICE_FRAME_LENGTH_BYTES + 2U, DSTAR_SYNC_BYTES, DSTAR_DATA_FRAME_LENGTH_BYTES);

		m_n = n;

		m_packetTimer.start();
		m_frames++;

		data[1U] = TAG_DATA;

#if defined(DUMP_DSTAR)
		writeFile(data + 1U, length - 1U);
#endif
		writeQueueData(data + 1U);
	} else {
		CUtils::dump("D-Star, unknown data from network", data, DSTAR_FRAME_LENGTH_BYTES + 1U);
	}
}
Пример #8
0
void CDMRSlot::writeModem(unsigned char *data)
{
	if (data[0U] == TAG_LOST && m_state == RS_RELAYING_RF_AUDIO) {
		LogMessage("DMR Slot %u, transmission lost, BER: %u%%", m_slotNo, (m_errs * 100U) / m_bits);
		writeEndOfTransmission();
		return;
	}

	if (data[0U] == TAG_LOST && m_state == RS_RELAYING_RF_DATA) {
		LogMessage("DMR Slot %u, transmission lost", m_slotNo);
		writeEndOfTransmission();
		return;
	}

	if (data[0U] == TAG_LOST && m_state == RS_LATE_ENTRY) {
		m_state = RS_LISTENING;
		return;
	}

	if (m_state == RS_RELAYING_NETWORK_AUDIO || m_state == RS_RELAYING_NETWORK_DATA)
		return;

	bool dataSync  = (data[1U] & DMR_SYNC_DATA)  == DMR_SYNC_DATA;
	bool audioSync = (data[1U] & DMR_SYNC_AUDIO) == DMR_SYNC_AUDIO;

	if (dataSync) {
		CSlotType slotType;
		slotType.putData(data + 2U);

		unsigned char dataType = slotType.getDataType();

		if (dataType == DT_VOICE_LC_HEADER) {
			if (m_state == RS_RELAYING_RF_AUDIO)
				return;

			CFullLC fullLC;
			m_lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
			if (m_lc == NULL) {
				LogMessage("DMR Slot %u: unable to decode the LC", m_slotNo);
				return;
			}

			// Regenerate the Slot Type
			slotType.getData(data + 2U);

			// Convert the Data Sync to be from the BS
			CDMRSync sync;
			sync.addSync(data + 2U, DST_BS_DATA);

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;

			m_networkWatchdog.stop();
			m_timeoutTimer.start();

			m_seqNo = 0U;
			m_n     = 0U;

			m_bits = 1U;
			m_errs = 0U;

			// Put a small delay into starting retransmission
			writeQueue(m_idle);

			for (unsigned i = 0U; i < 3U; i++) {
				writeNetwork(data, DT_VOICE_LC_HEADER);
				writeQueue(data);
			}

			m_state = RS_RELAYING_RF_AUDIO;
			setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());

			m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());

			LogMessage("DMR Slot %u, received RF voice header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
		} else if (dataType == DT_VOICE_PI_HEADER) {
			if (m_state != RS_RELAYING_RF_AUDIO)
				return;

			// Regenerate the Slot Type
			slotType.getData(data + 2U);

			// Convert the Data Sync to be from the BS
			CDMRSync sync;
			sync.addSync(data + 2U, DST_BS_DATA);

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;

			m_n = 0U;

			writeNetwork(data, DT_VOICE_PI_HEADER);
			writeQueue(data);
		} else if (dataType == DT_TERMINATOR_WITH_LC) {
			if (m_state != RS_RELAYING_RF_AUDIO)
				return;

			// Regenerate the Slot Type
			slotType.getData(data + 2U);

			// Set the Data Sync to be from the BS
			CDMRSync sync;
			sync.addSync(data + 2U, DST_BS_DATA);

			data[0U] = TAG_EOT;
			data[1U] = 0x00U;

			writeNetwork(data, DT_TERMINATOR_WITH_LC);
			writeQueue(data);

			LogMessage("DMR Slot %u, received RF end of voice transmission, BER: %u%%", m_slotNo, (m_errs * 100U) / m_bits);

			// 480ms of idle to space things out
			for (unsigned int i = 0U; i < 8U; i++)
				writeQueue(m_idle);

			writeEndOfTransmission();
		} else if (dataType == DT_DATA_HEADER) {
			if (m_state == RS_RELAYING_RF_DATA)
				return;

			// Regenerate the Slot Type
			slotType.getData(data + 2U);

			// Convert the Data Sync to be from the BS
			CDMRSync sync;
			sync.addSync(data + 2U, DST_BS_DATA);

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;

			m_networkWatchdog.stop();

			m_seqNo = 0U;
			m_n = 0U;

			// Put a small delay into starting retransmission
			writeQueue(m_idle);

			for (unsigned i = 0U; i < 3U; i++) {
				writeNetwork(data, DT_DATA_HEADER);
				writeQueue(data);
			}

			m_state = RS_RELAYING_RF_DATA;
			// setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());

			// m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());

			// LogMessage("DMR Slot %u, received RF data header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
			LogMessage("DMR Slot %u, received RF data header", m_slotNo);
		} else {
			// Regenerate the Slot Type
			slotType.getData(data + 2U);

			// Convert the Data Sync to be from the BS
			CDMRSync sync;
			sync.addSync(data + 2U, DST_BS_DATA);

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;

			writeNetwork(data, dataType);
			writeQueue(data);
		}
	} else if (audioSync) {
		if (m_state == RS_RELAYING_RF_AUDIO) {
			// Convert the Audio Sync to be from the BS
			CDMRSync sync;
			sync.addSync(data + 2U, DST_BS_AUDIO);

			unsigned char fid = m_lc->getFID();
			if (fid == FID_ETSI || fid == FID_DMRA)
				m_errs += m_fec.regenerateDMR(data + 2U);
			m_bits += 216U;

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;

			m_n = 0U;

			writeQueue(data);
			writeNetwork(data, DT_VOICE_SYNC);
		} else if (m_state == RS_LISTENING) {
			m_state = RS_LATE_ENTRY;
		}
	} else {
		CEMB emb;
		emb.putData(data + 2U);

		if (m_state == RS_RELAYING_RF_AUDIO) {
			// Regenerate the EMB
			emb.setColorCode(m_colorCode);
			emb.getData(data + 2U);

			unsigned char fid = m_lc->getFID();
			if (fid == FID_ETSI || fid == FID_DMRA)
				m_errs += m_fec.regenerateDMR(data + 2U);
			m_bits += 216U;

			data[0U] = TAG_DATA;
			data[1U] = 0x00U;

			m_n++;

			writeQueue(data);
			writeNetwork(data, DT_VOICE);
		} else if (m_state == RS_LATE_ENTRY) {
			// If we haven't received an LC yet, then be strict on the color code
			unsigned char colorCode = emb.getColorCode();
			if (colorCode != m_colorCode)
				return;

			m_lc = m_embeddedLC.addData(data + 2U, emb.getLCSS());
			if (m_lc != NULL) {
				// Create a dummy start frame to replace the received frame
				unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U];

				CDMRSync sync;
				sync.addSync(start + 2U, DST_BS_DATA);

				CFullLC fullLC;
				fullLC.encode(*m_lc, start + 2U, DT_VOICE_LC_HEADER);

				CSlotType slotType;
				slotType.setColorCode(m_colorCode);
				slotType.setDataType(DT_VOICE_LC_HEADER);
				slotType.getData(start + 2U);

				start[0U] = TAG_DATA;
				start[1U] = 0x00U;

				m_networkWatchdog.stop();
				m_timeoutTimer.start();

				m_seqNo = 0U;
				m_n     = 0U;

				m_bits = 1U;
				m_errs = 0U;

				for (unsigned int i = 0U; i < 3U; i++) {
					writeNetwork(start, DT_VOICE_LC_HEADER);
					writeQueue(start);
				}

				// Regenerate the EMB
				emb.getData(data + 2U);

				// Send the original audio frame out
				unsigned char fid = m_lc->getFID();
				if (fid == FID_ETSI || fid == FID_DMRA)
					m_errs += m_fec.regenerateDMR(data + 2U);
				m_bits += 216U;

				data[0U] = TAG_DATA;
				data[1U] = 0x00U;

				m_n++;

				writeQueue(data);
				writeNetwork(data, DT_VOICE);

				m_state = RS_RELAYING_RF_AUDIO;

				setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());

				m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());

				LogMessage("DMR Slot %u, received RF late entry from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
			}
		}
	}
}
Пример #9
0
void CDMRSlot::writeNetwork(const CDMRData& dmrData)
{
	if (m_state == RS_RELAYING_RF_AUDIO || m_state == RS_RELAYING_RF_DATA || m_state == RS_LATE_ENTRY)
		return;

	m_networkWatchdog.start();

	unsigned char dataType = dmrData.getDataType();

	unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U];
	dmrData.getData(data + 2U);

	if (dataType == DT_VOICE_LC_HEADER) {
		if (m_state == RS_RELAYING_NETWORK_AUDIO)
			return;

		CFullLC fullLC;
		m_lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
		if (m_lc == NULL) {
			LogMessage("DMR Slot %u, bad LC received from the network", m_slotNo);
			return;
		}

		// Regenerate the Slot Type
		CSlotType slotType;
		slotType.setColorCode(m_colorCode);
		slotType.setDataType(DT_VOICE_LC_HEADER);
		slotType.getData(data + 2U);

		// Convert the Data Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_DATA);

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		m_timeoutTimer.start();

		m_frames = 0U;

		m_bits = 1U;
		m_errs = 0U;

		// 540ms of idle to give breathing space for lost frames
		for (unsigned int i = 0U; i < 9U; i++)
			writeQueue(m_idle);

		for (unsigned int i = 0U; i < 3U; i++)
			writeQueue(data);

		m_state = RS_RELAYING_NETWORK_AUDIO;

		setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());

		m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());

#if defined(DUMP_DMR)
		openFile();
		writeFile(data);
#endif
		LogMessage("DMR Slot %u, received network voice header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
	} else if (dataType == DT_VOICE_PI_HEADER) {
		if (m_state != RS_RELAYING_NETWORK_AUDIO)
			return;

		// Regenerate the Slot Type
		CSlotType slotType;
		slotType.setColorCode(m_colorCode);
		slotType.setDataType(DT_VOICE_PI_HEADER);
		slotType.getData(data + 2U);

		// Convert the Data Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_DATA);

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		writeQueue(data);

#if defined(DUMP_DMR)
		writeFile(data);
#endif
	} else if (dataType == DT_TERMINATOR_WITH_LC) {
		if (m_state != RS_RELAYING_NETWORK_AUDIO)
			return;

		// Regenerate the Slot Type
		CSlotType slotType;
		slotType.setColorCode(m_colorCode);
		slotType.setDataType(DT_TERMINATOR_WITH_LC);
		slotType.getData(data + 2U);

		// Convert the Data Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_DATA);

		data[0U] = TAG_EOT;
		data[1U] = 0x00U;

		writeQueue(data);
		writeEndOfTransmission();

#if defined(DUMP_DMR)
		writeFile(data);
		closeFile();
#endif
		// We've received the voice header and terminator haven't we?
		m_frames += 2U;
		LogMessage("DMR Slot %u, received network end of voice transmission, %u%% packet loss, BER: %u%%", m_slotNo, (m_lost * 100U) / m_frames, (m_errs * 100U) / m_bits);
	} else if (dataType == DT_DATA_HEADER) {
		if (m_state == RS_RELAYING_NETWORK_DATA)
			return;

		// Regenerate the Slot Type
		CSlotType slotType;
		slotType.setColorCode(m_colorCode);
		slotType.setDataType(DT_DATA_HEADER);
		slotType.getData(data + 2U);

		// Convert the Data Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_DATA);

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		// Put a small delay into starting transmission
		writeQueue(m_idle);
		writeQueue(m_idle);

		for (unsigned i = 0U; i < 3U; i++)
			writeQueue(data);

		m_state = RS_RELAYING_NETWORK_DATA;

		// setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());

		// m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());

		// LogMessage("DMR Slot %u, received network data header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
		LogMessage("DMR Slot %u, received network data header", m_slotNo);
	} else if (dataType == DT_VOICE_SYNC) {
		if (m_state != RS_RELAYING_NETWORK_AUDIO)
			return;

		// Initialise the lost packet data
		if (m_frames == 0U) {
			m_seqNo = dmrData.getSeqNo();
			m_n     = dmrData.getN();
			m_elapsed.start();
			m_lost = 0U;
		} else {
			insertSilence(dmrData.getSeqNo());
		}

		// Convert the Audio Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_AUDIO);

		unsigned char fid = m_lc->getFID();
		if (fid == FID_ETSI || fid == FID_DMRA)
			m_errs += m_fec.regenerateDMR(data + 2U);
		m_bits += 216U;

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		writeQueue(data);

		m_packetTimer.start();
		m_frames++;

		// Save details in case we need to infill data
		m_seqNo = dmrData.getSeqNo();
		m_n     = dmrData.getN();
		::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U);

#if defined(DUMP_DMR)
		writeFile(data);
#endif
	} else if (dataType == DT_VOICE) {
		if (m_state != RS_RELAYING_NETWORK_AUDIO)
			return;

		// Initialise the lost packet data
		if (m_frames == 0U) {
			m_seqNo = dmrData.getSeqNo();
			m_n     = dmrData.getN();
			m_elapsed.start();
			m_lost = 0U;
		} else {
			insertSilence(dmrData.getSeqNo());
		}

		unsigned char fid = m_lc->getFID();
		if (fid == FID_ETSI || fid == FID_DMRA)
			m_errs += m_fec.regenerateDMR(data + 2U);
		m_bits += 216U;

		// Change the color code in the EMB
		CEMB emb;
		emb.putData(data + 2U);
		emb.setColorCode(m_colorCode);
		emb.getData(data + 2U);

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		writeQueue(data);

		m_packetTimer.start();
		m_frames++;

		// Save details in case we need to infill data
		m_seqNo = dmrData.getSeqNo();
		m_n     = dmrData.getN();
		::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U);

#if defined(DUMP_DMR)
		writeFile(data);
#endif
	} else {
		// Change the Color Code of the Slot Type
		CSlotType slotType;
		slotType.putData(data + 2U);
		slotType.setColorCode(m_colorCode);
		slotType.getData(data + 2U);

		// Convert the Data Sync to be from the BS
		CDMRSync sync;
		sync.addSync(data + 2U, DST_BS_DATA);

		data[0U] = TAG_DATA;
		data[1U] = 0x00U;

		writeQueue(data);

#if defined(DUMP_DMR)
		writeFile(data);
#endif
	}
}