correct RF talkgroup hang timer (allows the local RF to steer the talkgroup); fix labeling for the preamble and DMR Rx Delay; correct TDU preamble before voice transmission in P25;

pull/1/head
Bryan Biedenkapp 6 years ago
parent 95364cbcf1
commit 8feecf49ec

@ -13,7 +13,6 @@ network:
rconAddress: 127.0.0.1 rconAddress: 127.0.0.1
rconPort: 9990 rconPort: 9990
jitter: 360 jitter: 360
talkgroupHang: 10
password: "PASSWORD" password: "PASSWORD"
slot1: true slot1: true
slot2: true slot2: true
@ -38,7 +37,7 @@ protocols:
debug: false debug: false
p25: p25:
enable: true enable: true
preambleCount: 4 tduPreambleCount: 6
control: control:
enable: false enable: false
continuous: false continuous: false
@ -74,6 +73,7 @@ system:
# rfModeHang: 10 # rfModeHang: 10
# netModeHang: 10 # netModeHang: 10
# fixedMode: false # fixedMode: false
rfTalkgroupHang: 10
info: info:
latitude: 0.0 latitude: 0.0
longitude: 0.0 longitude: 0.0
@ -99,8 +99,8 @@ system:
pttInvert: false pttInvert: false
dcBlocker: true dcBlocker: true
cosLockout: false cosLockout: false
txDelay: 1 fdmaPreamble: 80
dmrDelay: 7 dmrRxDelay: 7
rxDCOffset: 0 rxDCOffset: 0
txDCOffset: 0 txDCOffset: 0
rxLevel: 50 rxLevel: 50

@ -63,16 +63,16 @@ using namespace dmr;
return false; \ return false; \
} }
#define CHECK_NET_TG_HANG(_DST_ID) \ #define CHECK_TG_HANG(_DST_ID) \
if (m_slot->m_rfLastDstId != 0U) { \ if (m_slot->m_rfLastDstId != 0U) { \
if (m_slot->m_rfLastDstId != _DST_ID && (m_slot->m_networkTGHang.isRunning() && !m_slot->m_networkTGHang.hasExpired())) { \ if (m_slot->m_rfLastDstId != _DST_ID && (m_slot->m_rfTGHang.isRunning() && !m_slot->m_rfTGHang.hasExpired())) { \
return; \ return; \
} \ } \
} }
#define CHECK_NET_TG_HANG_DELLC(_DST_ID) \ #define CHECK_TG_HANG_DELLC(_DST_ID) \
if (m_slot->m_rfLastDstId != 0U) { \ if (m_slot->m_rfLastDstId != 0U) { \
if (m_slot->m_rfLastDstId != _DST_ID && (m_slot->m_networkTGHang.isRunning() && !m_slot->m_networkTGHang.hasExpired())) { \ if (m_slot->m_rfLastDstId != _DST_ID && (m_slot->m_rfTGHang.isRunning() && !m_slot->m_rfTGHang.hasExpired())) { \
delete lc; \ delete lc; \
return; \ return; \
} \ } \
@ -577,7 +577,7 @@ void DataPacket::processNetwork(const data::Data& dmrData)
uint32_t dstId = lc->getDstId(); uint32_t dstId = lc->getDstId();
uint8_t flco = lc->getFLCO(); uint8_t flco = lc->getFLCO();
CHECK_NET_TG_HANG_DELLC(dstId); CHECK_TG_HANG_DELLC(dstId);
if (dstId != dmrData.getDstId() || srcId != dmrData.getSrcId() || flco != dmrData.getFLCO()) if (dstId != dmrData.getDstId() || srcId != dmrData.getSrcId() || flco != dmrData.getFLCO())
LogWarning(LOG_NET, "DMR Slot %u, DT_VOICE_LC_HEADER, header doesn't match the DMR RF header: %u->%s%u %u->%s%u", m_slot->m_slotNo, LogWarning(LOG_NET, "DMR Slot %u, DT_VOICE_LC_HEADER, header doesn't match the DMR RF header: %u->%s%u %u->%s%u", m_slot->m_slotNo,
@ -655,7 +655,7 @@ void DataPacket::processNetwork(const data::Data& dmrData)
uint32_t srcId = lc->getSrcId(); uint32_t srcId = lc->getSrcId();
uint32_t dstId = lc->getDstId(); uint32_t dstId = lc->getDstId();
CHECK_NET_TG_HANG_DELLC(dstId); CHECK_TG_HANG_DELLC(dstId);
m_netLC = lc; m_netLC = lc;
@ -793,7 +793,7 @@ void DataPacket::processNetwork(const data::Data& dmrData)
uint32_t srcId = csbk.getSrcId(); uint32_t srcId = csbk.getSrcId();
uint32_t dstId = csbk.getDstId(); uint32_t dstId = csbk.getDstId();
CHECK_NET_TG_HANG(dstId); CHECK_TG_HANG(dstId);
// Regenerate the CSBK data // Regenerate the CSBK data
csbk.encode(data + 2U); csbk.encode(data + 2U);
@ -923,7 +923,7 @@ void DataPacket::processNetwork(const data::Data& dmrData)
uint32_t srcId = dataHeader.getSrcId(); uint32_t srcId = dataHeader.getSrcId();
uint32_t dstId = dataHeader.getDstId(); uint32_t dstId = dataHeader.getDstId();
CHECK_NET_TG_HANG(dstId); CHECK_TG_HANG(dstId);
m_slot->m_netFrames = dataHeader.getBlocks(); m_slot->m_netFrames = dataHeader.getBlocks();

@ -98,9 +98,9 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz
m_rfSeqNo(0U), m_rfSeqNo(0U),
m_networkWatchdog(1000U, 0U, 1500U), m_networkWatchdog(1000U, 0U, 1500U),
m_rfTimeoutTimer(1000U, timeout), m_rfTimeoutTimer(1000U, timeout),
m_rfTGHang(1000U, tgHang),
m_netTimeoutTimer(1000U, timeout), m_netTimeoutTimer(1000U, timeout),
m_packetTimer(1000U, 0U, 50U), m_packetTimer(1000U, 0U, 50U),
m_networkTGHang(1000U, tgHang),
m_interval(), m_interval(),
m_elapsed(), m_elapsed(),
m_rfFrames(0U), m_rfFrames(0U),
@ -180,6 +180,7 @@ bool Slot::processFrame(uint8_t *data, uint32_t len)
if (data[0U] == TAG_LOST) { if (data[0U] == TAG_LOST) {
m_rfState = RS_RF_LISTENING; m_rfState = RS_RF_LISTENING;
m_rfLastDstId = 0U; m_rfLastDstId = 0U;
m_rfTGHang.stop();
return false; return false;
} }
@ -234,7 +235,7 @@ bool Slot::processFrame(uint8_t *data, uint32_t len)
} }
if ((dataSync || voiceSync) && m_rfState != RS_RF_LISTENING) if ((dataSync || voiceSync) && m_rfState != RS_RF_LISTENING)
m_networkTGHang.start(); m_rfTGHang.start();
if (dataSync) { if (dataSync) {
return m_data->process(data, len); return m_data->process(data, len);
@ -275,6 +276,17 @@ void Slot::processNetwork(const data::Data& dmrData)
return; return;
} }
// don't process network frames if the destination ID's don't match and the network TG hang timer is running
if (m_rfLastDstId != 0U) {
if (m_rfLastDstId != dmrData.getDstId() && (m_rfTGHang.isRunning() && !m_rfTGHang.hasExpired())) {
return;
}
if (m_rfLastDstId == dmrData.getDstId() && (m_rfTGHang.isRunning() && !m_rfTGHang.hasExpired())) {
m_rfTGHang.start();
}
}
m_networkWatchdog.start(); m_networkWatchdog.start();
uint8_t dataType = dmrData.getDataType(); uint8_t dataType = dmrData.getDataType();
@ -322,11 +334,14 @@ void Slot::clock()
} }
} }
if (m_networkTGHang.isRunning()) { if (m_rfTGHang.isRunning()) {
m_networkTGHang.clock(ms); m_rfTGHang.clock(ms);
if (m_networkTGHang.hasExpired()) { if (m_rfTGHang.hasExpired()) {
m_networkTGHang.stop(); m_rfTGHang.stop();
if (m_verbose) {
LogMessage(LOG_RF, "Slot %u, talkgroup hang has expired, lastDstId = %u", m_slotNo, m_rfLastDstId);
}
m_rfLastDstId = 0U; m_rfLastDstId = 0U;
} }
} }

