mirror of
https://github.com/g4klx/MMDVMHost
synced 2025-12-21 23:45:49 +08:00
Merge remote-tracking branch 'g4klx/master'
This commit is contained in:
@@ -85,18 +85,18 @@ bool CDMRControl::processWakeup(const unsigned char* data)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDMRControl::writeModemSlot1(unsigned char *data, unsigned int len)
|
bool CDMRControl::writeModemSlot1(unsigned char *data, unsigned int len)
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
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);
|
assert(data != NULL);
|
||||||
|
|
||||||
m_slot2.writeModem(data, len);
|
return m_slot2.writeModem(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CDMRControl::readModemSlot1(unsigned char *data)
|
unsigned int CDMRControl::readModemSlot1(unsigned char *data)
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ public:
|
|||||||
|
|
||||||
bool processWakeup(const unsigned char* data);
|
bool processWakeup(const unsigned char* data);
|
||||||
|
|
||||||
void writeModemSlot1(unsigned char* data, unsigned int len);
|
bool writeModemSlot1(unsigned char* data, unsigned int len);
|
||||||
void writeModemSlot2(unsigned char* data, unsigned int len);
|
bool writeModemSlot2(unsigned char* data, unsigned int len);
|
||||||
|
|
||||||
unsigned int readModemSlot1(unsigned char* data);
|
unsigned int readModemSlot1(unsigned char* data);
|
||||||
unsigned int readModemSlot2(unsigned char* data);
|
unsigned int readModemSlot2(unsigned char* data);
|
||||||
|
|||||||
98
DMRIDUpdateBM.sh
Normal file
98
DMRIDUpdateBM.sh
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# DMRIDUpdate.sh
|
||||||
|
#
|
||||||
|
# Copyright (C) 2016 by Tony Corbett G0WFV
|
||||||
|
# edit by R2AJV
|
||||||
|
# edit by CT2JAY
|
||||||
|
#
|
||||||
|
# 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 | sed -e 's/[[:space:]]\+/ /g' > ${DMRIDFILE}
|
||||||
|
|
||||||
|
# Restart MMDVMHost
|
||||||
|
eval ${RESTARTCOMMAND}
|
||||||
243
DMRSlot.cpp
243
DMRSlot.cpp
@@ -100,6 +100,8 @@ m_rfBits(1U),
|
|||||||
m_netBits(1U),
|
m_netBits(1U),
|
||||||
m_rfErrs(0U),
|
m_rfErrs(0U),
|
||||||
m_netErrs(0U),
|
m_netErrs(0U),
|
||||||
|
m_rfTimeout(false),
|
||||||
|
m_netTimeout(false),
|
||||||
m_lastFrame(NULL),
|
m_lastFrame(NULL),
|
||||||
m_lastFrameValid(false),
|
m_lastFrameValid(false),
|
||||||
m_rssi(0U),
|
m_rssi(0U),
|
||||||
@@ -124,7 +126,7 @@ CDMRSlot::~CDMRSlot()
|
|||||||
delete[] m_lastFrame;
|
delete[] m_lastFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
bool CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
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);
|
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
|
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));
|
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);
|
if (m_rfTimeout) {
|
||||||
return;
|
writeEndRF();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
writeEndRF(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) {
|
if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) {
|
||||||
LogMessage("DMR Slot %u, RF data transmission lost", m_slotNo);
|
LogMessage("DMR Slot %u, RF data transmission lost", m_slotNo);
|
||||||
writeEndRF();
|
writeEndRF();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[0U] == TAG_LOST) {
|
if (data[0U] == TAG_LOST) {
|
||||||
m_rfState = RS_RF_LISTENING;
|
m_rfState = RS_RF_LISTENING;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have we got RSSI bytes on the end?
|
// 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 (dataType == DT_VOICE_LC_HEADER) {
|
||||||
if (m_rfState == RS_RF_AUDIO)
|
if (m_rfState == RS_RF_AUDIO)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
CDMRFullLC fullLC;
|
CDMRFullLC fullLC;
|
||||||
CDMRLC* lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
|
CDMRLC* lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
|
||||||
if (lc == NULL)
|
if (lc == NULL)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
unsigned int srcId = lc->getSrcId();
|
unsigned int srcId = lc->getSrcId();
|
||||||
unsigned int dstId = lc->getDstId();
|
unsigned int dstId = lc->getDstId();
|
||||||
@@ -197,13 +204,13 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||||
delete lc;
|
delete lc;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) {
|
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);
|
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
|
||||||
delete lc;
|
delete lc;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rfLC = lc;
|
m_rfLC = lc;
|
||||||
@@ -226,6 +233,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
data[1U] = 0x00U;
|
data[1U] = 0x00U;
|
||||||
|
|
||||||
m_rfTimeoutTimer.start();
|
m_rfTimeoutTimer.start();
|
||||||
|
m_rfTimeout = false;
|
||||||
|
|
||||||
m_rfFrames = 0U;
|
m_rfFrames = 0U;
|
||||||
m_rfSeqNo = 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());
|
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) {
|
} else if (dataType == DT_VOICE_PI_HEADER) {
|
||||||
if (m_rfState != RS_RF_AUDIO)
|
if (m_rfState != RS_RF_AUDIO)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Regenerate the Slot Type
|
// Regenerate the Slot Type
|
||||||
slotType.getData(data + 2U);
|
slotType.getData(data + 2U);
|
||||||
@@ -287,9 +297,11 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
writeQueueRF(data);
|
writeQueueRF(data);
|
||||||
|
|
||||||
writeNetworkRF(data, DT_VOICE_PI_HEADER);
|
writeNetworkRF(data, DT_VOICE_PI_HEADER);
|
||||||
|
|
||||||
|
return true;
|
||||||
} else if (dataType == DT_TERMINATOR_WITH_LC) {
|
} else if (dataType == DT_TERMINATOR_WITH_LC) {
|
||||||
if (m_rfState != RS_RF_AUDIO)
|
if (m_rfState != RS_RF_AUDIO)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Regenerate the LC data
|
// Regenerate the LC data
|
||||||
CDMRFullLC fullLC;
|
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
|
// Convert the Data Sync to be from the BS or MS as needed
|
||||||
CSync::addDMRDataSync(data + 2U, m_duplex);
|
CSync::addDMRDataSync(data + 2U, m_duplex);
|
||||||
|
|
||||||
data[0U] = TAG_EOT;
|
if (!m_rfTimeout) {
|
||||||
data[1U] = 0x00U;
|
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) {
|
if (m_duplex) {
|
||||||
for (unsigned int i = 0U; i < m_hangCount; i++)
|
for (unsigned int i = 0U; i < m_hangCount; i++)
|
||||||
writeQueueRF(data);
|
writeQueueRF(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_rssi != 0U)
|
if (m_rssi != 0U)
|
||||||
@@ -317,15 +331,21 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
else
|
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));
|
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) {
|
} else if (dataType == DT_DATA_HEADER) {
|
||||||
if (m_rfState == RS_RF_DATA)
|
if (m_rfState == RS_RF_DATA)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
CDMRDataHeader dataHeader;
|
CDMRDataHeader dataHeader;
|
||||||
bool valid = dataHeader.put(data + 2U);
|
bool valid = dataHeader.put(data + 2U);
|
||||||
if (!valid)
|
if (!valid)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
bool gi = dataHeader.getGI();
|
bool gi = dataHeader.getGI();
|
||||||
unsigned int srcId = dataHeader.getSrcId();
|
unsigned int srcId = dataHeader.getSrcId();
|
||||||
@@ -333,12 +353,12 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
|
|
||||||
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) {
|
if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) {
|
||||||
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
|
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rfFrames = dataHeader.getBlocks();
|
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);
|
LogMessage("DMR Slot %u, ended RF data transmission", m_slotNo);
|
||||||
writeEndRF();
|
writeEndRF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
} else if (dataType == DT_CSBK) {
|
} else if (dataType == DT_CSBK) {
|
||||||
CDMRCSBK csbk;
|
CDMRCSBK csbk;
|
||||||
bool valid = csbk.put(data + 2U);
|
bool valid = csbk.put(data + 2U);
|
||||||
if (!valid)
|
if (!valid)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
CSBKO csbko = csbk.getCSBKO();
|
CSBKO csbko = csbk.getCSBKO();
|
||||||
if (csbko == CSBKO_BSDWNACT)
|
if (csbko == CSBKO_BSDWNACT)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
bool gi = csbk.getGI();
|
bool gi = csbk.getGI();
|
||||||
unsigned int srcId = csbk.getSrcId();
|
unsigned int srcId = csbk.getSrcId();
|
||||||
@@ -400,12 +422,12 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
if (srcId != 0U || dstId != 0U) {
|
if (srcId != 0U || dstId != 0U) {
|
||||||
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) {
|
if (!CDMRAccessControl::validateTGId(m_slotNo, gi, dstId)) {
|
||||||
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, 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);
|
LogWarning("DMR Slot %u, unhandled RF CSBK type - 0x%02X", m_slotNo, csbko);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
} else if (dataType == DT_RATE_12_DATA || dataType == DT_RATE_34_DATA || dataType == DT_RATE_1_DATA) {
|
} 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)
|
if (m_rfState != RS_RF_DATA || m_rfFrames == 0U)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Regenerate the rate 1/2 payload
|
// Regenerate the rate 1/2 payload
|
||||||
if (dataType == DT_RATE_12_DATA) {
|
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);
|
LogMessage("DMR Slot %u, ended RF data transmission", m_slotNo);
|
||||||
writeEndRF();
|
writeEndRF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} else if (audioSync) {
|
} else if (audioSync) {
|
||||||
if (m_rfState == RS_RF_AUDIO) {
|
if (m_rfState == RS_RF_AUDIO) {
|
||||||
@@ -508,23 +534,30 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
m_rfBits += 141U;
|
m_rfBits += 141U;
|
||||||
m_rfFrames++;
|
m_rfFrames++;
|
||||||
|
|
||||||
data[0U] = TAG_DATA;
|
|
||||||
data[1U] = 0x00U;
|
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
if (m_duplex)
|
|
||||||
writeQueueRF(data);
|
|
||||||
|
|
||||||
writeNetworkRF(data, DT_VOICE_SYNC, errors);
|
|
||||||
|
|
||||||
m_display->writeDMRRSSI(m_slotNo, m_rssi);
|
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) {
|
} else if (m_rfState == RS_RF_LISTENING) {
|
||||||
m_rfEmbeddedLC.reset();
|
m_rfEmbeddedLC.reset();
|
||||||
m_rfState = RS_RF_LATE_ENTRY;
|
m_rfState = RS_RF_LATE_ENTRY;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (m_rfState == RS_RF_AUDIO) {
|
if (m_rfState == RS_RF_AUDIO) {
|
||||||
@@ -626,23 +659,29 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
emb.setLCSS(lcss);
|
emb.setLCSS(lcss);
|
||||||
emb.getData(data + 2U);
|
emb.getData(data + 2U);
|
||||||
|
|
||||||
data[0U] = TAG_DATA;
|
if (!m_rfTimeout) {
|
||||||
data[1U] = 0x00U;
|
data[0U] = TAG_DATA;
|
||||||
|
data[1U] = 0x00U;
|
||||||
|
|
||||||
writeNetworkRF(data, DT_VOICE, errors);
|
writeNetworkRF(data, DT_VOICE, errors);
|
||||||
|
|
||||||
if (m_embeddedLCOnly) {
|
if (m_embeddedLCOnly) {
|
||||||
// Only send the previously received LC
|
// Only send the previously received LC
|
||||||
lcss = m_rfEmbeddedLC.getData(data + 2U, m_rfN);
|
lcss = m_rfEmbeddedLC.getData(data + 2U, m_rfN);
|
||||||
|
|
||||||
// Regenerate the EMB
|
// Regenerate the EMB
|
||||||
emb.setColorCode(m_colorCode);
|
emb.setColorCode(m_colorCode);
|
||||||
emb.setLCSS(lcss);
|
emb.setLCSS(lcss);
|
||||||
emb.getData(data + 2U);
|
emb.getData(data + 2U);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_duplex)
|
||||||
|
writeQueueRF(data);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_duplex)
|
return false;
|
||||||
writeQueueRF(data);
|
|
||||||
} else if (m_rfState == RS_RF_LATE_ENTRY) {
|
} else if (m_rfState == RS_RF_LATE_ENTRY) {
|
||||||
CDMREMB emb;
|
CDMREMB emb;
|
||||||
emb.putData(data + 2U);
|
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
|
// If we haven't received an LC yet, then be strict on the color code
|
||||||
unsigned char colorCode = emb.getColorCode();
|
unsigned char colorCode = emb.getColorCode();
|
||||||
if (colorCode != m_colorCode)
|
if (colorCode != m_colorCode)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
m_rfEmbeddedLC.addData(data + 2U, emb.getLCSS());
|
m_rfEmbeddedLC.addData(data + 2U, emb.getLCSS());
|
||||||
CDMRLC* lc = m_rfEmbeddedLC.getLC();
|
CDMRLC* lc = m_rfEmbeddedLC.getLC();
|
||||||
@@ -662,13 +701,13 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
if (!CDMRAccessControl::validateSrcId(srcId)) {
|
||||||
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
LogMessage("DMR Slot %u, RF user %u rejected", m_slotNo, srcId);
|
||||||
delete lc;
|
delete lc;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CDMRAccessControl::validateTGId(m_slotNo, flco == FLCO_GROUP, dstId)) {
|
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);
|
LogMessage("DMR Slot %u, RF user %u rejected for using TG %u", m_slotNo, srcId, dstId);
|
||||||
delete lc;
|
delete lc;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rfLC = lc;
|
m_rfLC = lc;
|
||||||
@@ -695,6 +734,7 @@ void CDMRSlot::writeModem(unsigned char *data, unsigned int len)
|
|||||||
start[1U] = 0x00U;
|
start[1U] = 0x00U;
|
||||||
|
|
||||||
m_rfTimeoutTimer.start();
|
m_rfTimeoutTimer.start();
|
||||||
|
m_rfTimeout = false;
|
||||||
|
|
||||||
m_rfFrames = 0U;
|
m_rfFrames = 0U;
|
||||||
m_rfSeqNo = 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());
|
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)
|
unsigned int CDMRSlot::readModem(unsigned char* data)
|
||||||
@@ -788,14 +832,8 @@ void CDMRSlot::writeEndRF(bool writeEnd)
|
|||||||
m_display->clearDMR(m_slotNo);
|
m_display->clearDMR(m_slotNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rfTimeoutTimer.stop();
|
|
||||||
|
|
||||||
m_rfFrames = 0U;
|
|
||||||
m_rfErrs = 0U;
|
|
||||||
m_rfBits = 1U;
|
|
||||||
|
|
||||||
if (writeEnd) {
|
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
|
// Create a dummy start end frame
|
||||||
unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U];
|
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;
|
delete m_rfLC;
|
||||||
m_rfLC = NULL;
|
m_rfLC = NULL;
|
||||||
}
|
}
|
||||||
@@ -831,17 +876,7 @@ void CDMRSlot::writeEndNet(bool writeEnd)
|
|||||||
|
|
||||||
m_lastFrameValid = false;
|
m_lastFrameValid = false;
|
||||||
|
|
||||||
m_networkWatchdog.stop();
|
if (writeEnd && !m_netTimeout) {
|
||||||
m_netTimeoutTimer.stop();
|
|
||||||
m_packetTimer.stop();
|
|
||||||
|
|
||||||
m_netFrames = 0U;
|
|
||||||
m_netLost = 0U;
|
|
||||||
|
|
||||||
m_netErrs = 0U;
|
|
||||||
m_netBits = 1U;
|
|
||||||
|
|
||||||
if (writeEnd) {
|
|
||||||
// Create a dummy start end frame
|
// Create a dummy start end frame
|
||||||
unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U];
|
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;
|
delete m_netLC;
|
||||||
m_netLC = NULL;
|
m_netLC = NULL;
|
||||||
|
|
||||||
@@ -926,6 +972,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||||||
m_lastFrameValid = false;
|
m_lastFrameValid = false;
|
||||||
|
|
||||||
m_netTimeoutTimer.start();
|
m_netTimeoutTimer.start();
|
||||||
|
m_netTimeout = false;
|
||||||
|
|
||||||
m_netFrames = 0U;
|
m_netFrames = 0U;
|
||||||
m_netLost = 0U;
|
m_netLost = 0U;
|
||||||
@@ -974,6 +1021,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||||||
m_lastFrameValid = false;
|
m_lastFrameValid = false;
|
||||||
|
|
||||||
m_netTimeoutTimer.start();
|
m_netTimeoutTimer.start();
|
||||||
|
m_netTimeout = false;
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
m_queue.clear();
|
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
|
// Convert the Data Sync to be from the BS or MS as needed
|
||||||
CSync::addDMRDataSync(data + 2U, m_duplex);
|
CSync::addDMRDataSync(data + 2U, m_duplex);
|
||||||
|
|
||||||
data[0U] = TAG_EOT;
|
if (!m_netTimeout) {
|
||||||
data[1U] = 0x00U;
|
data[0U] = TAG_EOT;
|
||||||
|
data[1U] = 0x00U;
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
for (unsigned int i = 0U; i < m_hangCount; i++)
|
for (unsigned int i = 0U; i < m_hangCount; i++)
|
||||||
writeQueueNet(data);
|
writeQueueNet(data);
|
||||||
} else {
|
}
|
||||||
for (unsigned int i = 0U; i < 3U; i++)
|
else {
|
||||||
writeQueueNet(data);
|
for (unsigned int i = 0U; i < 3U; i++)
|
||||||
|
writeQueueNet(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DUMP_DMR)
|
#if defined(DUMP_DMR)
|
||||||
@@ -1155,6 +1206,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||||||
m_lastFrameValid = false;
|
m_lastFrameValid = false;
|
||||||
|
|
||||||
m_netTimeoutTimer.start();
|
m_netTimeoutTimer.start();
|
||||||
|
m_netTimeout = false;
|
||||||
|
|
||||||
if (m_duplex) {
|
if (m_duplex) {
|
||||||
m_queue.clear();
|
m_queue.clear();
|
||||||
@@ -1231,7 +1283,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||||||
insertSilence(data, dmrData.getSeqNo());
|
insertSilence(data, dmrData.getSeqNo());
|
||||||
}
|
}
|
||||||
|
|
||||||
writeQueueNet(data);
|
if (!m_netTimeout)
|
||||||
|
writeQueueNet(data);
|
||||||
|
|
||||||
m_netEmbeddedReadN = (m_netEmbeddedReadN + 1U) % 2U;
|
m_netEmbeddedReadN = (m_netEmbeddedReadN + 1U) % 2U;
|
||||||
m_netEmbeddedWriteN = (m_netEmbeddedWriteN + 1U) % 2U;
|
m_netEmbeddedWriteN = (m_netEmbeddedWriteN + 1U) % 2U;
|
||||||
@@ -1363,7 +1416,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
|||||||
insertSilence(data, dmrData.getSeqNo());
|
insertSilence(data, dmrData.getSeqNo());
|
||||||
}
|
}
|
||||||
|
|
||||||
writeQueueNet(data);
|
if (!m_netTimeout)
|
||||||
|
writeQueueNet(data);
|
||||||
|
|
||||||
m_packetTimer.start();
|
m_packetTimer.start();
|
||||||
m_elapsed.start();
|
m_elapsed.start();
|
||||||
@@ -1493,7 +1547,20 @@ void CDMRSlot::clock()
|
|||||||
m_interval.start();
|
m_interval.start();
|
||||||
|
|
||||||
m_rfTimeoutTimer.clock(ms);
|
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);
|
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) {
|
if (m_netState == RS_NET_AUDIO || m_netState == RS_NET_DATA) {
|
||||||
m_networkWatchdog.clock(ms);
|
m_networkWatchdog.clock(ms);
|
||||||
@@ -1549,12 +1616,7 @@ void CDMRSlot::writeQueueRF(const unsigned char *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_queue.addData(&len, 1U);
|
m_queue.addData(&len, 1U);
|
||||||
|
m_queue.addData(data, len);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDMRSlot::writeNetworkRF(const unsigned char* data, unsigned char dataType, FLCO flco, unsigned int srcId, unsigned int dstId, unsigned char errors)
|
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)
|
if (m_network == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Don't send to the network if the timeout has expired
|
|
||||||
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
|
|
||||||
return;
|
|
||||||
|
|
||||||
CDMRData dmrData;
|
CDMRData dmrData;
|
||||||
dmrData.setSlotNo(m_slotNo);
|
dmrData.setSlotNo(m_slotNo);
|
||||||
dmrData.setDataType(dataType);
|
dmrData.setDataType(dataType);
|
||||||
@@ -1610,12 +1668,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_queue.addData(&len, 1U);
|
m_queue.addData(&len, 1U);
|
||||||
|
m_queue.addData(data, len);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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(unsigned int slotNo, unsigned int timeout);
|
||||||
~CDMRSlot();
|
~CDMRSlot();
|
||||||
|
|
||||||
void writeModem(unsigned char* data, unsigned int len);
|
bool writeModem(unsigned char* data, unsigned int len);
|
||||||
|
|
||||||
unsigned int readModem(unsigned char* data);
|
unsigned int readModem(unsigned char* data);
|
||||||
|
|
||||||
@@ -89,6 +89,8 @@ private:
|
|||||||
unsigned int m_netBits;
|
unsigned int m_netBits;
|
||||||
unsigned int m_rfErrs;
|
unsigned int m_rfErrs;
|
||||||
unsigned int m_netErrs;
|
unsigned int m_netErrs;
|
||||||
|
bool m_rfTimeout;
|
||||||
|
bool m_netTimeout;
|
||||||
unsigned char* m_lastFrame;
|
unsigned char* m_lastFrame;
|
||||||
bool m_lastFrameValid;
|
bool m_lastFrameValid;
|
||||||
unsigned char m_rssi;
|
unsigned char m_rssi;
|
||||||
|
|||||||
@@ -78,21 +78,21 @@ const char* HEADER4 = "Copyright(C) 2015-2017 by Jonathan Naylor, G4KLX and othe
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
const char* iniFile = DEFAULT_INI_FILE;
|
const char* iniFile = DEFAULT_INI_FILE;
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
for (int currentArg = 1; currentArg < argc; ++currentArg) {
|
for (int currentArg = 1; currentArg < argc; ++currentArg) {
|
||||||
std::string arg = argv[currentArg];
|
std::string arg = argv[currentArg];
|
||||||
if ((arg == "-v") || (arg == "--version")) {
|
if ((arg == "-v") || (arg == "--version")) {
|
||||||
::fprintf(stdout, "MMDVMHost version %s\n", VERSION);
|
::fprintf(stdout, "MMDVMHost version %s git #%.7s\n", VERSION, gitversion);
|
||||||
return 0;
|
return 0;
|
||||||
} else if (arg.substr(0,1) == "-") {
|
} else if (arg.substr(0,1) == "-") {
|
||||||
::fprintf(stderr, "Usage: MMDVMHost [-v|--version] [filename]\n");
|
::fprintf(stderr, "Usage: MMDVMHost [-v|--version] [filename]\n");
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
iniFile = argv[currentArg];
|
iniFile = argv[currentArg];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(_WIN64)
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
::signal(SIGTERM, sigHandler);
|
::signal(SIGTERM, sigHandler);
|
||||||
@@ -484,11 +484,13 @@ int CMMDVMHost::run()
|
|||||||
m_dmrTXTimer.start();
|
m_dmrTXTimer.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dmr->writeModemSlot1(data, len);
|
bool ret = dmr->writeModemSlot1(data, len);
|
||||||
dmrBeaconTimer.stop();
|
if (ret) {
|
||||||
m_modeTimer.start();
|
dmrBeaconTimer.stop();
|
||||||
if (m_duplex)
|
m_modeTimer.start();
|
||||||
m_dmrTXTimer.start();
|
if (m_duplex)
|
||||||
|
m_dmrTXTimer.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (m_mode != MODE_LOCKOUT) {
|
} else if (m_mode != MODE_LOCKOUT) {
|
||||||
LogWarning("DMR modem data received when in mode %u", m_mode);
|
LogWarning("DMR modem data received when in mode %u", m_mode);
|
||||||
@@ -519,11 +521,13 @@ int CMMDVMHost::run()
|
|||||||
m_dmrTXTimer.start();
|
m_dmrTXTimer.start();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dmr->writeModemSlot2(data, len);
|
bool ret = dmr->writeModemSlot2(data, len);
|
||||||
dmrBeaconTimer.stop();
|
if (ret) {
|
||||||
m_modeTimer.start();
|
dmrBeaconTimer.stop();
|
||||||
if (m_duplex)
|
m_modeTimer.start();
|
||||||
m_dmrTXTimer.start();
|
if (m_duplex)
|
||||||
|
m_dmrTXTimer.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (m_mode != MODE_LOCKOUT) {
|
} else if (m_mode != MODE_LOCKOUT) {
|
||||||
LogWarning("DMR modem data received when in mode %u", m_mode);
|
LogWarning("DMR modem data received when in mode %u", m_mode);
|
||||||
|
|||||||
106
RSSI/RSSI_gm340uhf_RA4NHY.dat
Normal file
106
RSSI/RSSI_gm340uhf_RA4NHY.dat
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#The 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
|
||||||
|
#Anton, 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
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2002-2004,2007-2011,2013,2014-2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2002-2004,2007-2011,2013,2014-2017 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
|
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -40,27 +40,17 @@
|
|||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
const unsigned int BUFFER_LENGTH = 1000U;
|
|
||||||
|
|
||||||
CSerialController::CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS) :
|
CSerialController::CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS) :
|
||||||
m_device(device),
|
m_device(device),
|
||||||
m_speed(speed),
|
m_speed(speed),
|
||||||
m_assertRTS(assertRTS),
|
m_assertRTS(assertRTS),
|
||||||
m_handle(INVALID_HANDLE_VALUE),
|
m_handle(INVALID_HANDLE_VALUE)
|
||||||
m_readOverlapped(),
|
|
||||||
m_writeOverlapped(),
|
|
||||||
m_readBuffer(NULL),
|
|
||||||
m_readLength(0U),
|
|
||||||
m_readPending(false)
|
|
||||||
{
|
{
|
||||||
assert(!device.empty());
|
assert(!device.empty());
|
||||||
|
|
||||||
m_readBuffer = new unsigned char[BUFFER_LENGTH];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CSerialController::~CSerialController()
|
CSerialController::~CSerialController()
|
||||||
{
|
{
|
||||||
delete[] m_readBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSerialController::open()
|
bool CSerialController::open()
|
||||||
@@ -71,7 +61,7 @@ bool CSerialController::open()
|
|||||||
|
|
||||||
std::string baseName = m_device.substr(4U); // Convert "\\.\COM10" to "COM10"
|
std::string baseName = m_device.substr(4U); // Convert "\\.\COM10" to "COM10"
|
||||||
|
|
||||||
m_handle = ::CreateFileA(m_device.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
m_handle = ::CreateFileA(m_device.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (m_handle == INVALID_HANDLE_VALUE) {
|
if (m_handle == INVALID_HANDLE_VALUE) {
|
||||||
LogError("Cannot open device - %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
LogError("Cannot open device - %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||||
return false;
|
return false;
|
||||||
@@ -85,17 +75,18 @@ bool CSerialController::open()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dcb.BaudRate = DWORD(m_speed);
|
dcb.BaudRate = DWORD(m_speed);
|
||||||
dcb.ByteSize = 8;
|
dcb.ByteSize = 8;
|
||||||
dcb.Parity = NOPARITY;
|
dcb.Parity = NOPARITY;
|
||||||
dcb.fParity = FALSE;
|
dcb.fParity = FALSE;
|
||||||
dcb.StopBits = ONESTOPBIT;
|
dcb.StopBits = ONESTOPBIT;
|
||||||
dcb.fInX = FALSE;
|
dcb.fInX = FALSE;
|
||||||
dcb.fOutX = FALSE;
|
dcb.fOutX = FALSE;
|
||||||
dcb.fOutxCtsFlow = FALSE;
|
dcb.fOutxCtsFlow = FALSE;
|
||||||
dcb.fOutxDsrFlow = FALSE;
|
dcb.fOutxDsrFlow = FALSE;
|
||||||
dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
dcb.fDsrSensitivity = FALSE;
|
||||||
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
||||||
|
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||||
|
|
||||||
if (::SetCommState(m_handle, &dcb) == 0) {
|
if (::SetCommState(m_handle, &dcb) == 0) {
|
||||||
LogError("Cannot set the attributes for %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
LogError("Cannot set the attributes for %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||||
@@ -139,16 +130,6 @@ bool CSerialController::open()
|
|||||||
|
|
||||||
::ClearCommError(m_handle, &errCode, NULL);
|
::ClearCommError(m_handle, &errCode, NULL);
|
||||||
|
|
||||||
::memset(&m_readOverlapped, 0x00U, sizeof(OVERLAPPED));
|
|
||||||
::memset(&m_writeOverlapped, 0x00U, sizeof(OVERLAPPED));
|
|
||||||
|
|
||||||
m_readOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
m_writeOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
|
|
||||||
m_readLength = 0U;
|
|
||||||
m_readPending = false;
|
|
||||||
::memset(m_readBuffer, 0x00U, BUFFER_LENGTH);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,49 +160,29 @@ int CSerialController::readNonblock(unsigned char* buffer, unsigned int length)
|
|||||||
assert(m_handle != INVALID_HANDLE_VALUE);
|
assert(m_handle != INVALID_HANDLE_VALUE);
|
||||||
assert(buffer != NULL);
|
assert(buffer != NULL);
|
||||||
|
|
||||||
if (length > BUFFER_LENGTH)
|
|
||||||
length = BUFFER_LENGTH;
|
|
||||||
|
|
||||||
if (m_readPending && length != m_readLength) {
|
|
||||||
::CancelIo(m_handle);
|
|
||||||
m_readPending = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_readLength = length;
|
|
||||||
|
|
||||||
if (length == 0U)
|
if (length == 0U)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!m_readPending) {
|
DWORD errors;
|
||||||
DWORD bytes = 0UL;
|
COMSTAT status;
|
||||||
BOOL res = ::ReadFile(m_handle, m_readBuffer, m_readLength, &bytes, &m_readOverlapped);
|
if (::ClearCommError(m_handle, &errors, &status) == 0) {
|
||||||
if (res) {
|
LogError("Error from ClearCommError for %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||||
::memcpy(buffer, m_readBuffer, bytes);
|
|
||||||
return int(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD error = ::GetLastError();
|
|
||||||
if (error != ERROR_IO_PENDING) {
|
|
||||||
LogError("Error from ReadFile: %04lx", error);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_readPending = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL res = HasOverlappedIoCompleted(&m_readOverlapped);
|
|
||||||
if (!res)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
DWORD bytes = 0UL;
|
|
||||||
res = ::GetOverlappedResult(m_handle, &m_readOverlapped, &bytes, TRUE);
|
|
||||||
if (!res) {
|
|
||||||
LogError("Error from GetOverlappedResult (ReadFile): %04lx", ::GetLastError());
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
::memcpy(buffer, m_readBuffer, bytes);
|
if (status.cbInQue == 0UL)
|
||||||
m_readPending = false;
|
return 0;
|
||||||
|
|
||||||
|
DWORD readLength = status.cbInQue;
|
||||||
|
if (length < readLength)
|
||||||
|
readLength = length;
|
||||||
|
|
||||||
|
DWORD bytes = 0UL;
|
||||||
|
BOOL ret = ::ReadFile(m_handle, buffer, readLength, &bytes, NULL);
|
||||||
|
if (!ret) {
|
||||||
|
LogError("Error from ReadFile for %s: %04lx", m_device.c_str(), ::GetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return int(bytes);
|
return int(bytes);
|
||||||
}
|
}
|
||||||
@@ -238,19 +199,10 @@ int CSerialController::write(const unsigned char* buffer, unsigned int length)
|
|||||||
|
|
||||||
while (ptr < length) {
|
while (ptr < length) {
|
||||||
DWORD bytes = 0UL;
|
DWORD bytes = 0UL;
|
||||||
BOOL res = ::WriteFile(m_handle, buffer + ptr, length - ptr, &bytes, &m_writeOverlapped);
|
BOOL ret = ::WriteFile(m_handle, buffer + ptr, length - ptr, &bytes, NULL);
|
||||||
if (!res) {
|
if (!ret) {
|
||||||
DWORD error = ::GetLastError();
|
LogError("Error from WriteFile for %s: %04lx", m_device.c_str(), ::GetLastError());
|
||||||
if (error != ERROR_IO_PENDING) {
|
return -1;
|
||||||
LogError("Error from WriteFile: %04lx", error);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = ::GetOverlappedResult(m_handle, &m_writeOverlapped, &bytes, TRUE);
|
|
||||||
if (!res) {
|
|
||||||
LogError("Error from GetOverlappedResult (WriteFile): %04lx", ::GetLastError());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr += bytes;
|
ptr += bytes;
|
||||||
@@ -265,9 +217,6 @@ void CSerialController::close()
|
|||||||
|
|
||||||
::CloseHandle(m_handle);
|
::CloseHandle(m_handle);
|
||||||
m_handle = INVALID_HANDLE_VALUE;
|
m_handle = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
::CloseHandle(m_readOverlapped.hEvent);
|
|
||||||
::CloseHandle(m_writeOverlapped.hEvent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
|
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -59,11 +59,6 @@ private:
|
|||||||
bool m_assertRTS;
|
bool m_assertRTS;
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
HANDLE m_handle;
|
HANDLE m_handle;
|
||||||
OVERLAPPED m_readOverlapped;
|
|
||||||
OVERLAPPED m_writeOverlapped;
|
|
||||||
unsigned char* m_readBuffer;
|
|
||||||
unsigned int m_readLength;
|
|
||||||
bool m_readPending;
|
|
||||||
#else
|
#else
|
||||||
int m_fd;
|
int m_fd;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user