bool CDMRNetwork::write(const CDMRData& data) { if (m_status != RUNNING) return false; unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH]; ::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH); buffer[0U] = 'D'; buffer[1U] = 'M'; buffer[2U] = 'R'; buffer[3U] = 'D'; unsigned int srcId = data.getSrcId(); buffer[5U] = srcId >> 16; buffer[6U] = srcId >> 8; buffer[7U] = srcId >> 0; unsigned int dstId = data.getDstId(); buffer[8U] = dstId >> 16; buffer[9U] = dstId >> 8; buffer[10U] = dstId >> 0; ::memcpy(buffer + 11U, m_id, 4U); unsigned int slotNo = data.getSlotNo(); // Individual slot disabling if (slotNo == 1U && !m_slot1) return false; if (slotNo == 2U && !m_slot2) return false; buffer[15U] = slotNo == 1U ? 0x00U : 0x80U; FLCO flco = data.getFLCO(); buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U; unsigned int slotIndex = slotNo - 1U; unsigned int count = 1U; unsigned char dataType = data.getDataType(); if (dataType == DT_VOICE_SYNC) { buffer[15U] |= 0x10U; } else if (dataType == DT_VOICE) { buffer[15U] |= data.getN(); } else { if (dataType == DT_VOICE_LC_HEADER) { m_streamId[slotIndex] = ::rand() + 1U; count = 2U; } if (dataType == DT_CSBK || dataType == DT_DATA_HEADER) { m_streamId[slotIndex] = ::rand() + 1U; count = 1U; } buffer[15U] |= (0x20U | dataType); } buffer[4U] = data.getSeqNo(); ::memcpy(buffer + 16U, m_streamId + slotIndex, 4U); data.getData(buffer + 20U); buffer[53U] = data.getBER(); if (m_rssi) buffer[54U] = data.getRSSI(); else buffer[54U] = 0x00U; if (m_debug) CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH); for (unsigned int i = 0U; i < count; i++) write(buffer, HOMEBREW_DATA_PACKET_LENGTH); return true; }
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 } }