@ -104,9 +104,9 @@ namespace dmr
Timer m_networkWatchdog; Timer m_networkWatchdog;
Timer m_rfTimeoutTimer; Timer m_rfTimeoutTimer;
Timer m_rfTGHang;
Timer m_netTimeoutTimer; Timer m_netTimeoutTimer;
Timer m_packetTimer; Timer m_packetTimer;
Timer m_networkTGHang;
StopWatch m_interval; StopWatch m_interval;
StopWatch m_elapsed; StopWatch m_elapsed;

@ -93,6 +93,9 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_slot->m_rfBits += 141U; m_slot->m_rfBits += 141U;
m_slot->m_rfFrames++; m_slot->m_rfFrames++;
m_slot->m_rfTGHang.start();
m_slot->m_rfLastDstId = m_slot->m_data->m_rfLC->getDstId();
m_rfEmbeddedReadN = (m_rfEmbeddedReadN + 1U) % 2U; m_rfEmbeddedReadN = (m_rfEmbeddedReadN + 1U) % 2U;
m_rfEmbeddedWriteN = (m_rfEmbeddedWriteN + 1U) % 2U; m_rfEmbeddedWriteN = (m_rfEmbeddedWriteN + 1U) % 2U;
m_rfEmbeddedData[m_rfEmbeddedWriteN].reset(); m_rfEmbeddedData[m_rfEmbeddedWriteN].reset();
@ -143,6 +146,9 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_slot->m_rfBits += 141U; m_slot->m_rfBits += 141U;
m_slot->m_rfFrames++; m_slot->m_rfFrames++;
m_slot->m_rfTGHang.start();
m_slot->m_rfLastDstId = m_slot->m_data->m_rfLC->getDstId();
// Get the LCSS from the EMB // Get the LCSS from the EMB
data::EMB emb; data::EMB emb;
emb.decode(data + 2U); emb.decode(data + 2U);
@ -381,6 +387,8 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_slot->writeNetworkRF(data, DT_VOICE, errors); m_slot->writeNetworkRF(data, DT_VOICE, errors);
m_slot->m_rfState = RS_RF_AUDIO; m_slot->m_rfState = RS_RF_AUDIO;
m_slot->m_rfTGHang.start();
m_slot->m_rfLastDstId = dstId; m_slot->m_rfLastDstId = dstId;
if (m_slot->m_netState == RS_NET_IDLE) { if (m_slot->m_netState == RS_NET_IDLE) {

@ -79,8 +79,8 @@ Host::Host(const std::string& confFile) :
m_fixedMode(false), m_fixedMode(false),
m_timeout(180U), m_timeout(180U),
m_rfModeHang(10U), m_rfModeHang(10U),
m_rfTalkgroupHang(10U),
m_netModeHang(3U), m_netModeHang(3U),
m_netTalkgroupHang(10U),
m_identity(), m_identity(),
m_cwCallsign(), m_cwCallsign(),
m_cwIdTime(0U), m_cwIdTime(0U),
@ -309,7 +309,7 @@ int Host::run()
g_fireDMRBeacon = true; g_fireDMRBeacon = true;
} }
dmr = new dmr::Control(m_dmrColorCode, callHang, dmrQueueSize, embeddedLCOnly, dumpTAData, m_timeout, m_netTalkgroupHang, dmr = new dmr::Control(m_dmrColorCode, callHang, dmrQueueSize, embeddedLCOnly, dumpTAData, m_timeout, m_rfTalkgroupHang,
m_modem, m_network, m_duplex, m_ridLookup, m_tidLookup, rssi, jitter, dmrDumpDataPacket, dmrRepeatDataPacket, dmrDebug, dmrVerbose); m_modem, m_network, m_duplex, m_ridLookup, m_tidLookup, rssi, jitter, dmrDumpDataPacket, dmrRepeatDataPacket, dmrDebug, dmrVerbose);
m_dmrTXTimer.setTimeout(txHang); m_dmrTXTimer.setTimeout(txHang);
@ -330,7 +330,7 @@ int Host::run()
LogInfo(" Enabled: %s", m_p25Enabled ? "yes" : "no"); LogInfo(" Enabled: %s", m_p25Enabled ? "yes" : "no");
if (m_p25Enabled) { if (m_p25Enabled) {
yaml::Node p25Protocol = protocolConf["p25"]; yaml::Node p25Protocol = protocolConf["p25"];
uint32_t preambleCount = p25Protocol["preambleCount"].as<uint32_t>(4U); uint32_t tduPreambleCount = p25Protocol["tduPreambleCount"].as<uint32_t>(8U);
m_controlData = p25Protocol["control"]["enable"].as<bool>(false); m_controlData = p25Protocol["control"]["enable"].as<bool>(false);
bool controlBcstContinuous = p25Protocol["control"]["continuous"].as<bool>(false); bool controlBcstContinuous = p25Protocol["control"]["continuous"].as<bool>(false);
bool p25DumpDataPacket = p25Protocol["dumpDataPacket"].as<bool>(false); bool p25DumpDataPacket = p25Protocol["dumpDataPacket"].as<bool>(false);
@ -340,7 +340,7 @@ int Host::run()
bool p25Verbose = p25Protocol["verbose"].as<bool>(true); bool p25Verbose = p25Protocol["verbose"].as<bool>(true);
bool p25Debug = p25Protocol["debug"].as<bool>(false); bool p25Debug = p25Protocol["debug"].as<bool>(false);
LogInfo(" Preamble Count: %u", preambleCount); LogInfo(" TDU Preamble before Voice: %u", tduPreambleCount);
LogInfo(" Dump Packet Data: %s", p25DumpDataPacket ? "yes" : "no"); LogInfo(" Dump Packet Data: %s", p25DumpDataPacket ? "yes" : "no");
LogInfo(" Repeat Packet Data: %s", p25RepeatDataPacket ? "yes" : "no"); LogInfo(" Repeat Packet Data: %s", p25RepeatDataPacket ? "yes" : "no");
LogInfo(" Call Hang: %us", callHang); LogInfo(" Call Hang: %us", callHang);
@ -371,7 +371,7 @@ int Host::run()
g_interruptP25Control = false; g_interruptP25Control = false;
} }
p25 = new p25::Control(m_p25NAC, callHang, p25QueueSize, m_modem, m_network, m_timeout, m_netTalkgroupHang, p25 = new p25::Control(m_p25NAC, callHang, p25QueueSize, m_modem, m_network, m_timeout, m_rfTalkgroupHang,
p25ControlBcstInterval, m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi, p25DumpDataPacket, p25RepeatDataPacket, p25Debug, p25Verbose); p25ControlBcstInterval, m_duplex, m_ridLookup, m_tidLookup, m_idenTable, rssi, p25DumpDataPacket, p25RepeatDataPacket, p25Debug, p25Verbose);
p25->setOptions(m_conf, m_cwCallsign, m_voiceChNo, m_p25PatchSuperGroup, m_p25NetId, m_p25SysId, m_p25RfssId, p25->setOptions(m_conf, m_cwCallsign, m_voiceChNo, m_p25PatchSuperGroup, m_p25NetId, m_p25SysId, m_p25RfssId,
m_p25SiteId, m_channelId, m_channelNo, true); m_p25SiteId, m_channelId, m_channelNo, true);
@ -1029,6 +1029,7 @@ bool Host::readParams()
m_timeout = systemConf["timeout"].as<uint32_t>(120U); m_timeout = systemConf["timeout"].as<uint32_t>(120U);
m_rfModeHang = systemConf["rfModeHang"].as<uint32_t>(10U); m_rfModeHang = systemConf["rfModeHang"].as<uint32_t>(10U);
m_rfTalkgroupHang = systemConf["rfTalkgroupHang"].as<uint32_t>(10U);
m_netModeHang = systemConf["netModeHang"].as<uint32_t>(3U); m_netModeHang = systemConf["netModeHang"].as<uint32_t>(3U);
if (!systemConf["modeHang"].isNone()) { if (!systemConf["modeHang"].isNone()) {
m_rfModeHang = m_netModeHang = systemConf["modeHang"].as<uint32_t>(); m_rfModeHang = m_netModeHang = systemConf["modeHang"].as<uint32_t>();
@ -1045,6 +1046,7 @@ bool Host::readParams()
LogInfo(" Duplex: %s", m_duplex ? "yes" : "no"); LogInfo(" Duplex: %s", m_duplex ? "yes" : "no");
LogInfo(" Timeout: %us", m_timeout); LogInfo(" Timeout: %us", m_timeout);
LogInfo(" RF Mode Hang: %us", m_rfModeHang); LogInfo(" RF Mode Hang: %us", m_rfModeHang);
LogInfo(" RF Talkgroup Hang: %us", m_rfTalkgroupHang);
LogInfo(" Net Mode Hang: %us", m_netModeHang); LogInfo(" Net Mode Hang: %us", m_netModeHang);
LogInfo(" Identity: %s", m_identity.c_str()); LogInfo(" Identity: %s", m_identity.c_str());
LogInfo(" Fixed Mode: %s", m_fixedMode ? "yes" : "no"); LogInfo(" Fixed Mode: %s", m_fixedMode ? "yes" : "no");
@ -1196,8 +1198,8 @@ bool Host::createModem()
bool pttInvert = modemConf["pttInvert"].as<bool>(false); bool pttInvert = modemConf["pttInvert"].as<bool>(false);
bool dcBlocker = modemConf["dcBlocker"].as<bool>(true); bool dcBlocker = modemConf["dcBlocker"].as<bool>(true);
bool cosLockout = modemConf["cosLockout"].as<bool>(false); bool cosLockout = modemConf["cosLockout"].as<bool>(false);
uint32_t txDelay = modemConf["txDelay"].as<uint32_t>(1U); uint8_t fdmaPreamble = (uint8_t)modemConf["fdmaPreamble"].as<uint32_t>(80U);
uint32_t dmrDelay = modemConf["dmrDelay"].as<uint32_t>(7U); uint8_t dmrRxDelay = (uint8_t)modemConf["dmrRxDelay"].as<uint32_t>(7U);
int rxDCOffset = modemConf["rxDCOffset"].as<int>(0); int rxDCOffset = modemConf["rxDCOffset"].as<int>(0);
int txDCOffset = modemConf["txDCOffset"].as<int>(0); int txDCOffset = modemConf["txDCOffset"].as<int>(0);
float rxLevel = modemConf["rxLevel"].as<float>(50.0F); float rxLevel = modemConf["rxLevel"].as<float>(50.0F);
@ -1218,10 +1220,10 @@ bool Host::createModem()
LogInfo(" PTT Invert: %s", pttInvert ? "yes" : "no"); LogInfo(" PTT Invert: %s", pttInvert ? "yes" : "no");
LogInfo(" DC Blocker: %s", dcBlocker ? "yes" : "no"); LogInfo(" DC Blocker: %s", dcBlocker ? "yes" : "no");
LogInfo(" COS Lockout: %s", cosLockout ? "yes" : "no"); LogInfo(" COS Lockout: %s", cosLockout ? "yes" : "no");
LogInfo(" TX Delay: %u (%ums)", txDelay, (txDelay * 10)); LogInfo(" FDMA Preambles: %u (%.1fms)", fdmaPreamble, float(fdmaPreamble) * 0.2083F);
LogInfo(" DMR RX Delay: %u (%.1fms)", dmrRxDelay, float(dmrRxDelay) * 0.0416666F);
LogInfo(" RX DC Offset: %d", rxDCOffset); LogInfo(" RX DC Offset: %d", rxDCOffset);
LogInfo(" TX DC Offset: %d", txDCOffset); LogInfo(" TX DC Offset: %d", txDCOffset);
LogInfo(" DMR Delay: %u (%.1fms)", dmrDelay, float(dmrDelay) * 0.0416666F);
LogInfo(" RX Level: %.1f%%", rxLevel); LogInfo(" RX Level: %.1f%%", rxLevel);
LogInfo(" CW Id TX Level: %.1f%%", cwIdTXLevel); LogInfo(" CW Id TX Level: %.1f%%", cwIdTXLevel);
LogInfo(" DMR TX Level: %.1f%%", dmrTXLevel); LogInfo(" DMR TX Level: %.1f%%", dmrTXLevel);
@ -1232,7 +1234,7 @@ bool Host::createModem()
LogInfo(" Debug: yes"); LogInfo(" Debug: yes");
} }
m_modem = Modem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, dcBlocker, cosLockout, txDelay, dmrDelay, disableOFlowReset, trace, debug); m_modem = Modem::createModem(port, m_duplex, rxInvert, txInvert, pttInvert, dcBlocker, cosLockout, fdmaPreamble, dmrRxDelay, disableOFlowReset, trace, debug);
m_modem->setModeParams(m_dmrEnabled, m_p25Enabled); m_modem->setModeParams(m_dmrEnabled, m_p25Enabled);
m_modem->setLevels(rxLevel, cwIdTXLevel, dmrTXLevel, p25TXLevel); m_modem->setLevels(rxLevel, cwIdTXLevel, dmrTXLevel, p25TXLevel);
m_modem->setDCOffsetParams(txDCOffset, rxDCOffset); m_modem->setDCOffsetParams(txDCOffset, rxDCOffset);
@ -1261,7 +1263,6 @@ bool Host::createNetwork()
uint32_t rconPort = networkConf["rconPort"].as<uint32_t>(RCON_DEFAULT_PORT); uint32_t rconPort = networkConf["rconPort"].as<uint32_t>(RCON_DEFAULT_PORT);
uint32_t id = networkConf["id"].as<uint32_t>(0U); uint32_t id = networkConf["id"].as<uint32_t>(0U);
uint32_t jitter = networkConf["talkgroupHang"].as<uint32_t>(360U); uint32_t jitter = networkConf["talkgroupHang"].as<uint32_t>(360U);
m_netTalkgroupHang = networkConf["talkgroupHang"].as<uint32_t>(10U);
std::string password = networkConf["password"].as<std::string>(); std::string password = networkConf["password"].as<std::string>();
bool slot1 = networkConf["slot1"].as<bool>(true); bool slot1 = networkConf["slot1"].as<bool>(true);
bool slot2 = networkConf["slot2"].as<bool>(true); bool slot2 = networkConf["slot2"].as<bool>(true);
@ -1282,7 +1283,6 @@ bool Host::createNetwork()
LogInfo(" RCON Address: %s", rconAddress.c_str()); LogInfo(" RCON Address: %s", rconAddress.c_str());
LogInfo(" RCON Port: %u", rconPort); LogInfo(" RCON Port: %u", rconPort);
LogInfo(" DMR Jitter: %ums", jitter); LogInfo(" DMR Jitter: %ums", jitter);
LogInfo(" Talkgroup Hang: %us", m_netTalkgroupHang);
LogInfo(" Slot 1: %s", slot1 ? "enabled" : "disabled"); LogInfo(" Slot 1: %s", slot1 ? "enabled" : "disabled");
LogInfo(" Slot 2: %s", slot2 ? "enabled" : "disabled"); LogInfo(" Slot 2: %s", slot2 ? "enabled" : "disabled");
LogInfo(" Transfer Activity Log: %s", transferActivityLog ? "enabled" : "disabled"); LogInfo(" Transfer Activity Log: %s", transferActivityLog ? "enabled" : "disabled");

