Merge remote-tracking branch 'g4klx/nxdn' into nxdn

This commit is contained in:
Andy CA6JAU 2018-01-31 22:04:21 -03:00
commit 0f9f24310a
25 changed files with 716 additions and 475 deletions

View file

@ -298,7 +298,14 @@ bool CConf::read()
char* value = ::strtok(NULL, "\r\n");
if (value == NULL)
continue;
// Remove quotes from the value
size_t len = ::strlen(value);
if (len > 1U && *value == '"' && value[len - 1U] == '"') {
value[len - 1U] = '\0';
value++;
}
if (section == SECTION_GENERAL) {
if (::strcmp(key, "Callsign") == 0) {
// Convert the callsign to upper case

View file

@ -498,6 +498,9 @@ 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) ||
@ -511,6 +514,7 @@ void CDMRNetwork::receiveData(const unsigned char* data, unsigned int length)
unsigned char seqNo = data[4U];
m_jitterBuffers[slotNo]->addData(data, length, seqNo);
}
*/
}
bool CDMRNetwork::writeLogin()

View file

@ -198,7 +198,7 @@
<ClInclude Include="NXDNCRC.h" />
<ClInclude Include="NXDNDefines.h" />
<ClInclude Include="NXDNFACCH1.h" />
<ClInclude Include="NXDNFACCH2.h" />
<ClInclude Include="NXDNLayer3.h" />
<ClInclude Include="NXDNLICH.h" />
<ClInclude Include="NXDNLookup.h" />
<ClInclude Include="NXDNNetwork.h" />
@ -280,7 +280,7 @@
<ClCompile Include="NXDNConvolution.cpp" />
<ClCompile Include="NXDNCRC.cpp" />
<ClCompile Include="NXDNFACCH1.cpp" />
<ClCompile Include="NXDNFACCH2.cpp" />
<ClCompile Include="NXDNLayer3.cpp" />
<ClCompile Include="NXDNLICH.cpp" />
<ClCompile Include="NXDNLookup.cpp" />
<ClCompile Include="NXDNNetwork.cpp" />

View file

@ -257,10 +257,10 @@
<ClInclude Include="NXDNFACCH1.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNFACCH2.h">
<ClInclude Include="NXDNUDCH.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNUDCH.h">
<ClInclude Include="NXDNLayer3.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
@ -487,10 +487,10 @@
<ClCompile Include="NXDNFACCH1.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNFACCH2.cpp">
<ClCompile Include="NXDNUDCH.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNUDCH.cpp">
<ClCompile Include="NXDNLayer3.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>

View file

@ -10,9 +10,9 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \
P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -10,9 +10,9 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \
P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -10,9 +10,9 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o \
Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -10,7 +10,7 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o

View file

@ -3,16 +3,16 @@
CC = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DOLED -I/usr/local/include
LIBS = -lArduiPi_OLED -lpthread
LIBS = -lArduiPi_OLED -li2c -lpthread
LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o JitterBuffer.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \
P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -10,7 +10,7 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o

View file

@ -10,9 +10,9 @@ OBJECTS = \
AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o DMRLookup.o DMRLC.o \
DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \
Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o NullDisplay.o NXDNControl.o \
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNFACCH2.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o \
P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \
StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o \
P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \
SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o
all: MMDVMHost

View file

