mirror of
https://github.com/g4klx/MMDVMHost
synced 2025-12-21 15:09:23 +08:00
Experimenting using real data, moving forward with start and end blocks.
This commit is contained in:
147
NXDNControl.cpp
147
NXDNControl.cpp
@@ -63,7 +63,7 @@ m_rfBits(1U),
|
|||||||
m_netErrs(0U),
|
m_netErrs(0U),
|
||||||
m_netBits(1U),
|
m_netBits(1U),
|
||||||
m_rfLastLICH(),
|
m_rfLastLICH(),
|
||||||
m_rfSACCHMessage(),
|
m_rfLayer3(),
|
||||||
m_rfMask(0x00U),
|
m_rfMask(0x00U),
|
||||||
m_netN(0U),
|
m_netN(0U),
|
||||||
m_rssiMapper(rssiMapper),
|
m_rssiMapper(rssiMapper),
|
||||||
@@ -103,13 +103,9 @@ bool CNXDNControl::writeModem(unsigned char *data, unsigned int len)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == TAG_LOST && m_rfState == RS_RF_REJECTED) {
|
|
||||||
m_rfState = RS_RF_LISTENING;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == TAG_LOST) {
|
if (type == TAG_LOST) {
|
||||||
m_rfState = RS_RF_LISTENING;
|
m_rfState = RS_RF_LISTENING;
|
||||||
|
m_rfMask = 0x00U;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,11 +176,117 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (m_rfState == RS_RF_LISTENING && !valid)
|
// XXX Reconstruct invalid LICH
|
||||||
// return false;
|
|
||||||
|
|
||||||
// XXX the FACCH1 data in the header may also be useful
|
if (usc == NXDN_LICH_USC_SACCH_NS) {
|
||||||
if (m_rfState == RS_RF_LISTENING) {
|
// 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);
|
||||||
|
|
||||||
|
unsigned char buffer[10U];
|
||||||
|
if (valid1)
|
||||||
|
facch11.getData(buffer);
|
||||||
|
else if (valid2)
|
||||||
|
facch12.getData(buffer);
|
||||||
|
|
||||||
|
if (valid1 || valid2) {
|
||||||
|
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];
|
unsigned char message[3U];
|
||||||
sacch.getData(message);
|
sacch.getData(message);
|
||||||
|
|
||||||
@@ -192,19 +294,19 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne
|
|||||||
switch (structure) {
|
switch (structure) {
|
||||||
case NXDN_SR_1_4:
|
case NXDN_SR_1_4:
|
||||||
m_rfMask |= 0x01U;
|
m_rfMask |= 0x01U;
|
||||||
m_rfSACCHMessage.decode(message, 18U, 0U);
|
m_rfLayer3.decode(message, 18U, 0U);
|
||||||
break;
|
break;
|
||||||
case NXDN_SR_2_4:
|
case NXDN_SR_2_4:
|
||||||
m_rfMask |= 0x02U;
|
m_rfMask |= 0x02U;
|
||||||
m_rfSACCHMessage.decode(message, 18U, 18U);
|
m_rfLayer3.decode(message, 18U, 18U);
|
||||||
break;
|
break;
|
||||||
case NXDN_SR_3_4:
|
case NXDN_SR_3_4:
|
||||||
m_rfMask |= 0x04U;
|
m_rfMask |= 0x04U;
|
||||||
m_rfSACCHMessage.decode(message, 18U, 36U);
|
m_rfLayer3.decode(message, 18U, 36U);
|
||||||
break;
|
break;
|
||||||
case NXDN_SR_4_4:
|
case NXDN_SR_4_4:
|
||||||
m_rfMask |= 0x08U;
|
m_rfMask |= 0x08U;
|
||||||
m_rfSACCHMessage.decode(message, 18U, 54U);
|
m_rfLayer3.decode(message, 18U, 54U);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -213,13 +315,13 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne
|
|||||||
if (m_rfMask != 0x0FU)
|
if (m_rfMask != 0x0FU)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
unsigned char messageType = m_rfSACCHMessage.getMessageType();
|
unsigned char messageType = m_rfLayer3.getMessageType();
|
||||||
if (messageType != NXDN_MESSAGE_TYPE_VCALL)
|
if (messageType != NXDN_MESSAGE_TYPE_VCALL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
unsigned short srcId = m_rfSACCHMessage.getSourceUnitId();
|
unsigned short srcId = m_rfLayer3.getSourceUnitId();
|
||||||
unsigned short dstId = m_rfSACCHMessage.getDestinationGroupId();
|
unsigned short dstId = m_rfLayer3.getDestinationGroupId();
|
||||||
bool grp = m_rfSACCHMessage.getIsGroup();
|
bool grp = m_rfLayer3.getIsGroup();
|
||||||
|
|
||||||
if (m_selfOnly) {
|
if (m_selfOnly) {
|
||||||
if (srcId != m_id) {
|
if (srcId != m_id) {
|
||||||
@@ -263,7 +365,7 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne
|
|||||||
// XXX Regenerate SACCH here
|
// XXX Regenerate SACCH here
|
||||||
|
|
||||||
// Regenerate the audio and interpret the FACCH1 data
|
// Regenerate the audio and interpret the FACCH1 data
|
||||||
unsigned char voiceMode = m_rfSACCHMessage.getCallOptions() & 0x07U;
|
unsigned char voiceMode = m_rfLayer3.getCallOptions() & 0x07U;
|
||||||
|
|
||||||
if (option == NXDN_LICH_STEAL_NONE) {
|
if (option == NXDN_LICH_STEAL_NONE) {
|
||||||
CAMBEFEC ambe;
|
CAMBEFEC ambe;
|
||||||
@@ -358,7 +460,6 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne
|
|||||||
m_rfFrames++;
|
m_rfFrames++;
|
||||||
|
|
||||||
m_display->writeNXDNRSSI(m_rssi);
|
m_display->writeNXDNRSSI(m_rssi);
|
||||||
// }
|
|
||||||
|
|
||||||
#ifdef notdef
|
#ifdef notdef
|
||||||
// Process end of audio here
|
// Process end of audio here
|
||||||
@@ -835,9 +936,9 @@ void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count, b
|
|||||||
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
|
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unsigned short srcId = m_rfSACCHMessage.getSourceUnitId();
|
unsigned short srcId = m_rfLayer3.getSourceUnitId();
|
||||||
unsigned short dstId = m_rfSACCHMessage.getDestinationGroupId();
|
unsigned short dstId = m_rfLayer3.getDestinationGroupId();
|
||||||
bool grp = m_rfSACCHMessage.getIsGroup();
|
bool grp = m_rfLayer3.getIsGroup();
|
||||||
|
|
||||||
m_network->write(data + 2U, srcId, grp, dstId, count % 256U, end);
|
m_network->write(data + 2U, srcId, grp, dstId, count % 256U, end);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ private:
|
|||||||
unsigned int m_netErrs;
|
unsigned int m_netErrs;
|
||||||
unsigned int m_netBits;
|
unsigned int m_netBits;
|
||||||
CNXDNLICH m_rfLastLICH;
|
CNXDNLICH m_rfLastLICH;
|
||||||
CNXDNLayer3 m_rfSACCHMessage;
|
CNXDNLayer3 m_rfLayer3;
|
||||||
unsigned char m_rfMask;
|
unsigned char m_rfMask;
|
||||||
unsigned char m_netN;
|
unsigned char m_netN;
|
||||||
CRSSIInterpolator* m_rssiMapper;
|
CRSSIInterpolator* m_rssiMapper;
|
||||||
|
|||||||
@@ -101,4 +101,6 @@ const unsigned char NXDN_DATA_CALL_OPTION_DUPLEX = 0x10U;
|
|||||||
const unsigned char NXDN_DATA_CALL_OPTION_4800 = 0x00U;
|
const unsigned char NXDN_DATA_CALL_OPTION_4800 = 0x00U;
|
||||||
const unsigned char NXDN_DATA_CALL_OPTION_9600 = 0x02U;
|
const unsigned char NXDN_DATA_CALL_OPTION_9600 = 0x02U;
|
||||||
|
|
||||||
|
const unsigned char SACCH_IDLE[] = { NXDN_MESSAGE_TYPE_IDLE, 0x00U, 0x00U };
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset)
|
|||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
CUtils::dump("NXDN, FACCH1 input", data, 18U);
|
// CUtils::dump("NXDN, FACCH1 input", data, 18U);
|
||||||
|
|
||||||
unsigned char temp1[18U];
|
unsigned char temp1[18U];
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset)
|
|||||||
WRITE_BIT1(temp1, i, b);
|
WRITE_BIT1(temp1, i, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
CUtils::dump("NXDN, FACCH1 de-interleaved", temp1, 18U);
|
// CUtils::dump("NXDN, FACCH1 de-interleaved", temp1, 18U);
|
||||||
|
|
||||||
uint8_t temp2[192U];
|
uint8_t temp2[192U];
|
||||||
|
|
||||||
@@ -129,14 +129,14 @@ void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const
|
|||||||
|
|
||||||
CNXDNCRC::encodeCRC12(temp1, 80U);
|
CNXDNCRC::encodeCRC12(temp1, 80U);
|
||||||
|
|
||||||
CUtils::dump("NXDN, FACCH1 encoded with CRC", temp1, 12U);
|
// CUtils::dump("NXDN, FACCH1 encoded with CRC", temp1, 12U);
|
||||||
|
|
||||||
unsigned char temp2[24U];
|
unsigned char temp2[24U];
|
||||||
|
|
||||||
CNXDNConvolution conv;
|
CNXDNConvolution conv;
|
||||||
conv.encode(temp1, temp2, 96U);
|
conv.encode(temp1, temp2, 96U);
|
||||||
|
|
||||||
CUtils::dump("NXDN, FACCH1 convolved", temp2, 24U);
|
// CUtils::dump("NXDN, FACCH1 convolved", temp2, 24U);
|
||||||
|
|
||||||
unsigned char temp3[18U];
|
unsigned char temp3[18U];
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CUtils::dump("NXDN, FACCH1 punctured", temp3, 18U);
|
// CUtils::dump("NXDN, FACCH1 punctured", temp3, 18U);
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) {
|
for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) {
|
||||||
unsigned int n = INTERLEAVE_TABLE[i] + offset;
|
unsigned int n = INTERLEAVE_TABLE[i] + offset;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ bool CNXDNLICH::decode(const unsigned char* bytes)
|
|||||||
|
|
||||||
bool parity = b[7U] ^ b[6U] ^ b[5U] ^ b[4U];
|
bool parity = b[7U] ^ b[6U] ^ b[5U] ^ b[4U];
|
||||||
|
|
||||||
LogMessage("NXDN, LICH bits: %d%d %d%d %d%d %d - %d, parity: %d", b[7U] ? 1 : 0, b[6U] ? 1 : 0, b[5U] ? 1 : 0, b[4U] ? 1 : 0, b[3U] ? 1 : 0, b[2U] ? 1 : 0, b[1U] ? 1 : 0, b[0U] ? 1 : 0, parity ? 1 : 0);
|
// LogMessage("NXDN, LICH bits: %d%d %d%d %d%d %d - %d, parity: %d", b[7U] ? 1 : 0, b[6U] ? 1 : 0, b[5U] ? 1 : 0, b[4U] ? 1 : 0, b[3U] ? 1 : 0, b[2U] ? 1 : 0, b[1U] ? 1 : 0, b[0U] ? 1 : 0, parity ? 1 : 0);
|
||||||
|
|
||||||
if (parity != b[0U])
|
if (parity != b[0U])
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ bool CNXDNSACCH::decode(const unsigned char* data)
|
|||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
CUtils::dump("NXDN, SACCH input", data, 12U);
|
// CUtils::dump("NXDN, SACCH input", data, 12U);
|
||||||
|
|
||||||
unsigned char temp1[8U];
|
unsigned char temp1[8U];
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ bool CNXDNSACCH::decode(const unsigned char* data)
|
|||||||
WRITE_BIT1(temp1, i, b);
|
WRITE_BIT1(temp1, i, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
CUtils::dump("NXDN, SACCH de-interleaved", temp1, 8U);
|
// CUtils::dump("NXDN, SACCH de-interleaved", temp1, 8U);
|
||||||
|
|
||||||
uint8_t temp2[72U];
|
uint8_t temp2[72U];
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ void CNXDNSACCH::encode(unsigned char* data) const
|
|||||||
CNXDNConvolution conv;
|
CNXDNConvolution conv;
|
||||||
conv.encode(temp1, temp2, 36U);
|
conv.encode(temp1, temp2, 36U);
|
||||||
|
|
||||||
CUtils::dump("NXDN, SACCH convolved", temp2, 8U);
|
// CUtils::dump("NXDN, SACCH convolved", temp2, 8U);
|
||||||
|
|
||||||
unsigned char temp3[8U];
|
unsigned char temp3[8U];
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ void CNXDNSACCH::encode(unsigned char* data) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CUtils::dump("NXDN, SACCH punctured", temp3, 8U);
|
// CUtils::dump("NXDN, SACCH punctured", temp3, 8U);
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) {
|
for (unsigned int i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) {
|
||||||
unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;
|
unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;
|
||||||
|
|||||||
Reference in New Issue
Block a user