diff --git a/Conf.cpp b/Conf.cpp index 7e68f9d..513cae3 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -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 diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index d296b57..51843db 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -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() diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 21583f8..5e39637 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -198,7 +198,7 @@ - + @@ -280,7 +280,7 @@ - + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index c0b4ae1..8eedd67 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -257,10 +257,10 @@ Header Files - + Header Files - + Header Files @@ -487,10 +487,10 @@ Source Files - + Source Files - + Source Files diff --git a/Makefile b/Makefile index 9176107..12f36e8 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/Makefile.Pi b/Makefile.Pi index 900cfc0..7379f9f 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -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 diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index a46caee..564c4a4 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -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 diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 5bde70a..dbb7df5 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -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 diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index e8b4e5e..19c0c62 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -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 diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index d4dacca..5d28a2b 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -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 diff --git a/Makefile.Solaris b/Makefile.Solaris index 3a93712..d40317f 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -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 diff --git a/NXDNControl.cpp b/NXDNControl.cpp index fd0809f..74b2991 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -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 diff --git a/NXDNControl.h b/NXDNControl.h index da2fd12..5f000e7 100644 --- a/NXDNControl.h +++ b/NXDNControl.h @@ -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; diff --git a/NXDNConvolution.cpp b/NXDNConvolution.cpp index 2881412..049bdb6 100755 --- a/NXDNConvolution.cpp +++ b/NXDNConvolution.cpp @@ -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; diff --git a/NXDNDefines.h b/NXDNDefines.h index c9ab105..463ca61 100644 --- a/NXDNDefines.h +++ b/NXDNDefines.h @@ -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 diff --git a/NXDNFACCH1.cpp b/NXDNFACCH1.cpp index f548a8d..48f4639 100644 --- a/NXDNFACCH1.cpp +++ b/NXDNFACCH1.cpp @@ -28,6 +28,22 @@ #include #include +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 diff --git a/NXDNFACCH1.h b/NXDNFACCH1.h index 3c9c664..adb4112 100644 --- a/NXDNFACCH1.h +++ b/NXDNFACCH1.h @@ -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); diff --git a/NXDNLICH.cpp b/NXDNLICH.cpp index b5e363c..df735b9 100644 --- a/NXDNLICH.cpp +++ b/NXDNLICH.cpp @@ -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; diff --git a/NXDNFACCH2.cpp b/NXDNLayer3.cpp similarity index 50% rename from NXDNFACCH2.cpp rename to NXDNLayer3.cpp index ac705fa..f4da16b 100644 --- a/NXDNFACCH2.cpp +++ b/NXDNLayer3.cpp @@ -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 @@ -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; } diff --git a/NXDNFACCH2.h b/NXDNLayer3.h similarity index 58% rename from NXDNFACCH2.h rename to NXDNLayer3.h index 7f8ee57..81aff2b 100644 --- a/NXDNFACCH2.h +++ b/NXDNLayer3.h @@ -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; diff --git a/NXDNNetwork.cpp b/NXDNNetwork.cpp index 5476766..6453829 100644 --- a/NXDNNetwork.cpp +++ b/NXDNNetwork.cpp @@ -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() diff --git a/NXDNNetwork.h b/NXDNNetwork.h index ea96826..c69602a 100644 --- a/NXDNNetwork.h +++ b/NXDNNetwork.h @@ -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(); diff --git a/NXDNSACCH.cpp b/NXDNSACCH.cpp index 262cde2..304b20d 100755 --- a/NXDNSACCH.cpp +++ b/NXDNSACCH.cpp @@ -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 diff --git a/NXDNUDCH.cpp b/NXDNUDCH.cpp index 1d194b9..e58460e 100644 --- a/NXDNUDCH.cpp +++ b/NXDNUDCH.cpp @@ -28,6 +28,43 @@ #include #include +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) diff --git a/NXDNUDCH.h b/NXDNUDCH.h index 6847c9c..366cd09 100644 --- a/NXDNUDCH.h +++ b/NXDNUDCH.h @@ -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);