@ -13,7 +13,6 @@
#include "NXDNControl.h"
#include "NXDNFACCH1.h"
#include "NXDNFACCH2.h"
#include "NXDNSACCH.h"
#include "NXDNUDCH.h"
#include "AMBEFEC.h"
@ -63,7 +62,9 @@ m_rfErrs(0U),
m_rfBits(1U),
m_netErrs(0U),
m_netBits(1U),
m_lastLICH(),
m_rfLastLICH(),
m_rfLayer3(),
m_rfMask(0x00U),
m_netN(0U),
m_rssiMapper(rssiMapper),
m_rssi(0U),
@ -97,13 +98,14 @@ bool CNXDNControl::writeModem(unsigned char *data, unsigned int len)
return false;
}
if (type == TAG_LOST && m_rfState == RS_RF_REJECTED) {
m_rfState = RS_RF_LISTENING;
if (type == TAG_LOST && m_rfState == RS_RF_DATA) {
writeEndRF();
return false;
}
if (type == TAG_LOST) {
m_rfState = RS_RF_LISTENING;
m_rfMask = 0x00U;
return false;
}
@ -139,21 +141,21 @@ bool CNXDNControl::writeModem(unsigned char *data, unsigned int len)
bool valid = lich.decode(data + 2U);
if (valid)
m_lastLICH = lich;
m_rfLastLICH = lich;
// Stop repeater packets coming through, unless we're acting as a remote gateway
if (m_remoteGateway) {
unsigned char direction = m_lastLICH.getDirection();
unsigned char direction = m_rfLastLICH.getDirection();
if (direction == NXDN_LICH_DIRECTION_INBOUND)
return false;
} else {
unsigned char direction = m_lastLICH.getDirection();
unsigned char direction = m_rfLastLICH.getDirection();
if (direction == NXDN_LICH_DIRECTION_OUTBOUND)
return false;
}
unsigned char usc = m_lastLICH.getFCT();
unsigned char option = m_lastLICH.getOption();
unsigned char usc = m_rfLastLICH.getFCT();
unsigned char option = m_rfLastLICH.getOption();
bool ret;
if (usc == NXDN_LICH_USC_UDCH)
@ -174,397 +176,346 @@ bool CNXDNControl::processVoice(unsigned char usc, unsigned char option, unsigne
return false;
}
if (option == NXDN_LICH_STEAL_NONE) {
CAMBEFEC ambe;
unsigned int errors = 0U;
//errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES);
//errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U);
//errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U);
//errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U);
//LogDebug("NXDN, EHR, AMBE FEC %u/188 (%.1f%%)", errors, float(errors) / 1.88F);
//errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES);
//errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U);
//LogDebug("NXDN, EFR, AMBE FEC %u/288 (%.1f%%)", errors, float(errors) / 2.88F);
}
// XXX Reconstruct invalid LICH
#ifdef notdef
unsigned char fi = m_lastFICH.getFI();
if (valid && fi == YSF_FI_HEADER) {
if (m_rfState == RS_RF_LISTENING) {
bool valid = m_rfPayload.processHeaderData(data + 2U);
if (!valid)
return false;
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);
m_rfSource = m_rfPayload.getSource();
CNXDNFACCH1 facch12;
bool valid2 = facch12.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);
if (m_selfOnly) {
bool ret = checkCallsign(m_rfSource);
if (!ret) {
LogMessage("NXDN, invalid access attempt from %10.10s", m_rfSource);
m_rfState = RS_RF_REJECTED;
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;
}
}
}
unsigned char cm = m_lastFICH.getCM();
if (cm == YSF_CM_GROUP1 || cm == YSF_CM_GROUP2)
m_rfDest = (unsigned char*)"ALL ";
else
m_rfDest = m_rfPayload.getDest();
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_display->writeFusion((char*)m_rfSource, (char*)m_rfDest, "R", " ");
LogMessage("NXDN, received RF header from %10.10s to %10.10s", m_rfSource, m_rfDest);
data[0U] = type == NXDN_MESSAGE_TYPE_TX_REL ? TAG_EOT : TAG_DATA;
data[1U] = 0x00U;
CSync::addNXDNSync(data + 2U);
CYSFFICH fich = m_lastFICH;
CNXDNLICH lich = m_rfLastLICH;
lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
lich.encode(data + 2U);
// Remove any DSQ information
fich.setSQL(false);
fich.setSQ(0U);
fich.encode(data + 2U);
CNXDNSACCH sacch;
sacch.setRAN(m_ran);
sacch.setStructure(NXDN_SR_SINGLE);
sacch.setData(SACCH_IDLE);
sacch.encode(data + 2U);
data[0U] = TAG_DATA;
data[1U] = 0x00U;
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);
}
writeNetwork(data, m_rfFrames % 128U);
scrambler(data + 2U);
// writeNetwork(data, m_rfFrames, );
#if defined(DUMP_NXDN)
writeFile(data + 2U);
#endif
if (m_duplex) {
fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY);
fich.encode(data + 2U);
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;
}
m_rfFrames++;
m_display->writeFusionRSSI(m_rssi);
return true;
}
} else if (valid && fi == YSF_FI_TERMINATOR) {
if (m_rfState == RS_RF_REJECTED) {
m_rfPayload.reset();
m_rfSource = NULL;
m_rfDest = NULL;
m_rfState = RS_RF_LISTENING;
} else if (m_rfState == RS_RF_AUDIO) {
m_rfPayload.processHeaderData(data + 2U);
CSync::addNXDNSync(data + 2U);
return false;
} else {
unsigned char message[3U];
sacch.getData(message);
CYSFFICH fich = m_lastFICH;
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;
}
// Remove any DSQ information
fich.setSQL(false);
fich.setSQ(0U);
fich.encode(data + 2U);
if (m_rfMask != 0x0FU)
return false;
data[0U] = TAG_EOT;
data[1U] = 0x00U;
unsigned char messageType = m_rfLayer3.getMessageType();
if (messageType != NXDN_MESSAGE_TYPE_VCALL)
return false;
writeNetwork(data, m_rfFrames % 128U);
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)
writeFile(data + 2U);
openFile();
#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) {
fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY);
fich.encode(data + 2U);
writeQueueRF(data);
m_rfState = RS_RF_AUDIO;
}
// if (m_rfState == RS_RF_AUDIO) {
// Regenerate the sync
CSync::addNXDNSync(data + 2U);
// Regenerate the LICH
CNXDNLICH lich;
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(usc);
lich.setOption(option);
lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
lich.encode(data + 2U);
// XXX Regenerate SACCH here
// Regenerate the audio and interpret the FACCH1 data
unsigned char voiceMode = m_rfLayer3.getCallOptions() & 0x07U;
if (option == NXDN_LICH_STEAL_NONE) {
CAMBEFEC ambe;
unsigned int errors = 0U;
if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) {
errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES);
errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U);
m_rfErrs += errors;
m_rfBits += 288U;
m_display->writeNXDNBER(float(errors) / 2.88F);
LogDebug("NXDN, EFR, AMBE FEC %u/288 (%.1f%%)", errors, float(errors) / 2.88F);
} else {
errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES);
errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U);
errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U);
errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U);
m_rfErrs += errors;
m_rfBits += 188U;
m_display->writeNXDNBER(float(errors) / 1.88F);
LogDebug("NXDN, EHR, AMBE FEC %u/188 (%.1f%%)", errors, float(errors) / 1.88F);
}
} else if (option == NXDN_LICH_STEAL_FACCH1_1) {
CNXDNFACCH1 facch1;
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS);
if (valid)
facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS);
CAMBEFEC ambe;
unsigned int errors = 0U;
if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) {
errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U);
m_rfErrs += errors;
m_rfBits += 144U;
m_display->writeNXDNBER(float(errors) / 1.44F);
LogDebug("NXDN, EFR, AMBE FEC %u/144 (%.1f%%)", errors, float(errors) / 1.44F);
} else {
errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 18U);
errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 27U);
m_rfErrs += errors;
m_rfBits += 94U;
m_display->writeNXDNBER(float(errors) / 0.94F);
LogDebug("NXDN, EHR, AMBE FEC %u/94 (%.1f%%)", errors, float(errors) / 0.94F);
}
} else if (option == NXDN_LICH_STEAL_FACCH1_2) {
CAMBEFEC ambe;
unsigned int errors = 0U;
if (voiceMode == NXDN_VOICE_CALL_OPTION_9600_EFR) {
errors += ambe.regenerateIMBE(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES);
m_rfErrs += errors;
m_rfBits += 144U;
m_display->writeNXDNBER(float(errors) / 1.44F);
LogDebug("NXDN, EFR, AMBE FEC %u/144 (%.1f%%)", errors, float(errors) / 1.44F);
} else {
errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES);
errors += ambe.regenerateDMR(data + 2U + NXDN_FSW_LICH_SACCH_LENGTH_BYTES + 9U);
m_rfErrs += errors;
m_rfBits += 94U;
m_display->writeNXDNBER(float(errors) / 0.94F);
LogDebug("NXDN, EHR, AMBE FEC %u/94 (%.1f%%)", errors, float(errors) / 0.94F);
}
m_rfFrames++;
CNXDNFACCH1 facch1;
bool valid = facch1.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);
if (valid)
facch1.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);
} else {
CNXDNFACCH1 facch11;
bool valid1 = facch11.decode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS);
if (valid1)
facch11.encode(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);
if (valid2)
facch12.encode(data + 2U, NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS + NXDN_SACCH_LENGTH_BITS + NXDN_FACCH1_LENGTH_BITS);
}
data[0U] = TAG_DATA;
data[1U] = 0x00U;
scrambler(data + 2U);
// writeNetwork(data, m_rfFrames, );
#if defined(DUMP_NXDN)
writeFile(data + 2U);
#endif
if (m_duplex)
writeQueueRF(data);
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 {
if (m_rfState == RS_RF_AUDIO) {
// If valid is false, update the m_lastFICH for this transmission
if (!valid) {
unsigned char ft = m_lastFICH.getFT();
unsigned char fn = m_lastFICH.getFN() + 1U;
if (fn > ft)
fn = 0U;
m_lastFICH.setFN(fn);
}
CSync::addNXDNSync(data + 2U);
unsigned char fn = m_lastFICH.getFN();
unsigned char dt = m_lastFICH.getDT();
switch (dt) {
case YSF_DT_VD_MODE1: {
m_rfPayload.processVDMode1Data(data + 2U, fn);
unsigned int errors = m_rfPayload.processVDMode1Audio(data + 2U);
m_rfErrs += errors;
m_rfBits += 235U;
m_display->writeFusionBER(float(errors) / 2.35F);
LogDebug("NXDN, V/D Mode 1, seq %u, AMBE FEC %u/235 (%.1f%%)", m_rfFrames % 128, errors, float(errors) / 2.35F);
}
break;
case YSF_DT_VD_MODE2: {
m_rfPayload.processVDMode2Data(data + 2U, fn);
unsigned int errors = m_rfPayload.processVDMode2Audio(data + 2U);
m_rfErrs += errors;
m_rfBits += 135U;
m_display->writeFusionBER(float(errors) / 1.35F);
LogDebug("NXDN, V/D Mode 2, seq %u, Repetition FEC %u/135 (%.1f%%)", m_rfFrames % 128, errors, float(errors) / 1.35F);
}
break;
default:
break;
}
CYSFFICH fich = m_lastFICH;
// Remove any DSQ information
fich.setSQL(false);
fich.setSQ(0U);
fich.encode(data + 2U);
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeNetwork(data, m_rfFrames % 128U);
if (m_duplex) {
fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY);
fich.encode(data + 2U);
writeQueueRF(data);
}
#if defined(DUMP_NXDN)
writeFile(data + 2U);
#endif
m_rfFrames++;
m_display->writeFusionRSSI(m_rssi);
return true;
} else if (valid && m_rfState == RS_RF_LISTENING) {
// Only use clean frames for late entry.
unsigned char fn = m_lastFICH.getFN();
unsigned char dt = m_lastFICH.getDT();
switch (dt) {
case YSF_DT_VD_MODE1:
valid = m_rfPayload.processVDMode1Data(data + 2U, fn);
break;
case YSF_DT_VD_MODE2:
valid = m_rfPayload.processVDMode2Data(data + 2U, fn);
break;
default:
valid = false;
break;
}
if (!valid)
return false;
unsigned char cm = m_lastFICH.getCM();
if (cm == YSF_CM_GROUP1 || cm == YSF_CM_GROUP2)
m_rfDest = (unsigned char*)"ALL ";
else
m_rfDest = m_rfPayload.getDest();
m_rfSource = m_rfPayload.getSource();
if (m_rfSource == NULL || m_rfDest == NULL)
return false;
if (m_selfOnly) {
bool ret = checkCallsign(m_rfSource);
if (!ret) {
LogMessage("NXDN, invalid access attempt from %10.10s", m_rfSource);
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
// Build a new header and transmit it
unsigned char buffer[YSF_FRAME_LENGTH_BYTES + 2U];
CSync::addNXDNSync(buffer + 2U);
CYSFFICH fich = m_lastFICH;
fich.setFI(YSF_FI_HEADER);
fich.setSQL(false);
fich.setSQ(0U);
fich.encode(buffer + 2U);
unsigned char csd1[20U], csd2[20U];
memcpy(csd1 + YSF_CALLSIGN_LENGTH, m_rfSource, YSF_CALLSIGN_LENGTH);
memset(csd2, ' ', YSF_CALLSIGN_LENGTH + YSF_CALLSIGN_LENGTH);
if (cm == YSF_CM_GROUP1 || cm == YSF_CM_GROUP2)
memset(csd1 + 0U, '*', YSF_CALLSIGN_LENGTH);
else
memcpy(csd1 + 0U, m_rfDest, YSF_CALLSIGN_LENGTH);
CYSFPayload payload;
payload.writeHeader(buffer + 2U, csd1, csd2);
buffer[0U] = TAG_DATA;
buffer[1U] = 0x00U;
writeNetwork(buffer, m_rfFrames % 128U);
if (m_duplex) {
fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY);
fich.encode(buffer + 2U);
writeQueueRF(buffer);
}
#if defined(DUMP_NXDN)
writeFile(buffer + 2U);
#endif
m_display->writeFusion((char*)m_rfSource, (char*)m_rfDest, "R", " ");
LogMessage("NXDN, received RF late entry from %10.10s to %10.10s", m_rfSource, m_rfDest);
CSync::addNXDNSync(data + 2U);
fich = m_lastFICH;
// Remove any DSQ information
fich.setSQL(false);
fich.setSQ(0U);
fich.encode(data + 2U);
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeNetwork(data, m_rfFrames % 128U);
if (m_duplex) {
fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY);
fich.encode(data + 2U);
writeQueueRF(data);
}
#if defined(DUMP_NXDN)
writeFile(data + 2U);
#endif
m_rfFrames++;
m_display->writeFusionRSSI(m_rssi);
return true;
} else {
m_rfState = RS_RF_LISTENING;
m_rfMask = 0x00U;
return false;
}
}
#endif
return false;
return true;
}
bool CNXDNControl::processData(unsigned char option, unsigned char *data)
{
if (option == NXDN_LICH_STEAL_FACCH) {
CNXDNFACCH2 facch2;
bool valid = facch2.decode(data + 2U);
if (valid) {
unsigned char ran = facch2.getRAN();
if (ran != m_ran && ran != 0U)
return false;
CNXDNUDCH udch;
bool valid = udch.decode(data + 2U);
if (valid) {
unsigned char ran = udch.getRAN();
if (ran != m_ran && ran != 0U)
return false;
data[0U] = TAG_DATA;
data[1U] = 0x00U;
data[0U] = TAG_DATA;
data[1U] = 0x00U;
CSync::addNXDNSync(data + 2U);
CSync::addNXDNSync(data + 2U);
CNXDNLICH lich;
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_UDCH);
lich.setOption(NXDN_LICH_STEAL_FACCH);
lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
lich.encode(data + 2U);
CNXDNLICH lich;
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_UDCH);
lich.setOption(option);
lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
lich.encode(data + 2U);
facch2.setRAN(m_ran);
facch2.encode(data + 2U);
udch.setRAN(m_ran);
udch.encode(data + 2U);
writeQueueNet(data);
scrambler(data + 2U);
if (m_duplex)
writeQueueRF(data);
writeQueueNet(data);
if (m_duplex)
writeQueueRF(data);
#if defined(DUMP_NXDN)
writeFile(data + 2U);
writeFile(data + 2U);
#endif
return true;
}
} else {
CNXDNUDCH udch;
bool valid = udch.decode(data + 2U);
if (valid) {
data[0U] = TAG_DATA;
data[1U] = 0x00U;
CSync::addNXDNSync(data + 2U);
CNXDNLICH lich;
lich.setRFCT(NXDN_LICH_RFCT_RDCH);
lich.setFCT(NXDN_LICH_USC_UDCH);
lich.setOption(NXDN_LICH_STEAL_NONE);
lich.setDirection(m_remoteGateway ? NXDN_LICH_DIRECTION_INBOUND : NXDN_LICH_DIRECTION_OUTBOUND);
lich.encode(data + 2U);
udch.encode(data + 2U);
writeQueueNet(data);
if (m_duplex)
writeQueueRF(data);
#if defined(DUMP_NXDN)
writeFile(data + 2U);
#endif
return true;
}
return true;
}
#ifdef notdef
@ -618,7 +569,7 @@ bool CNXDNControl::processData(unsigned char option, unsigned char *data)
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeNetwork(data, m_rfFrames % 128U);
writeNetwork(data, m_rfFrames);
#if defined(DUMP_NXDN)
writeFile(data + 2U);
@ -657,7 +608,7 @@ bool CNXDNControl::processData(unsigned char option, unsigned char *data)
data[0U] = TAG_EOT;
data[1U] = 0x00U;
writeNetwork(data, m_rfFrames % 128U);
writeNetwork(data, m_rfFrames);
#if defined(DUMP_NXDN)
writeFile(data + 2U);
@ -707,7 +658,7 @@ bool CNXDNControl::processData(unsigned char option, unsigned char *data)
data[0U] = TAG_DATA;
data[1U] = 0x00U;
writeNetwork(data, m_rfFrames % 128U);
writeNetwork(data, m_rfFrames);
if (m_duplex) {
fich.setMR(m_remoteGateway ? YSF_MR_NOT_BUSY : YSF_MR_BUSY);
@ -749,6 +700,8 @@ void CNXDNControl::writeEndRF()
{
m_rfState = RS_RF_LISTENING;
m_rfMask = 0x00U;
m_rfTimeoutTimer.stop();
if (m_netState == RS_NET_IDLE) {
@ -973,7 +926,7 @@ void CNXDNControl::writeQueueNet(const unsigned char *data)
m_queue.addData(data, len);
}
void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count)
void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count, bool end)
{
assert(data != NULL);
@ -983,7 +936,11 @@ void CNXDNControl::writeNetwork(const unsigned char *data, unsigned int count)
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired())
return;
m_network->write(data + 2U, count, data[0U] == TAG_EOT);
unsigned short srcId = m_rfLayer3.getSourceUnitId();
unsigned short dstId = m_rfLayer3.getDestinationGroupId();
bool grp = m_rfLayer3.getIsGroup();
m_network->write(data + 2U, srcId, grp, dstId, count % 256U, end);
}
void CNXDNControl::scrambler(unsigned char* data) const

