add logic to check the NXDN FSW sync word; change NXDN convolution decoder to report boolean status for decode fail instead of code assert; use a buffer for LICH instead of attempting to direct write a byte (slightly more code at the expense of less inaccuracy); handle failed convolutional decode; set verbosity flag in appropriate places; fix data offsets when encoding/decoding FACCH;

2.0-maint
Bryan Biedenkapp 3 years ago
parent 82be3e643b
commit a78199c6a2

@ -53,6 +53,8 @@ using namespace nxdn::packet;
// Constants // Constants
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const uint8_t MAX_SYNC_BYTES_ERRS = 0U;
const uint8_t SCRAMBLER[] = { const uint8_t SCRAMBLER[] = {
0x00U, 0x00U, 0x00U, 0x82U, 0xA0U, 0x88U, 0x8AU, 0x00U, 0xA2U, 0xA8U, 0x82U, 0x8AU, 0x82U, 0x02U, 0x00U, 0x00U, 0x00U, 0x82U, 0xA0U, 0x88U, 0x8AU, 0x00U, 0xA2U, 0xA8U, 0x82U, 0x8AU, 0x82U, 0x02U,
0x20U, 0x08U, 0x8AU, 0x20U, 0xAAU, 0xA2U, 0x82U, 0x08U, 0x22U, 0x8AU, 0xAAU, 0x08U, 0x28U, 0x88U, 0x20U, 0x08U, 0x8AU, 0x20U, 0xAAU, 0xA2U, 0x82U, 0x08U, 0x22U, 0x8AU, 0xAAU, 0x08U, 0x28U, 0x88U,
@ -290,6 +292,7 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
assert(data != NULL); assert(data != NULL);
uint8_t type = data[0U]; uint8_t type = data[0U];
bool sync = data[1U] == 0x01U;
if (type == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) { if (type == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) {
if (m_rssi != 0U) { if (m_rssi != 0U) {
@ -348,6 +351,32 @@ bool Control::processFrame(uint8_t* data, uint32_t len)
m_rssiCount++; m_rssiCount++;
} }
if (!sync && m_rfState == RS_RF_LISTENING) {
uint8_t syncBytes[NXDN_FSW_BYTES_LENGTH];
::memcpy(syncBytes, data + 2U, NXDN_FSW_BYTES_LENGTH);
uint8_t errs = 0U;
for (uint8_t i = 0U; i < NXDN_FSW_BYTES_LENGTH; i++)
errs += Utils::countBits8(syncBytes[i] ^ NXDN_FSW_BYTES[i]);
if (errs >= MAX_SYNC_BYTES_ERRS) {
LogWarning(LOG_RF, "NXDN, possible sync word rejected, errs = %u, sync word = %02X %02X %02X", errs,
syncBytes[0U], syncBytes[1U], syncBytes[2U]);
return false;
}
else {
LogWarning(LOG_RF, "NXDN, possible sync word, errs = %u, sync word = %02X %02X %02X", errs,
syncBytes[0U], syncBytes[1U], syncBytes[2U]);
sync = true; // we found a completly valid sync with no errors...
}
}
if (sync && m_debug) {
Utils::symbols("!!! *Rx NXDN", data + 2U, len - 2U);
}
scrambler(data + 2U); scrambler(data + 2U);
channel::LICH lich; channel::LICH lich;
@ -799,10 +828,10 @@ void Control::scrambler(uint8_t* data) const
{ {
assert(data != NULL); assert(data != NULL);
if (m_debug) {
Utils::symbols("!!! *Tx NXDN (Unscrambled)", data, NXDN_FRAME_LENGTH_BYTES);
}
for (uint32_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) for (uint32_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++)
data[i] ^= SCRAMBLER[i]; data[i] ^= SCRAMBLER[i];
if (m_debug) {
Utils::symbols("!!! *NXDN (Scrambled)", data, NXDN_FRAME_LENGTH_BYTES);
}
} }

@ -12,6 +12,7 @@
// //
/* /*
* Copyright (C) 2009-2016,2018,2021 by Jonathan Naylor G4KLX * Copyright (C) 2009-2016,2018,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2022 by Bryan Biedenkapp N2PLL
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -28,6 +29,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "nxdn/Convolution.h" #include "nxdn/Convolution.h"
#include "Log.h"
#include "Utils.h"
using namespace nxdn; using namespace nxdn;
@ -127,7 +130,7 @@ uint32_t Convolution::chainback(uint8_t* out, uint32_t nBits)
/// </summary> /// </summary>
/// <param name="s0"></param> /// <param name="s0"></param>
/// <param name="s1"></param> /// <param name="s1"></param>
void Convolution::decode(uint8_t s0, uint8_t s1) bool Convolution::decode(uint8_t s0, uint8_t s1)
{ {
*m_dp = 0U; *m_dp = 0U;
@ -151,11 +154,15 @@ void Convolution::decode(uint8_t s0, uint8_t s1)
++m_dp; ++m_dp;
assert((m_dp - m_decisions) <= 300); if ((m_dp - m_decisions) > 300) {
return false;
}
uint16_t* tmp = m_oldMetrics; uint16_t* tmp = m_oldMetrics;
m_oldMetrics = m_newMetrics; m_oldMetrics = m_newMetrics;
m_newMetrics = tmp; m_newMetrics = tmp;
return true;
} }
/// <summary> /// <summary>

@ -12,6 +12,7 @@
// //
/* /*
* Copyright (C) 2015,2016,2018,2021 by Jonathan Naylor G4KLX * Copyright (C) 2015,2016,2018,2021 by Jonathan Naylor G4KLX
* Copyright (C) 2022 by Bryan Biedenkapp N2PLL
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -54,7 +55,7 @@ namespace nxdn
uint32_t chainback(uint8_t* out, uint32_t nBits); uint32_t chainback(uint8_t* out, uint32_t nBits);
/// <summary></summary> /// <summary></summary>
void decode(uint8_t s0, uint8_t s1); bool decode(uint8_t s0, uint8_t s1);
/// <summary></summary> /// <summary></summary>
void encode(const uint8_t* in, uint8_t* out, uint32_t nBits) const; void encode(const uint8_t* in, uint8_t* out, uint32_t nBits) const;

@ -216,7 +216,10 @@ bool CAC::decode(const uint8_t* data)
uint8_t s0 = buffer[n++]; uint8_t s0 = buffer[n++];
uint8_t s1 = buffer[n++]; uint8_t s1 = buffer[n++];
conv.decode(s0, s1); if (!conv.decode(s0, s1)) {
LogError(LOG_NXDN, "CAC::decode(), failed to decode convolution");
return false;
}
} }
conv.chainback(m_data, NXDN_CAC_SHORT_CRC_LENGTH_BITS); conv.chainback(m_data, NXDN_CAC_SHORT_CRC_LENGTH_BITS);
@ -228,7 +231,7 @@ bool CAC::decode(const uint8_t* data)
// check CRC-16 // check CRC-16
bool ret = CRC::checkCRC16(m_data, NXDN_CAC_SHORT_LENGTH_BITS); bool ret = CRC::checkCRC16(m_data, NXDN_CAC_SHORT_LENGTH_BITS);
if (!ret) { if (!ret) {
LogError(LOG_NXDN, "SACCH::decode(), failed CRC-6 check"); LogError(LOG_NXDN, "CAC::decode(), failed CRC-6 check");
return false; return false;
} }

@ -163,7 +163,10 @@ bool FACCH1::decode(const uint8_t* data, uint32_t offset)
uint8_t s0 = puncture[n++]; uint8_t s0 = puncture[n++];
uint8_t s1 = puncture[n++]; uint8_t s1 = puncture[n++];
conv.decode(s0, s1); if (!conv.decode(s0, s1)) {
LogError(LOG_NXDN, "FACCH1::decode(), failed to decode convolution");
return false;
}
} }
conv.chainback(m_data, NXDN_FACCH1_CRC_LENGTH_BITS); conv.chainback(m_data, NXDN_FACCH1_CRC_LENGTH_BITS);

@ -106,12 +106,17 @@ bool LICH::decode(const uint8_t* data)
{ {
assert(data != NULL); assert(data != NULL);
uint8_t lich[1U];
::memset(lich, 0x00U, 1U);
uint32_t offset = NXDN_FSW_LENGTH_BITS; uint32_t offset = NXDN_FSW_LENGTH_BITS;
for (uint32_t i = 0U; i < (NXDN_LICH_LENGTH_BITS / 2U); i++, offset += 2U) { for (uint32_t i = 0U; i < (NXDN_LICH_LENGTH_BITS / 2U); i++, offset += 2U) {
bool b = READ_BIT(data, offset); bool b = READ_BIT(data, offset);
m_lich = (b) ? (m_lich | BIT_MASK_TABLE[(i) & 7]) : (m_lich & ~BIT_MASK_TABLE[(i) & 7]); WRITE_BIT(lich, i, b);
} }
m_lich = lich[0U];
#if DEBUG_NXDN_LICH #if DEBUG_NXDN_LICH
LogDebug(LOG_NXDN, "LICH::decode(), m_lich = %02X", m_lich); LogDebug(LOG_NXDN, "LICH::decode(), m_lich = %02X", m_lich);
#endif #endif
@ -159,9 +164,14 @@ void LICH::encode(uint8_t* data)
else else
m_lich &= 0xFEU; m_lich &= 0xFEU;
uint8_t lich[1U];
::memset(lich, 0x00U, 1U);
lich[0U] = m_lich;
uint32_t offset = NXDN_FSW_LENGTH_BITS; uint32_t offset = NXDN_FSW_LENGTH_BITS;
for (uint32_t i = 0U; i < (NXDN_LICH_LENGTH_BITS / 2U); i++) { for (uint32_t i = 0U; i < (NXDN_LICH_LENGTH_BITS / 2U); i++) {
bool b = (m_lich & BIT_MASK_TABLE[(i) & 7]); bool b = READ_BIT(lich, i);
WRITE_BIT(data, offset, b); WRITE_BIT(data, offset, b);
offset++; offset++;
WRITE_BIT(data, offset, true); WRITE_BIT(data, offset, true);

@ -139,6 +139,8 @@ bool SACCH::decode(const uint8_t* data)
// depuncture // depuncture
uint8_t puncture[90U]; uint8_t puncture[90U];
::memset(puncture, 0x00U, 90U);
uint32_t n = 0U, index = 0U; uint32_t n = 0U, index = 0U;
for (uint32_t i = 0U; i < NXDN_SACCH_FEC_LENGTH_BITS; i++) { for (uint32_t i = 0U; i < NXDN_SACCH_FEC_LENGTH_BITS; i++) {
if (n == PUNCTURE_LIST[index]) { if (n == PUNCTURE_LIST[index]) {
@ -154,6 +156,10 @@ bool SACCH::decode(const uint8_t* data)
puncture[n++] = 0U; puncture[n++] = 0U;
} }
#if DEBUG_NXDN_SACCH
Utils::dump(2U, "SACCH::decode(), SACCH Puncture List", puncture, 90U);
#endif
// decode convolution // decode convolution
Convolution conv; Convolution conv;
conv.start(); conv.start();
@ -163,7 +169,10 @@ bool SACCH::decode(const uint8_t* data)
uint8_t s0 = puncture[n++]; uint8_t s0 = puncture[n++];
uint8_t s1 = puncture[n++]; uint8_t s1 = puncture[n++];
conv.decode(s0, s1); if (!conv.decode(s0, s1)) {
LogError(LOG_NXDN, "SACCH::decode(), failed to decode convolution");
return false;
}
} }
conv.chainback(m_data, NXDN_SACCH_CRC_LENGTH_BITS); conv.chainback(m_data, NXDN_SACCH_CRC_LENGTH_BITS);

@ -189,7 +189,10 @@ bool UDCH::decode(const uint8_t* data)
uint8_t s0 = puncture[n++]; uint8_t s0 = puncture[n++];
uint8_t s1 = puncture[n++]; uint8_t s1 = puncture[n++];
conv.decode(s0, s1); if (!conv.decode(s0, s1)) {
LogError(LOG_NXDN, "UDCH::decode(), failed to decode convolution");
return false;
}
} }
conv.chainback(m_data, NXDN_UDCH_CRC_LENGTH_BITS); conv.chainback(m_data, NXDN_UDCH_CRC_LENGTH_BITS);

@ -182,6 +182,7 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len)
assert(data != NULL); assert(data != NULL);
channel::UDCH udch; channel::UDCH udch;
udch.setVerbose(m_verbose);
bool validUDCH = udch.decode(data + 2U); bool validUDCH = udch.decode(data + 2U);
if (m_nxdn->m_rfState == RS_RF_LISTENING && !validUDCH) if (m_nxdn->m_rfState == RS_RF_LISTENING && !validUDCH)
return false; return false;
@ -197,6 +198,7 @@ bool Data::process(uint8_t option, uint8_t* data, uint32_t len)
udch.getData(buffer); udch.getData(buffer);
lc::RTCH lc; lc::RTCH lc;
lc.setVerbose(m_verbose);
lc.decode(buffer, NXDN_UDCH_LENGTH_BITS); lc.decode(buffer, NXDN_UDCH_LENGTH_BITS);
uint16_t dstId = lc.getDstId(); uint16_t dstId = lc.getDstId();
uint16_t srcId = lc.getSrcId(); uint16_t srcId = lc.getSrcId();
@ -296,6 +298,7 @@ bool Data::processNetwork(uint8_t option, lc::RTCH& netLC, uint8_t* data, uint32
} }
channel::UDCH udch; channel::UDCH udch;
udch.setVerbose(m_verbose);
bool validUDCH = udch.decode(data + 2U); bool validUDCH = udch.decode(data + 2U);
if (m_nxdn->m_netState == RS_NET_IDLE && !validUDCH) if (m_nxdn->m_netState == RS_NET_IDLE && !validUDCH)
return false; return false;
@ -305,6 +308,7 @@ bool Data::processNetwork(uint8_t option, lc::RTCH& netLC, uint8_t* data, uint32
udch.getData(buffer); udch.getData(buffer);
lc::RTCH lc; lc::RTCH lc;
lc.setVerbose(m_verbose);
lc.decode(buffer, NXDN_UDCH_LENGTH_BITS); lc.decode(buffer, NXDN_UDCH_LENGTH_BITS);
uint16_t dstId = lc.getDstId(); uint16_t dstId = lc.getDstId();
uint16_t srcId = lc.getSrcId(); uint16_t srcId = lc.getSrcId();

@ -189,6 +189,7 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
assert(data != NULL); assert(data != NULL);
channel::SACCH sacch; channel::SACCH sacch;
sacch.setVerbose(m_verbose);
bool valid = sacch.decode(data + 2U); bool valid = sacch.decode(data + 2U);
if (valid) { if (valid) {
uint8_t ran = sacch.getRAN(); uint8_t ran = sacch.getRAN();
@ -201,9 +202,10 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
if (fct == NXDN_LICH_USC_SACCH_NS) { if (fct == NXDN_LICH_USC_SACCH_NS) {
// the SACCH on a non-superblock frame is usually an idle and not interesting apart from the RAN. // the SACCH on a non-superblock frame is usually an idle and not interesting apart from the RAN.
channel::FACCH1 facch; channel::FACCH1 facch;
bool valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch.setVerbose(m_verbose);
bool valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
if (!valid) if (!valid)
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
if (!valid) if (!valid)
return false; return false;
@ -211,7 +213,8 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
facch.getData(buffer); facch.getData(buffer);
lc::RTCH lc; lc::RTCH lc;
lc.decode(buffer, NXDN_FACCH1_LENGTH_BITS); lc.setVerbose(m_verbose);
lc.decode(buffer, NXDN_FACCH1_FEC_LENGTH_BITS);
uint16_t dstId = lc.getDstId(); uint16_t dstId = lc.getDstId();
uint16_t srcId = lc.getSrcId(); uint16_t srcId = lc.getSrcId();
bool group = lc.getGroup(); bool group = lc.getGroup();
@ -252,13 +255,14 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
// generate the SACCH // generate the SACCH
channel::SACCH sacch; channel::SACCH sacch;
sacch.setVerbose(m_verbose);
sacch.setData(SACCH_IDLE); sacch.setData(SACCH_IDLE);
sacch.setRAN(m_nxdn->m_ran); sacch.setRAN(m_nxdn->m_ran);
sacch.setStructure(NXDN_SR_SINGLE); sacch.setStructure(NXDN_SR_SINGLE);
sacch.encode(data + 2U); 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_FEC_LENGTH_BITS);
facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
m_nxdn->scrambler(data + 2U); m_nxdn->scrambler(data + 2U);
@ -311,18 +315,19 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
} else { } else {
if (m_nxdn->m_rfState == RS_RF_LISTENING) { if (m_nxdn->m_rfState == RS_RF_LISTENING) {
channel::FACCH1 facch; channel::FACCH1 facch;
facch.setVerbose(m_verbose);
bool valid = false; bool valid = false;
switch (option) { switch (option) {
case NXDN_LICH_STEAL_FACCH: case NXDN_LICH_STEAL_FACCH:
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
if (!valid) if (!valid)
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
break; break;
case NXDN_LICH_STEAL_FACCH1_1: case NXDN_LICH_STEAL_FACCH1_1:
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
break; break;
case NXDN_LICH_STEAL_FACCH1_2: case NXDN_LICH_STEAL_FACCH1_2:
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
break; break;
default: default:
break; break;
@ -334,7 +339,8 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
facch.getData(buffer); facch.getData(buffer);
lc::RTCH lc; lc::RTCH lc;
lc.decode(buffer, NXDN_FACCH1_LENGTH_BITS); lc.setVerbose(m_verbose);
lc.decode(buffer, NXDN_FACCH1_FEC_LENGTH_BITS);
hasInfo = lc.getMessageType() == RTCH_MESSAGE_TYPE_VCALL; hasInfo = lc.getMessageType() == RTCH_MESSAGE_TYPE_VCALL;
if (!hasInfo) if (!hasInfo)
@ -431,6 +437,7 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
// generate the SACCH // generate the SACCH
channel::SACCH sacch; channel::SACCH sacch;
sacch.setVerbose(m_verbose);
sacch.setData(SACCH_IDLE); sacch.setData(SACCH_IDLE);
sacch.setRAN(m_nxdn->m_ran); sacch.setRAN(m_nxdn->m_ran);
sacch.setStructure(NXDN_SR_SINGLE); sacch.setStructure(NXDN_SR_SINGLE);
@ -440,8 +447,8 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
m_nxdn->m_rfLC.encode(buffer, NXDN_RTCH_LC_LENGTH_BITS); m_nxdn->m_rfLC.encode(buffer, NXDN_RTCH_LC_LENGTH_BITS);
facch.setData(buffer); facch.setData(buffer);
facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
m_nxdn->scrambler(start + 2U); m_nxdn->scrambler(start + 2U);
@ -472,6 +479,7 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
// regenerate SACCH if it's valid // regenerate SACCH if it's valid
channel::SACCH sacch; channel::SACCH sacch;
sacch.setVerbose(m_verbose);
bool validSACCH = sacch.decode(data + 2U); bool validSACCH = sacch.decode(data + 2U);
if (validSACCH) { if (validSACCH) {
sacch.setRAN(m_nxdn->m_ran); sacch.setRAN(m_nxdn->m_ran);
@ -510,9 +518,10 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
} }
} else if (option == NXDN_LICH_STEAL_FACCH1_1) { } else if (option == NXDN_LICH_STEAL_FACCH1_1) {
channel::FACCH1 facch1; channel::FACCH1 facch1;
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch1.setVerbose(m_verbose);
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
if (valid) if (valid)
facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
edac::AMBEFEC ambe; edac::AMBEFEC ambe;
@ -565,19 +574,22 @@ bool Voice::process(uint8_t fct, uint8_t option, uint8_t* data, uint32_t len)
} }
channel::FACCH1 facch1; channel::FACCH1 facch1;
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch1.setVerbose(m_verbose);
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
if (valid) if (valid)
facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
} else { } else {
channel::FACCH1 facch11; channel::FACCH1 facch11;
bool valid1 = facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch11.setVerbose(m_verbose);
bool valid1 = facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
if (valid1) 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_FEC_LENGTH_BITS);
channel::FACCH1 facch12; channel::FACCH1 facch12;
bool valid2 = facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch12.setVerbose(m_verbose);
bool valid2 = facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
if (valid2) if (valid2)
facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
} }
data[0U] = modem::TAG_DATA; data[0U] = modem::TAG_DATA;
@ -621,14 +633,16 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
} }
channel::SACCH sacch; channel::SACCH sacch;
sacch.setVerbose(m_verbose);
sacch.decode(data + 2U); sacch.decode(data + 2U);
if (fct == NXDN_LICH_USC_SACCH_NS) { if (fct == NXDN_LICH_USC_SACCH_NS) {
// the SACCH on a non-superblock frame is usually an idle and not interesting apart from the RAN. // the SACCH on a non-superblock frame is usually an idle and not interesting apart from the RAN.
channel::FACCH1 facch; channel::FACCH1 facch;
bool valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch.setVerbose(m_verbose);
bool valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
if (!valid) if (!valid)
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
if (!valid) if (!valid)
return false; return false;
@ -636,7 +650,8 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
facch.getData(buffer); facch.getData(buffer);
lc::RTCH lc; lc::RTCH lc;
lc.decode(buffer, NXDN_FACCH1_LENGTH_BITS); lc.setVerbose(m_verbose);
lc.decode(buffer, NXDN_FACCH1_FEC_LENGTH_BITS);
uint16_t dstId = lc.getDstId(); uint16_t dstId = lc.getDstId();
uint16_t srcId = lc.getSrcId(); uint16_t srcId = lc.getSrcId();
bool group = lc.getGroup(); bool group = lc.getGroup();
@ -677,13 +692,14 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
// generate the SACCH // generate the SACCH
channel::SACCH sacch; channel::SACCH sacch;
sacch.setVerbose(m_verbose);
sacch.setData(SACCH_IDLE); sacch.setData(SACCH_IDLE);
sacch.setRAN(m_nxdn->m_ran); sacch.setRAN(m_nxdn->m_ran);
sacch.setStructure(NXDN_SR_SINGLE); sacch.setStructure(NXDN_SR_SINGLE);
sacch.encode(data + 2U); 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_FEC_LENGTH_BITS);
facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
m_nxdn->scrambler(data + 2U); m_nxdn->scrambler(data + 2U);
@ -719,18 +735,19 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
} else { } else {
if (m_nxdn->m_netState == RS_NET_IDLE) { if (m_nxdn->m_netState == RS_NET_IDLE) {
channel::FACCH1 facch; channel::FACCH1 facch;
facch.setVerbose(m_verbose);
bool valid = false; bool valid = false;
switch (option) { switch (option) {
case NXDN_LICH_STEAL_FACCH: case NXDN_LICH_STEAL_FACCH:
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
if (!valid) if (!valid)
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
break; break;
case NXDN_LICH_STEAL_FACCH1_1: case NXDN_LICH_STEAL_FACCH1_1:
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
break; break;
case NXDN_LICH_STEAL_FACCH1_2: case NXDN_LICH_STEAL_FACCH1_2:
valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); valid = facch.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
break; break;
default: default:
break; break;
@ -742,7 +759,8 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
facch.getData(buffer); facch.getData(buffer);
lc::RTCH lc; lc::RTCH lc;
lc.decode(buffer, NXDN_FACCH1_LENGTH_BITS); lc.setVerbose(m_verbose);
lc.decode(buffer, NXDN_FACCH1_FEC_LENGTH_BITS);
hasInfo = lc.getMessageType() == RTCH_MESSAGE_TYPE_VCALL; hasInfo = lc.getMessageType() == RTCH_MESSAGE_TYPE_VCALL;
if (!hasInfo) if (!hasInfo)
@ -832,6 +850,7 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
// generate the SACCH // generate the SACCH
channel::SACCH sacch; channel::SACCH sacch;
sacch.setVerbose(m_verbose);
sacch.setData(SACCH_IDLE); sacch.setData(SACCH_IDLE);
sacch.setRAN(m_nxdn->m_ran); sacch.setRAN(m_nxdn->m_ran);
sacch.setStructure(NXDN_SR_SINGLE); sacch.setStructure(NXDN_SR_SINGLE);
@ -841,8 +860,8 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
m_nxdn->m_rfLC.encode(buffer, NXDN_RTCH_LC_LENGTH_BITS); m_nxdn->m_rfLC.encode(buffer, NXDN_RTCH_LC_LENGTH_BITS);
facch.setData(buffer); facch.setData(buffer);
facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch.encode(start + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
m_nxdn->scrambler(start + 2U); m_nxdn->scrambler(start + 2U);
@ -869,6 +888,7 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
// regenerate SACCH if it's valid // regenerate SACCH if it's valid
channel::SACCH sacch; channel::SACCH sacch;
sacch.setVerbose(m_verbose);
bool validSACCH = sacch.decode(data + 2U); bool validSACCH = sacch.decode(data + 2U);
if (validSACCH) { if (validSACCH) {
sacch.setRAN(m_nxdn->m_ran); sacch.setRAN(m_nxdn->m_ran);
@ -894,9 +914,10 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
} }
} else if (option == NXDN_LICH_STEAL_FACCH1_1) { } else if (option == NXDN_LICH_STEAL_FACCH1_1) {
channel::FACCH1 facch1; channel::FACCH1 facch1;
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch1.setVerbose(m_verbose);
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
if (valid) if (valid)
facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
edac::AMBEFEC ambe; edac::AMBEFEC ambe;
@ -926,19 +947,22 @@ bool Voice::processNetwork(uint8_t fct, uint8_t option, lc::RTCH& netLC, uint8_t
LogMessage(LOG_NET, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL ", audio, errs = %u/94 (%.1f%%)", errors, float(errors) / 0.94F); LogMessage(LOG_NET, "NXDN, " NXDN_RTCH_MSG_TYPE_VCALL ", audio, errs = %u/94 (%.1f%%)", errors, float(errors) / 0.94F);
} }
channel::FACCH1 facch1; channel::FACCH1 facch1;
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch1.setVerbose(m_verbose);
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
if (valid) if (valid)
facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
} else { } else {
channel::FACCH1 facch11; channel::FACCH1 facch11;
bool valid1 = facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS); facch11.setVerbose(m_verbose);
bool valid1 = facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS);
if (valid1) 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_FEC_LENGTH_BITS);
channel::FACCH1 facch12; channel::FACCH1 facch12;
bool valid2 = facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch12.setVerbose(m_verbose);
bool valid2 = facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
if (valid2) if (valid2)
facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS); facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_FEC_LENGTH_BITS + NXDN_FACCH1_FEC_LENGTH_BITS);
} }
data[0U] = modem::TAG_DATA; data[0U] = modem::TAG_DATA;

Loading…
Cancel
Save

Powered by TurnKey Linux.