Merge remote-tracking branch 'g4klx/nxdn' into nxdn
This commit is contained in:
commit
7c95bb7d6d
14 changed files with 265 additions and 307 deletions
8
Conf.cpp
8
Conf.cpp
|
@ -165,6 +165,7 @@ m_dmrNetworkLocal(0U),
|
|||
m_dmrNetworkPassword(),
|
||||
m_dmrNetworkOptions(),
|
||||
m_dmrNetworkDebug(false),
|
||||
m_dmrNetworkJitterEnabled(true),
|
||||
m_dmrNetworkJitter(300U),
|
||||
m_dmrNetworkSlot1(true),
|
||||
m_dmrNetworkSlot2(true),
|
||||
|
@ -595,6 +596,8 @@ bool CConf::read()
|
|||
m_dmrNetworkOptions = value;
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_dmrNetworkDebug = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "JitterEnabled") == 0)
|
||||
m_dmrNetworkJitterEnabled = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "Jitter") == 0)
|
||||
m_dmrNetworkJitter = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Slot1") == 0)
|
||||
|
@ -1266,6 +1269,11 @@ bool CConf::getDMRNetworkDebug() const
|
|||
return m_dmrNetworkDebug;
|
||||
}
|
||||
|
||||
bool CConf::getDMRNetworkJitterEnabled() const
|
||||
{
|
||||
return m_dmrNetworkJitterEnabled;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRNetworkJitter() const
|
||||
{
|
||||
return m_dmrNetworkJitter;
|
||||
|
|
2
Conf.h
2
Conf.h
|
@ -167,6 +167,7 @@ public:
|
|||
std::string getDMRNetworkPassword() const;
|
||||
std::string getDMRNetworkOptions() const;
|
||||
bool getDMRNetworkDebug() const;
|
||||
bool getDMRNetworkJitterEnabled() const;
|
||||
unsigned int getDMRNetworkJitter() const;
|
||||
bool getDMRNetworkSlot1() const;
|
||||
bool getDMRNetworkSlot2() const;
|
||||
|
@ -360,6 +361,7 @@ private:
|
|||
std::string m_dmrNetworkPassword;
|
||||
std::string m_dmrNetworkOptions;
|
||||
bool m_dmrNetworkDebug;
|
||||
bool m_dmrNetworkJitterEnabled;
|
||||
unsigned int m_dmrNetworkJitter;
|
||||
bool m_dmrNetworkSlot1;
|
||||
bool m_dmrNetworkSlot2;
|
||||
|
|
|
@ -32,7 +32,7 @@ const unsigned int BUFFER_LENGTH = 500U;
|
|||
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
|
||||
|
||||
|
||||
CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, unsigned int jitter) :
|
||||
CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, bool jitterEnabled, unsigned int jitter) :
|
||||
m_address(),
|
||||
m_port(port),
|
||||
m_id(NULL),
|
||||
|
@ -44,6 +44,7 @@ m_socket(local),
|
|||
m_enabled(false),
|
||||
m_slot1(slot1),
|
||||
m_slot2(slot2),
|
||||
m_jitterEnabled(jitterEnabled),
|
||||
m_jitterBuffers(NULL),
|
||||
m_hwType(hwType),
|
||||
m_status(WAITING_CONNECT),
|
||||
|
@ -498,23 +499,23 @@ void CDMRNetwork::receiveData(const unsigned char* data, unsigned int length)
|
|||
if (slotNo == 2U && !m_slot2)
|
||||
return;
|
||||
|
||||
m_jitterBuffers[slotNo]->appendData(data, length);
|
||||
|
||||
/*
|
||||
unsigned char dataType = data[15U] & 0x3FU;
|
||||
if (dataType == (0x20U | DT_CSBK) ||
|
||||
dataType == (0x20U | DT_DATA_HEADER) ||
|
||||
dataType == (0x20U | DT_RATE_1_DATA) ||
|
||||
dataType == (0x20U | DT_RATE_34_DATA) ||
|
||||
dataType == (0x20U | DT_RATE_12_DATA)) {
|
||||
// Data & CSBK frames
|
||||
m_jitterBuffers[slotNo]->appendData(data, length);
|
||||
if (m_jitterEnabled) {
|
||||
unsigned char dataType = data[15U] & 0x3FU;
|
||||
if (dataType == (0x20U | DT_CSBK) ||
|
||||
dataType == (0x20U | DT_DATA_HEADER) ||
|
||||
dataType == (0x20U | DT_RATE_1_DATA) ||
|
||||
dataType == (0x20U | DT_RATE_34_DATA) ||
|
||||
dataType == (0x20U | DT_RATE_12_DATA)) {
|
||||
// Data & CSBK frames
|
||||
m_jitterBuffers[slotNo]->appendData(data, length);
|
||||
} else {
|
||||
// Voice frames
|
||||
unsigned char seqNo = data[4U];
|
||||
m_jitterBuffers[slotNo]->addData(data, length, seqNo);
|
||||
}
|
||||
} else {
|
||||
// Voice frames
|
||||
unsigned char seqNo = data[4U];
|
||||
m_jitterBuffers[slotNo]->addData(data, length, seqNo);
|
||||
m_jitterBuffers[slotNo]->appendData(data, length);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writeLogin()
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
class CDMRNetwork
|
||||
{
|
||||
public:
|
||||
CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, unsigned int jitter);
|
||||
CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, bool jitterEnabled, unsigned int jitter);
|
||||
~CDMRNetwork();
|
||||
|
||||
void setOptions(const std::string& options);
|
||||
|
@ -70,6 +70,7 @@ private:
|
|||
bool m_enabled;
|
||||
bool m_slot1;
|
||||
bool m_slot2;
|
||||
bool m_jitterEnabled;
|
||||
CJitterBuffer** m_jitterBuffers;
|
||||
HW_TYPE m_hwType;
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ Debug=0
|
|||
Enable=1
|
||||
Address=44.131.4.1
|
||||
Port=62031
|
||||
JitterEnabled=1
|
||||
Jitter=500
|
||||
# Local=62032
|
||||
Password=PASSWORD
|
||||
|
|
|
@ -1035,6 +1035,7 @@ bool CMMDVMHost::createDMRNetwork()
|
|||
unsigned int id = m_conf.getDMRId();
|
||||
std::string password = m_conf.getDMRNetworkPassword();
|
||||
bool debug = m_conf.getDMRNetworkDebug();
|
||||
bool jitterEnabled = m_conf.getDMRNetworkJitterEnabled();
|
||||
unsigned int jitter = m_conf.getDMRNetworkJitter();
|
||||
bool slot1 = m_conf.getDMRNetworkSlot1();
|
||||
bool slot2 = m_conf.getDMRNetworkSlot2();
|
||||
|
@ -1048,12 +1049,13 @@ bool CMMDVMHost::createDMRNetwork()
|
|||
LogInfo(" Local: %u", local);
|
||||
else
|
||||
LogInfo(" Local: random");
|
||||
LogInfo(" Jitter Buffer: %s", jitterEnabled ? "enabled" : "disabled");
|
||||
LogInfo(" Jitter: %ums", jitter);
|
||||
LogInfo(" Slot 1: %s", slot1 ? "enabled" : "disabled");
|
||||
LogInfo(" Slot 2: %s", slot2 ? "enabled" : "disabled");
|
||||
LogInfo(" Mode Hang: %us", m_dmrNetModeHang);
|
||||
|
||||
m_dmrNetwork = new CDMRNetwork(address, port, local, id, password, m_duplex, VERSION, debug, slot1, slot2, hwType, jitter);
|
||||
m_dmrNetwork = new CDMRNetwork(address, port, local, id, password, m_duplex, VERSION, debug, slot1, slot2, hwType, jitterEnabled, jitter);
|
||||
|
||||
std::string options = m_conf.getDMRNetworkOptions();
|
||||
if (!options.empty()) {
|
||||
|
|
150
NXDNCRC.cpp
150
NXDNCRC.cpp
|
@ -22,30 +22,25 @@
|
|||
#include <cassert>
|
||||
|
||||
const uint8_t BIT_MASK_TABLE1[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
|
||||
const uint16_t BIT_MASK_TABLE2[] = { 0x8000U, 0x4000U, 0x2000U, 0x1000U, 0x0800U, 0x0400U, 0x0200U, 0x0100U,
|
||||
0x0080U, 0x0040U, 0x0020U, 0x0010U, 0x0008U, 0x0004U, 0x0002U, 0x0001U };
|
||||
|
||||
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE1[(i)&7])
|
||||
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7])
|
||||
|
||||
#define READ_BIT2(p,i) (p[(i)>>4] & BIT_MASK_TABLE2[(i)&15])
|
||||
|
||||
bool CNXDNCRC::checkCRC6(const unsigned char* in, unsigned int length)
|
||||
{
|
||||
assert(in != NULL);
|
||||
|
||||
uint8_t crc[1U];
|
||||
crc[0U] = createCRC6(in, length);
|
||||
uint8_t crc = createCRC6(in, length);
|
||||
|
||||
unsigned int n = length;
|
||||
for (unsigned int i = 0U; i < 6U; i++, n++) {
|
||||
bool b1 = READ_BIT1(crc, i);
|
||||
bool b2 = READ_BIT1(in, n);
|
||||
if (b1 != b2)
|
||||
return false;
|
||||
uint8_t temp[1U];
|
||||
temp[0U] = 0x00U;
|
||||
unsigned int j = length;
|
||||
for (unsigned int i = 2U; i < 8U; i++, j++) {
|
||||
bool b = READ_BIT1(in, j);
|
||||
WRITE_BIT1(temp, i, b);
|
||||
}
|
||||
|
||||
return true;
|
||||
return crc == temp[0U];
|
||||
}
|
||||
|
||||
void CNXDNCRC::encodeCRC6(unsigned char* in, unsigned int length)
|
||||
|
@ -56,7 +51,7 @@ void CNXDNCRC::encodeCRC6(unsigned char* in, unsigned int length)
|
|||
crc[0U] = createCRC6(in, length);
|
||||
|
||||
unsigned int n = length;
|
||||
for (unsigned int i = 0U; i < 6U; i++, n++) {
|
||||
for (unsigned int i = 2U; i < 8U; i++, n++) {
|
||||
bool b = READ_BIT1(crc, i);
|
||||
WRITE_BIT1(in, n, b);
|
||||
}
|
||||
|
@ -66,30 +61,36 @@ bool CNXDNCRC::checkCRC12(const unsigned char* in, unsigned int length)
|
|||
{
|
||||
assert(in != NULL);
|
||||
|
||||
uint16_t crc[1U];
|
||||
crc[0U] = createCRC12(in, length);
|
||||
uint16_t crc = createCRC12(in, length);
|
||||
uint8_t temp1[2U];
|
||||
temp1[0U] = (crc >> 8) & 0xFFU;
|
||||
temp1[1U] = (crc >> 0) & 0xFFU;
|
||||
|
||||
unsigned int n = length;
|
||||
for (unsigned int i = 0U; i < 12U; i++, n++) {
|
||||
bool b1 = READ_BIT2(crc, i);
|
||||
bool b2 = READ_BIT1(in, n);
|
||||
if (b1 != b2)
|
||||
return false;
|
||||
uint8_t temp2[2U];
|
||||
temp2[0U] = 0x00U;
|
||||
temp2[1U] = 0x00U;
|
||||
unsigned int j = length;
|
||||
for (unsigned int i = 4U; i < 16U; i++, j++) {
|
||||
bool b = READ_BIT1(in, j);
|
||||
WRITE_BIT1(temp2, i, b);
|
||||
}
|
||||
|
||||
return true;
|
||||
return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U];
|
||||
}
|
||||
|
||||
void CNXDNCRC::encodeCRC12(unsigned char* in, unsigned int length)
|
||||
{
|
||||
assert(in != NULL);
|
||||
|
||||
uint16_t crc[1U];
|
||||
crc[0U] = createCRC12(in, length);
|
||||
uint16_t crc = createCRC12(in, length);
|
||||
|
||||
uint8_t temp[2U];
|
||||
temp[0U] = (crc >> 8) & 0xFFU;
|
||||
temp[1U] = (crc >> 0) & 0xFFU;
|
||||
|
||||
unsigned int n = length;
|
||||
for (unsigned int i = 0U; i < 12U; i++, n++) {
|
||||
bool b = READ_BIT2(crc, i);
|
||||
for (unsigned int i = 4U; i < 16U; i++, n++) {
|
||||
bool b = READ_BIT1(temp, i);
|
||||
WRITE_BIT1(in, n, b);
|
||||
}
|
||||
}
|
||||
|
@ -98,123 +99,90 @@ bool CNXDNCRC::checkCRC15(const unsigned char* in, unsigned int length)
|
|||
{
|
||||
assert(in != NULL);
|
||||
|
||||
uint16_t crc[1U];
|
||||
crc[0U] = createCRC15(in, length);
|
||||
uint16_t crc = createCRC15(in, length);
|
||||
uint8_t temp1[2U];
|
||||
temp1[0U] = (crc >> 8) & 0xFFU;
|
||||
temp1[1U] = (crc >> 0) & 0xFFU;
|
||||
|
||||
unsigned int n = length;
|
||||
for (unsigned int i = 0U; i < 15U; i++, n++) {
|
||||
bool b1 = READ_BIT2(crc, i);
|
||||
bool b2 = READ_BIT1(in, n);
|
||||
if (b1 != b2)
|
||||
return false;
|
||||
uint16_t temp2[2U];
|
||||
temp2[0U] = 0x00U;
|
||||
temp2[1U] = 0x00U;
|
||||
unsigned int j = length;
|
||||
for (unsigned int i = 1U; i < 16U; i++, j++) {
|
||||
bool b = READ_BIT1(in, j);
|
||||
WRITE_BIT1(temp2, i, b);
|
||||
}
|
||||
|
||||
return true;
|
||||
return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U];
|
||||
}
|
||||
|
||||
void CNXDNCRC::encodeCRC15(unsigned char* in, unsigned int length)
|
||||
{
|
||||
assert(in != NULL);
|
||||
|
||||
uint16_t crc[1U];
|
||||
crc[0U] = createCRC15(in, length);
|
||||
uint16_t crc = createCRC15(in, length);
|
||||
|
||||
uint8_t temp[2U];
|
||||
temp[0U] = (crc >> 8) & 0xFFU;
|
||||
temp[1U] = (crc >> 0) & 0xFFU;
|
||||
|
||||
unsigned int n = length;
|
||||
for (unsigned int i = 0U; i < 15U; i++, n++) {
|
||||
bool b = READ_BIT2(crc, i);
|
||||
for (unsigned int i = 1U; i < 16U; i++, n++) {
|
||||
bool b = READ_BIT1(temp, i);
|
||||
WRITE_BIT1(in, n, b);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t CNXDNCRC::createCRC6(const unsigned char* in, unsigned int length)
|
||||
{
|
||||
uint8_t crc = 0x3EU;
|
||||
uint8_t crc = 0x3FU;
|
||||
|
||||
for (unsigned int i = 0U; i < length; i++) {
|
||||
bool bit1 = READ_BIT1(in, i) != 0x00U;
|
||||
bool bit2 = (crc & 0x20U) == 0x20U;
|
||||
|
||||
crc <<= 1;
|
||||
crc &= 0x3EU;
|
||||
|
||||
if (bit1)
|
||||
crc |= 0x01U;
|
||||
|
||||
if (bit2)
|
||||
crc ^= 0x27U;
|
||||
|
||||
crc &= 0x3FU;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0U; i < 6U; i++) {
|
||||
bool bit = (crc & 0x20U) == 0x20U;
|
||||
|
||||
crc <<= 1;
|
||||
|
||||
if (bit)
|
||||
if (bit1 ^ bit2)
|
||||
crc ^= 0x27U;
|
||||
}
|
||||
|
||||
return (crc & 0x3FU) << 2U;
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint16_t CNXDNCRC::createCRC12(const unsigned char* in, unsigned int length)
|
||||
{
|
||||
uint16_t crc = 0x0D9EU;
|
||||
uint16_t crc = 0x0FFFU;
|
||||
|
||||
for (unsigned int i = 0U; i < length; i++) {
|
||||
bool bit1 = READ_BIT1(in, i) != 0x00U;
|
||||
bool bit2 = (crc & 0x0800U) == 0x0800U;
|
||||
|
||||
crc <<= 1;
|
||||
crc &= 0x0FFEU;
|
||||
|
||||
if (bit1)
|
||||
crc |= 0x0001U;
|
||||
|
||||
if (bit2)
|
||||
crc ^= 0x080FU;
|
||||
|
||||
crc &= 0x0FFFU;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0U; i < 12U; i++) {
|
||||
bool bit = (crc & 0x0800U) == 0x0800U;
|
||||
|
||||
crc <<= 1;
|
||||
|
||||
if (bit)
|
||||
if (bit1 ^ bit2)
|
||||
crc ^= 0x080FU;
|
||||
}
|
||||
|
||||
return (crc & 0x0FFFU) << 4U;
|
||||
return crc & 0x0FFFU;
|
||||
}
|
||||
|
||||
uint16_t CNXDNCRC::createCRC15(const unsigned char* in, unsigned int length)
|
||||
{
|
||||
uint16_t crc = 0x02E4U;
|
||||
uint16_t crc = 0x7FFFU;
|
||||
|
||||
for (unsigned int i = 0U; i < length; i++) {
|
||||
bool bit1 = READ_BIT1(in, i) != 0x00U;
|
||||
bool bit2 = (crc & 0x4000U) == 0x4000U;
|
||||
|
||||
crc <<= 1;
|
||||
crc &= 0x7FFEU;
|
||||
|
||||
if (bit1)
|
||||
crc |= 0x0001U;
|
||||
|
||||
if (bit2)
|
||||
crc ^= 0x4CC5U;
|
||||
|
||||
crc &= 0x7FFFU;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0U; i < 15U; i++) {
|
||||
bool bit = (crc & 0x4000U) == 0x4000U;
|
||||
|
||||
crc <<= 1;
|
||||
|
||||
if (bit)
|
||||
if (bit1 ^ bit2)
|
||||
crc ^= 0x4CC5U;
|
||||
}
|
||||
|
||||
return (crc & 0x7FFFU) << 1U;
|
||||
return crc & 0x7FFFU;
|
||||
}
|
||||
|
|
324
NXDNControl.cpp
324
NXDNControl.cpp
|
@ -91,9 +91,9 @@ bool CNXDNControl::writeModem(unsigned char *data, unsigned int len)
|
|||
|
||||
if (type == TAG_LOST && m_rfState == RS_RF_AUDIO) {
|
||||
if (m_rssi != 0U)
|
||||
LogMessage("NXDN, transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
||||
LogMessage("NXDN, transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
||||
else
|
||||
LogMessage("NXDN, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
LogMessage("NXDN, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
writeEndRF();
|
||||
return false;
|
||||
}
|
||||
|
@ -174,183 +174,172 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne
|
|||
unsigned char ran = sacch.getRAN();
|
||||
if (ran != m_ran && ran != 0U)
|
||||
return false;
|
||||
} else if (m_rfState == RS_RF_LISTENING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX Reconstruct invalid LICH
|
||||
|
||||
if (usc == NXDN_LICH_USC_SACCH_NS) {
|
||||
// The SACCH on a non-superblock frame is usually an idle and not interesting apart from the RAN.
|
||||
CNXDNFACCH1 facch11;
|
||||
bool valid1 = facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS);
|
||||
|
||||
CNXDNFACCH1 facch12;
|
||||
bool valid2 = facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);
|
||||
CNXDNFACCH1 facch;
|
||||
bool valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS);
|
||||
if (!valid)
|
||||
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);
|
||||
if (!valid)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[10U];
|
||||
if (valid1)
|
||||
facch11.getData(buffer);
|
||||
else if (valid2)
|
||||
facch12.getData(buffer);
|
||||
facch.getData(buffer);
|
||||
|
||||
if (valid1 || valid2) {
|
||||
CNXDNLayer3 layer3;
|
||||
layer3.decode(buffer, NXDN_FACCH1_LENGTH_BITS);
|
||||
CNXDNLayer3 layer3;
|
||||
layer3.decode(buffer, NXDN_FACCH1_LENGTH_BITS);
|
||||
|
||||
unsigned char type = layer3.getMessageType();
|
||||
if (type == NXDN_MESSAGE_TYPE_TX_REL) {
|
||||
if (m_rfState != RS_RF_AUDIO) {
|
||||
m_rfState = RS_RF_LISTENING;
|
||||
m_rfMask = 0x00U;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (m_selfOnly) {
|
||||
unsigned short srcId = layer3.getSourceUnitId();
|
||||
if (srcId != m_id) {
|
||||
m_rfState = RS_RF_REJECTED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
CSync::addNXDNSync(data + 2U);
|
||||
|
||||
CNXDNLICH lich = m_rfLastLICH;
|
||||
lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
|
||||
lich.encode(data + 2U);
|
||||
|
||||
CNXDNSACCH sacch;
|
||||
sacch.setRAN(m_ran);
|
||||
sacch.setStructure(NXDN_SR_SINGLE);
|
||||
sacch.setData(SACCH_IDLE);
|
||||
sacch.encode(data + 2U);
|
||||
|
||||
if (valid1) {
|
||||
facch11.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS);
|
||||
facch11.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);
|
||||
} else {
|
||||
facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS);
|
||||
facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);
|
||||
}
|
||||
|
||||
scrambler(data + 2U);
|
||||
|
||||
// writeNetwork(data, m_rfFrames, );
|
||||
|
||||
#if defined(DUMP_NXDN)
|
||||
writeFile(data + 2U);
|
||||
#endif
|
||||
|
||||
if (m_duplex)
|
||||
writeQueueRF(data);
|
||||
|
||||
if (type == NXDN_MESSAGE_TYPE_TX_REL) {
|
||||
m_rfFrames++;
|
||||
if (m_rssi != 0U)
|
||||
LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
||||
else
|
||||
LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
writeEndRF();
|
||||
return true;
|
||||
} else {
|
||||
m_rfFrames = 0U;
|
||||
m_rfErrs = 0U;
|
||||
m_rfBits = 1U;
|
||||
m_rfTimeoutTimer.start();
|
||||
m_rfState = RS_RF_AUDIO;
|
||||
|
||||
m_minRSSI = m_rssi;
|
||||
m_maxRSSI = m_rssi;
|
||||
m_aveRSSI = m_rssi;
|
||||
m_rssiCount = 1U;
|
||||
#if defined(DUMP_NXDN)
|
||||
openFile();
|
||||
#endif
|
||||
m_rfLayer3 = layer3;
|
||||
|
||||
unsigned short srcId = m_rfLayer3.getSourceUnitId();
|
||||
unsigned short dstId = m_rfLayer3.getDestinationGroupId();
|
||||
bool grp = m_rfLayer3.getIsGroup();
|
||||
|
||||
std::string source = m_lookup->find(srcId);
|
||||
LogMessage("NXDN, received RF voice transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
|
||||
m_display->writeNXDN(source.c_str(), grp, dstId, "R");
|
||||
|
||||
m_rfState = RS_RF_AUDIO;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
unsigned char message[3U];
|
||||
sacch.getData(message);
|
||||
|
||||
unsigned char structure = sacch.getStructure();
|
||||
switch (structure) {
|
||||
case NXDN_SR_1_4:
|
||||
m_rfMask |= 0x01U;
|
||||
m_rfLayer3.decode(message, 18U, 0U);
|
||||
break;
|
||||
case NXDN_SR_2_4:
|
||||
m_rfMask |= 0x02U;
|
||||
m_rfLayer3.decode(message, 18U, 18U);
|
||||
break;
|
||||
case NXDN_SR_3_4:
|
||||
m_rfMask |= 0x04U;
|
||||
m_rfLayer3.decode(message, 18U, 36U);
|
||||
break;
|
||||
case NXDN_SR_4_4:
|
||||
m_rfMask |= 0x08U;
|
||||
m_rfLayer3.decode(message, 18U, 54U);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_rfMask != 0x0FU)
|
||||
return false;
|
||||
|
||||
unsigned char messageType = m_rfLayer3.getMessageType();
|
||||
if (messageType != NXDN_MESSAGE_TYPE_VCALL)
|
||||
return false;
|
||||
|
||||
unsigned short srcId = m_rfLayer3.getSourceUnitId();
|
||||
unsigned short dstId = m_rfLayer3.getDestinationGroupId();
|
||||
bool grp = m_rfLayer3.getIsGroup();
|
||||
|
||||
if (m_selfOnly) {
|
||||
if (srcId != m_id) {
|
||||
m_rfState = RS_RF_REJECTED;
|
||||
unsigned char type = layer3.getMessageType();
|
||||
if (type == NXDN_MESSAGE_TYPE_TX_REL) {
|
||||
if (m_rfState != RS_RF_AUDIO) {
|
||||
m_rfState = RS_RF_LISTENING;
|
||||
m_rfMask = 0x00U;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
bool hasInfo = layer3.getHasInfo();
|
||||
if (m_rfState == RS_RF_LISTENING && m_selfOnly && hasInfo) {
|
||||
unsigned short srcId = layer3.getSourceUnitId();
|
||||
if (srcId != m_id) {
|
||||
m_rfState = RS_RF_REJECTED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_rfFrames = 0U;
|
||||
m_rfErrs = 0U;
|
||||
m_rfBits = 1U;
|
||||
m_rfTimeoutTimer.start();
|
||||
m_rfState = RS_RF_AUDIO;
|
||||
data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
CSync::addNXDNSync(data + 2U);
|
||||
|
||||
CNXDNLICH lich = m_rfLastLICH;
|
||||
lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
|
||||
lich.encode(data + 2U);
|
||||
|
||||
CNXDNSACCH sacch;
|
||||
sacch.setRAN(m_ran);
|
||||
sacch.setStructure(NXDN_SR_SINGLE);
|
||||
sacch.setData(SACCH_IDLE);
|
||||
sacch.encode(data + 2U);
|
||||
|
||||
facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS);
|
||||
facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);
|
||||
|
||||
scrambler(data + 2U);
|
||||
|
||||
// writeNetwork(data, m_rfFrames, );
|
||||
|
||||
m_minRSSI = m_rssi;
|
||||
m_maxRSSI = m_rssi;
|
||||
m_aveRSSI = m_rssi;
|
||||
m_rssiCount = 1U;
|
||||
#if defined(DUMP_NXDN)
|
||||
openFile();
|
||||
writeFile(data + 2U);
|
||||
#endif
|
||||
std::string source = m_lookup->find(srcId);
|
||||
LogMessage("NXDN, received RF voice transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
|
||||
m_display->writeNXDN(source.c_str(), grp, dstId, "R");
|
||||
if (m_duplex)
|
||||
writeQueueRF(data);
|
||||
|
||||
m_rfState = RS_RF_AUDIO;
|
||||
if (type == NXDN_MESSAGE_TYPE_TX_REL) {
|
||||
m_rfFrames++;
|
||||
if (m_rssi != 0U)
|
||||
LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
||||
else
|
||||
LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 25.0F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
writeEndRF();
|
||||
} else {
|
||||
m_rfFrames = 0U;
|
||||
m_rfErrs = 0U;
|
||||
m_rfBits = 1U;
|
||||
m_rfTimeoutTimer.start();
|
||||
m_rfState = RS_RF_AUDIO;
|
||||
m_minRSSI = m_rssi;
|
||||
m_maxRSSI = m_rssi;
|
||||
m_aveRSSI = m_rssi;
|
||||
m_rssiCount = 1U;
|
||||
#if defined(DUMP_NXDN)
|
||||
openFile();
|
||||
#endif
|
||||
m_rfLayer3 = layer3;
|
||||
|
||||
unsigned short srcId = m_rfLayer3.getSourceUnitId();
|
||||
unsigned short dstId = m_rfLayer3.getDestinationGroupId();
|
||||
bool grp = m_rfLayer3.getIsGroup();
|
||||
|
||||
std::string source = m_lookup->find(srcId);
|
||||
LogMessage("NXDN, received RF header from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
|
||||
m_display->writeNXDN(source.c_str(), grp, dstId, "R");
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (m_rfState == RS_RF_LISTENING) {
|
||||
unsigned char message[3U];
|
||||
sacch.getData(message);
|
||||
|
||||
unsigned char structure = sacch.getStructure();
|
||||
switch (structure) {
|
||||
case NXDN_SR_1_4:
|
||||
m_rfMask |= 0x01U;
|
||||
m_rfLayer3.decode(message, 18U, 0U);
|
||||
break;
|
||||
case NXDN_SR_2_4:
|
||||
m_rfMask |= 0x02U;
|
||||
m_rfLayer3.decode(message, 18U, 18U);
|
||||
break;
|
||||
case NXDN_SR_3_4:
|
||||
m_rfMask |= 0x04U;
|
||||
m_rfLayer3.decode(message, 18U, 36U);
|
||||
break;
|
||||
case NXDN_SR_4_4:
|
||||
m_rfMask |= 0x08U;
|
||||
m_rfLayer3.decode(message, 18U, 54U);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_rfMask != 0x0FU)
|
||||
return false;
|
||||
|
||||
bool hasInfo = m_rfLayer3.getHasInfo();
|
||||
if (!hasInfo)
|
||||
return false;
|
||||
|
||||
unsigned short srcId = m_rfLayer3.getSourceUnitId();
|
||||
unsigned short dstId = m_rfLayer3.getDestinationGroupId();
|
||||
bool grp = m_rfLayer3.getIsGroup();
|
||||
|
||||
if (m_selfOnly) {
|
||||
if (srcId != m_id) {
|
||||
m_rfState = RS_RF_REJECTED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_rfFrames = 0U;
|
||||
m_rfErrs = 0U;
|
||||
m_rfBits = 1U;
|
||||
m_rfTimeoutTimer.start();
|
||||
m_rfState = RS_RF_AUDIO;
|
||||
|
||||
m_minRSSI = m_rssi;
|
||||
m_maxRSSI = m_rssi;
|
||||
m_aveRSSI = m_rssi;
|
||||
m_rssiCount = 1U;
|
||||
#if defined(DUMP_NXDN)
|
||||
openFile();
|
||||
#endif
|
||||
std::string source = m_lookup->find(srcId);
|
||||
LogMessage("NXDN, received RF late entry from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
|
||||
m_display->writeNXDN(source.c_str(), grp, dstId, "R");
|
||||
|
||||
m_rfState = RS_RF_AUDIO;
|
||||
}
|
||||
}
|
||||
|
||||
// if (m_rfState == RS_RF_AUDIO) {
|
||||
if (m_rfState == RS_RF_AUDIO) {
|
||||
// Regenerate the sync
|
||||
CSync::addNXDNSync(data + 2U);
|
||||
|
||||
|
@ -460,24 +449,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne
|
|||
m_rfFrames++;
|
||||
|
||||
m_display->writeNXDNRSSI(m_rssi);
|
||||
|
||||
#ifdef notdef
|
||||
// Process end of audio here
|
||||
if (endofdata) {
|
||||
if (m_rfState == RS_RF_AUDIO) {
|
||||
if (m_rssi != 0U)
|
||||
LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
|
||||
else
|
||||
LogMessage("NXDN, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 10.0F, float(m_rfErrs * 100U) / float(m_rfBits));
|
||||
|
||||
writeEndRF();
|
||||
} else {
|
||||
m_rfState = RS_RF_LISTENING;
|
||||
m_rfMask = 0x00U;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||
|
||||
|
@ -72,7 +73,7 @@ void CNXDNConvolution::decode(uint8_t s0, uint8_t s1)
|
|||
for (uint8_t i = 0U; i < NUM_OF_STATES_D2; i++) {
|
||||
uint8_t j = i * 2U;
|
||||
|
||||
uint16_t metric = abs(BRANCH_TABLE1[i] - s0) + abs(BRANCH_TABLE2[i] - s1);
|
||||
uint16_t metric = ::abs(BRANCH_TABLE1[i] - s0) + ::abs(BRANCH_TABLE2[i] - s1);
|
||||
|
||||
uint16_t m0 = m_oldMetrics[i] + metric;
|
||||
uint16_t m1 = m_oldMetrics[i + NUM_OF_STATES_D2] + (M - metric);
|
||||
|
|
|
@ -115,7 +115,7 @@ bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset)
|
|||
|
||||
conv.chainback(m_data, 96U);
|
||||
|
||||
CUtils::dump("NXDN, FACCH1 decoded", m_data, 12U);
|
||||
// CUtils::dump("NXDN, FACCH1 decoded", m_data, 12U);
|
||||
|
||||
return CNXDNCRC::checkCRC12(m_data, 80U);
|
||||
}
|
||||
|
@ -126,11 +126,7 @@ void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const
|
|||
|
||||
unsigned char temp1[12U];
|
||||
::memset(temp1, 0x00U, 12U);
|
||||
|
||||
for (unsigned int i = 0U; i < 80U; i++) {
|
||||
bool b = READ_BIT1(m_data, i);
|
||||
WRITE_BIT1(temp1, i, b);
|
||||
}
|
||||
::memcpy(temp1, m_data, 10U);
|
||||
|
||||
CNXDNCRC::encodeCRC12(temp1, 80U);
|
||||
|
||||
|
|
|
@ -93,6 +93,15 @@ unsigned char CNXDNLayer3::getCallOptions() const
|
|||
return m_data[2U] & 0x1FU;
|
||||
}
|
||||
|
||||
bool CNXDNLayer3::getHasInfo() const
|
||||
{
|
||||
unsigned char type = getMessageType();
|
||||
|
||||
return type != NXDN_MESSAGE_TYPE_IDLE &&
|
||||
type != NXDN_MESSAGE_TYPE_VCALL_IV &&
|
||||
type != NXDN_MESSAGE_TYPE_SDCALL_IV;
|
||||
}
|
||||
|
||||
CNXDNLayer3& CNXDNLayer3::operator=(const CNXDNLayer3& layer3)
|
||||
{
|
||||
if (&layer3 != this)
|
||||
|
|
|
@ -34,6 +34,7 @@ public:
|
|||
unsigned short getDestinationGroupId() const;
|
||||
bool getIsGroup() const;
|
||||
unsigned char getCallOptions() const;
|
||||
bool getHasInfo() const;
|
||||
|
||||
CNXDNLayer3& operator=(const CNXDNLayer3& layer3);
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ bool CNXDNSACCH::decode(const unsigned char* data)
|
|||
|
||||
conv.chainback(m_data, 36U);
|
||||
|
||||
CUtils::dump("NXDN, SACCH decoded", m_data, 4U);
|
||||
// CUtils::dump("NXDN, SACCH decoded", m_data, 4U);
|
||||
|
||||
return CNXDNCRC::checkCRC6(m_data, 26U);
|
||||
}
|
||||
|
@ -127,14 +127,14 @@ void CNXDNSACCH::encode(unsigned char* data) const
|
|||
|
||||
CNXDNCRC::encodeCRC6(temp1, 26U);
|
||||
|
||||
CUtils::dump("NXDN, SACCH encoded with CRC", temp1, 4U);
|
||||
// CUtils::dump("NXDN, SACCH encoded with CRC", temp1, 4U);
|
||||
|
||||
unsigned char temp2[8U];
|
||||
unsigned char temp2[9U];
|
||||
|
||||
CNXDNConvolution conv;
|
||||
conv.encode(temp1, temp2, 36U);
|
||||
|
||||
// CUtils::dump("NXDN, SACCH convolved", temp2, 8U);
|
||||
// CUtils::dump("NXDN, SACCH convolved", temp2, 9U);
|
||||
|
||||
unsigned char temp3[8U];
|
||||
|
||||
|
|
18
NXDNUDCH.cpp
18
NXDNUDCH.cpp
|
@ -93,7 +93,7 @@ bool CNXDNUDCH::decode(const unsigned char* data)
|
|||
{
|
||||
assert(data != NULL);
|
||||
|
||||
CUtils::dump("NXDN, UDCH/FACCH2 input", data, 44U);
|
||||
// CUtils::dump("NXDN, UDCH/FACCH2 input", data, 44U);
|
||||
|
||||
unsigned char temp1[44U];
|
||||
|
||||
|
@ -103,7 +103,7 @@ bool CNXDNUDCH::decode(const unsigned char* data)
|
|||
WRITE_BIT1(temp1, i, b);
|
||||
}
|
||||
|
||||
CUtils::dump("NXDN, UDCH/FACCH2 de-interleaved", temp1, 44U);
|
||||
// CUtils::dump("NXDN, UDCH/FACCH2 de-interleaved", temp1, 44U);
|
||||
|
||||
uint8_t temp2[420U];
|
||||
|
||||
|
@ -136,7 +136,7 @@ bool CNXDNUDCH::decode(const unsigned char* data)
|
|||
|
||||
conv.chainback(m_data, 203U);
|
||||
|
||||
CUtils::dump("NXDN, UDCH/FACCH2 decoded", m_data, 25U);
|
||||
// CUtils::dump("NXDN, UDCH/FACCH2 decoded", m_data, 25U);
|
||||
|
||||
return CNXDNCRC::checkCRC15(m_data, 184U);
|
||||
}
|
||||
|
@ -147,22 +147,18 @@ void CNXDNUDCH::encode(unsigned char* data) const
|
|||
|
||||
unsigned char temp1[25U];
|
||||
::memset(temp1, 0x00U, 25U);
|
||||
|
||||
for (unsigned int i = 0U; i < 184U; i++) {
|
||||
bool b = READ_BIT1(m_data, i);
|
||||
WRITE_BIT1(temp1, i, b);
|
||||
}
|
||||
::memcpy(temp1, m_data, 23U);
|
||||
|
||||
CNXDNCRC::encodeCRC15(temp1, 184U);
|
||||
|
||||
CUtils::dump("NXDN, UDCH/FACCH2 encoded with CRC", temp1, 25U);
|
||||
// CUtils::dump("NXDN, UDCH/FACCH2 encoded with CRC", temp1, 25U);
|
||||
|
||||
unsigned char temp2[51U];
|
||||
|
||||
CNXDNConvolution conv;
|
||||
conv.encode(temp1, temp2, 203U);
|
||||
|
||||
CUtils::dump("NXDN, UDCH/FACCH2 convolved", temp2, 51U);
|
||||
// CUtils::dump("NXDN, UDCH/FACCH2 convolved", temp2, 51U);
|
||||
|
||||
unsigned char temp3[44U];
|
||||
|
||||
|
@ -178,7 +174,7 @@ void CNXDNUDCH::encode(unsigned char* data) const
|
|||
}
|
||||
}
|
||||
|
||||
CUtils::dump("NXDN, UDCH/FACCH2 punctured", temp3, 44U);
|
||||
// CUtils::dump("NXDN, UDCH/FACCH2 punctured", temp3, 44U);
|
||||
|
||||
for (unsigned int i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) {
|
||||
unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;
|
||||
|
|
Loading…
Reference in a new issue