View file

@ -22,6 +22,7 @@
#include "RSSIInterpolator.h"
#include "NXDNNetwork.h"
#include "NXDNDefines.h"
#include "NXDNLayer3.h"
#include "NXDNLookup.h"
#include "RingBuffer.h"
#include "StopWatch.h"
@ -68,7 +69,9 @@ private:
unsigned int m_rfBits;
unsigned int m_netErrs;
unsigned int m_netBits;
CNXDNLICH m_lastLICH;
CNXDNLICH m_rfLastLICH;
CNXDNLayer3 m_rfLayer3;
unsigned char m_rfMask;
unsigned char m_netN;
CRSSIInterpolator* m_rssiMapper;
unsigned char m_rssi;
@ -83,7 +86,7 @@ private:
void writeQueueRF(const unsigned char* data);
void writeQueueNet(const unsigned char* data);
void writeNetwork(const unsigned char* data, unsigned int count);
void writeNetwork(const unsigned char* data, unsigned int count, bool end);
void writeNetwork();
void scrambler(unsigned char* data) const;

View file

@ -45,7 +45,7 @@ m_dp(NULL)
{
m_metrics1 = new uint16_t[16U];
m_metrics2 = new uint16_t[16U];
m_decisions = new uint64_t[180U];
m_decisions = new uint64_t[300U];
}
CNXDNConvolution::~CNXDNConvolution()
@ -98,7 +98,7 @@ void CNXDNConvolution::decode(uint8_t s0, uint8_t s1)
++m_dp;
assert((m_dp - m_decisions) <= 180);
assert((m_dp - m_decisions) <= 300);
uint16_t* tmp = m_oldMetrics;
m_oldMetrics = m_newMetrics;

