diff --git a/AMBEFEC.cpp b/AMBEFEC.cpp index 31ccfaf..37749a2 100644 --- a/AMBEFEC.cpp +++ b/AMBEFEC.cpp @@ -596,7 +596,7 @@ unsigned int CAMBEFEC::regenerateDStar(unsigned char* bytes) const return errors; } -unsigned int CAMBEFEC::regenerateYSF1(unsigned char* bytes) const +unsigned int CAMBEFEC::regenerateYSFDN(unsigned char* bytes) const { assert(bytes != NULL); @@ -638,7 +638,7 @@ unsigned int CAMBEFEC::regenerateYSF1(unsigned char* bytes) const return errors; } -unsigned int CAMBEFEC::regenerateYSF3(unsigned char* bytes) const +unsigned int CAMBEFEC::regenerateIMBE(unsigned char* bytes) const { assert(bytes != NULL); diff --git a/AMBEFEC.h b/AMBEFEC.h index 19453db..2173fda 100644 --- a/AMBEFEC.h +++ b/AMBEFEC.h @@ -28,9 +28,9 @@ public: unsigned int regenerateDStar(unsigned char* bytes) const; - unsigned int regenerateYSF1(unsigned char* bytes) const; + unsigned int regenerateYSFDN(unsigned char* bytes) const; - unsigned int regenerateYSF3(unsigned char* bytes) const; + unsigned int regenerateIMBE(unsigned char* bytes) const; private: unsigned int regenerate(unsigned int& a, unsigned int& b, unsigned int& c, bool b23) const; diff --git a/Conf.cpp b/Conf.cpp index 781dc33..eb9fa4d 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -111,7 +111,7 @@ m_dmrCallHang(3U), m_dmrTXHang(4U), m_fusionEnabled(true), m_p25Enabled(true), -m_p25Id(0U), +m_p25NAC(0x293U), m_dstarNetworkEnabled(true), m_dstarGatewayAddress(), m_dstarGatewayPort(0U), @@ -438,8 +438,8 @@ bool CConf::read() } else if (section == SECTION_P25) { if (::strcmp(key, "Enable") == 0) m_p25Enabled = ::atoi(value) == 1; - else if (::strcmp(key, "Id") == 0) - m_p25Id = (unsigned int)::atoi(value); + else if (::strcmp(key, "NAC") == 0) + m_p25NAC = (unsigned int)::strtoul(value, NULL, 16); } else if (section == SECTION_DSTAR_NETWORK) { if (::strcmp(key, "Enable") == 0) m_dstarNetworkEnabled = ::atoi(value) == 1; @@ -849,9 +849,9 @@ bool CConf::getP25Enabled() const return m_p25Enabled; } -unsigned int CConf::getP25Id() const +unsigned int CConf::getP25NAC() const { - return m_p25Id; + return m_p25NAC; } bool CConf::getDStarNetworkEnabled() const diff --git a/Conf.h b/Conf.h index 66eaeed..9b985df 100644 --- a/Conf.h +++ b/Conf.h @@ -108,7 +108,7 @@ public: // The P25 section bool getP25Enabled() const; - unsigned int getP25Id() const; + unsigned int getP25NAC() const; // The D-Star Network section bool getDStarNetworkEnabled() const; @@ -243,7 +243,7 @@ private: bool m_fusionEnabled; bool m_p25Enabled; - unsigned int m_p25Id; + unsigned int m_p25NAC; bool m_dstarNetworkEnabled; std::string m_dstarGatewayAddress; diff --git a/DMRControl.cpp b/DMRControl.cpp index 3ba58ee..d13b43f 100644 --- a/DMRControl.cpp +++ b/DMRControl.cpp @@ -20,7 +20,7 @@ #include #include -CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector& prefixes, const std::vector& blackList, const std::vector& DstIdBlacklistSlot1RF, const std::vector& DstIdWhitelistSlot1RF, const std::vector& DstIdBlacklistSlot2RF, const std::vector& DstIdWhitelistSlot2RF, const std::vector& DstIdBlacklistSlot1NET, const std::vector& DstIdWhitelistSlot1NET, const std::vector& DstIdBlacklistSlot2NET, const std::vector& DstIdWhitelistSlot2NET, unsigned int timeout, CModem* modem, CDMRIPSC* network, CDisplay* display, bool duplex, const std::string& lookupFile, int rssiMultiplier, int rssiOffset, unsigned int jitter) : +CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector& prefixes, const std::vector& blackList, const std::vector& DstIdBlacklistSlot1RF, const std::vector& DstIdWhitelistSlot1RF, const std::vector& DstIdBlacklistSlot2RF, const std::vector& DstIdWhitelistSlot2RF, const std::vector& DstIdBlacklistSlot1NET, const std::vector& DstIdWhitelistSlot1NET, const std::vector& DstIdBlacklistSlot2NET, const std::vector& DstIdWhitelistSlot2NET, unsigned int timeout, CModem* modem, CDMRIPSC* network, CDisplay* display, bool duplex, CDMRLookup* lookup, int rssiMultiplier, int rssiOffset, unsigned int jitter) : m_id(id), m_colorCode(colorCode), m_selfOnly(selfOnly), @@ -30,15 +30,13 @@ m_modem(modem), m_network(network), m_slot1(1U, timeout), m_slot2(2U, timeout), -m_lookup(NULL) +m_lookup(lookup) { assert(modem != NULL); assert(display != NULL); + assert(lookup != NULL); - m_lookup = new CDMRLookup(lookupFile); - m_lookup->read(); - - CDMRSlot::init(id, colorCode, callHang, selfOnly, prefixes, blackList, DstIdBlacklistSlot1RF, DstIdWhitelistSlot1RF, DstIdBlacklistSlot2RF, DstIdWhitelistSlot2RF, DstIdBlacklistSlot1NET, DstIdWhitelistSlot1NET, DstIdBlacklistSlot2NET, DstIdWhitelistSlot2NET, modem, network, display, duplex, m_lookup, rssiMultiplier, rssiOffset, jitter); + CDMRSlot::init(id, colorCode, callHang, selfOnly, prefixes, blackList, DstIdBlacklistSlot1RF, DstIdWhitelistSlot1RF, DstIdBlacklistSlot2RF, DstIdWhitelistSlot2RF, DstIdBlacklistSlot1NET, DstIdWhitelistSlot1NET, DstIdBlacklistSlot2NET, DstIdWhitelistSlot2NET, modem, network, display, duplex, lookup, rssiMultiplier, rssiOffset, jitter); } CDMRControl::~CDMRControl() diff --git a/DMRControl.h b/DMRControl.h index 3187828..09ed3be 100644 --- a/DMRControl.h +++ b/DMRControl.h @@ -30,7 +30,7 @@ class CDMRControl { public: - CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector& prefixes, const std::vector& blackList, const std::vector& DstIdBlacklistSlot1RF, const std::vector& DstIdWhitelistSlot1RF, const std::vector& DstIdBlacklistSlot2RF, const std::vector& DstIdWhitelistSlot2RF,const std::vector& DstIdBlacklistSlot1NET, const std::vector& DstIdWhitelistSlot1NET, const std::vector& DstIdBlacklistSlot2NET, const std::vector& DstIdWhitelistSlot2NET, unsigned int timeout, CModem* modem, CDMRIPSC* network, CDisplay* display, bool duplex, const std::string& lookupFile, int rssiMultiplier, int rssiOffset, unsigned int jitter); + CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector& prefixes, const std::vector& blackList, const std::vector& DstIdBlacklistSlot1RF, const std::vector& DstIdWhitelistSlot1RF, const std::vector& DstIdBlacklistSlot2RF, const std::vector& DstIdWhitelistSlot2RF,const std::vector& DstIdBlacklistSlot1NET, const std::vector& DstIdWhitelistSlot1NET, const std::vector& DstIdBlacklistSlot2NET, const std::vector& DstIdWhitelistSlot2NET, unsigned int timeout, CModem* modem, CDMRIPSC* network, CDisplay* display, bool duplex, CDMRLookup* lookup, int rssiMultiplier, int rssiOffset, unsigned int jitter); ~CDMRControl(); bool processWakeup(const unsigned char* data); diff --git a/DMRLookup.cpp b/DMRLookup.cpp index d358ed7..a77b053 100644 --- a/DMRLookup.cpp +++ b/DMRLookup.cpp @@ -37,7 +37,7 @@ bool CDMRLookup::read() { FILE* fp = ::fopen(m_filename.c_str(), "rt"); if (fp == NULL) { - LogWarning("Cannot open the DMR Id lookup file - %s", m_filename.c_str()); + LogWarning("Cannot open the Id lookup file - %s", m_filename.c_str()); return false; } @@ -64,7 +64,7 @@ bool CDMRLookup::read() if (size == 0U) return false; - LogInfo("Loaded %u DMR Ids to the callsign lookup table", size); + LogInfo("Loaded %u Ids to the callsign lookup table", size); return true; } diff --git a/MMDVM.ini b/MMDVM.ini index 55a992d..b8d7463 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -47,7 +47,7 @@ TXLevel=50 OscOffset=0 RSSIMultiplier=1 RSSIOffset=10 -Debug=0 +Debug=1 [D-Star] Enable=1 @@ -79,7 +79,7 @@ Enable=1 [P25] Enable=1 -Id=123456 +NAC=293 [D-Star Network] Enable=1 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index ade732a..84d2ea6 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -23,6 +23,7 @@ #include "Defines.h" #include "DStarControl.h" #include "DMRControl.h" +#include "DMRLookup.h" #include "TFTSerial.h" #include "NullDisplay.h" #include "YSFControl.h" @@ -267,6 +268,16 @@ int CMMDVMHost::run() CTimer dmrBeaconTimer(1000U, 4U); bool dmrBeaconsEnabled = m_dmrEnabled && m_conf.getDMRBeacons(); + // For DMR and P25 we try to map IDs to callsigns + CDMRLookup* lookup = NULL; + if (m_dmrEnabled || m_p25Enabled) { + std::string lookupFile = m_conf.getDMRLookupFile(); + LogInfo("ID lookup File: %s", lookupFile.length() > 0U ? lookupFile.c_str() : "None"); + + lookup = new CDMRLookup(lookupFile); + lookup->read(); + } + CStopWatch stopWatch; stopWatch.start(); @@ -308,7 +319,6 @@ int CMMDVMHost::run() std::vector dstIDBlackListSlot2NET = m_conf.getDMRDstIdBlacklistSlot2NET(); std::vector dstIDWhiteListSlot1NET = m_conf.getDMRDstIdWhitelistSlot1NET(); std::vector dstIDWhiteListSlot2NET = m_conf.getDMRDstIdWhitelistSlot2NET(); - std::string lookupFile = m_conf.getDMRLookupFile(); unsigned int callHang = m_conf.getDMRCallHang(); unsigned int txHang = m_conf.getDMRTXHang(); int rssiMultiplier = m_conf.getModemRSSIMultiplier(); @@ -348,7 +358,6 @@ int CMMDVMHost::run() if (dstIDWhiteListSlot2NET.size() > 0U) LogInfo(" Slot 2 NET Destination ID White List: %u entries", dstIDWhiteListSlot2NET.size()); - LogInfo(" Lookup File: %s", lookupFile.length() > 0U ? lookupFile.c_str() : "None"); LogInfo(" Call Hang: %us", callHang); LogInfo(" TX Hang: %us", txHang); @@ -357,7 +366,7 @@ int CMMDVMHost::run() LogInfo(" RSSI Offset: %d", rssiOffset); } - dmr = new CDMRControl(id, colorCode, callHang, selfOnly, prefixes, blackList,dstIDBlackListSlot1RF,dstIDWhiteListSlot1RF, dstIDBlackListSlot2RF, dstIDWhiteListSlot2RF, dstIDBlackListSlot1NET,dstIDWhiteListSlot1NET, dstIDBlackListSlot2NET, dstIDWhiteListSlot2NET, m_timeout, m_modem, m_dmrNetwork, m_display, m_duplex, lookupFile, rssiMultiplier, rssiOffset, jitter); + dmr = new CDMRControl(id, colorCode, callHang, selfOnly, prefixes, blackList,dstIDBlackListSlot1RF,dstIDWhiteListSlot1RF, dstIDBlackListSlot2RF, dstIDWhiteListSlot2RF, dstIDBlackListSlot1NET,dstIDWhiteListSlot1NET, dstIDBlackListSlot2NET, dstIDWhiteListSlot2NET, m_timeout, m_modem, m_dmrNetwork, m_display, m_duplex, lookup, rssiMultiplier, rssiOffset, jitter); m_dmrTXTimer.setTimeout(txHang); } @@ -379,19 +388,19 @@ int CMMDVMHost::run() CP25Control* p25 = NULL; if (m_p25Enabled) { - unsigned int id = m_conf.getP25Id(); + unsigned int nac = m_conf.getP25NAC(); int rssiMultiplier = m_conf.getModemRSSIMultiplier(); int rssiOffset = m_conf.getModemRSSIOffset(); LogInfo("P25 Parameters"); - LogInfo(" Id: %u", id); + LogInfo(" NAC: $%03X", nac); if (rssiMultiplier != 0) { LogInfo(" RSSI Multiplier: %d", rssiMultiplier); LogInfo(" RSSI Offset: %d", rssiOffset); } - p25 = new CP25Control(id, m_display, m_timeout, m_duplex, rssiMultiplier, rssiOffset); + p25 = new CP25Control(nac, m_display, m_timeout, m_duplex, lookup, rssiMultiplier, rssiOffset); } setMode(MODE_IDLE); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 04bba5f..0123da0 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -181,8 +181,11 @@ + + + @@ -236,7 +239,10 @@ + + + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index e1dbca3..5a74ec4 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -179,6 +179,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -328,5 +337,14 @@ Source Files + + Source Files + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index 929fc2c..74bc40f 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,8 @@ LDFLAGS = -g OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.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 Log.o MMDVMHost.o \ - Modem.o Nextion.o NullDisplay.o P25Control.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o \ - YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25NID.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \ + Timer.o UDPSocket.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 fef63c3..ec2c504 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -9,8 +9,8 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.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 Log.o \ - MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Control.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o \ - UDPSocket.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25NID.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ + Thread.o Timer.o UDPSocket.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 9dac5df..4f2a19d 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -9,8 +9,8 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.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 Log.o \ - MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Control.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o \ - Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25NID.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ + Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index b95bc1e..27dacfd 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -9,8 +9,8 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.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 OLED.o Log.o \ - MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Control.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o \ - UDPSocket.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25NID.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ + Thread.o Timer.o UDPSocket.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 990725c..9fbfd7b 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -9,8 +9,8 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.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 Log.o \ - MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Control.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o \ - UDPSocket.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25NID.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ + Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Solaris b/Makefile.Solaris index a66f313..a4b0494 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -9,8 +9,8 @@ LDFLAGS = -g OBJECTS = \ AMBEFEC.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRIPSC.o DMRLookup.o DMRLC.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 Log.o MMDVMHost.o \ - Modem.o Nextion.o NullDisplay.o P25Control.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o \ - YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25NID.o QR1676.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o \ + Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Modem.cpp b/Modem.cpp index 30d355d..5589b72 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -36,6 +36,98 @@ #include #endif +const unsigned char P25_DATA[6U][222U] = { + { 0xE0U, 0x67U, 0x30U, 0x01U, 0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU, 0x29U, 0x30U, 0x0EU, 0xCEU, 0xD7U, 0x7EU, + 0x00U, 0x70U, 0x80U, 0x00U, 0x00U, 0x02U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x0AU, 0x37U, 0x18U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x8EU, + 0xB5U, 0xE0U, 0x96U, 0x52U, 0x7CU, 0x2AU, 0x23U, 0x54U, 0x0DU, 0x9FU, 0x34U, 0x7EU, 0xF1U, 0xD4U, 0x1EU, 0x42U, + 0x1EU, 0xA2U, 0x35U, 0x8BU, 0xFEU, 0x31U, 0x2AU, 0x5EU, 0x37U, 0x18U, 0x4AU, 0x96U, 0x51U, 0xBAU, 0x30U, 0xA4U, + 0xF8U, 0x0CU, 0x75U, 0x4CU, 0x75U, 0x10U, 0x02U, 0x00U, 0x00U, 0x0FU, 0x3AU, 0x14U, 0xE9U, 0x4DU, 0x8CU, 0xCEU, + 0xE7U, 0x52U, 0x17U, 0x28U, 0xD6U, 0x45U, 0x77U, 0xF0U, 0xD2U, 0x23U, 0x25U, 0x6BU, 0x00U, 0x00U, 0x27U, 0x6CU, + 0xF2U, 0x86U, 0x46U, 0x45U, 0xE0U, 0x1AU, 0x90U, 0xD1U, 0x27U, 0x00U, 0x0AU, 0xD0U, 0x02U, 0x67U, 0x6AU, 0x13U, + 0x36U, 0xF9U, 0x4AU, 0xFEU, 0xFEU, 0x2AU, 0x8CU, 0x41U, 0xC3U, 0xCFU, 0x94U, 0x30U, 0x56U, 0xEBU, 0x10U, 0xC0U, + 0x8AU, 0xEFU, 0x5FU, 0x14U, 0xB3U, 0x82U, 0xE7U, 0xC4U, 0x4FU, 0x55U, 0x18U, 0xDEU, 0x33U, 0xDCU, 0x7EU, 0x69U, + 0x71U, 0xFFU, 0xB1U, 0xE9U, 0x10U, 0x27U, 0xD8U, 0x1AU, 0x28U, 0xF4U, 0xBFU, 0xB6U, 0x85U, 0x9AU, 0x12U, 0xB7U, + 0x92U, 0x42U, 0x33U, 0xB9U, 0x55U, 0xE0U, 0x8FU, 0x22U, 0x2FU, 0xD6U, 0x2FU, 0x71U, 0x07U, 0x61U, 0x38U, 0xFDU, + 0xF8U, 0x22U, 0xB2U, 0x11U, 0xCBU, 0x8FU, 0x3EU, 0x69U, 0x88U, 0x6FU, 0xDDU, 0x22U, 0x00U, 0x00U }, + + { 0xE0U, 0xDEU, 0x31U, 0x01U, 0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU, 0x29U, 0x35U, 0x56U, 0x7BU, 0xCBU, 0x19U, + 0x4DU, 0x0DU, 0xDBU, 0x10U, 0xBAU, 0x16U, 0xDEU, 0x2EU, 0x82U, 0x69U, 0x36U, 0x3DU, 0x98U, 0x1FU, 0x9AU, 0xF8U, + 0x8EU, 0xC6U, 0x2BU, 0x80U, 0x11U, 0xB1U, 0x0BU, 0xA2U, 0x5DU, 0xE2U, 0xE8U, 0x26U, 0x93U, 0x63U, 0xD9U, 0x81U, + 0xFAU, 0x6FU, 0x88U, 0xECU, 0x62U, 0xB8U, 0x01U, 0x80U, 0x00U, 0x02U, 0x00U, 0x00U, 0x06U, 0xC4U, 0x2EU, 0x85U, + 0xDEU, 0x2EU, 0x82U, 0x9AU, 0x4DU, 0x8FU, 0x66U, 0x07U, 0xE6U, 0xF8U, 0x8EU, 0xC6U, 0x8AU, 0xE0U, 0x04U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x1CU, 0x6EU, 0x10U, 0xBAU, 0x17U, 0x78U, 0xBAU, 0x09U, 0xA4U, 0xD8U, 0xF6U, 0x98U, 0x1FU, + 0x9BU, 0xE2U, 0x3BU, 0x18U, 0xAEU, 0x00U, 0x62U, 0x00U, 0x00U, 0x0FU, 0x3AU, 0x14U, 0xE9U, 0x4DU, 0x8CU, 0xCEU, + 0xE7U, 0x52U, 0x17U, 0x28U, 0xD6U, 0x45U, 0x77U, 0xF0U, 0xD2U, 0x23U, 0x25U, 0x6BU, 0x00U, 0x00U, 0x27U, 0x6CU, + 0xF2U, 0x86U, 0x46U, 0x45U, 0xE0U, 0x1AU, 0x90U, 0xD1U, 0x27U, 0x00U, 0x0AU, 0xD0U, 0x02U, 0x67U, 0x6AU, 0x13U, + 0x36U, 0xF9U, 0x4AU, 0xFEU, 0xFEU, 0x2AU, 0x8CU, 0x41U, 0xC3U, 0xCFU, 0x94U, 0x30U, 0x56U, 0xEBU, 0x10U, 0xC0U, + 0x8AU, 0xEFU, 0x5FU, 0x14U, 0xB3U, 0x82U, 0xE7U, 0xC4U, 0x4FU, 0x55U, 0x18U, 0xDEU, 0x33U, 0xDCU, 0x7EU, 0x69U, + 0x71U, 0xFFU, 0xB1U, 0xE9U, 0x10U, 0x27U, 0xD8U, 0x1AU, 0x28U, 0xF4U, 0xBFU, 0xB6U, 0x85U, 0x9AU, 0x12U, 0xB7U, + 0x92U, 0x42U, 0x33U, 0xB9U, 0x55U, 0xE0U, 0x8FU, 0x22U, 0x2FU, 0xD6U, 0x2FU, 0x71U, 0x07U, 0x61U, 0x38U, 0xFDU, + 0xF8U, 0x22U, 0xB2U, 0x11U, 0xCBU, 0x8FU, 0x3EU, 0x69U, 0x88U, 0x6FU, 0xDDU, 0x22U, 0x00U, 0x00U }, + + { 0xE0U, 0xDCU, 0x31U, 0x01U, 0x55U, 0x75U, 0xF5U, 0xFEU, 0x77U, 0xFFU, 0x29U, 0x3AU, 0xBAU, 0xA4U, 0xEFU, 0xB0U, + 0x9AU, 0x8AU, 0xCEU, 0x9DU, 0xADU, 0x1EU, 0xCDU, 0x06U, 0xFBU, 0xF6U, 0xA8U, 0x28U, 0xEDU, 0x7BU, 0x5AU, 0x8CU, + 0x15U, 0xC7U, 0x08U, 0xEEU, 0x38U, 0xD1U, 0x4BU, 0xEEU, 0xA5U, 0xE7U, 0xE0U, 0xD5U, 0x5DU, 0x49U, 0x05U, 0x0DU, + 0x72U, 0xFAU, 0xB0U, 0xD4U, 0xA6U, 0x08U, 0x64U, 0x40U, 0x00U, 0x02U, 0x00U, 0x00U, 0x07U, 0xA3U, 0x36U, 0x5CU, + 0x96U, 0x5AU, 0x26U, 0xFDU, 0xD6U, 0x35U, 0x64U, 0x11U, 0x82U, 0x0CU, 0x8DU, 0xFAU, 0x75U, 0xF6U, 0xD7U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x72U, 0x20U, 0x56U, 0x60U, 0xA5U, 0xEBU, 0x24U, 0x6BU, 0xF6U, 0x1AU, 0x83U, 0xECU, + 0xA9U, 0x39U, 0xACU, 0x7DU, 0x44U, 0xC4U, 0x42U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x4AU, 0x00U, 0xDAU, 0x66U, + 0xF2U, 0x8FU, 0x3BU, 0xBAU, 0xA5U, 0x8EU, 0x9BU, 0xC4U, 0x0EU, 0x49U, 0x17U, 0xE9U, 0x5AU, 0x14U, 0xA0U, 0xE0U, + 0x00U, 0x02U, 0x00U, 0x03U, 0x75U, 0xD6U, 0xB9U, 0x6CU, 0x54U, 0x24U, 0x56U, 0x5CU, 0xACU, 0x5AU, 0x81U, 0xA5U, + 0x9BU, 0x06U, 0x47U, 0x96U, 0xE9U, 0x49U, 0xAEU, 0x8BU, 0x48U, 0xB6U, 0x49U, 0x9CU, 0x42U, 0xD8U, 0xA1U, 0x5DU, + 0x58U, 0xC0U, 0x70U, 0xC4U, 0xBAU, 0xEEU, 0x39U, 0x99U, 0xC8U, 0x2EU, 0xFFU, 0x31U, 0x37U, 0xA9U, 0xAAU, 0xF4U, + 0xF1U, 0xFDU, 0x63U, 0x0BU, 0xC2U, 0x71U, 0xD9U, 0x12U, 0xA7U, 0x35U, 0x13U, 0x15U, 0xBAU, 0x31U, 0x1EU, 0xAEU, + 0x6EU, 0xC7U, 0x3CU, 0x70U, 0x96U, 0x7CU, 0x41U, 0x1CU, 0x1CU, 0xE2U, 0xA2U, 0x44U, 0x59U, 0xE8U, 0x46U, 0x88U, + 0x3AU, 0x70U, 0xFEU, 0xD3U, 0xD3U, 0x13U, 0x44U, 0xA1U, 0x67U, 0xECU, 0xF8U, 0xAEU }, + + { 0xE0U, 0xDCU, 0x31U, 0x01U, 0x55U, 0x75U, 0xF5U, 0xFEU, 0x77U, 0xFFU, 0x29U, 0x35U, 0x56U, 0x7BU, 0xCBU, 0x19U, + 0x4DU, 0x0DU, 0xFDU, 0x2AU, 0x9AU, 0x12U, 0x2BU, 0x2AU, 0xE1U, 0xB0U, 0xA1U, 0xDBU, 0x88U, 0x26U, 0x82U, 0x5FU, + 0x40U, 0xFEU, 0x15U, 0x3DU, 0x20U, 0x92U, 0x1BU, 0x2EU, 0x49U, 0xF3U, 0xACU, 0x3FU, 0xB3U, 0x8DU, 0x39U, 0x2AU, + 0xF6U, 0x09U, 0x14U, 0x58U, 0xF1U, 0xE7U, 0x23U, 0x80U, 0x00U, 0x02U, 0x00U, 0x00U, 0x04U, 0x23U, 0x01U, 0xC3U, + 0x59U, 0x60U, 0xFAU, 0xD9U, 0xE1U, 0x12U, 0x6DU, 0x32U, 0x23U, 0x44U, 0x86U, 0xEEU, 0x11U, 0x87U, 0x68U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x1CU, 0x52U, 0xB4U, 0xD1U, 0x4DU, 0x55U, 0x33U, 0x6EU, 0x63U, 0x92U, 0x42U, 0x8CU, 0xB1U, + 0x9BU, 0x37U, 0xE9U, 0x42U, 0x9BU, 0x2DU, 0xA2U, 0x00U, 0x00U, 0x0FU, 0x3AU, 0x17U, 0x2EU, 0xDBU, 0x20U, 0x0EU, + 0x55U, 0xA3U, 0x6FU, 0x53U, 0xF1U, 0x25U, 0x31U, 0x3EU, 0xDEU, 0x12U, 0x42U, 0x69U, 0xA3U, 0x42U, 0x67U, 0x6CU, + 0xF2U, 0x86U, 0x46U, 0x4DU, 0x6AU, 0x91U, 0x60U, 0x8FU, 0x64U, 0xAAU, 0x1EU, 0xCAU, 0x52U, 0xA0U, 0x60U, 0x49U, + 0xA9U, 0x0CU, 0x70U, 0xCAU, 0x4EU, 0x3BU, 0x8CU, 0x41U, 0xC3U, 0xCFU, 0x90U, 0x80U, 0xBAU, 0x5EU, 0x59U, 0x39U, + 0x21U, 0x12U, 0x19U, 0x3FU, 0xEFU, 0x4AU, 0x2CU, 0xA6U, 0x36U, 0x1AU, 0x07U, 0xCBU, 0xFEU, 0x4CU, 0x7EU, 0x69U, + 0x71U, 0xFFU, 0xB1U, 0xF1U, 0xC7U, 0xE9U, 0x42U, 0x86U, 0xCFU, 0xE9U, 0x48U, 0xC0U, 0xAEU, 0xA4U, 0x58U, 0x97U, + 0xA6U, 0xE6U, 0x71U, 0x82U, 0x52U, 0xEAU, 0x90U, 0xAAU, 0x90U, 0x82U, 0x67U, 0x51U, 0xB5U, 0x5AU, 0x12U, 0xB8U, + 0x1BU, 0xFDU, 0x8AU, 0xBAU, 0xCBU, 0x93U, 0x21U, 0xEEU, 0xA3U, 0x60U, 0x46U, 0x66U }, + + { 0xE0U, 0xDCU, 0x31U, 0x01U, 0x55U, 0x75U, 0xF5U, 0xEFU, 0x77U, 0xFFU, 0x29U, 0x3AU, 0xBAU, 0xA4U, 0xEEU, 0xB0U, + 0x9AU, 0x8AU, 0xC5U, 0x11U, 0xD1U, 0xA2U, 0x0CU, 0x58U, 0xF4U, 0x8DU, 0xC8U, 0xF1U, 0xEDU, 0xA6U, 0x6EU, 0x2CU, + 0x67U, 0xA9U, 0x57U, 0xD1U, 0x38U, 0x02U, 0x91U, 0x2AU, 0xEBU, 0x63U, 0x28U, 0x49U, 0x1AU, 0xAFU, 0xA9U, 0xC6U, + 0xBAU, 0x3CU, 0xD3U, 0x61U, 0x2DU, 0x13U, 0x31U, 0x00U, 0x00U, 0x02U, 0x00U, 0x00U, 0x05U, 0x2BU, 0x48U, 0x4DU, + 0x8DU, 0x7EU, 0x82U, 0x7DU, 0xECU, 0x39U, 0x61U, 0x82U, 0x1DU, 0x3EU, 0xBCU, 0xF2U, 0x66U, 0x8BU, 0x02U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x06U, 0x31U, 0x30U, 0x79U, 0xF1U, 0xBBU, 0x5AU, 0x5AU, 0x51U, 0xB6U, 0x74U, 0x17U, + 0xEEU, 0x3EU, 0xA8U, 0x2BU, 0xA0U, 0xC3U, 0x02U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0xCAU, 0x9CU, 0xA2U, 0x2AU, + 0x82U, 0xC7U, 0x03U, 0x4DU, 0xF1U, 0xE8U, 0xF1U, 0x20U, 0xAEU, 0xA9U, 0xC4U, 0xE9U, 0x1CU, 0xC0U, 0xA0U, 0xE0U, + 0x00U, 0x02U, 0x00U, 0x05U, 0x4AU, 0x05U, 0x38U, 0xE3U, 0x4EU, 0xEAU, 0x92U, 0x7AU, 0x51U, 0x23U, 0x32U, 0x12U, + 0xDEU, 0x69U, 0x0BU, 0x42U, 0x3AU, 0x85U, 0xAEU, 0x8BU, 0x48U, 0xB6U, 0x49U, 0x0AU, 0x36U, 0x16U, 0x9DU, 0xFDU, + 0x51U, 0x67U, 0xD0U, 0x76U, 0x44U, 0x6AU, 0x6DU, 0x4AU, 0x22U, 0x47U, 0xA1U, 0x91U, 0xEAU, 0xA9U, 0xAAU, 0xF4U, + 0xF1U, 0xFDU, 0x62U, 0x9FU, 0x1BU, 0x80U, 0xAFU, 0x4EU, 0xEEU, 0x4DU, 0x48U, 0x7CU, 0x99U, 0x41U, 0xA9U, 0xFAU, + 0x62U, 0xEFU, 0x9DU, 0x79U, 0x92U, 0x6AU, 0x90U, 0xA0U, 0x8FU, 0x2AU, 0xDDU, 0x20U, 0x70U, 0x62U, 0x1CU, 0xF1U, + 0x5FU, 0x71U, 0x4EU, 0xC0U, 0x54U, 0x80U, 0xE2U, 0x76U, 0x71U, 0xA9U, 0x30U, 0xCAU }, + + { 0xE0U, 0xDCU, 0x31U, 0x01U, 0x55U, 0x75U, 0xF5U, 0xFEU, 0x77U, 0xFFU, 0x29U, 0x33U, 0x3AU, 0x5DU, 0xDCU, 0xA3U, + 0x3BU, 0x5BU, 0x80U, 0x00U, 0x00U, 0x02U, 0x16U, 0x60U, 0x02U, 0x80U, 0x08U, 0x00U, 0x20U, 0x20U, 0x00U, 0x80U, + 0x00U, 0x00U, 0x00U, 0x80U, 0x00U, 0x00U, 0x25U, 0x88U, 0x00U, 0x28U, 0x22U, 0x20U, 0x01U, 0xB3U, 0x81U, 0x6AU, + 0x95U, 0x16U, 0x61U, 0x23U, 0xE7U, 0x20U, 0x00U, 0xD8U, 0xDFU, 0xE9U, 0xACU, 0xC9U, 0x07U, 0x69U, 0xB6U, 0x41U, + 0x92U, 0x04U, 0x63U, 0x4AU, 0xF4U, 0xA1U, 0x6FU, 0xF4U, 0xA7U, 0xEAU, 0xACU, 0xE6U, 0xD8U, 0x71U, 0xE3U, 0xE6U, + 0x95U, 0x2DU, 0x3CU, 0xBAU, 0x64U, 0x9EU, 0x97U, 0xF3U, 0x4AU, 0x66U, 0x85U, 0x40U, 0x73U, 0xDCU, 0x28U, 0x83U, + 0x7AU, 0x71U, 0xC7U, 0x01U, 0x5DU, 0xFCU, 0x19U, 0xBAU, 0x61U, 0xD1U, 0xCAU, 0xC7U, 0x82U, 0x96U, 0xF7U, 0x29U, + 0x7BU, 0xD2U, 0xB0U, 0xFBU, 0x21U, 0x13U, 0x31U, 0x54U, 0xFFU, 0x1BU, 0x50U, 0x0DU, 0xD7U, 0x68U, 0x76U, 0xCBU, + 0xA5U, 0xA7U, 0x86U, 0x5EU, 0xE0U, 0x21U, 0x45U, 0x7AU, 0x31U, 0x3EU, 0x50U, 0xAEU, 0x2AU, 0x30U, 0x80U, 0x25U, + 0xA9U, 0x9BU, 0x7DU, 0x4AU, 0x0EU, 0x17U, 0x92U, 0x2AU, 0xA6U, 0xD4U, 0xB2U, 0x60U, 0xCAU, 0xC7U, 0x9AU, 0x5EU, + 0x0AU, 0x14U, 0xD3U, 0xE2U, 0x35U, 0x04U, 0x48U, 0xBAU, 0xE6U, 0x44U, 0xE9U, 0x2EU, 0x73U, 0xB8U, 0xAEU, 0xD8U, + 0xA9U, 0x66U, 0x0DU, 0xA4U, 0x8AU, 0xB2U, 0x5FU, 0xE6U, 0x01U, 0x97U, 0xF4U, 0x1AU, 0x33U, 0x09U, 0x60U, 0x44U, + 0x8EU, 0xA6U, 0xB5U, 0xACU, 0x43U, 0x50U, 0xAFU, 0x5BU, 0xF6U, 0x42U, 0xA3U, 0x27U, 0x01U, 0x44U, 0xAFU, 0x7AU, + 0xB1U, 0x05U, 0x01U, 0x9FU, 0xA4U, 0xFDU, 0x2DU, 0x8FU, 0x48U, 0xA3U, 0xC1U, 0xA3U } }; + + const unsigned char MMDVM_FRAME_START = 0xE0U; const unsigned char MMDVM_GET_VERSION = 0x00U; @@ -127,7 +219,8 @@ m_p25Space(0U), m_tx(false), m_lockout(false), m_error(false), -m_hwType(HWT_UNKNOWN) +m_hwType(HWT_UNKNOWN), +m_nn(0U) { assert(!port.empty()); @@ -214,6 +307,28 @@ void CModem::clock(unsigned int ms) if (m_statusTimer.hasExpired()) { readStatus(); m_statusTimer.start(); + + + const unsigned char* dat = P25_DATA[m_nn]; + if (m_nn == 0U) { + unsigned char data = 101U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_HEADER; + m_rxP25Data.addData(&data, 1U); + + m_rxP25Data.addData(dat + 3U, 100U); + } else if (m_nn > 0U && m_nn < 6U) { + unsigned char data = 220U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_DATA; + m_rxP25Data.addData(&data, 1U); + + m_rxP25Data.addData(dat + 3U, 219U); + } + + m_nn++; } m_inactivityTimer.clock(ms); diff --git a/Modem.h b/Modem.h index 97b1cb5..7efd723 100644 --- a/Modem.h +++ b/Modem.h @@ -129,6 +129,7 @@ private: bool m_lockout; bool m_error; HW_TYPE m_hwType; + unsigned int m_nn; bool readVersion(); bool readStatus(); diff --git a/P25Audio.cpp b/P25Audio.cpp new file mode 100644 index 0000000..98cb8cd --- /dev/null +++ b/P25Audio.cpp @@ -0,0 +1,107 @@ +/* +* Copyright (C) 2016 by Jonathan Naylor G4KLX +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "P25Audio.h" + +#include +#include + +const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT(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_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +CP25Audio::CP25Audio() : +m_fec() +{ +} + +CP25Audio::~CP25Audio() +{ +} + +unsigned int CP25Audio::process(unsigned char* data) +{ + assert(data != NULL); + + unsigned int errs = 0U; + + unsigned char imbe[18U]; + + read(data, imbe, 114U, 262U, 142U, 143U, 214U, 215U); + errs += m_fec.regenerateIMBE(imbe); + write(data, imbe, 114U, 262U, 142U, 143U, 214U, 215U); + + read(data, imbe, 262U, 410U, 286U, 287U, 358U, 359U); + errs += m_fec.regenerateIMBE(imbe); + write(data, imbe, 262U, 410U, 286U, 287U, 358U, 359U); + + read(data, imbe, 452U, 600U, 502U, 503U, 574U, 575U); + errs += m_fec.regenerateIMBE(imbe); + write(data, imbe, 452U, 600U, 502U, 503U, 574U, 575U); + + read(data, imbe, 640U, 788U, 646U, 647U, 718U, 719U); + errs += m_fec.regenerateIMBE(imbe); + write(data, imbe, 640U, 788U, 646U, 647U, 718U, 719U); + + read(data, imbe, 830U, 978U, 862U, 863U, 934U, 935U); + errs += m_fec.regenerateIMBE(imbe); + write(data, imbe, 830U, 978U, 862U, 863U, 934U, 935U); + + read(data, imbe, 1020U, 1168U, 1078U, 1079U, 1150U, 1151U); + errs += m_fec.regenerateIMBE(imbe); + write(data, imbe, 1020U, 1168U, 1078U, 1079U, 1150U, 1151U); + + read(data, imbe, 1208U, 1356U, 1222U, 1223U, 1294U, 1295U); + errs += m_fec.regenerateIMBE(imbe); + write(data, imbe, 1208U, 1356U, 1222U, 1223U, 1294U, 1295U); + + read(data, imbe, 1398U, 1546U, 1438U, 1439U, 1510U, 1511U); + errs += m_fec.regenerateIMBE(imbe); + write(data, imbe, 1398U, 1546U, 1438U, 1439U, 1510U, 1511U); + + read(data, imbe, 1578U, 1726U, 1582U, 1583U, 1654U, 1655U); + errs += m_fec.regenerateIMBE(imbe); + write(data, imbe, 1578U, 1726U, 1582U, 1583U, 1654U, 1655U); + + return errs; +} + +void CP25Audio::read(const unsigned char* data, unsigned char* out, unsigned int start, unsigned int stop, unsigned int avoid1, unsigned int avoid2, unsigned int avoid3, unsigned int avoid4) +{ + unsigned int n = 0U; + for (unsigned int offset = start; offset < stop; offset++) { + if (offset != avoid1 && offset != avoid2 && offset != avoid3 && offset != avoid4) { + bool b = READ_BIT(data, offset); + WRITE_BIT(out, n, b); + n++; + } + } +} + +void CP25Audio::write(unsigned char* data, const unsigned char* in, unsigned int start, unsigned int stop, unsigned int avoid1, unsigned int avoid2, unsigned int avoid3, unsigned int avoid4) +{ + unsigned int n = 0U; + for (unsigned int offset = start; offset < stop; offset++) { + if (offset != avoid1 && offset != avoid2 && offset != avoid3 && offset != avoid4) { + bool b = READ_BIT(in, n); + WRITE_BIT(data, offset, b); + n++; + } + } +} diff --git a/P25Audio.h b/P25Audio.h new file mode 100644 index 0000000..bc2b097 --- /dev/null +++ b/P25Audio.h @@ -0,0 +1,38 @@ +/* +* Copyright (C) 2016 by Jonathan Naylor G4KLX +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#if !defined(P25Audio_H) +#define P25Audio_H + +#include "AMBEFEC.h" + +class CP25Audio { +public: + CP25Audio(); + ~CP25Audio(); + + unsigned int process(unsigned char* data); + +private: + CAMBEFEC m_fec; + + void read(const unsigned char* data, unsigned char* out, unsigned int start, unsigned int stop, unsigned int avoid1, unsigned int avoid2, unsigned int avoid3, unsigned int avoid4); + void write(unsigned char* data, const unsigned char* in, unsigned int start, unsigned int stop, unsigned int avoid1, unsigned int avoid2, unsigned int avoid3, unsigned int avoid4); +}; + +#endif diff --git a/P25Control.cpp b/P25Control.cpp index 1c4fd22..e524d93 100644 --- a/P25Control.cpp +++ b/P25Control.cpp @@ -20,6 +20,7 @@ #include "P25Defines.h" #include "Sync.h" #include "Log.h" +#include "Utils.h" #include #include @@ -29,10 +30,11 @@ const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U #define WRITE_BIT(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_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) -CP25Control::CP25Control(unsigned int id, CDisplay* display, unsigned int timeout, bool duplex, int rssiMultiplier, int rssiOffset) : -m_id(id), +CP25Control::CP25Control(unsigned int nac, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, int rssiMultiplier, int rssiOffset) : +m_nac(nac), m_display(display), m_duplex(duplex), +m_lookup(lookup), m_rssiMultiplier(rssiMultiplier), m_rssiOffset(rssiOffset), m_queue(1000U, "P25 Control"), @@ -42,9 +44,14 @@ m_rfTimeout(1000U, timeout), m_netTimeout(1000U, timeout), m_rfFrames(0U), m_rfBits(0U), -m_rfErrs(0U) +m_rfErrs(0U), +m_nid(), +m_audio(), +m_rfData(), +m_netData() { assert(display != NULL); + assert(lookup != NULL); } CP25Control::~CP25Control() @@ -55,6 +62,8 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) { assert(data != NULL); + CUtils::dump(1U, "P25 Data", data, len); + bool sync = data[1U] == 0x01U; if (data[0U] == TAG_LOST && m_rfState == RS_RF_LISTENING) @@ -62,24 +71,34 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) if (data[0U] == TAG_LOST) { LogMessage("P25, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits)); + m_display->clearP25(); m_rfState = RS_RF_LISTENING; m_rfTimeout.stop(); + m_rfData.reset(); return false; } if (!sync && m_rfState == RS_RF_LISTENING) return false; - // Put into the NID decoder - unsigned char duid = 0U; // XXX + // Regenerate the NID + m_nid.process(data + 2U); + unsigned char duid = m_nid.getDUID(); + unsigned int nac = m_nid.getNAC(); + + LogDebug("P25, DUID=$%X NAC=$%03X", duid, nac); + + if (m_rfState == RS_RF_LISTENING && nac != m_nac) + return false; if (data[0U] == TAG_HEADER) { + m_rfData.reset(); + // Regenerate Sync CSync::addP25Sync(data + 2U); - // Regenerate NID - // Regenerate Enc Data + m_rfData.processHeader(data + 2U); // Add busy bits addBusyBits(data + 2U, P25_HDR_FRAME_LENGTH_BITS, false, true); @@ -102,18 +121,16 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) m_rfErrs = 0U; m_rfBits = 1U; m_rfTimeout.start(); - // Decode LDU1 } // Regenerate Sync CSync::addP25Sync(data + 2U); - // Regenerate NID - // Regenerate LDU1 Data + m_rfData.processLDU1(data + 2U); // Regenerate Audio - unsigned int errors = 0U; // XXX + unsigned int errors = m_audio.process(data + 2U); LogDebug("P25, LDU1 audio, errs: %u/1233", errors); m_rfBits += 1233U; @@ -130,7 +147,12 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) } if (m_rfState == RS_RF_LISTENING) { - // LogMessage("P25, received RF LC from %8.8s/%4.4s to %8.8s", my1, my2, your); + unsigned int src = m_rfData.getSource(); + bool grp = m_rfData.getGroup(); + unsigned int dst = m_rfData.getDest(); + std::string source = m_lookup->find(src); + LogMessage("P25, received RF from %s to %s%u", source.c_str(), grp ? "TG" : "", dst); + m_display->writeP25(source.c_str(), grp, dst, "R"); m_rfState = RS_RF_AUDIO; } } else if (duid == P25_DUID_LDU2) { @@ -138,16 +160,15 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) return false; // Decode LDU2 + m_rfData.processLDU2(data + 2U); // Regenerate Sync CSync::addP25Sync(data + 2U); - // Regenerate NID - // Regenerate LDU2 Data // Regenerate Audio - unsigned int errors = 0U; // XXX + unsigned int errors = m_audio.process(data + 2U); LogDebug("P25, LDU2 audio, errs: %u/1233", errors); m_rfBits += 1233U; @@ -169,17 +190,18 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) // Regenerate Sync CSync::addP25Sync(data + 2U); - // Regenerate NID - // Regenerate LDU1 Data + m_rfData.processTerminator(data + 2U); // Add busy bits addBusyBits(data + 2U, P25_TERMLC_FRAME_LENGTH_BITS, false, true); m_rfState = RS_RF_LISTENING; m_rfTimeout.stop(); + m_rfData.reset(); LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits)); + m_display->clearP25(); if (m_duplex) { data[0U] = TAG_EOT; @@ -193,15 +215,15 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len) // Regenerate Sync CSync::addP25Sync(data + 2U); - // Regenerate NID - // Add busy bits addBusyBits(data + 2U, P25_TERM_FRAME_LENGTH_BITS, false, true); m_rfState = RS_RF_LISTENING; m_rfTimeout.stop(); + m_rfData.reset(); LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits)); + m_display->clearP25(); if (m_duplex) { data[0U] = TAG_EOT; diff --git a/P25Control.h b/P25Control.h index 054e3d6..508520b 100644 --- a/P25Control.h +++ b/P25Control.h @@ -20,14 +20,18 @@ #define P25Control_H #include "RingBuffer.h" +#include "DMRLookup.h" +#include "P25Audio.h" #include "Defines.h" #include "Display.h" +#include "P25Data.h" +#include "P25NID.h" #include "Modem.h" #include "Timer.h" class CP25Control { public: - CP25Control(unsigned int id, CDisplay* display, unsigned int timeout, bool duplex, int rssiMultiplier, int rssiOffset); + CP25Control(unsigned int nac, CDisplay* display, unsigned int timeout, bool duplex, CDMRLookup* lookup, int rssiMultiplier, int rssiOffset); ~CP25Control(); bool writeModem(unsigned char* data, unsigned int len); @@ -37,9 +41,10 @@ public: void clock(unsigned int ms); private: - unsigned int m_id; + unsigned int m_nac; CDisplay* m_display; bool m_duplex; + CDMRLookup* m_lookup; int m_rssiMultiplier; int m_rssiOffset; CRingBuffer m_queue; @@ -50,6 +55,10 @@ private: unsigned int m_rfFrames; unsigned int m_rfBits; unsigned int m_rfErrs; + CP25NID m_nid; + CP25Audio m_audio; + CP25Data m_rfData; + CP25Data m_netData; void writeQueueRF(const unsigned char* data, unsigned int length); void addBusyBits(unsigned char* data, unsigned int length, bool b1, bool b2); diff --git a/P25Data.cpp b/P25Data.cpp new file mode 100644 index 0000000..77fe3fa --- /dev/null +++ b/P25Data.cpp @@ -0,0 +1,151 @@ +/* +* Copyright (C) 2016 by Jonathan Naylor G4KLX +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "P25Data.h" +#include "Log.h" + +const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT(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_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +CP25Data::CP25Data() : +m_source(0U), +m_group(true), +m_dest(0U) +{ +} + +CP25Data::~CP25Data() +{ +} + +void CP25Data::processHeader(unsigned char* data) +{ +} + +void CP25Data::processLDU1(unsigned char* data) +{ + // XXX No FEC done yet + bool b[24U]; + b[7U] = READ_BIT(data, 411U); + b[6U] = READ_BIT(data, 410U); + b[5U] = READ_BIT(data, 413U); + b[4U] = READ_BIT(data, 412U); + b[3U] = READ_BIT(data, 415U); + b[2U] = READ_BIT(data, 414U); + b[1U] = READ_BIT(data, 421U); + b[0U] = READ_BIT(data, 420U); + + unsigned char format = 0U; + unsigned char mult = 1U; + for (unsigned int i = 0U; i < 8U; i++, mult <<= 1) + format += b[i] ? mult : 0U; + + LogDebug("P25, LC_format = $%02X", format); + + if (format == 0x03U) { + LogDebug("P25, non talk group destination"); + m_group = false; + } else { + m_group = true; + + b[15U] = READ_BIT(data, 613U); // 39 + b[14U] = READ_BIT(data, 612U); + b[13U] = READ_BIT(data, 615U); // 37 + b[12U] = READ_BIT(data, 614U); + b[11U] = READ_BIT(data, 621U); // 35 + b[10U] = READ_BIT(data, 620U); + b[9U] = READ_BIT(data, 623U); // 33 + b[8U] = READ_BIT(data, 622U); + b[7U] = READ_BIT(data, 625U); // 31 + b[6U] = READ_BIT(data, 624U); + b[5U] = READ_BIT(data, 631U); // 29 + b[4U] = READ_BIT(data, 630U); + b[3U] = READ_BIT(data, 633U); // 27 + b[2U] = READ_BIT(data, 632U); + b[1U] = READ_BIT(data, 635U); + b[0U] = READ_BIT(data, 634U); // 24 + + mult = 1U; + for (unsigned int i = 0U; i < 16U; i++, mult <<= 1) + m_dest += b[i] ? mult : 0U; + + LogDebug("P25, TG ID = %u", m_dest); + } + + b[23U] = READ_BIT(data, 789U); + b[22U] = READ_BIT(data, 788U); + b[21U] = READ_BIT(data, 793U); + b[20U] = READ_BIT(data, 792U); + b[19U] = READ_BIT(data, 795U); + b[18U] = READ_BIT(data, 794U); + b[17U] = READ_BIT(data, 801U); + b[16U] = READ_BIT(data, 800U); + b[15U] = READ_BIT(data, 803U); + b[14U] = READ_BIT(data, 802U); + b[13U] = READ_BIT(data, 805U); + b[12U] = READ_BIT(data, 804U); + b[11U] = READ_BIT(data, 811U); + b[10U] = READ_BIT(data, 810U); + b[9U] = READ_BIT(data, 813U); + b[8U] = READ_BIT(data, 812U); + b[7U] = READ_BIT(data, 815U); + b[6U] = READ_BIT(data, 814U); + b[5U] = READ_BIT(data, 821U); + b[4U] = READ_BIT(data, 820U); + b[3U] = READ_BIT(data, 823U); + b[2U] = READ_BIT(data, 822U); + b[1U] = READ_BIT(data, 825U); + b[0U] = READ_BIT(data, 824U); + + mult = 1U; + for (unsigned int i = 0U; i < 24U; i++, mult <<= 1) + m_source += b[i] ? mult : 0U; + + LogDebug("P25, SRC ID = %u", m_source); +} + +void CP25Data::processLDU2(unsigned char* data) +{ +} + +void CP25Data::processTerminator(unsigned char* data) +{ +} + +unsigned int CP25Data::getSource() const +{ + return m_source; +} + +bool CP25Data::getGroup() const +{ + return m_group; +} + +unsigned int CP25Data::getDest() const +{ + return m_dest; +} + +void CP25Data::reset() +{ + m_source = 0U; + m_dest = 0U; +} diff --git a/P25Data.h b/P25Data.h new file mode 100644 index 0000000..5c52aa0 --- /dev/null +++ b/P25Data.h @@ -0,0 +1,48 @@ +/* +* Copyright (C) 2016 by Jonathan Naylor G4KLX +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#if !defined(P25Data_H) +#define P25Data_H + +class CP25Data { +public: + CP25Data(); + ~CP25Data(); + + void processHeader(unsigned char* data); + + void processLDU1(unsigned char* data); + + void processLDU2(unsigned char* data); + + void processTerminator(unsigned char* data); + + unsigned int getSource() const; + + bool getGroup() const; + unsigned int getDest() const; + + void reset(); + +private: + unsigned int m_source; + bool m_group; + unsigned int m_dest; +}; + +#endif diff --git a/P25Defines.h b/P25Defines.h index 1c971cf..d8ac5f0 100644 --- a/P25Defines.h +++ b/P25Defines.h @@ -40,7 +40,7 @@ const unsigned char P25_SYNC_BYTES_LENGTH = 6U; const unsigned char P25_DUID_HEADER = 0x00U; const unsigned char P25_DUID_TERM = 0x03U; const unsigned char P25_DUID_LDU1 = 0x05U; -const unsigned char P25_DUID_LDU2 = 0x09U; +const unsigned char P25_DUID_LDU2 = 0x0AU; const unsigned char P25_DUID_PDU = 0x0CU; const unsigned char P25_DUID_TERM_LC = 0x0FU; diff --git a/P25NID.cpp b/P25NID.cpp new file mode 100644 index 0000000..5e15c74 --- /dev/null +++ b/P25NID.cpp @@ -0,0 +1,80 @@ +/* +* Copyright (C) 2016 by Jonathan Naylor G4KLX +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "P25NID.h" +#include "P25Defines.h" + +#include +#include + +const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT(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_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +CP25NID::CP25NID() : +m_duid(0U), +m_nac(0U) +{ +} + +CP25NID::~CP25NID() +{ +} + +void CP25NID::process(unsigned char* data) +{ + assert(data != NULL); + + unsigned char nid[P25_NID_LENGTH_BYTES]; + + unsigned int n = 0U; + for (unsigned int offset = 48U; offset < 114U; offset++) { + if (offset != 70U && offset != 71U) { + bool b = READ_BIT(data, offset); + WRITE_BIT(nid, n, b); + n++; + } + } + + // XXX Process FEC here + + m_duid = nid[1U] & 0x0FU; + + m_nac = (nid[0U] << 4) & 0xFF0U; + m_nac |= (nid[1U] >> 4) & 0x00FU; + + n = 0U; + for (unsigned int offset = 48U; offset < 114U; offset++) { + if (offset != 70U && offset != 71U) { + bool b = READ_BIT(nid, n); + WRITE_BIT(data, offset, b); + n++; + } + } +} + +unsigned char CP25NID::getDUID() const +{ + return m_duid; +} + +unsigned int CP25NID::getNAC() const +{ + return m_nac; +} diff --git a/P25NID.h b/P25NID.h new file mode 100644 index 0000000..414c0b5 --- /dev/null +++ b/P25NID.h @@ -0,0 +1,37 @@ +/* +* Copyright (C) 2016 by Jonathan Naylor G4KLX +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#if !defined(P25NID_H) +#define P25NID_H + +class CP25NID { +public: + CP25NID(); + ~CP25NID(); + + void process(unsigned char* data); + + unsigned char getDUID() const; + unsigned int getNAC() const; + +private: + unsigned char m_duid; + unsigned int m_nac; +}; + +#endif diff --git a/YSFPayload.cpp b/YSFPayload.cpp index 19b32da..253b35e 100644 --- a/YSFPayload.cpp +++ b/YSFPayload.cpp @@ -257,11 +257,11 @@ unsigned int CYSFPayload::processVDMode1Audio(unsigned char* data) // Regenerate the AMBE FEC unsigned int errors = 0U; - errors += m_fec.regenerateYSF1(data + 9U); - errors += m_fec.regenerateYSF1(data + 27U); - errors += m_fec.regenerateYSF1(data + 45U); - errors += m_fec.regenerateYSF1(data + 63U); - errors += m_fec.regenerateYSF1(data + 81U); + errors += m_fec.regenerateYSFDN(data + 9U); + errors += m_fec.regenerateYSFDN(data + 27U); + errors += m_fec.regenerateYSFDN(data + 45U); + errors += m_fec.regenerateYSFDN(data + 63U); + errors += m_fec.regenerateYSFDN(data + 81U); return errors; } @@ -788,13 +788,13 @@ unsigned int CYSFPayload::processVoiceFRModeAudio(unsigned char* data) data += YSF_SYNC_LENGTH_BYTES + YSF_FICH_LENGTH_BYTES; - // Regenerate the AMBE FEC + // Regenerate the IMBE FEC unsigned int errors = 0U; - errors += m_fec.regenerateYSF3(data + 0U); - errors += m_fec.regenerateYSF3(data + 18U); - errors += m_fec.regenerateYSF3(data + 36U); - errors += m_fec.regenerateYSF3(data + 54U); - errors += m_fec.regenerateYSF3(data + 72U); + errors += m_fec.regenerateIMBE(data + 0U); + errors += m_fec.regenerateIMBE(data + 18U); + errors += m_fec.regenerateIMBE(data + 36U); + errors += m_fec.regenerateIMBE(data + 54U); + errors += m_fec.regenerateIMBE(data + 72U); return errors; }