@ -86,8 +86,8 @@ private:
uint32_t m_timeout; uint32_t m_timeout;
uint32_t m_rfModeHang; uint32_t m_rfModeHang;
uint32_t m_rfTalkgroupHang;
uint32_t m_netModeHang; uint32_t m_netModeHang;
uint32_t m_netTalkgroupHang;
std::string m_identity; std::string m_identity;
std::string m_cwCallsign; std::string m_cwCallsign;

@ -148,8 +148,8 @@ HostCal::HostCal(const std::string& confFile) :
m_p25Rx1K(false), m_p25Rx1K(false),
m_txDCOffset(0), m_txDCOffset(0),
m_rxDCOffset(0), m_rxDCOffset(0),
m_txDelay(1U), m_fdmaPreamble(80U),
m_dmrDelay(7U), m_dmrRxDelay(7U),
m_debug(false), m_debug(false),
m_mode(STATE_DMR_CAL), m_mode(STATE_DMR_CAL),
m_modeStr(DMR_CAL_STR), m_modeStr(DMR_CAL_STR),
@ -235,8 +235,8 @@ int HostCal::run()
m_rxLevel = modemConf["rxLevel"].as<float>(50.0F); m_rxLevel = modemConf["rxLevel"].as<float>(50.0F);
m_txLevel = modemConf["txLevel"].as<float>(50.0F); m_txLevel = modemConf["txLevel"].as<float>(50.0F);
m_txDelay = modemConf["txDelay"].as<uint32_t>(1U); m_fdmaPreamble = (uint8_t)modemConf["fdmaPreamble"].as<uint32_t>(80U);
m_dmrDelay = modemConf["dmrDelay"].as<uint32_t>(7U); m_dmrRxDelay = (uint8_t)modemConf["dmrRxDelay"].as<uint32_t>(7U);
writeConfig(); writeConfig();
@ -1456,7 +1456,12 @@ bool HostCal::writeConfig(uint8_t modeOverride)
if (m_p25Enabled) if (m_p25Enabled)
buffer[4U] |= 0x08U; buffer[4U] |= 0x08U;
buffer[5U] = m_txDelay; if (m_fdmaPreamble > MAX_FDMA_PREAMBLE) {
LogWarning(LOG_P25, "oversized FDMA preamble count, reducing to maximum %u", MAX_FDMA_PREAMBLE);
m_fdmaPreamble = MAX_FDMA_PREAMBLE;
}
buffer[5U] = m_fdmaPreamble;
buffer[6U] = modeOverride; buffer[6U] = modeOverride;
@ -1468,7 +1473,7 @@ bool HostCal::writeConfig(uint8_t modeOverride)
buffer[9U] = 1U; buffer[9U] = 1U;
buffer[10U] = m_dmrDelay; buffer[10U] = m_dmrRxDelay;
buffer[11U] = 128U; buffer[11U] = 128U;
buffer[13U] = (uint8_t)(m_txLevel * 2.55F + 0.5F); buffer[13U] = (uint8_t)(m_txLevel * 2.55F + 0.5F);
@ -1562,7 +1567,7 @@ void HostCal::printStatus()
LogMessage(LOG_CAL, " - PTT Invert: %s, RX Invert: %s, TX Invert: %s, DC Blocker: %s, RX Level: %.1f%%, TX Level: %.1f%%, TX DC Offset: %d, RX DC Offset: %d", LogMessage(LOG_CAL, " - PTT Invert: %s, RX Invert: %s, TX Invert: %s, DC Blocker: %s, RX Level: %.1f%%, TX Level: %.1f%%, TX DC Offset: %d, RX DC Offset: %d",
m_pttInvert ? "yes" : "no", m_rxInvert ? "yes" : "no", m_txInvert ? "yes" : "no", m_dcBlocker ? "yes" : "no", m_pttInvert ? "yes" : "no", m_rxInvert ? "yes" : "no", m_txInvert ? "yes" : "no", m_dcBlocker ? "yes" : "no",
m_rxLevel, m_txLevel, m_txDCOffset, m_rxDCOffset); m_rxLevel, m_txLevel, m_txDCOffset, m_rxDCOffset);
LogMessage(LOG_CAL, " - TX Delay: %u (%ums), DMR Delay: %u (%.1fms)", m_txDelay, (m_txDelay * 10), m_dmrDelay, float(m_dmrDelay) * 0.0416666F); LogMessage(LOG_CAL, " - FDMA Preambles: %u (%.1fms), DMR Rx Delay: %u (%.1fms)", m_fdmaPreamble, float(m_fdmaPreamble) * 0.2083F, m_dmrRxDelay, float(m_dmrRxDelay) * 0.0416666F);
LogMessage(LOG_CAL, " - Operating Mode: %s", m_modeStr.c_str()); LogMessage(LOG_CAL, " - Operating Mode: %s", m_modeStr.c_str());
uint8_t buffer[50U]; uint8_t buffer[50U];