View file

@ -66,4 +66,41 @@ const unsigned char NXDN_SR_3_4 = 1U;
const unsigned char NXDN_SR_2_4 = 2U;
const unsigned char NXDN_SR_1_4 = 3U;
const unsigned char NXDN_MESSAGE_TYPE_VCALL = 0x01U;
const unsigned char NXDN_MESSAGE_TYPE_VCALL_IV = 0x03U;
const unsigned char NXDN_MESSAGE_TYPE_DCALL_HDR = 0x09U;
const unsigned char NXDN_MESSAGE_TYPE_DCALL_DATA = 0x0BU;
const unsigned char NXDN_MESSAGE_TYPE_DCALL_ACK = 0x0CU;
const unsigned char NXDN_MESSAGE_TYPE_TX_REL = 0x08U;
const unsigned char NXDN_MESSAGE_TYPE_HEAD_DLY = 0x0FU;
const unsigned char NXDN_MESSAGE_TYPE_SDCALL_REQ_HDR = 0x38U;
const unsigned char NXDN_MESSAGE_TYPE_SDCALL_REQ_DATA = 0x39U;
const unsigned char NXDN_MESSAGE_TYPE_SDCALL_RESP = 0x3BU;
const unsigned char NXDN_MESSAGE_TYPE_SDCALL_IV = 0x3AU;
const unsigned char NXDN_MESSAGE_TYPE_STAT_INQ_REQ = 0x30U;
const unsigned char NXDN_MESSAGE_TYPE_STAT_INQ_RESP = 0x31U;
const unsigned char NXDN_MESSAGE_TYPE_STAT_REQ = 0x32U;
const unsigned char NXDN_MESSAGE_TYPE_STAT_RESP = 0x33U;
const unsigned char NXDN_MESSAGE_TYPE_REM_CON_REQ = 0x34U;
const unsigned char NXDN_MESSAGE_TYPE_REM_CON_RESP = 0x35U;
const unsigned char NXDN_MESSAGE_TYPE_IDLE = 0x10U;
const unsigned char NXDN_MESSAGE_TYPE_AUTH_INQ_REQ = 0x28U;
const unsigned char NXDN_MESSAGE_TYPE_AUTH_INQ_RESP = 0x29U;
const unsigned char NXDN_MESSAGE_TYPE_PROP_FORM = 0x3FU;
const unsigned char NXDN_VOICE_CALL_OPTION_HALF_DUPLEX = 0x00U;
const unsigned char NXDN_VOICE_CALL_OPTION_DUPLEX = 0x10U;
const unsigned char NXDN_VOICE_CALL_OPTION_4800_EHR = 0x00U;
const unsigned char NXDN_VOICE_CALL_OPTION_9600_EHR = 0x02U;
const unsigned char NXDN_VOICE_CALL_OPTION_9600_EFR = 0x03U;
const unsigned char NXDN_DATA_CALL_OPTION_HALF_DUPLEX = 0x00U;
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_9600 = 0x02U;
const unsigned char SACCH_IDLE[] = { NXDN_MESSAGE_TYPE_IDLE, 0x00U, 0x00U };
#endif

