void CDMRSlot::writeNetwork(const unsigned char* data, unsigned char dataType) { assert(m_lc != NULL); if (m_network == NULL) return; // Don't send to the network if the timeout has expired if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) return; CDMRData dmrData; dmrData.setSlotNo(m_slotNo); dmrData.setDataType(dataType); dmrData.setSrcId(m_lc->getSrcId()); dmrData.setDstId(m_lc->getDstId()); dmrData.setFLCO(m_lc->getFLCO()); dmrData.setN(m_n); dmrData.setSeqNo(m_seqNo); m_seqNo++; dmrData.setData(data + 2U); m_network->write(dmrData); }
void CDMRControl::clock() { if (m_network != NULL) { CDMRData data; bool ret = m_network->read(data); if (ret) { unsigned int slotNo = data.getSlotNo(); switch (slotNo) { case 1U: m_slot1.writeNetwork(data); break; case 2U: m_slot2.writeNetwork(data); break; default: LogError("Invalid slot no %u", slotNo); break; } } } m_slot1.clock(); m_slot2.clock(); }
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; }
bool CDMRNetwork::read(CDMRData& data) { if (m_status != RUNNING) return false; if (m_rxData.isEmpty()) return false; unsigned char length = 0U; m_rxData.getData(&length, 1U); m_rxData.getData(m_buffer, length); // Is this a data packet? if (::memcmp(m_buffer, "DMRD", 4U) != 0) return false; unsigned char seqNo = m_buffer[4U]; unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; // DMO mode slot disabling if (slotNo == 1U && !m_duplex) return false; // Individual slot disabling if (slotNo == 1U && !m_slot1) return false; if (slotNo == 2U && !m_slot2) return false; FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP; data.setSeqNo(seqNo); data.setSlotNo(slotNo); data.setSrcId(srcId); data.setDstId(dstId); data.setFLCO(flco); bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U; bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U; if (dataSync) { unsigned char dataType = m_buffer[15U] & 0x0FU; data.setData(m_buffer + 20U); data.setDataType(dataType); data.setN(0U); } else if (voiceSync) { data.setData(m_buffer + 20U); data.setDataType(DT_VOICE_SYNC); data.setN(0U); } else { unsigned char n = m_buffer[15U] & 0x0FU; data.setData(m_buffer + 20U); data.setDataType(DT_VOICE); data.setN(n); } return true; }
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 } }
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 } }