@ -86,8 +86,8 @@ private:
int m_txDCOffset; int m_txDCOffset;
int m_rxDCOffset; int m_rxDCOffset;
uint32_t m_txDelay; uint8_t m_fdmaPreamble;
uint32_t m_dmrDelay; uint8_t m_dmrRxDelay;
bool m_debug; bool m_debug;

@ -64,13 +64,13 @@ using namespace modem;
/// <param name="pttInvert">Flag indicating the PTT polarity should be inverted.</param> /// <param name="pttInvert">Flag indicating the PTT polarity should be inverted.</param>
/// <param name="dcBlocker">Flag indicating whether the DSP DC-level blocking should be enabled.</param> /// <param name="dcBlocker">Flag indicating whether the DSP DC-level blocking should be enabled.</param>
/// <param name="cosLockout">Flag indicating whether the COS signal should be used to lockout the modem.</param> /// <param name="cosLockout">Flag indicating whether the COS signal should be used to lockout the modem.</param>
/// <param name="txDelay">Compensation for transmitter to settle in ms.</param> /// <param name="fdmaPreamble">Count of FDMA preambles to transmit before data. (P25/DMR DMO)</param>
/// <param name="dmrDelay">Compensate for delay in transmitter audio chain in ms. Usually DSP based.</param> /// <param name="dmrRxDelay">Compensate for delay in receiver audio chain in ms. Usually DSP based.</param>
/// <param name="disableOFlowReset">Flag indicating whether the ADC/DAC overflow reset logic is disabled.</param> /// <param name="disableOFlowReset">Flag indicating whether the ADC/DAC overflow reset logic is disabled.</param>
/// <param name="trace">Flag indicating whether modem DSP trace is enabled.</param> /// <param name="trace">Flag indicating whether modem DSP trace is enabled.</param>
/// <param name="debug">Flag indicating whether modem DSP debug is enabled.</param> /// <param name="debug">Flag indicating whether modem DSP debug is enabled.</param>
Modem::Modem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker, Modem::Modem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker,
bool cosLockout, uint32_t txDelay, uint32_t dmrDelay, bool disableOFlowReset, bool trace, bool debug) : bool cosLockout, uint8_t fdmaPreamble, uint8_t dmrRxDelay, bool disableOFlowReset, bool trace, bool debug) :
m_port(port), m_port(port),
m_dmrColorCode(0U), m_dmrColorCode(0U),
m_duplex(duplex), m_duplex(duplex),
@ -79,8 +79,8 @@ Modem::Modem(const std::string& port, bool duplex, bool rxInvert, bool txInvert,
m_pttInvert(pttInvert), m_pttInvert(pttInvert),
m_dcBlocker(dcBlocker), m_dcBlocker(dcBlocker),
m_cosLockout(cosLockout), m_cosLockout(cosLockout),
m_txDelay(txDelay), m_fdmaPreamble(fdmaPreamble),
m_dmrDelay(dmrDelay), m_dmrRxDelay(dmrRxDelay),
m_rxLevel(0U), m_rxLevel(0U),
m_cwIdTXLevel(0U), m_cwIdTXLevel(0U),
m_dmrTXLevel(0U), m_dmrTXLevel(0U),
@ -1028,19 +1028,19 @@ bool Modem::sendCWId(const std::string& callsign)
/// <param name="pttInvert">Flag indicating the PTT polarity should be inverted.</param> /// <param name="pttInvert">Flag indicating the PTT polarity should be inverted.</param>
/// <param name="dcBlocker">Flag indicating whether the DSP DC-level blocking should be enabled.</param> /// <param name="dcBlocker">Flag indicating whether the DSP DC-level blocking should be enabled.</param>
/// <param name="cosLockout">Flag indicating whether the COS signal should be used to lockout the modem.</param> /// <param name="cosLockout">Flag indicating whether the COS signal should be used to lockout the modem.</param>
/// <param name="txDelay">Amount of time to delay before transmitting frames.</param> /// <param name="fdmaPreamble">Count of FDMA preambles to transmit before data. (P25/DMR DMO)</param>
/// <param name="dmrDelay"></param> /// <param name="dmrRxDelay">Compensate for delay in receiver audio chain in ms. Usually DSP based.</param>
/// <param name="disableOFlowReset">Flag indicating whether the ADC/DAC overflow reset logic is disabled.</param> /// <param name="disableOFlowReset">Flag indicating whether the ADC/DAC overflow reset logic is disabled.</param>
/// <param name="trace">Flag indicating whether modem DSP trace is enabled.</param> /// <param name="trace">Flag indicating whether modem DSP trace is enabled.</param>
/// <param name="debug">Flag indicating whether modem DSP debug is enabled.</param> /// <param name="debug">Flag indicating whether modem DSP debug is enabled.</param>
Modem* Modem::createModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker, Modem* Modem::createModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker,
bool cosLockout, uint32_t txDelay, uint32_t dmrDelay, bool disableOFlowReset, bool trace, bool debug) bool cosLockout, uint8_t fdmaPreamble, uint8_t dmrRxDelay, bool disableOFlowReset, bool trace, bool debug)
{ {
if (port == NULL_MODEM) { if (port == NULL_MODEM) {
return new NullModem(port, duplex, rxInvert, txInvert, pttInvert, dcBlocker, cosLockout, txDelay, dmrDelay, disableOFlowReset, trace, debug); return new NullModem(port, duplex, rxInvert, txInvert, pttInvert, dcBlocker, cosLockout, fdmaPreamble, dmrRxDelay, disableOFlowReset, trace, debug);
} }
else { else {
return new Modem(port, duplex, rxInvert, txInvert, pttInvert, dcBlocker, cosLockout, txDelay, dmrDelay, disableOFlowReset, trace, debug); return new Modem(port, duplex, rxInvert, txInvert, pttInvert, dcBlocker, cosLockout, fdmaPreamble, dmrRxDelay, disableOFlowReset, trace, debug);
} }
} }
@ -1137,7 +1137,12 @@ bool Modem::writeConfig()
if (m_p25Enabled) if (m_p25Enabled)
buffer[4U] |= 0x08U; buffer[4U] |= 0x08U;
buffer[5U] = m_txDelay / 10U; // In 10ms units if (m_fdmaPreamble > MAX_FDMA_PREAMBLE) {
LogWarning(LOG_P25, "oversized FDMA preamble count, reducing to maximum %u", MAX_FDMA_PREAMBLE);
m_fdmaPreamble = MAX_FDMA_PREAMBLE;
}
buffer[5U] = m_fdmaPreamble;
buffer[6U] = STATE_IDLE; buffer[6U] = STATE_IDLE;
@ -1147,7 +1152,7 @@ bool Modem::writeConfig()
buffer[9U] = m_dmrColorCode; buffer[9U] = m_dmrColorCode;
buffer[10U] = m_dmrDelay; buffer[10U] = m_dmrRxDelay;
buffer[11U] = 128U; // Was OscOffset buffer[11U] = 128U; // Was OscOffset