View file

@ -28,6 +28,22 @@
#include <cassert>
#include <cstring>
const unsigned int INTERLEAVE_TABLE[] = {
0U, 9U, 18U, 27U, 36U, 45U, 54U, 63U, 72U, 81U, 90U, 99U, 108U, 117U, 126U, 135U,
1U, 10U, 19U, 28U, 37U, 46U, 55U, 64U, 73U, 82U, 91U, 100U, 109U, 118U, 127U, 136U,
2U, 11U, 20U, 29U, 38U, 47U, 56U, 65U, 74U, 83U, 92U, 101U, 110U, 119U, 128U, 137U,
3U, 12U, 21U, 30U, 39U, 48U, 57U, 66U, 75U, 84U, 93U, 102U, 111U, 120U, 129U, 138U,
4U, 13U, 22U, 31U, 40U, 49U, 58U, 67U, 76U, 85U, 94U, 103U, 112U, 121U, 130U, 139U,
5U, 14U, 23U, 32U, 41U, 50U, 59U, 68U, 77U, 86U, 95U, 104U, 113U, 122U, 131U, 140U,
6U, 15U, 24U, 33U, 42U, 51U, 60U, 69U, 78U, 87U, 96U, 105U, 114U, 123U, 132U, 141U,
7U, 16U, 25U, 34U, 43U, 52U, 61U, 70U, 79U, 88U, 97U, 106U, 115U, 124U, 133U, 142U,
8U, 17U, 26U, 35U, 44U, 53U, 62U, 71U, 80U, 89U, 98U, 107U, 116U, 125U, 134U, 143U };
const unsigned int PUNCTURE_LIST[] = { 1U, 5U, 9U, 13U, 17U, 21U, 25U, 29U, 33U, 37U,
41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U, 73U, 77U,
81U, 85U, 89U, 93U, 97U, 101U, 105U, 109U, 113U, 117U,
121U, 125U, 129U, 133U, 137U, 141U};
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
@ -51,16 +67,98 @@ CNXDNFACCH1::~CNXDNFACCH1()
delete[] m_data;
}
bool CNXDNFACCH1::decode(const unsigned char* data)
bool CNXDNFACCH1::decode(const unsigned char* data, unsigned int offset)
{
assert(data != NULL);
return true;
// CUtils::dump("NXDN, FACCH1 input", data, 18U);
unsigned char temp1[18U];
for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) {
unsigned int n = INTERLEAVE_TABLE[i] + offset;
bool b = READ_BIT1(data, n);
WRITE_BIT1(temp1, i, b);
}
// CUtils::dump("NXDN, FACCH1 de-interleaved", temp1, 18U);
uint8_t temp2[192U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) {
if (n == PUNCTURE_LIST[index]) {
temp2[n++] = 99U;
index++;
}
bool b = READ_BIT1(temp1, i);
temp2[n++] = b ? 1U : 0U;
}
CNXDNConvolution conv;
conv.start();
n = 0U;
for (unsigned int i = 0U; i < 96U; i++) {
uint8_t s0 = temp2[n++];
uint8_t s1 = temp2[n++];
conv.decode(s0, s1);
}
conv.chainback(m_data, 92U);
CUtils::dump("NXDN, FACCH1 decoded", m_data, 12U);
return CNXDNCRC::checkCRC12(m_data, 80U);
}
void CNXDNFACCH1::encode(unsigned char* data) const
void CNXDNFACCH1::encode(unsigned char* data, unsigned int offset) const
{
assert(data != NULL);
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);
}
CNXDNCRC::encodeCRC12(temp1, 80U);
// CUtils::dump("NXDN, FACCH1 encoded with CRC", temp1, 12U);
unsigned char temp2[24U];
CNXDNConvolution conv;
conv.encode(temp1, temp2, 96U);
// CUtils::dump("NXDN, FACCH1 convolved", temp2, 24U);
unsigned char temp3[18U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < 192U; i++) {
if (i != PUNCTURE_LIST[index]) {
bool b = READ_BIT1(temp2, i);
WRITE_BIT1(temp3, n, b);
n++;
} else {
index++;
}
}
// CUtils::dump("NXDN, FACCH1 punctured", temp3, 18U);
for (unsigned int i = 0U; i < NXDN_FACCH1_LENGTH_BITS; i++) {
unsigned int n = INTERLEAVE_TABLE[i] + offset;
bool b = READ_BIT1(temp3, i);
WRITE_BIT1(data, n, b);
}
}
void CNXDNFACCH1::getData(unsigned char* data) const

