mirror of
https://github.com/g4klx/MMDVMHost.git
synced 2025-12-31 21:50:07 +01:00
commit
a87bf4d51c
|
|
@ -85,18 +85,18 @@ bool CDMRControl::processWakeup(const unsigned char* data)
|
|||
return false;
|
||||
}
|
||||
|
||||
void CDMRControl::writeModemSlot1(unsigned char *data, unsigned int len)
|
||||
bool CDMRControl::writeModemSlot1(unsigned char *data, unsigned int len)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
m_slot1.writeModem(data, len);
|
||||
return m_slot1.writeModem(data, len);
|
||||
}
|
||||
|
||||
void CDMRControl::writeModemSlot2(unsigned char *data, unsigned int len)
|
||||
bool CDMRControl::writeModemSlot2(unsigned char *data, unsigned int len)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
m_slot2.writeModem(data, len);
|
||||
return m_slot2.writeModem(data, len);
|
||||
}
|
||||
|
||||
unsigned int CDMRControl::readModemSlot1(unsigned char *data)
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ public:
|
|||
|
||||
bool processWakeup(const unsigned char* data);
|
||||
|
||||
void writeModemSlot1(unsigned char* data, unsigned int len);
|
||||
void writeModemSlot2(unsigned char* data, unsigned int len);
|
||||
bool writeModemSlot1(unsigned char* data, unsigned int len);
|
||||
bool writeModemSlot2(unsigned char* data, unsigned int len);
|
||||
|
||||
unsigned int readModemSlot1(unsigned char* data);
|
||||
unsigned int readModemSlot2(unsigned char* data);
|
||||
|
|
|
|||
97
DMRIDUpdateBM.sh
Normal file
97
DMRIDUpdateBM.sh
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
#! /bin/bash
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# DMRIDUpdate.sh
|
||||
#
|
||||
# Copyright (C) 2016 by Tony Corbett G0WFV
|
||||
# edit by R2AJV
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
#
|
||||
###############################################################################
|
||||
#
|
||||
# On a Linux based system, such as a Raspberry Pi, this script will perform all
|
||||
# the steps required to maintain the DMRIds.dat (or similar) file for you.
|
||||
#
|
||||
# It is designed to run from crontab and will download the latest IDs from the
|
||||
# BM network database and optionally keep a backup of previously
|
||||
# created files for you.
|
||||
#
|
||||
# It will also prune the number of backup files according to a value specified
|
||||
# by you in the configuration below.
|
||||
#
|
||||
# When done, it will restart MMDVMHost to make the ID changes take effect.
|
||||
#
|
||||
# To install in root's crontab use the command ...
|
||||
#
|
||||
# sudo crontab -e
|
||||
#
|
||||
# ... and add the following line to the bottom of the file ...
|
||||
#
|
||||
# 0 0 * * * /path/to/script/DMRIDUpdateBM.sh 1>/dev/null 2>&1
|
||||
#
|
||||
# ... where /path/to/script/ should be replaced by the path to this script.
|
||||
#
|
||||
###############################################################################
|
||||
#
|
||||
# CONFIGURATION
|
||||
#
|
||||
# Full path to DMR ID file
|
||||
DMRIDFILE=/path/to/DMR/ID/file/DMRIds.dat
|
||||
#
|
||||
# How many DMR ID files do you want backed up (0 = do not keep backups)
|
||||
DMRFILEBACKUP=1
|
||||
#
|
||||
# Command line to restart MMDVMHost
|
||||
RESTARTCOMMAND="systemctl restart mmdvmhost.service"
|
||||
# RESTARTCOMMAND="killall MMDVMHost ; /path/to/MMDVMHost/executable/MMDVMHost /path/to/MMDVM/ini/file/MMDVM.ini"
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Do not edit below here
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# Check we are root
|
||||
if [ "$(id -u)" != "0" ]
|
||||
then
|
||||
echo "This script must be run as root" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create backup of old file
|
||||
if [ ${DMRFILEBACKUP} -ne 0 ]
|
||||
then
|
||||
cp ${DMRIDFILE} ${DMRIDFILE}.$(date +%d%m%y)
|
||||
fi
|
||||
|
||||
# Prune backups
|
||||
BACKUPCOUNT=$(ls ${DMRIDFILE}.* | wc -l)
|
||||
BACKUPSTODELETE=$(expr ${BACKUPCOUNT} - ${DMRFILEBACKUP})
|
||||
|
||||
if [ ${BACKUPCOUNT} -gt ${DMRFILEBACKUP} ]
|
||||
then
|
||||
for f in $(ls -tr ${DMRIDFILE}.* | head -${BACKUPSTODELETE})
|
||||
do
|
||||
rm $f
|
||||
done
|
||||
fi
|
||||
|
||||
# Generate new file
|
||||
curl 'http://registry.dstar.su/dmr/DMRIds.php' 2>/dev/null > ${DMRIDFILE}
|
||||
|
||||
# Restart MMDVMHost
|
||||
eval ${RESTARTCOMMAND}
|
||||
243
DMRSlot.cpp
243
DMRSlot.cpp
|
|
@ -100,6 +100,8 @@ m_rfBits(1U),
|
|||
m_netBits(1U),
|
||||
m_rfErrs(0U),
|
||||
m_netErrs(0U),
|
||||
m_rfTimeout(false),
|
||||
m_netTimeout(false),
|
||||
m_lastFrame(NULL),
|
||||
m_lastFrameValid(false),
|
||||
m_rssi(0U),
|
||||
|
|
@ -124,7 +126,7 @@ CDMRSlot::~CDMRSlot()
|
|||
delete[] m_lastFrame;
|
||||
}
|
||||
|
||||
void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
||||
bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
|
|
@ -133,19 +135,24 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
LogMessage("DMR Slot %u, RF voice transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
||||
else
|
||||
LogMessage("DMR Slot %u, RF voice transmission lost, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
writeEndRF(true);
|
||||
return;
|
||||
if (m_rfTimeout) {
|
||||
writeEndRF();
|
||||
return false;
|
||||
} else {
|
||||
writeEndRF(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) {
|
||||
LogMessage("DMR Slot %u, RF data transmission lost", m_slotNo);
|
||||
writeEndRF();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data[0U] == TAG_LOST) {
|
||||
m_rfState = RS_RF_LISTENING;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Have we got RSSI bytes on the end?
|
||||
|
|
@ -183,12 +190,12 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
|
||||
if (dataType == DT_VOICE_LC_HEADER) {
|
||||
if (m_rfState == RS_RF_AUDIO)
|
||||
return;
|
||||
return true;
|
||||
|
||||
CDMRFullLC fullLC;
|
||||
CDMRLC* lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
|
||||
if (lc == NULL)
|
||||
return;
|
||||
return false;
|
||||
|
||||
unsigned int srcId = lc->getSrcId();
|
||||
unsigned int dstId = lc->getDstId();
|
||||
|
|
@ -197,13 +204,13 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||
delete lc;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) {
|
||||
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
|
||||
delete lc;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_rfLC = lc;
|
||||
|
|
@ -226,6 +233,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
data[1U] = 0x00U;
|
||||
|
||||
m_rfTimeoutTimer.start();
|
||||
m_rfTimeout = false;
|
||||
|
||||
m_rfFrames = 0U;
|
||||
m_rfSeqNo = 0U;
|
||||
|
|
@ -264,9 +272,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
}
|
||||
|
||||
LogMessage("DMR Slot %u, received RF voice header from %s to %s%s", m_slotNo, src.c_str(), flco == FLCO_GROUP ? "TG " : "", dst.c_str());
|
||||
|
||||
return true;
|
||||
} else if (dataType == DT_VOICE_PI_HEADER) {
|
||||
if (m_rfState != RS_RF_AUDIO)
|
||||
return;
|
||||
return false;
|
||||
|
||||
// Regenerate the Slot Type
|
||||
slotType.getData(data + 2U);
|
||||
|
|
@ -287,9 +297,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
writeQueueRF(data);
|
||||
|
||||
writeNetworkRF(data, DT_VOICE_PI_HEADER);
|
||||
|
||||
return true;
|
||||
} else if (dataType == DT_TERMINATOR_WITH_LC) {
|
||||
if (m_rfState != RS_RF_AUDIO)
|
||||
return;
|
||||
return false;
|
||||
|
||||
// Regenerate the LC data
|
||||
CDMRFullLC fullLC;
|
||||
|
|
@ -301,15 +313,17 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
// Convert the Data Sync to be from the BS or MS as needed
|
||||
CSync::addDMRDataSync(data + 2U, m_duplex);
|
||||
|
||||
data[0U] = TAG_EOT;
|
||||
data[1U] = 0x00U;
|
||||
if (!m_rfTimeout) {
|
||||
data[0U] = TAG_EOT;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
writeNetworkRF(data, DT_TERMINATOR_WITH_LC);
|
||||
writeNetworkRF(data, DT_TERMINATOR_WITH_LC);
|
||||
writeNetworkRF(data, DT_TERMINATOR_WITH_LC);
|
||||
writeNetworkRF(data, DT_TERMINATOR_WITH_LC);
|
||||
|
||||
if (m_duplex) {
|
||||
for (unsigned int i = 0U; i < m_hangCount; i++)
|
||||
writeQueueRF(data);
|
||||
if (m_duplex) {
|
||||
for (unsigned int i = 0U; i < m_hangCount; i++)
|
||||
writeQueueRF(data);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_rssi != 0U)
|
||||
|
|
@ -317,15 +331,21 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
else
|
||||
LogMessage("DMR Slot %u, received RF end of voice transmission, %.1f seconds, BER: %.1f%%", m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
|
||||
writeEndRF();
|
||||
if (m_rfTimeout) {
|
||||
writeEndRF();
|
||||
return false;
|
||||
} else {
|
||||
writeEndRF();
|
||||
return true;
|
||||
}
|
||||
} else if (dataType == DT_DATA_HEADER) {
|
||||
if (m_rfState == RS_RF_DATA)
|
||||
return;
|
||||
return true;
|
||||
|
||||
CDMRDataHeader dataHeader;
|
||||
bool valid = dataHeader.put(data + 2U);
|
||||
if (!valid)
|
||||
return;
|
||||
return false;
|
||||
|
||||
bool gi = dataHeader.getGI();
|
||||
unsigned int srcId = dataHeader.getSrcId();
|
||||
|
|
@ -333,12 +353,12 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
|
||||
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) {
|
||||
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_rfFrames = dataHeader.getBlocks();
|
||||
|
|
@ -383,15 +403,17 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
LogMessage("DMR Slot %u, ended RF data transmission", m_slotNo);
|
||||
writeEndRF();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (dataType == DT_CSBK) {
|
||||
CDMRCSBK csbk;
|
||||
bool valid = csbk.put(data + 2U);
|
||||
if (!valid)
|
||||
return;
|
||||
return false;
|
||||
|
||||
CSBKO csbko = csbk.getCSBKO();
|
||||
if (csbko == CSBKO_BSDWNACT)
|
||||
return;
|
||||
return false;
|
||||
|
||||
bool gi = csbk.getGI();
|
||||
unsigned int srcId = csbk.getSrcId();
|
||||
|
|
@ -400,12 +422,12 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
if (srcId != 0U || dstId != 0U) {
|
||||
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) {
|
||||
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -448,9 +470,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
LogWarning("DMR Slot %u, unhandled RF CSBK type - 0x%02X", m_slotNo, csbko);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (dataType == DT_RATE_12_DATA || dataType == DT_RATE_34_DATA || dataType == DT_RATE_1_DATA) {
|
||||
if (m_rfState != RS_RF_DATA || m_rfFrames == 0U)
|
||||
return;
|
||||
return false;
|
||||
|
||||
// Regenerate the rate 1/2 payload
|
||||
if (dataType == DT_RATE_12_DATA) {
|
||||
|
|
@ -490,6 +514,8 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
LogMessage("DMR Slot %u, ended RF data transmission", m_slotNo);
|
||||
writeEndRF();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (audioSync) {
|
||||
if (m_rfState == RS_RF_AUDIO) {
|
||||
|
|
@ -508,23 +534,30 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
m_rfBits += 141U;
|
||||
m_rfFrames++;
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
m_rfEmbeddedReadN = (m_rfEmbeddedReadN + 1U) % 2U;
|
||||
m_rfEmbeddedWriteN = (m_rfEmbeddedWriteN + 1U) % 2U;
|
||||
|
||||
m_rfEmbeddedData[m_rfEmbeddedWriteN].reset();
|
||||
|
||||
if (m_duplex)
|
||||
writeQueueRF(data);
|
||||
|
||||
writeNetworkRF(data, DT_VOICE_SYNC, errors);
|
||||
|
||||
m_display->writeDMRRSSI(m_slotNo, m_rssi);
|
||||
|
||||
if (!m_rfTimeout) {
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
if (m_duplex)
|
||||
writeQueueRF(data);
|
||||
|
||||
writeNetworkRF(data, DT_VOICE_SYNC, errors);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if (m_rfState == RS_RF_LISTENING) {
|
||||
m_rfEmbeddedLC.reset();
|
||||
m_rfState = RS_RF_LATE_ENTRY;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (m_rfState == RS_RF_AUDIO) {
|
||||
|
|
@ -626,23 +659,29 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
emb.setLCSS(lcss);
|
||||
emb.getData(data + 2U);
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
if (!m_rfTimeout) {
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
writeNetworkRF(data, DT_VOICE, errors);
|
||||
writeNetworkRF(data, DT_VOICE, errors);
|
||||
|
||||
if (m_embeddedLCOnly) {
|
||||
// Only send the previously received LC
|
||||
lcss = m_rfEmbeddedLC.getData(data + 2U, m_rfN);
|
||||
if (m_embeddedLCOnly) {
|
||||
// Only send the previously received LC
|
||||
lcss = m_rfEmbeddedLC.getData(data + 2U, m_rfN);
|
||||
|
||||
// Regenerate the EMB
|
||||
emb.setColorCode(m_colorCode);
|
||||
emb.setLCSS(lcss);
|
||||
emb.getData(data + 2U);
|
||||
// Regenerate the EMB
|
||||
emb.setColorCode(m_colorCode);
|
||||
emb.setLCSS(lcss);
|
||||
emb.getData(data + 2U);
|
||||
}
|
||||
|
||||
if (m_duplex)
|
||||
writeQueueRF(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_duplex)
|
||||
writeQueueRF(data);
|
||||
return false;
|
||||
} else if (m_rfState == RS_RF_LATE_ENTRY) {
|
||||
CDMREMB emb;
|
||||
emb.putData(data + 2U);
|
||||
|
|
@ -650,7 +689,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
// 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;
|
||||
return false;
|
||||
|
||||
m_rfEmbeddedLC.addData(data + 2U, emb.getLCSS());
|
||||
CDMRLC* lc = m_rfEmbeddedLC.getLC();
|
||||
|
|
@ -662,13 +701,13 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||
delete lc;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) {
|
||||
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
|
||||
delete lc;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_rfLC = lc;
|
||||
|
|
@ -695,6 +734,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
start[1U] = 0x00U;
|
||||
|
||||
m_rfTimeoutTimer.start();
|
||||
m_rfTimeout = false;
|
||||
|
||||
m_rfFrames = 0U;
|
||||
m_rfSeqNo = 0U;
|
||||
|
|
@ -759,9 +799,13 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||
}
|
||||
|
||||
LogMessage("DMR Slot %u, received RF late entry from %s to %s%s", m_slotNo, src.c_str(), flco == FLCO_GROUP ? "TG " : "", dst.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int CDMRSlot::readModem(unsigned char* data)
|
||||
|
|
@ -788,14 +832,8 @@ void CDMRSlot::writeEndRF(bool writeEnd)
|
|||
m_display->clearDMR(m_slotNo);
|
||||
}
|
||||
|
||||
m_rfTimeoutTimer.stop();
|
||||
|
||||
m_rfFrames = 0U;
|
||||
m_rfErrs = 0U;
|
||||
m_rfBits = 1U;
|
||||
|
||||
if (writeEnd) {
|
||||
if (m_netState == RS_NET_IDLE && m_duplex) {
|
||||
if (m_netState == RS_NET_IDLE && m_duplex && !m_rfTimeout) {
|
||||
// Create a dummy start end frame
|
||||
unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U];
|
||||
|
||||
|
|
@ -817,6 +855,13 @@ void CDMRSlot::writeEndRF(bool writeEnd)
|
|||
}
|
||||
}
|
||||
|
||||
m_rfTimeoutTimer.stop();
|
||||
m_rfTimeout = false;
|
||||
|
||||
m_rfFrames = 0U;
|
||||
m_rfErrs = 0U;
|
||||
m_rfBits = 1U;
|
||||
|
||||
delete m_rfLC;
|
||||
m_rfLC = NULL;
|
||||
}
|
||||
|
|
@ -831,17 +876,7 @@ void CDMRSlot::writeEndNet(bool writeEnd)
|
|||
|
||||
m_lastFrameValid = false;
|
||||
|
||||
m_networkWatchdog.stop();
|
||||
m_netTimeoutTimer.stop();
|
||||
m_packetTimer.stop();
|
||||
|
||||
m_netFrames = 0U;
|
||||
m_netLost = 0U;
|
||||
|
||||
m_netErrs = 0U;
|
||||
m_netBits = 1U;
|
||||
|
||||
if (writeEnd) {
|
||||
if (writeEnd && !m_netTimeout) {
|
||||
// Create a dummy start end frame
|
||||
unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U];
|
||||
|
||||
|
|
@ -867,6 +902,17 @@ void CDMRSlot::writeEndNet(bool writeEnd)
|
|||
}
|
||||
}
|
||||
|
||||
m_networkWatchdog.stop();
|
||||
m_netTimeoutTimer.stop();
|
||||
m_packetTimer.stop();
|
||||
m_netTimeout = false;
|
||||
|
||||
m_netFrames = 0U;
|
||||
m_netLost = 0U;
|
||||
|
||||
m_netErrs = 0U;
|
||||
m_netBits = 1U;
|
||||
|
||||
delete m_netLC;
|
||||
m_netLC = NULL;
|
||||
|
||||
|
|
@ -926,6 +972,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||
m_lastFrameValid = false;
|
||||
|
||||
m_netTimeoutTimer.start();
|
||||
m_netTimeout = false;
|
||||
|
||||
m_netFrames = 0U;
|
||||
m_netLost = 0U;
|
||||
|
|
@ -974,6 +1021,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||
m_lastFrameValid = false;
|
||||
|
||||
m_netTimeoutTimer.start();
|
||||
m_netTimeout = false;
|
||||
|
||||
if (m_duplex) {
|
||||
m_queue.clear();
|
||||
|
|
@ -1063,15 +1111,18 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||
// Convert the Data Sync to be from the BS or MS as needed
|
||||
CSync::addDMRDataSync(data + 2U, m_duplex);
|
||||
|
||||
data[0U] = TAG_EOT;
|
||||
data[1U] = 0x00U;
|
||||
if (!m_netTimeout) {
|
||||
data[0U] = TAG_EOT;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
if (m_duplex) {
|
||||
for (unsigned int i = 0U; i < m_hangCount; i++)
|
||||
writeQueueNet(data);
|
||||
} else {
|
||||
for (unsigned int i = 0U; i < 3U; i++)
|
||||
writeQueueNet(data);
|
||||
if (m_duplex) {
|
||||
for (unsigned int i = 0U; i < m_hangCount; i++)
|
||||
writeQueueNet(data);
|
||||
}
|
||||
else {
|
||||
for (unsigned int i = 0U; i < 3U; i++)
|
||||
writeQueueNet(data);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DUMP_DMR)
|
||||
|
|
@ -1155,6 +1206,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||
m_lastFrameValid = false;
|
||||
|
||||
m_netTimeoutTimer.start();
|
||||
m_netTimeout = false;
|
||||
|
||||
if (m_duplex) {
|
||||
m_queue.clear();
|
||||
|
|
@ -1231,7 +1283,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||
insertSilence(data, dmrData.getSeqNo());
|
||||
}
|
||||
|
||||
writeQueueNet(data);
|
||||
if (!m_netTimeout)
|
||||
writeQueueNet(data);
|
||||
|
||||
m_netEmbeddedReadN = (m_netEmbeddedReadN + 1U) % 2U;
|
||||
m_netEmbeddedWriteN = (m_netEmbeddedWriteN + 1U) % 2U;
|
||||
|
|
@ -1363,7 +1416,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||
insertSilence(data, dmrData.getSeqNo());
|
||||
}
|
||||
|
||||
writeQueueNet(data);
|
||||
if (!m_netTimeout)
|
||||
writeQueueNet(data);
|
||||
|
||||
m_packetTimer.start();
|
||||
m_elapsed.start();
|
||||
|
|
@ -1493,7 +1547,20 @@ void CDMRSlot::clock()
|
|||
m_interval.start();
|
||||
|
||||
m_rfTimeoutTimer.clock(ms);
|
||||
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) {
|
||||
if (!m_rfTimeout) {
|
||||
LogMessage("DMR Slot %u, RF user has timed out", m_slotNo);
|
||||
m_rfTimeout = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_netTimeoutTimer.clock(ms);
|
||||
if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired()) {
|
||||
if (!m_netTimeout) {
|
||||
LogMessage("DMR Slot %u, network user has timed out", m_slotNo);
|
||||
m_netTimeout = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_netState == RS_NET_AUDIO || m_netState == RS_NET_DATA) {
|
||||
m_networkWatchdog.clock(ms);
|
||||
|
|
@ -1549,12 +1616,7 @@ void CDMRSlot::writeQueueRF(const unsigned char *data)
|
|||
}
|
||||
|
||||
m_queue.addData(&len, 1U);
|
||||
|
||||
// If the timeout has expired, replace the audio with idles to keep the slot busy
|
||||
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
|
||||
m_queue.addData(m_idle, len);
|
||||
else
|
||||
m_queue.addData(data, len);
|
||||
m_queue.addData(data, len);
|
||||
}
|
||||
|
||||
void CDMRSlot::writeNetworkRF(const unsigned char* data, unsigned char dataType, FLCO flco, unsigned int srcId, unsigned int dstId, unsigned char errors)
|
||||
|
|
@ -1567,10 +1629,6 @@ void CDMRSlot::writeNetworkRF(const unsigned char* data, unsigned char dataType,
|
|||
if (m_network == NULL)
|
||||
return;
|
||||
|
||||
// Don't send to the network if the timeout has expired
|
||||
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
|
||||
return;
|
||||
|
||||
CDMRData dmrData;
|
||||
dmrData.setSlotNo(m_slotNo);
|
||||
dmrData.setDataType(dataType);
|
||||
|
|
@ -1610,12 +1668,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data)
|
|||
}
|
||||
|
||||
m_queue.addData(&len, 1U);
|
||||
|
||||
// If the timeout has expired, replace the audio with idles to keep the slot busy
|
||||
if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired())
|
||||
m_queue.addData(m_idle, len);
|
||||
else
|
||||
m_queue.addData(data, len);
|
||||
m_queue.addData(data, len);
|
||||
}
|
||||
|
||||
void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public:
|
|||
CDMRSlot(unsigned int slotNo, unsigned int timeout);
|
||||
~CDMRSlot();
|
||||
|
||||
void writeModem(unsigned char* data, unsigned int len);
|
||||
bool writeModem(unsigned char* data, unsigned int len);
|
||||
|
||||
unsigned int readModem(unsigned char* data);
|
||||
|
||||
|
|
@ -89,6 +89,8 @@ private:
|
|||
unsigned int m_netBits;
|
||||
unsigned int m_rfErrs;
|
||||
unsigned int m_netErrs;
|
||||
bool m_rfTimeout;
|
||||
bool m_netTimeout;
|
||||
unsigned char* m_lastFrame;
|
||||
bool m_lastFrameValid;
|
||||
unsigned char m_rssi;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@ D-Star: No obvious issues.
|
|||
|
||||
DMR: There is an issue where transmitted data (text messages) isn’t picked up as reliably from an MMDVM than (say) a Hytera repeater. In order to address this, I need to see a trace from a Hytera repeater transmitting text, both from cold (no tx) and when already running. The DMRRX receiver from the DV4RX code in my GitHub repository would do the job, provided you have a DV4mini and a repeater within range.
|
||||
|
||||
Timeouts aren't handled cleany, i.e. the repeater should go off transmit rather than stay on.
|
||||
|
||||
It seems like there is a need to add some idle frames at the beginning of a DMO transmission in order allow older DMR radios to wake up.
|
||||
|
||||
YSF: There is an issue that need addressing: The data sent to aprs.fi from southern hemisphere users isn’t always correct. Maybe the GPS format used by YSF still has some secrets to reveal.
|
||||
|
||||
P25: No obvious issues.
|
||||
|
||||
General: The Windows serial handling isn't working with the STM32 series of devices. This needs investigating.
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ static void sigHandler(int signum)
|
|||
const char* HEADER1 = "This software is for use on amateur radio networks only,";
|
||||
const char* HEADER2 = "it is to be used for educational purposes only. Its use on";
|
||||
const char* HEADER3 = "commercial networks is strictly prohibited.";
|
||||
const char* HEADER4 = "Copyright(C) 2015, 2016 by Jonathan Naylor, G4KLX and others";
|
||||
const char* HEADER4 = "Copyright(C) 2015-2017 by Jonathan Naylor, G4KLX and others";
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
|
@ -484,11 +484,13 @@ int CMMDVMHost::run()
|
|||
m_dmrTXTimer.start();
|
||||
}
|
||||
} else {
|
||||
dmr->writeModemSlot1(data, len);
|
||||
dmrBeaconTimer.stop();
|
||||
m_modeTimer.start();
|
||||
if (m_duplex)
|
||||
m_dmrTXTimer.start();
|
||||
bool ret = dmr->writeModemSlot1(data, len);
|
||||
if (ret) {
|
||||
dmrBeaconTimer.stop();
|
||||
m_modeTimer.start();
|
||||
if (m_duplex)
|
||||
m_dmrTXTimer.start();
|
||||
}
|
||||
}
|
||||
} else if (m_mode != MODE_LOCKOUT) {
|
||||
LogWarning("DMR modem data received when in mode %u", m_mode);
|
||||
|
|
@ -519,11 +521,13 @@ int CMMDVMHost::run()
|
|||
m_dmrTXTimer.start();
|
||||
}
|
||||
} else {
|
||||
dmr->writeModemSlot2(data, len);
|
||||
dmrBeaconTimer.stop();
|
||||
m_modeTimer.start();
|
||||
if (m_duplex)
|
||||
m_dmrTXTimer.start();
|
||||
bool ret = dmr->writeModemSlot2(data, len);
|
||||
if (ret) {
|
||||
dmrBeaconTimer.stop();
|
||||
m_modeTimer.start();
|
||||
if (m_duplex)
|
||||
m_dmrTXTimer.start();
|
||||
}
|
||||
}
|
||||
} else if (m_mode != MODE_LOCKOUT) {
|
||||
LogWarning("DMR modem data received when in mode %u", m_mode);
|
||||
|
|
|
|||
6
Makefile
6
Makefile
|
|
@ -15,17 +15,17 @@ OBJECTS = \
|
|||
|
||||
all: MMDVMHost
|
||||
|
||||
MMDVMHost: gitversion.h $(OBJECTS)
|
||||
MMDVMHost: GitVersion.h $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h
|
||||
|
||||
# Export the current git version if the index file exists, else 000...
|
||||
gitversion.h:
|
||||
GitVersion.h:
|
||||
ifneq ("$(wildcard .git/index)","")
|
||||
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ OBJECTS = \
|
|||
|
||||
all: MMDVMHost
|
||||
|
||||
MMDVMHost: gitversion.h $(OBJECTS)
|
||||
MMDVMHost: GitVersion.h $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h
|
||||
|
||||
# Export the current git version if the index file exists, else 000...
|
||||
gitversion.h:
|
||||
GitVersion.h:
|
||||
ifneq ("$(wildcard .git/index)","")
|
||||
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ OBJECTS = \
|
|||
|
||||
all: MMDVMHost
|
||||
|
||||
MMDVMHost: gitversion.h $(OBJECTS)
|
||||
MMDVMHost: GitVersion.h $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h
|
||||
|
||||
# Export the current git version if the index file exists, else 000...
|
||||
gitversion.h:
|
||||
GitVersion.h:
|
||||
ifneq ("$(wildcard .git/index)","")
|
||||
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ OBJECTS = \
|
|||
|
||||
all: MMDVMHost
|
||||
|
||||
MMDVMHost: gitversion.h $(OBJECTS)
|
||||
MMDVMHost: GitVersion.h $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h
|
||||
|
||||
# Export the current git version if the index file exists, else 000...
|
||||
gitversion.h:
|
||||
GitVersion.h:
|
||||
ifneq ("$(wildcard .git/index)","")
|
||||
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ OBJECTS = \
|
|||
|
||||
all: MMDVMHost
|
||||
|
||||
MMDVMHost: gitversion.h $(OBJECTS)
|
||||
MMDVMHost: GitVersion.h $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h
|
||||
|
||||
# Export the current git version if the index file exists, else 000...
|
||||
gitversion.h:
|
||||
GitVersion.h:
|
||||
ifneq ("$(wildcard .git/index)","")
|
||||
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ OBJECTS = \
|
|||
|
||||
all: MMDVMHost
|
||||
|
||||
MMDVMHost: gitversion.h $(OBJECTS)
|
||||
MMDVMHost: GitVersion.h $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h
|
||||
|
||||
# Export the current git version if the index file exists, else 000...
|
||||
gitversion.h:
|
||||
GitVersion.h:
|
||||
ifneq ("$(wildcard .git/index)","")
|
||||
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ OBJECTS = \
|
|||
|
||||
all: MMDVMHost
|
||||
|
||||
MMDVMHost: gitversion.h $(OBJECTS)
|
||||
MMDVMHost: GitVersion.h $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o MMDVMHost
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ gitversion.h
|
||||
$(RM) MMDVMHost *.o *.d *.bak *~ GitVersion.h
|
||||
|
||||
# Export the current git version if the index file exists, else 000...
|
||||
gitversion.h:
|
||||
GitVersion.h:
|
||||
ifneq ("$(wildcard .git/index)","")
|
||||
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
|
||||
else
|
||||
|
|
|
|||
106
RSSI/RSSI_gm340uhf_RA4NHY.dat
Normal file
106
RSSI/RSSI_gm340uhf_RA4NHY.dat
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#Data to RSSI.dat by RA4NHY
|
||||
#Values in the RSSI.dat file are obtained using the MMDVMCal calibration program (S mode), the high-frequency generator and the Motorola GM340UHF radio station.
|
||||
#For different radio stations, the values are slightly different.
|
||||
#For example, for those GM340 that I had, the discrepancy is about 10 dB.
|
||||
#Therefore, it is desirable to carry out calibration for each radio station.
|
||||
#More about RSSI and a homebrew MMDVM node you can read here https://drive.google.com/file/d/0B_UNZTdPtyZUUjN2d2llV0RtNTQ/view but unfortunately in Russian only
|
||||
#Ivan, RA4NHY
|
||||
|
||||
1045 -43
|
||||
1043 -46
|
||||
1042 -47
|
||||
1041 -48
|
||||
1039 -49
|
||||
1036 -50
|
||||
1030 -51
|
||||
1024 -52
|
||||
1017 -53
|
||||
1009 -54
|
||||
1003 -55
|
||||
992 -56
|
||||
980 -57
|
||||
967 -58
|
||||
955 -59
|
||||
941 -60
|
||||
929 -61
|
||||
916 -62
|
||||
905 -63
|
||||
893 -64
|
||||
884 -65
|
||||
874 -66
|
||||
865 -67
|
||||
856 -68
|
||||
848 -69
|
||||
839 -70
|
||||
831 -71
|
||||
823 -72
|
||||
815 -73
|
||||
805 -74
|
||||
799 -75
|
||||
789 -76
|
||||
778 -77
|
||||
767 -78
|
||||
757 -79
|
||||
746 -80
|
||||
737 -81
|
||||
727 -82
|
||||
719 -83
|
||||
711 -84
|
||||
704 -85
|
||||
696 -86
|
||||
689 -87
|
||||
682 -88
|
||||
674 -89
|
||||
667 -90
|
||||
659 -91
|
||||
650 -92
|
||||
641 -93
|
||||
630 -94
|
||||
621 -95
|
||||
610 -96
|
||||
598 -97
|
||||
586 -98
|
||||
575 -99
|
||||
564 -100
|
||||
554 -101
|
||||
544 -102
|
||||
535 -103
|
||||
526 -104
|
||||
521 -105
|
||||
512 -106
|
||||
504 -107
|
||||
495 -108
|
||||
486 -109
|
||||
477 -110
|
||||
468 -111
|
||||
458 -112
|
||||
449 -113
|
||||
439 -114
|
||||
431 -115
|
||||
421 -116
|
||||
412 -117
|
||||
404 -118
|
||||
395 -119
|
||||
387 -120
|
||||
381 -121
|
||||
374 -122
|
||||
368 -123
|
||||
363 -124
|
||||
360 -125
|
||||
355 -126
|
||||
352 -127
|
||||
348 -128
|
||||
345 -129
|
||||
344 -130
|
||||
342 -131
|
||||
340 -132
|
||||
339 -133
|
||||
338 -134
|
||||
337 -135
|
||||
336 -136
|
||||
335 -137
|
||||
334 -138
|
||||
333 -139
|
||||
332 -140
|
||||
331 -141
|
||||
330 -142
|
||||
Loading…
Reference in a new issue