@ -132,12 +132,13 @@ namespace modem
RSN_INVALID_REQUEST = 4U, RSN_INVALID_REQUEST = 4U,
RSN_RINGBUFF_FULL = 8U, RSN_RINGBUFF_FULL = 8U,
RSN_INVALID_TXDELAY = 10U, RSN_INVALID_FDMA_PREAMBLE = 10U,
RSN_INVALID_MODE = 11U, RSN_INVALID_MODE = 11U,
RSN_INVALID_DMR_CC = 12U, RSN_INVALID_DMR_CC = 12U,
RSN_INVALID_DMR_SLOT = 13U, RSN_INVALID_DMR_SLOT = 13U,
RSN_INVALID_DMR_START = 14U, RSN_INVALID_DMR_START = 14U,
RSN_INVALID_DMR_RX_DELAY = 15U,
RSN_DMR_DISABLED = 63U, RSN_DMR_DISABLED = 63U,
RSN_P25_DISABLED = 64U, RSN_P25_DISABLED = 64U,
@ -145,6 +146,8 @@ namespace modem
const uint8_t DVM_FRAME_START = 0xFEU; const uint8_t DVM_FRAME_START = 0xFEU;
const uint8_t MAX_FDMA_PREAMBLE = 255U;
const uint32_t MAX_RESPONSES = 30U; const uint32_t MAX_RESPONSES = 30U;
const uint32_t BUFFER_LENGTH = 2000U; const uint32_t BUFFER_LENGTH = 2000U;
@ -160,7 +163,7 @@ namespace modem
public: public:
/// <summary>Initializes a new instance of the Modem class.</summary> /// <summary>Initializes a new instance of the Modem class.</summary>
Modem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker, Modem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker,
bool cosLockout, uint32_t txDelay, uint32_t dmrDelay, bool disableOFlowReset, bool trace, bool debug); bool cosLockout, uint8_t fdmaPreamble, uint8_t dmrRxDelay, bool disableOFlowReset, bool trace, bool debug);
/// <summary>Finalizes a instance of the Modem class.</summary> /// <summary>Finalizes a instance of the Modem class.</summary>
virtual ~Modem(); virtual ~Modem();
@ -244,7 +247,7 @@ namespace modem
/// <summary>Helper to create an instance of the Modem class.</summary> /// <summary>Helper to create an instance of the Modem class.</summary>
static Modem* createModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker, static Modem* createModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker,
bool cosLockout, uint32_t txDelay, uint32_t dmrDelay, bool disableOFlowReset, bool trace, bool debug); bool cosLockout, uint8_t fdmaPreamble, uint8_t dmrRxDelay, bool disableOFlowReset, bool trace, bool debug);
private: private:
std::string m_port; std::string m_port;
@ -260,8 +263,8 @@ namespace modem
bool m_dcBlocker; bool m_dcBlocker;
bool m_cosLockout; bool m_cosLockout;
uint32_t m_txDelay; uint8_t m_fdmaPreamble;
uint32_t m_dmrDelay; uint8_t m_dmrRxDelay;
float m_rxLevel; float m_rxLevel;
float m_cwIdTXLevel; float m_cwIdTXLevel;

@ -47,14 +47,14 @@ using namespace modem;
/// <param name="pttInvert">Flag indicating the PTT polarity should be inverted.</param> /// <param name="pttInvert">Flag indicating the PTT polarity should be inverted.</param>
/// <param name="dcBlocker">Flag indicating whether the DSP DC-level blocking should be enabled.</param> /// <param name="dcBlocker">Flag indicating whether the DSP DC-level blocking should be enabled.</param>
/// <param name="cosLockout">Flag indicating whether the COS signal should be used to lockout the modem.</param> /// <param name="cosLockout">Flag indicating whether the COS signal should be used to lockout the modem.</param>
/// <param name="txDelay">Compensation for transmitter to settle in ms.</param> /// <param name="fdmaPreamble">Count of FDMA preambles to transmit before data. (P25/DMR DMO)</param>
/// <param name="dmrDelay">Compensate for delay in transmitter audio chain in ms. Usually DSP based.</param> /// <param name="dmrRxDelay">Compensate for delay in receiver audio chain in ms. Usually DSP based.</param>
/// <param name="disableOFlowReset">Flag indicating whether the ADC/DAC overflow reset logic is disabled.</param> /// <param name="disableOFlowReset">Flag indicating whether the ADC/DAC overflow reset logic is disabled.</param>
/// <param name="trace">Flag indicating whether modem DSP trace is enabled.</param> /// <param name="trace">Flag indicating whether modem DSP trace is enabled.</param>
/// <param name="debug">Flag indicating whether modem DSP debug is enabled.</param> /// <param name="debug">Flag indicating whether modem DSP debug is enabled.</param>
NullModem::NullModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker, NullModem::NullModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker,
bool cosLockout, uint32_t txDelay, uint32_t dmrDelay, bool disableOFlowReset, bool trace, bool debug) : bool cosLockout, uint8_t fdmaPreamble, uint8_t dmrRxDelay, bool disableOFlowReset, bool trace, bool debug) :
Modem(port, duplex, rxInvert, txInvert, pttInvert, dcBlocker, cosLockout, txDelay, dmrDelay, disableOFlowReset, trace, debug) Modem(port, duplex, rxInvert, txInvert, pttInvert, dcBlocker, cosLockout, fdmaPreamble, dmrRxDelay, disableOFlowReset, trace, debug)
{ {
/* stub */ /* stub */
} }