View file

@ -25,9 +25,10 @@ public:
CNXDNFACCH1();
~CNXDNFACCH1();
bool decode(const unsigned char* data);
bool decode(const unsigned char* data, unsigned int offset);
void encode(unsigned char* data, unsigned int offset) const;
void encode(unsigned char* data) const;
void getData(unsigned char* data) const;
void setData(const unsigned char* data);

View file

@ -61,7 +61,7 @@ bool CNXDNLICH::decode(const unsigned char* bytes)
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])
return false;

View file

@ -16,11 +16,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNFACCH2.h"
#include "NXDNDefines.h"
#include "NXDNUDCH.h"
#include "Utils.h"
#include "NXDNLayer3.h"
#include "Log.h"
#include <cstdio>
@ -32,78 +29,74 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CNXDNFACCH2::CNXDNFACCH2(const CNXDNFACCH2& facch2) :
CNXDNLayer3::CNXDNLayer3(const CNXDNLayer3& layer3) :
m_data(NULL)
{
m_data = new unsigned char[23U];
::memcpy(m_data, facch2.m_data, 23U);
m_data = new unsigned char[22U];
::memcpy(m_data, layer3.m_data, 22U);
}
CNXDNFACCH2::CNXDNFACCH2() :
CNXDNLayer3::CNXDNLayer3() :
m_data(NULL)
{
m_data = new unsigned char[23U];
m_data = new unsigned char[22U];
::memset(m_data, 0x00U, 22U);
}
CNXDNFACCH2::~CNXDNFACCH2()
CNXDNLayer3::~CNXDNLayer3()
{
delete[] m_data;
}
bool CNXDNFACCH2::decode(const unsigned char* data)
void CNXDNLayer3::decode(const unsigned char* bytes, unsigned int length, unsigned int offset)
{
assert(data != NULL);
assert(bytes != NULL);
CNXDNUDCH udch;
bool valid = udch.decode(data);
if (!valid)
return false;
udch.getData(m_data);
return true;
for (unsigned int i = 0U; i < length; i++, offset++) {
bool b = READ_BIT1(bytes, offset);
WRITE_BIT1(m_data, i, b);
}
}
void CNXDNFACCH2::encode(unsigned char* data) const
void CNXDNLayer3::encode(unsigned char* bytes, unsigned int length, unsigned int offset)
{
assert(data != NULL);
assert(bytes != NULL);
CNXDNUDCH udch;
udch.setData(m_data);
udch.encode(data);
for (unsigned int i = 0U; i < length; i++, offset++) {
bool b = READ_BIT1(m_data, i);
WRITE_BIT1(bytes, offset, b);
}
}
unsigned char CNXDNFACCH2::getRAN() const
unsigned char CNXDNLayer3::getMessageType() const
{
return m_data[0U] & 0x3FU;
}
void CNXDNFACCH2::getData(unsigned char* data) const
unsigned short CNXDNLayer3::getSourceUnitId() const
{
assert(data != NULL);
::memcpy(data, m_data + 1U, 22U);
return (m_data[3U] << 8) | m_data[4U];
}
void CNXDNFACCH2::setRAN(unsigned char ran)
unsigned short CNXDNLayer3::getDestinationGroupId() const
{
m_data[0U] &= 0xC0U;
m_data[0U] |= ran;
return (m_data[5U] << 8) | m_data[6U];
}
void CNXDNFACCH2::setData(const unsigned char* data)
bool CNXDNLayer3::getIsGroup() const
{
assert(data != NULL);
::memcpy(m_data + 1U, data, 22U);
return (m_data[2U] & 0x80U) != 0x80U;
}
CNXDNFACCH2& CNXDNFACCH2::operator=(const CNXDNFACCH2& facch2)
unsigned char CNXDNLayer3::getCallOptions() const
{
if (&facch2 != this)
::memcpy(m_data, facch2.m_data, 23U);
return m_data[2U] & 0x1FU;
}
CNXDNLayer3& CNXDNLayer3::operator=(const CNXDNLayer3& layer3)
{
if (&layer3 != this)
::memcpy(m_data, layer3.m_data, 22U);
return *this;
}

View file

