A semi-working P25 repeater without much FEC.

This commit is contained in:
Jonathan Naylor 2016-09-12 23:26:05 +01:00
parent 7171af365d
commit 34e0d10343
29 changed files with 713 additions and 74 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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

4
Conf.h
View file

@ -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;

View file

@ -20,7 +20,7 @@
#include <cassert>
#include <algorithm>
CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blackList, const std::vector<unsigned int>& DstIdBlacklistSlot1RF, const std::vector<unsigned int>& DstIdWhitelistSlot1RF, const std::vector<unsigned int>& DstIdBlacklistSlot2RF, const std::vector<unsigned int>& DstIdWhitelistSlot2RF, const std::vector<unsigned int>& DstIdBlacklistSlot1NET, const std::vector<unsigned int>& DstIdWhitelistSlot1NET, const std::vector<unsigned int>& DstIdBlacklistSlot2NET, const std::vector<unsigned int>& 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<unsigned int>& prefixes, const std::vector<unsigned int>& blackList, const std::vector<unsigned int>& DstIdBlacklistSlot1RF, const std::vector<unsigned int>& DstIdWhitelistSlot1RF, const std::vector<unsigned int>& DstIdBlacklistSlot2RF, const std::vector<unsigned int>& DstIdWhitelistSlot2RF, const std::vector<unsigned int>& DstIdBlacklistSlot1NET, const std::vector<unsigned int>& DstIdWhitelistSlot1NET, const std::vector<unsigned int>& DstIdBlacklistSlot2NET, const std::vector<unsigned int>& 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()

View file

@ -30,7 +30,7 @@
class CDMRControl {
public:
CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blackList, const std::vector<unsigned int>& DstIdBlacklistSlot1RF, const std::vector<unsigned int>& DstIdWhitelistSlot1RF, const std::vector<unsigned int>& DstIdBlacklistSlot2RF, const std::vector<unsigned int>& DstIdWhitelistSlot2RF,const std::vector<unsigned int>& DstIdBlacklistSlot1NET, const std::vector<unsigned int>& DstIdWhitelistSlot1NET, const std::vector<unsigned int>& DstIdBlacklistSlot2NET, const std::vector<unsigned int>& 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<unsigned int>& prefixes, const std::vector<unsigned int>& blackList, const std::vector<unsigned int>& DstIdBlacklistSlot1RF, const std::vector<unsigned int>& DstIdWhitelistSlot1RF, const std::vector<unsigned int>& DstIdBlacklistSlot2RF, const std::vector<unsigned int>& DstIdWhitelistSlot2RF,const std::vector<unsigned int>& DstIdBlacklistSlot1NET, const std::vector<unsigned int>& DstIdWhitelistSlot1NET, const std::vector<unsigned int>& DstIdBlacklistSlot2NET, const std::vector<unsigned int>& 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);

View file

@ -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;
}

View file

@ -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

View file

@ -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<unsigned int> dstIDBlackListSlot2NET = m_conf.getDMRDstIdBlacklistSlot2NET();
std::vector<unsigned int> dstIDWhiteListSlot1NET = m_conf.getDMRDstIdWhitelistSlot1NET();
std::vector<unsigned int> 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);

View file

@ -181,8 +181,11 @@
<ClInclude Include="Modem.h" />
<ClInclude Include="Nextion.h" />
<ClInclude Include="NullDisplay.h" />
<ClInclude Include="P25Audio.h" />
<ClInclude Include="P25Control.h" />
<ClInclude Include="P25Defines.h" />
<ClInclude Include="P25Data.h" />
<ClInclude Include="P25NID.h" />
<ClInclude Include="QR1676.h" />
<ClInclude Include="RingBuffer.h" />
<ClInclude Include="RS129.h" />
@ -236,7 +239,10 @@
<ClCompile Include="Modem.cpp" />
<ClCompile Include="Nextion.cpp" />
<ClCompile Include="NullDisplay.cpp" />
<ClCompile Include="P25Audio.cpp" />
<ClCompile Include="P25Control.cpp" />
<ClCompile Include="P25Data.cpp" />
<ClCompile Include="P25NID.cpp" />
<ClCompile Include="QR1676.cpp" />
<ClCompile Include="RS129.cpp" />
<ClCompile Include="SerialController.cpp" />

View file

@ -179,6 +179,15 @@
<ClInclude Include="P25Control.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25NID.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Audio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Data.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BPTC19696.cpp">
@ -328,5 +337,14 @@
<ClCompile Include="P25Control.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25NID.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Audio.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Data.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

117
Modem.cpp
View file

@ -36,6 +36,98 @@
#include <unistd.h>
#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);

View file

@ -129,6 +129,7 @@ private:
bool m_lockout;
bool m_error;
HW_TYPE m_hwType;
unsigned int m_nn;
bool readVersion();
bool readStatus();

107
P25Audio.cpp Normal file
View file

@ -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 <cstdio>
#include <cassert>
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++;
}
}
}

38
P25Audio.h Normal file
View file

@ -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

View file

@ -20,6 +20,7 @@
#include "P25Defines.h"
#include "Sync.h"
#include "Log.h"
#include "Utils.h"
#include <cstdio>
#include <cassert>
@ -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;

View file

@ -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<unsigned char> 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);

151
P25Data.cpp Normal file
View file

@ -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;
}

48
P25Data.h Normal file
View file

@ -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

View file

@ -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;

80
P25NID.cpp Normal file
View file

@ -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 <cstdio>
#include <cassert>
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;
}

37
P25NID.h Normal file
View file

@ -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

View file

@ -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;
}