@ -45,7 +45,7 @@ namespace modem
public: public:
/// <summary>Initializes a new instance of the NullModem class.</summary> /// <summary>Initializes a new instance of the NullModem class.</summary>
NullModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker, NullModem(const std::string& port, bool duplex, bool rxInvert, bool txInvert, bool pttInvert, bool dcBlocker,
bool cosLockout, uint32_t txDelay, uint32_t dmrDelay, bool disableOFlowReset, bool trace, bool debug); bool cosLockout, uint8_t fdmaPreamble, uint8_t dmrRxDelay, bool disableOFlowReset, bool trace, bool debug);
/// <summary>Finalizes a instance of the NullModem class.</summary> /// <summary>Finalizes a instance of the NullModem class.</summary>
~NullModem(); ~NullModem();

@ -51,7 +51,7 @@ using namespace p25;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const uint32_t TSBK_PCH_CCH_CNT = 6U; const uint32_t TSBK_PCH_CCH_CNT = 6U;
const uint32_t MAX_PREAMBLE_CNT = 85U; const uint32_t MAX_PREAMBLE_TDU_CNT = 64U;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
@ -107,11 +107,11 @@ Control::Control(uint32_t nac, uint32_t callHang, uint32_t queueSize, modem::Mod
m_ccRunning(false), m_ccRunning(false),
m_ccBcstInterval(ccBcstInterval), m_ccBcstInterval(ccBcstInterval),
m_rfTimeout(1000U, timeout), m_rfTimeout(1000U, timeout),
m_rfTGHang(1000U, tgHang),
m_netTimeout(1000U, timeout), m_netTimeout(1000U, timeout),
m_networkWatchdog(1000U, 0U, 1500U), m_networkWatchdog(1000U, 0U, 1500U),
m_networkTGHang(1000U, tgHang),
m_hangCount(3U * 8U), m_hangCount(3U * 8U),
m_preambleCount(0U), m_tduPreambleCount(8U),
m_ccFrameCnt(0U), m_ccFrameCnt(0U),
m_ccSeq(0U), m_ccSeq(0U),
m_nid(nac), m_nid(nac),
@ -154,7 +154,6 @@ Control::~Control()
void Control::reset() void Control::reset()
{ {
m_rfState = RS_RF_LISTENING; m_rfState = RS_RF_LISTENING;
m_rfLastDstId = 0U;
m_voice->resetRF(); m_voice->resetRF();
m_trunk->resetRF(); m_trunk->resetRF();
@ -176,7 +175,7 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
m_trunk->setCallsign(cwCallsign); m_trunk->setCallsign(cwCallsign);
m_preambleCount = p25Protocol["preambleCount"].as<uint32_t>(4U); m_tduPreambleCount = p25Protocol["tduPreambleCount"].as<uint32_t>(8U);
m_trunk->m_patchSuperGroup = pSuperGroup; m_trunk->m_patchSuperGroup = pSuperGroup;
m_trunk->setSiteData(netId, sysId, rfssId, siteId, 0U, channelId, channelNo); m_trunk->setSiteData(netId, sysId, rfssId, siteId, 0U, channelId, channelNo);
@ -292,6 +291,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
m_rfState = RS_RF_LISTENING; m_rfState = RS_RF_LISTENING;
m_rfLastDstId = 0U; m_rfLastDstId = 0U;
m_rfTGHang.stop();
m_tailOnIdle = true; m_tailOnIdle = true;
@ -307,6 +307,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) { if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) {
m_rfState = RS_RF_LISTENING; m_rfState = RS_RF_LISTENING;
m_rfLastDstId = 0U; m_rfLastDstId = 0U;
m_rfTGHang.stop();
m_tailOnIdle = true; m_tailOnIdle = true;
@ -320,7 +321,6 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
if (data[0U] == TAG_LOST) { if (data[0U] == TAG_LOST) {
m_rfState = RS_RF_LISTENING; m_rfState = RS_RF_LISTENING;
m_rfLastDstId = 0U;
m_voice->resetRF(); m_voice->resetRF();
m_trunk->resetRF(); m_trunk->resetRF();
@ -544,11 +544,14 @@ void Control::clock(uint32_t ms)
m_rfTimeout.clock(ms); m_rfTimeout.clock(ms);
m_netTimeout.clock(ms); m_netTimeout.clock(ms);
if (m_networkTGHang.isRunning()) { if (m_rfTGHang.isRunning()) {
m_networkTGHang.clock(ms); m_rfTGHang.clock(ms);
if (m_networkTGHang.hasExpired()) { if (m_rfTGHang.hasExpired()) {
m_networkTGHang.stop(); m_rfTGHang.stop();
if (m_verbose) {
LogMessage(LOG_RF, "talkgroup hang has expired, lastDstId = %u", m_rfLastDstId);
}
m_rfLastDstId = 0U; m_rfLastDstId = 0U;
} }
} }
@ -716,26 +719,23 @@ void Control::processNetwork()
void Control::writeRF_Nulls() void Control::writeRF_Nulls()
{ {
const uint8_t NULLS_LENGTH_BYTES = 25U; const uint8_t NULLS_LENGTH_BYTES = 25U;
// write null bits (0x00)
uint8_t data[NULLS_LENGTH_BYTES + 2U]; uint8_t data[NULLS_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, NULLS_LENGTH_BYTES); ::memset(data + 2U, 0x00U, NULLS_LENGTH_BYTES);
data[0U] = TAG_EOT; data[0U] = TAG_EOT;
data[1U] = 0x00U; data[1U] = 0x00U;
// fill nulls
for (uint8_t i = 0; i < NULLS_LENGTH_BYTES; i++) {
data[i + 2U] = 0x00U;
}
writeQueueRF(data, NULLS_LENGTH_BYTES + 2U); writeQueueRF(data, NULLS_LENGTH_BYTES + 2U);
} }
/// <summary> /// <summary>
/// Helper to write preamble packet burst. /// Helper to write TDU preamble packet burst.
/// </summary> /// </summary>
void Control::writeRF_Preamble() void Control::writeRF_Preamble()
{ {
if (m_modem->hasTX() || m_preambleCount == 0U) { if (m_modem->hasTX() || m_tduPreambleCount == 0U) {
return; return;
} }
@ -743,12 +743,13 @@ void Control::writeRF_Preamble()
return; return;
} }
if (m_preambleCount > MAX_PREAMBLE_CNT) { if (m_tduPreambleCount > MAX_PREAMBLE_TDU_CNT) {
m_preambleCount = MAX_PREAMBLE_CNT; LogWarning(LOG_P25, "oversized TDU preamble count, reducing to maximum %u", MAX_PREAMBLE_TDU_CNT);
m_tduPreambleCount = MAX_PREAMBLE_TDU_CNT;
} }
writeRF_Nulls(); // write TDUs if requested
for (uint8_t i = 0U; i < m_preambleCount; i++) { for (uint8_t i = 0U; i < m_tduPreambleCount; i++) {
writeRF_TDU(true); writeRF_TDU(true);
} }
} }

@ -146,12 +146,12 @@ namespace p25
uint32_t m_ccBcstInterval; uint32_t m_ccBcstInterval;
Timer m_rfTimeout; Timer m_rfTimeout;
Timer m_rfTGHang;
Timer m_netTimeout; Timer m_netTimeout;
Timer m_networkWatchdog; Timer m_networkWatchdog;
Timer m_networkTGHang;
uint32_t m_hangCount; uint32_t m_hangCount;
uint32_t m_preambleCount; uint32_t m_tduPreambleCount;
uint8_t m_ccFrameCnt; uint8_t m_ccFrameCnt;
uint8_t m_ccSeq; uint8_t m_ccSeq;
@ -178,7 +178,7 @@ namespace p25
/// <summary>Helper to write data nulls.</summary> /// <summary>Helper to write data nulls.</summary>
void writeRF_Nulls(); void writeRF_Nulls();
/// <summary>Helper to write preamble packet burst.</summary> /// <summary>Helper to write TDU preamble packet burst.</summary>
void writeRF_Preamble(); void writeRF_Preamble();
/// <summary>Helper to write a P25 TDU packet.</summary> /// <summary>Helper to write a P25 TDU packet.</summary>
void writeRF_TDU(bool noNetwork); void writeRF_TDU(bool noNetwork);

@ -386,8 +386,6 @@ bool DataPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, da
// write data to RF interface? // write data to RF interface?
if (m_repeatPDU) { if (m_repeatPDU) {
if (m_netDataBlockCnt >= m_netBlocksToFollow) { if (m_netDataBlockCnt >= m_netBlocksToFollow) {
m_p25->writeRF_Preamble();
uint32_t bitLength = ((m_netDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS; uint32_t bitLength = ((m_netDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
uint32_t offset = P25_PREAMBLE_LENGTH_BITS; uint32_t offset = P25_PREAMBLE_LENGTH_BITS;
@ -597,8 +595,6 @@ void DataPacket::writeNetworkRF(const uint8_t dataType, const uint8_t *data, uin
/// </summary> /// </summary>
void DataPacket::writeRF_PDU() void DataPacket::writeRF_PDU()
{ {
m_p25->writeRF_Preamble();
uint32_t bitLength = ((m_rfDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS; uint32_t bitLength = ((m_rfDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
uint32_t offset = P25_PREAMBLE_LENGTH_BITS; uint32_t offset = P25_PREAMBLE_LENGTH_BITS;

@ -75,6 +75,7 @@ namespace p25
const uint8_t P25_SYNC_BYTES[] = { 0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU }; const uint8_t P25_SYNC_BYTES[] = { 0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU };
const uint32_t P25_SYNC_LENGTH_BYTES = 6U; const uint32_t P25_SYNC_LENGTH_BYTES = 6U;
const uint32_t P25_SYNC_LENGTH_BITS = P25_SYNC_LENGTH_BYTES * 8U; const uint32_t P25_SYNC_LENGTH_BITS = P25_SYNC_LENGTH_BYTES * 8U;
const uint8_t P25_START_SYNC = 0x5FU;
const uint32_t P25_PREAMBLE_LENGTH_BYTES = P25_SYNC_LENGTH_BYTES + P25_NID_LENGTH_BYTES; const uint32_t P25_PREAMBLE_LENGTH_BYTES = P25_SYNC_LENGTH_BYTES + P25_NID_LENGTH_BYTES;
const uint32_t P25_PREAMBLE_LENGTH_BITS = P25_SYNC_LENGTH_BITS + P25_NID_LENGTH_BITS; const uint32_t P25_PREAMBLE_LENGTH_BITS = P25_SYNC_LENGTH_BITS + P25_NID_LENGTH_BITS;

@ -319,8 +319,6 @@ bool TrunkPacket::process(uint8_t* data, uint32_t len)
resetStatusCommand(m_rfTSBK); resetStatusCommand(m_rfTSBK);
m_p25->writeRF_Preamble();
switch (m_rfTSBK.getLCO()) { switch (m_rfTSBK.getLCO()) {
case TSBK_IOSP_GRP_VCH: case TSBK_IOSP_GRP_VCH:
// make sure control data is supported // make sure control data is supported
@ -1251,7 +1249,6 @@ TrunkPacket::TrunkPacket(Control* p25, network::BaseNetwork* network, bool debug
m_siteData(), m_siteData(),
m_adjSiteUpdateTimer(1000U), m_adjSiteUpdateTimer(1000U),
m_adjSiteUpdateInterval(ADJ_SITE_TIMER_TIMEOUT), m_adjSiteUpdateInterval(ADJ_SITE_TIMER_TIMEOUT),
m_skipSBFPreamble(false),
m_verbose(verbose), m_verbose(verbose),
m_debug(debug) m_debug(debug)
{ {
@ -1560,12 +1557,6 @@ void TrunkPacket::writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite)
m_p25->m_queue.clear(); m_p25->m_queue.clear();
} }
if (!m_skipSBFPreamble) {
m_p25->writeRF_Preamble();
}
m_skipSBFPreamble = false;
if (m_p25->m_duplex) { if (m_p25->m_duplex) {
data[0U] = TAG_DATA; data[0U] = TAG_DATA;
data[1U] = 0x00U; data[1U] = 0x00U;
@ -1866,7 +1857,7 @@ bool TrunkPacket::writeRF_TSDU_Grant(bool grp, bool skip)
// don't transmit grants if the destination ID's don't match and the network TG hang timer is running // don't transmit grants if the destination ID's don't match and the network TG hang timer is running
if (m_p25->m_rfLastDstId != 0U) { if (m_p25->m_rfLastDstId != 0U) {
if (m_p25->m_rfLastDstId != m_rfTSBK.getDstId() && (m_p25->m_networkTGHang.isRunning() && !m_p25->m_networkTGHang.hasExpired())) { if (m_p25->m_rfLastDstId != m_rfTSBK.getDstId() && (m_p25->m_rfTGHang.isRunning() && !m_p25->m_rfTGHang.hasExpired())) {
m_rfTSBK.setLCO(lco); m_rfTSBK.setLCO(lco);
return false; return false;
} }

@ -179,8 +179,6 @@ namespace p25
Timer m_adjSiteUpdateTimer; Timer m_adjSiteUpdateTimer;
uint32_t m_adjSiteUpdateInterval; uint32_t m_adjSiteUpdateInterval;
bool m_skipSBFPreamble;
bool m_verbose; bool m_verbose;
bool m_debug; bool m_debug;

@ -111,8 +111,9 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
g_interruptP25Control = true; g_interruptP25Control = true;
} }
if (m_p25->m_rfState != RS_RF_LISTENING) if (m_p25->m_rfState != RS_RF_LISTENING) {
m_p25->m_networkTGHang.start(); m_p25->m_rfTGHang.start();
}
// handle individual DUIDs // handle individual DUIDs
if (duid == P25_DUID_HDU) { if (duid == P25_DUID_HDU) {
@ -125,12 +126,6 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_p25->m_queue.clear(); m_p25->m_queue.clear();
resetRF(); resetRF();
resetNet(); resetNet();
m_p25->writeRF_Preamble();
if (!m_p25->m_ccRunning) {
m_p25->m_trunk->writeRF_ControlData(255U, 0U, false);
}
} }
if (m_p25->m_rfState == RS_RF_LISTENING || m_p25->m_rfState == RS_RF_AUDIO) { if (m_p25->m_rfState == RS_RF_LISTENING || m_p25->m_rfState == RS_RF_AUDIO) {
@ -148,6 +143,24 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
LogMessage(LOG_RF, P25_HDU_STR ", HDU_BSDWNACT, dstId = %u, algo = $%02X, kid = $%04X", m_rfLC.getDstId(), m_rfLC.getAlgId(), m_rfLC.getKId()); LogMessage(LOG_RF, P25_HDU_STR ", HDU_BSDWNACT, dstId = %u, algo = $%02X, kid = $%04X", m_rfLC.getDstId(), m_rfLC.getAlgId(), m_rfLC.getKId());
} }
// don't process RF frames if the network isn't in a idle state and the RF destination is the network destination
if (m_p25->m_netState != RS_NET_IDLE && m_rfLC.getDstId() == m_p25->m_netLastDstId) {
LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing network traffic!");
resetRF();
return false;
}
// stop network frames from processing -- RF wants to transmit on a different talkgroup
if (m_p25->m_netState != RS_NET_IDLE) {
LogWarning(LOG_RF, "Traffic collision detect, preempting existing network traffic to new RF traffic, rfDstId = %u, netDstId = %u", m_rfLC.getDstId(),
m_p25->m_netLastDstId);
resetNet();
m_p25->writeRF_TDU(true);
}
m_p25->m_rfTGHang.start();
m_p25->m_rfLastDstId = m_rfLC.getDstId();
m_rfLastHDU.reset(); m_rfLastHDU.reset();
m_rfLastHDU = m_rfLC; m_rfLastHDU = m_rfLC;
} }
@ -161,6 +174,10 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_lastDUID = P25_DUID_LDU1; m_lastDUID = P25_DUID_LDU1;
if (m_p25->m_rfState == RS_RF_LISTENING) { if (m_p25->m_rfState == RS_RF_LISTENING) {
if (!m_p25->m_ccRunning && m_p25->m_voiceOnControl) {
m_p25->m_trunk->writeRF_ControlData(255U, 0U, false);
}
bool ret = m_rfLC.decodeLDU1(data + 2U); bool ret = m_rfLC.decodeLDU1(data + 2U);
if (!ret) { if (!ret) {
return false; return false;
@ -172,13 +189,21 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
uint32_t srcId = m_rfLC.getSrcId(); uint32_t srcId = m_rfLC.getSrcId();
uint32_t dstId = m_rfLC.getDstId(); uint32_t dstId = m_rfLC.getDstId();
// don't process RF frames if the network isn't in a idle state // don't process RF frames if the network isn't in a idle state and the RF destination is the network destination
if (m_p25->m_netState != RS_NET_IDLE && dstId == m_p25->m_netLastDstId) { if (m_p25->m_netState != RS_NET_IDLE && dstId == m_p25->m_netLastDstId) {
LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing network traffic!"); LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing network traffic!");
resetRF(); resetRF();
return false; return false;
} }
// stop network frames from processing -- RF wants to transmit on a different talkgroup
if (m_p25->m_netState != RS_NET_IDLE) {
LogWarning(LOG_RF, "Traffic collision detect, preempting existing network traffic to new RF traffic, rfDstId = %u, netDstId = %u", m_rfLC.getDstId(),
m_p25->m_netLastDstId);
resetNet();
m_p25->writeRF_TDU(true);
}
m_p25->m_trunk->setRFLC(m_rfLC); m_p25->m_trunk->setRFLC(m_rfLC);
// validate the source RID // validate the source RID
@ -238,14 +263,12 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
// are we auto-registering legacy radios to groups? // are we auto-registering legacy radios to groups?
if (m_p25->m_legacyGroupReg && m_rfLC.getGroup()) { if (m_p25->m_legacyGroupReg && m_rfLC.getGroup()) {
if (!m_p25->m_trunk->hasSrcIdGrpAff(srcId, dstId)) { if (!m_p25->m_trunk->hasSrcIdGrpAff(srcId, dstId)) {
m_p25->m_trunk->m_skipSBFPreamble = true; // HACK: force an SBF to skip generating preambles
if (!m_p25->m_trunk->writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId)) { if (!m_p25->m_trunk->writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId)) {
return false; return false;
} }
} }
} }
m_p25->m_trunk->m_skipSBFPreamble = true; // HACK: force an SBF to skip generating preambles
if (!m_p25->m_trunk->writeRF_TSDU_Grant(m_rfLC.getGroup(), false)) { if (!m_p25->m_trunk->writeRF_TSDU_Grant(m_rfLC.getGroup(), false)) {
return false; return false;
} }
@ -282,7 +305,11 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
} }
} }
m_p25->writeRF_Preamble();
m_p25->m_rfState = RS_RF_AUDIO; m_p25->m_rfState = RS_RF_AUDIO;
m_p25->m_rfTGHang.start();
m_p25->m_rfLastDstId = dstId; m_p25->m_rfLastDstId = dstId;
uint8_t buffer[P25_HDU_FRAME_LENGTH_BYTES + 2U]; uint8_t buffer[P25_HDU_FRAME_LENGTH_BYTES + 2U];
@ -895,10 +922,14 @@ void VoicePacket::writeNet_HDU(const lc::LC& control, const data::LowSpeedData&
// don't process network frames if the destination ID's don't match and the network TG hang timer is running // don't process network frames if the destination ID's don't match and the network TG hang timer is running
if (m_p25->m_rfLastDstId != 0U) { if (m_p25->m_rfLastDstId != 0U) {
if (m_p25->m_rfLastDstId != dstId && (m_p25->m_networkTGHang.isRunning() && !m_p25->m_networkTGHang.hasExpired())) { if (m_p25->m_rfLastDstId != dstId && (m_p25->m_rfTGHang.isRunning() && !m_p25->m_rfTGHang.hasExpired())) {
resetNet(); resetNet();
return; return;
} }
if (m_p25->m_rfLastDstId == dstId && (m_p25->m_rfTGHang.isRunning() && !m_p25->m_rfTGHang.hasExpired())) {
m_p25->m_rfTGHang.start();
}
} }
// ensure our srcId and dstId are sane from the last LDU1 // ensure our srcId and dstId are sane from the last LDU1
@ -988,6 +1019,8 @@ void VoicePacket::writeNet_HDU(const lc::LC& control, const data::LowSpeedData&
m_p25->m_trunk->setRFLC(m_rfLC); m_p25->m_trunk->setRFLC(m_rfLC);
m_p25->writeRF_Preamble();
if (m_p25->m_control) { if (m_p25->m_control) {
if (group && (m_lastPatchGroup != dstId) && if (group && (m_lastPatchGroup != dstId) &&
(dstId != m_p25->m_trunk->m_patchSuperGroup)) { (dstId != m_p25->m_trunk->m_patchSuperGroup)) {
@ -1146,10 +1179,14 @@ void VoicePacket::writeNet_LDU1(const lc::LC& control, const data::LowSpeedData&
// don't process network frames if the destination ID's don't match and the network TG hang timer is running // don't process network frames if the destination ID's don't match and the network TG hang timer is running
if (m_p25->m_rfLastDstId != 0U) { if (m_p25->m_rfLastDstId != 0U) {
if (m_p25->m_rfLastDstId != dstId && (m_p25->m_networkTGHang.isRunning() && !m_p25->m_networkTGHang.hasExpired())) { if (m_p25->m_rfLastDstId != dstId && (m_p25->m_rfTGHang.isRunning() && !m_p25->m_rfTGHang.hasExpired())) {
resetNet(); resetNet();
return; return;
} }
if (m_p25->m_rfLastDstId == dstId && (m_p25->m_rfTGHang.isRunning() && !m_p25->m_rfTGHang.hasExpired())) {
m_p25->m_rfTGHang.start();
}
} }
uint8_t serviceOptions = (uint8_t)(m_netLDU1[201U]); uint8_t serviceOptions = (uint8_t)(m_netLDU1[201U]);
@ -1256,6 +1293,14 @@ void VoicePacket::writeNet_LDU2(const lc::LC& control, const data::LowSpeedData&
uint8_t algId = m_netLDU2[126U]; uint8_t algId = m_netLDU2[126U];
uint32_t kId = (m_netLDU2[127U] << 8) + m_netLDU2[128U]; uint32_t kId = (m_netLDU2[127U] << 8) + m_netLDU2[128U];
// don't process network frames if the destination ID's don't match and the network TG hang timer is running
if (m_p25->m_rfLastDstId != 0U) {
if (m_p25->m_rfLastDstId != m_netLastLDU1.getDstId() && (m_p25->m_rfTGHang.isRunning() && !m_p25->m_rfTGHang.hasExpired())) {
resetNet();
return;
}
}
uint8_t mi[P25_MI_LENGTH_BYTES]; uint8_t mi[P25_MI_LENGTH_BYTES];
::memcpy(mi + 0U, m_netLDU2 + 51U, 3U); ::memcpy(mi + 0U, m_netLDU2 + 51U, 3U);
::memcpy(mi + 3U, m_netLDU2 + 76U, 3U); ::memcpy(mi + 3U, m_netLDU2 + 76U, 3U);

Loading…
Cancel
Save

Powered by TurnKey Linux.