@ -16,28 +16,26 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(NXDNFACCH2_H)
#define NXDNFACCH2_H
#if !defined(NXDNLayer3_H)
#define NXDNLayer3_H
class CNXDNFACCH2 {
class CNXDNLayer3 {
public:
CNXDNFACCH2(const CNXDNFACCH2& facch);
CNXDNFACCH2();
~CNXDNFACCH2();
CNXDNLayer3(const CNXDNLayer3& layer3);
CNXDNLayer3();
~CNXDNLayer3();
bool decode(const unsigned char* data);
void decode(const unsigned char* bytes, unsigned int length, unsigned int offset = 0U);
void encode(unsigned char* data) const;
void encode(unsigned char* bytes, unsigned int length, unsigned int offset = 0U);
unsigned char getRAN() const;
unsigned char getMessageType() const;
unsigned short getSourceUnitId() const;
unsigned short getDestinationGroupId() const;
bool getIsGroup() const;
unsigned char getCallOptions() const;
void getData(unsigned char* data) const;
void setRAN(unsigned char ran);
void setData(const unsigned char* data);
CNXDNFACCH2& operator=(const CNXDNFACCH2& facch);
CNXDNLayer3& operator=(const CNXDNLayer3& layer3);
private:
unsigned char* m_data;

View file

@ -56,11 +56,11 @@ bool CNXDNNetwork::open()
return m_socket.open();
}
bool CNXDNNetwork::write(const unsigned char* data, unsigned int count, bool end)
bool CNXDNNetwork::write(const unsigned char* data, unsigned short src, bool grp, unsigned short dst, unsigned char cnt, bool end)
{
assert(data != NULL);
unsigned char buffer[200U];
unsigned char buffer[100U];
buffer[0U] = 'N';
buffer[1U] = 'X';
@ -68,15 +68,23 @@ bool CNXDNNetwork::write(const unsigned char* data, unsigned int count, bool end
buffer[3U] = 'N';
buffer[4U] = 'D';
buffer[5U] = end ? 0x01U : 0x00U;
buffer[5U] |= (count & 0x7FU) << 1;
buffer[5U] = (src >> 8) & 0xFFU;
buffer[6U] = (src >> 8) & 0xFFU;
::memcpy(buffer + 6U, data, NXDN_FRAME_LENGTH_BYTES);
buffer[7U] = grp ? 0x01U : 0x00U;
buffer[7U] |= end ? 0x80U : 0x00U;
buffer[8U] = (dst >> 8) & 0xFFU;
buffer[9U] = (dst >> 8) & 0xFFU;
buffer[10U] = cnt;
::memcpy(buffer + 11U, data, NXDN_FRAME_LENGTH_BYTES);
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Sent", buffer, 54U);
CUtils::dump(1U, "NXDN Network Data Sent", buffer, 59U);
return m_socket.write(buffer, 54U, m_address, m_port);
return m_socket.write(buffer, 59U, m_address, m_port);
}
bool CNXDNNetwork::writePoll()
@ -131,19 +139,29 @@ void CNXDNNetwork::clock(unsigned int ms)
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Received", buffer, length);
m_buffer.addData(buffer, 54U);
m_buffer.addData(buffer, 59U);
}
unsigned int CNXDNNetwork::read(unsigned char* data)
unsigned int CNXDNNetwork::read(unsigned char* data, unsigned short& src, bool& grp, unsigned short& dst, unsigned char& cnt, bool& end)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return 0U;
m_buffer.getData(data, 54U);
unsigned char buffer[100U];
m_buffer.getData(buffer, 59U);
return 155U;
src = (buffer[5U] << 8) + buffer[6U];
grp = (buffer[7U] & 0x01U) == 0x01U;
end = (buffer[7U] & 0x80U) == 0x80U;
dst = (buffer[8U] << 8) + buffer[9U];
cnt = buffer[10U];
::memcpy(data, buffer + 11U, NXDN_FRAME_LENGTH_BYTES);
return NXDN_FRAME_LENGTH_BYTES;
}
void CNXDNNetwork::reset()

View file

@ -36,9 +36,9 @@ public:
void enable(bool enabled);
bool write(const unsigned char* data, unsigned int count, bool end);
bool write(const unsigned char* data, unsigned short src, bool grp, unsigned short dst, unsigned char cnt, bool end);
unsigned int read(unsigned char* data);
unsigned int read(unsigned char* data, unsigned short& src, bool& grp, unsigned short& dst, unsigned char& cnt, bool& end);
void reset();

View file

@ -65,7 +65,7 @@ bool CNXDNSACCH::decode(const unsigned char* data)
{
assert(data != NULL);
CUtils::dump("NXDN, SACCH input", data, 12U);
// CUtils::dump("NXDN, SACCH input", data, 12U);
unsigned char temp1[8U];
@ -75,29 +75,22 @@ bool CNXDNSACCH::decode(const unsigned char* data)
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];
char text[500U];
::strcpy(text, "NXDN, SACCH de-punctured: ");
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < NXDN_SACCH_LENGTH_BITS; i++) {
if (n == PUNCTURE_LIST[index]) {
::strcat(text, "X, ");
temp2[n++] = 99U;
index++;
}
bool b = READ_BIT1(temp1, i);
temp2[n++] = b ? 1U : 0U;
::strcat(text, b ? "1, " : "0, ");
}
LogMessage(text);
CNXDNConvolution conv;
conv.start();
@ -111,7 +104,7 @@ bool CNXDNSACCH::decode(const unsigned char* data)
conv.chainback(m_data, 32U);
CUtils::dump("NXDN, SACCH decoded", m_data, 5U);
CUtils::dump("NXDN, SACCH decoded", m_data, 4U);
return CNXDNCRC::checkCRC6(m_data, 26U);
}
@ -130,14 +123,14 @@ void CNXDNSACCH::encode(unsigned char* data) const
CNXDNCRC::encodeCRC6(temp1, 26U);
CUtils::dump("NXDN, SACCH encoded with CRC", temp1, 5U);
CUtils::dump("NXDN, SACCH encoded with CRC", temp1, 4U);
unsigned char temp2[9U];
unsigned char temp2[8U];
CNXDNConvolution conv;
conv.encode(temp1, temp2, 36U);
CUtils::dump("NXDN, SACCH convolved", temp2, 9U);
// CUtils::dump("NXDN, SACCH convolved", temp2, 8U);
unsigned char temp3[8U];
@ -153,15 +146,13 @@ 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++) {
unsigned int n = INTERLEAVE_TABLE[i] + NXDN_FSW_LENGTH_BITS + NXDN_LICH_LENGTH_BITS;
bool b = READ_BIT1(temp3, i);
WRITE_BIT1(data, n, b);
}
CUtils::dump("NXDN, SACCH re-encoded", data, 12U);
}
unsigned char CNXDNSACCH::getRAN() const

View file

@ -28,6 +28,43 @@
#include <cassert>
#include <cstring>
const unsigned int INTERLEAVE_TABLE[] = {
0U, 29U, 58U, 87U, 116U, 145U, 174U, 203U, 232U, 261U, 290U, 319U,
1U, 30U, 59U, 88U, 117U, 146U, 175U, 204U, 233U, 262U, 291U, 320U,
2U, 31U, 60U, 89U, 118U, 147U, 176U, 205U, 234U, 263U, 292U, 321U,
3U, 32U, 61U, 90U, 119U, 148U, 177U, 206U, 235U, 264U, 293U, 322U,
4U, 33U, 62U, 91U, 120U, 149U, 178U, 207U, 236U, 265U, 294U, 323U,
5U, 34U, 63U, 92U, 121U, 150U, 179U, 208U, 237U, 266U, 295U, 324U,
6U, 35U, 64U, 93U, 122U, 151U, 180U, 209U, 238U, 267U, 296U, 325U,
7U, 36U, 65U, 94U, 123U, 152U, 181U, 210U, 239U, 268U, 297U, 326U,
8U, 37U, 66U, 95U, 124U, 153U, 182U, 211U, 240U, 269U, 298U, 327U,
9U, 38U, 67U, 96U, 125U, 154U, 183U, 212U, 241U, 270U, 299U, 328U,
10U, 39U, 68U, 97U, 126U, 155U, 184U, 213U, 242U, 271U, 300U, 329U,
11U, 40U, 69U, 98U, 127U, 156U, 185U, 214U, 243U, 272U, 301U, 330U,
12U, 41U, 70U, 99U, 128U, 157U, 186U, 215U, 244U, 273U, 302U, 331U,
13U, 42U, 71U, 100U, 129U, 158U, 187U, 216U, 245U, 274U, 303U, 332U,
14U, 43U, 72U, 101U, 130U, 159U, 188U, 217U, 246U, 275U, 304U, 333U,
15U, 44U, 73U, 102U, 131U, 160U, 189U, 218U, 247U, 276U, 305U, 334U,
16U, 45U, 74U, 103U, 132U, 161U, 190U, 219U, 248U, 277U, 306U, 335U,
17U, 46U, 75U, 104U, 133U, 162U, 191U, 220U, 249U, 278U, 307U, 336U,
18U, 47U, 76U, 105U, 134U, 163U, 192U, 221U, 250U, 279U, 308U, 337U,
19U, 48U, 77U, 106U, 135U, 164U, 193U, 222U, 251U, 280U, 309U, 338U,
20U, 49U, 78U, 107U, 136U, 165U, 194U, 223U, 252U, 281U, 310U, 339U,
21U, 50U, 79U, 108U, 137U, 166U, 195U, 224U, 253U, 282U, 311U, 340U,
22U, 51U, 80U, 109U, 138U, 167U, 196U, 225U, 254U, 283U, 312U, 341U,
23U, 52U, 81U, 110U, 139U, 168U, 197U, 226U, 255U, 284U, 313U, 342U,
24U, 53U, 82U, 111U, 140U, 169U, 198U, 227U, 256U, 285U, 314U, 343U,
25U, 54U, 83U, 112U, 141U, 170U, 199U, 228U, 257U, 286U, 315U, 344U,
26U, 55U, 84U, 113U, 142U, 171U, 200U, 229U, 258U, 287U, 316U, 345U,
27U, 56U, 85U, 114U, 143U, 172U, 201U, 230U, 259U, 288U, 317U, 346U,
28U, 57U, 86U, 115U, 144U, 173U, 202U, 231U, 260U, 289U, 318U, 347U };
const unsigned int PUNCTURE_LIST[] = { 3U, 11U, 17U, 25U, 31U, 39U, 45U, 53U, 59U, 67U,
73U, 81U, 87U, 95U, 101U, 109U, 115U, 123U, 129U, 137U,
143U, 151U, 157U, 165U, 171U, 179U, 185U, 193U, 199U, 207U,
213U, 221U, 227U, 235U, 241U, 249U, 255U, 263U, 269U, 277U,
283U, 291U, 297U, 305U, 311U, 319U, 325U, 333U, 339U, 347U };
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
@ -55,26 +92,119 @@ bool CNXDNUDCH::decode(const unsigned char* data)
{
assert(data != NULL);
return true;
CUtils::dump("NXDN, UDCH/FACCH2 input", data, 44U);
unsigned char temp1[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;
bool b = READ_BIT1(data, n);
WRITE_BIT1(temp1, i, b);
}
CUtils::dump("NXDN, UDCH/FACCH2 de-interleaved", temp1, 44U);
uint8_t temp2[406U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < NXDN_FACCH2_LENGTH_BITS; i++) {
if (n == PUNCTURE_LIST[index]) {
temp2[n++] = 99U;
index++;
}
bool b = READ_BIT1(temp1, i);
temp2[n++] = b ? 1U : 0U;
}
CNXDNConvolution conv;
conv.start();
n = 0U;
for (unsigned int i = 0U; i < 203U; i++) {
uint8_t s0 = temp2[n++];
uint8_t s1 = temp2[n++];
conv.decode(s0, s1);
}
conv.chainback(m_data, 199U);
CUtils::dump("NXDN, UDCH/FACCH2 decoded", m_data, 25U);
return CNXDNCRC::checkCRC15(m_data, 184U);
}
void CNXDNUDCH::encode(unsigned char* data) const
{
assert(data != NULL);
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);
}
CNXDNCRC::encodeCRC15(temp1, 184U);
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);
unsigned char temp3[44U];
unsigned int n = 0U;
unsigned int index = 0U;
for (unsigned int i = 0U; i < 406U; i++) {
if (i != PUNCTURE_LIST[index]) {
bool b = READ_BIT1(temp2, i);
WRITE_BIT1(temp3, n, b);
n++;
} else {
index++;
}
}
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;
bool b = READ_BIT1(temp3, i);
WRITE_BIT1(data, n, b);
}
}
unsigned char CNXDNUDCH::getRAN() const
{
return m_data[0U] & 0x3FU;
}
void CNXDNUDCH::getData(unsigned char* data) const
{
assert(data != NULL);
::memcpy(data, m_data, 23U);
::memcpy(data, m_data + 1U, 22U);
}
void CNXDNUDCH::setRAN(unsigned char ran)
{
m_data[0U] &= 0xC0U;
m_data[0U] |= ran;
}
void CNXDNUDCH::setData(const unsigned char* data)
{
assert(data != NULL);
::memcpy(m_data, data, 23U);
::memcpy(m_data + 1U, data, 22U);
}
CNXDNUDCH& CNXDNUDCH::operator=(const CNXDNUDCH& udch)

View file

@ -29,8 +29,12 @@ public:
void encode(unsigned char* data) const;
unsigned char getRAN() const;
void getData(unsigned char* data) const;
void setRAN(unsigned char ran);
void setData(const unsigned char* data);
CNXDNUDCH& operator=(const CNXDNUDCH& udch);