From dc2028dd6acc0c644450b91ec22441af3d33223b Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 8 Sep 2016 18:38:59 +0100 Subject: [PATCH] Start full host support got P25. --- Conf.cpp | 76 ++++++++++++++++- Conf.h | 22 +++++ MMDVM.ini | 12 +++ MMDVMHost.cpp | 21 ++++- MMDVMHost.h | 1 + MMDVMHost.vcxproj | 1 + MMDVMHost.vcxproj.filters | 3 + Modem.cpp | 175 +++++++++++++++++++++++++++++--------- Modem.h | 12 ++- P25Defines.h | 33 +++++++ Sync.cpp | 8 ++ Sync.h | 2 + 12 files changed, 321 insertions(+), 45 deletions(-) create mode 100644 P25Defines.h diff --git a/Conf.cpp b/Conf.cpp index 43f11e8..34fac00 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -37,9 +37,11 @@ enum SECTION { SECTION_DSTAR, SECTION_DMR, SECTION_FUSION, + SECTION_P25, SECTION_DSTAR_NETWORK, SECTION_DMR_NETWORK, SECTION_FUSION_NETWORK, + SECTION_P25_NETWORK, SECTION_TFTSERIAL, SECTION_HD44780, SECTION_NEXTION, @@ -80,6 +82,7 @@ m_modemRXLevel(50U), m_modemDStarTXLevel(50U), m_modemDMRTXLevel(50U), m_modemYSFTXLevel(50U), +m_modemP25TXLevel(50U), m_modemOscOffset(0), m_modemRSSIMultiplier(0), m_modemRSSIOffset(0), @@ -107,6 +110,8 @@ m_dmrLookupFile(), m_dmrCallHang(3U), m_dmrTXHang(4U), m_fusionEnabled(true), +m_p25Enabled(true), +m_p25Id(0U), m_dstarNetworkEnabled(true), m_dstarGatewayAddress(), m_dstarGatewayPort(0U), @@ -127,6 +132,11 @@ m_fusionNetworkMyPort(0U), m_fusionNetworkGwyAddress(), m_fusionNetworkGwyPort(0U), m_fusionNetworkDebug(false), +m_p25NetworkEnabled(true), +m_p25GatewayAddress(), +m_p25GatewayPort(0U), +m_p25LocalPort(0U), +m_p25NetworkDebug(false), m_tftSerialPort("/dev/ttyAMA0"), m_tftSerialBrightness(50U), m_hd44780Rows(2U), @@ -186,13 +196,17 @@ bool CConf::read() section = SECTION_DMR; else if (::strncmp(buffer, "[System Fusion]", 15U) == 0) section = SECTION_FUSION; + else if (::strncmp(buffer, "[P25]", 5U) == 0) + section = SECTION_P25; else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0) section = SECTION_DSTAR_NETWORK; else if (::strncmp(buffer, "[DMR Network]", 13U) == 0) section = SECTION_DMR_NETWORK; else if (::strncmp(buffer, "[System Fusion Network]", 23U) == 0) section = SECTION_FUSION_NETWORK; - else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0) + else if (::strncmp(buffer, "[P25 Network]", 13U) == 0) + section = SECTION_P25_NETWORK; + else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0) section = SECTION_TFTSERIAL; else if (::strncmp(buffer, "[HD44780]", 9U) == 0) section = SECTION_HD44780; @@ -280,13 +294,15 @@ bool CConf::read() else if (::strcmp(key, "RXLevel") == 0) m_modemRXLevel = (unsigned int)::atoi(value); else if (::strcmp(key, "TXLevel") == 0) - m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = (unsigned int)::atoi(value); + m_modemDStarTXLevel = m_modemDMRTXLevel = m_modemYSFTXLevel = m_modemP25TXLevel = (unsigned int)::atoi(value); else if (::strcmp(key, "D-StarTXLevel") == 0) m_modemDStarTXLevel = (unsigned int)::atoi(value); else if (::strcmp(key, "DMRTXLevel") == 0) m_modemDMRTXLevel = (unsigned int)::atoi(value); else if (::strcmp(key, "YSFTXLevel") == 0) m_modemYSFTXLevel = (unsigned int)::atoi(value); + else if (::strcmp(key, "P25TXLevel") == 0) + m_modemP25TXLevel = (unsigned int)::atoi(value); else if (::strcmp(key, "OscOffset") == 0) m_modemOscOffset = ::atoi(value); else if (::strcmp(key, "RSSIMultiplier") == 0) @@ -418,6 +434,11 @@ bool CConf::read() } else if (section == SECTION_FUSION) { if (::strcmp(key, "Enable") == 0) m_fusionEnabled = ::atoi(value) == 1; + } 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 (section == SECTION_DSTAR_NETWORK) { if (::strcmp(key, "Enable") == 0) m_dstarNetworkEnabled = ::atoi(value) == 1; @@ -461,6 +482,17 @@ bool CConf::read() m_fusionNetworkGwyPort = (unsigned int)::atoi(value); else if (::strcmp(key, "Debug") == 0) m_fusionNetworkDebug = ::atoi(value) == 1; + } else if (section == SECTION_P25_NETWORK) { + if (::strcmp(key, "Enable") == 0) + m_p25NetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "GatewayAddress") == 0) + m_p25GatewayAddress = value; + else if (::strcmp(key, "GatewayPort") == 0) + m_p25GatewayPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "LocalPort") == 0) + m_p25LocalPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "Debug") == 0) + m_p25NetworkDebug = ::atoi(value) == 1; } else if (section == SECTION_TFTSERIAL) { if (::strcmp(key, "Port") == 0) m_tftSerialPort = value; @@ -680,6 +712,11 @@ unsigned int CConf::getModemYSFTXLevel() const return m_modemYSFTXLevel; } +unsigned int CConf::getModemP25TXLevel() const +{ + return m_modemP25TXLevel; +} + int CConf::getModemOscOffset() const { return m_modemOscOffset; @@ -804,6 +841,16 @@ bool CConf::getFusionEnabled() const return m_fusionEnabled; } +bool CConf::getP25Enabled() const +{ + return m_p25Enabled; +} + +unsigned int CConf::getP25Id() const +{ + return m_p25Id; +} + bool CConf::getDStarNetworkEnabled() const { return m_dstarNetworkEnabled; @@ -904,6 +951,31 @@ bool CConf::getFusionNetworkDebug() const return m_fusionNetworkDebug; } +bool CConf::getP25NetworkEnabled() const +{ + return m_p25NetworkEnabled; +} + +std::string CConf::getP25GatewayAddress() const +{ + return m_p25GatewayAddress; +} + +unsigned int CConf::getP25GatewayPort() const +{ + return m_p25GatewayPort; +} + +unsigned int CConf::getP25LocalPort() const +{ + return m_p25LocalPort; +} + +bool CConf::getP25NetworkDebug() const +{ + return m_p25NetworkDebug; +} + std::string CConf::getTFTSerialPort() const { return m_tftSerialPort; diff --git a/Conf.h b/Conf.h index 14f411d..874feac 100644 --- a/Conf.h +++ b/Conf.h @@ -71,6 +71,7 @@ public: unsigned int getModemDStarTXLevel() const; unsigned int getModemDMRTXLevel() const; unsigned int getModemYSFTXLevel() const; + unsigned int getModemP25TXLevel() const; int getModemOscOffset() const; int getModemRSSIMultiplier() const; int getModemRSSIOffset() const; @@ -105,6 +106,10 @@ public: // The System Fusion section bool getFusionEnabled() const; + // The P25 section + bool getP25Enabled() const; + unsigned int getP25Id() const; + // The D-Star Network section bool getDStarNetworkEnabled() const; std::string getDStarGatewayAddress() const; @@ -131,6 +136,13 @@ public: unsigned int getFusionNetworkGwyPort() const; bool getFusionNetworkDebug() const; + // The P25 Network section + bool getP25NetworkEnabled() const; + std::string getP25GatewayAddress() const; + unsigned int getP25GatewayPort() const; + unsigned int getP25LocalPort() const; + bool getP25NetworkDebug() const; + // The TFTSERIAL section std::string getTFTSerialPort() const; unsigned int getTFTSerialBrightness() const; @@ -197,6 +209,7 @@ private: unsigned int m_modemDStarTXLevel; unsigned int m_modemDMRTXLevel; unsigned int m_modemYSFTXLevel; + unsigned int m_modemP25TXLevel; int m_modemOscOffset; int m_modemRSSIMultiplier; int m_modemRSSIOffset; @@ -228,6 +241,9 @@ private: bool m_fusionEnabled; + bool m_p25Enabled; + unsigned int m_p25Id; + bool m_dstarNetworkEnabled; std::string m_dstarGatewayAddress; unsigned int m_dstarGatewayPort; @@ -251,6 +267,12 @@ private: unsigned int m_fusionNetworkGwyPort; bool m_fusionNetworkDebug; + bool m_p25NetworkEnabled; + std::string m_p25GatewayAddress; + unsigned int m_p25GatewayPort; + unsigned int m_p25LocalPort; + bool m_p25NetworkDebug; + std::string m_tftSerialPort; unsigned int m_tftSerialBrightness; diff --git a/MMDVM.ini b/MMDVM.ini index d4b937f..8accfad 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -43,6 +43,7 @@ TXLevel=50 # D-StarTXLevel=50 # DMRTXLevel=50 # YSFTXLevel=50 +# P25TXLevel=50 OscOffset=0 RSSIMultiplier=1 RSSIOffset=10 @@ -76,6 +77,10 @@ TXHang=4 [System Fusion] Enable=1 +[P25] +Enable=1 +Id=123456 + [D-Star Network] Enable=1 GatewayAddress=127.0.0.1 @@ -102,6 +107,13 @@ GwyAddress=127.0.0.1 GwyPort=4200 Debug=0 +[P25 Network] +Enable=1 +GatewayAddress=127.0.0.1 +GatewayPort=20010 +LocalPort=20011 +Debug=0 + [TFT Serial] Port=/dev/ttyAMA0 Brightness=50 diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 7a3d335..b7e60bc 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -133,6 +133,7 @@ m_timeout(180U), m_dstarEnabled(false), m_dmrEnabled(false), m_ysfEnabled(false), +m_p25Enabled(false), m_callsign() { } @@ -684,6 +685,7 @@ bool CMMDVMHost::createModem() unsigned int dstarTXLevel = m_conf.getModemDStarTXLevel(); unsigned int dmrTXLevel = m_conf.getModemDMRTXLevel(); unsigned int ysfTXLevel = m_conf.getModemYSFTXLevel(); + unsigned int p25TXLevel = m_conf.getModemP25TXLevel(); bool debug = m_conf.getModemDebug(); unsigned int colorCode = m_conf.getDMRColorCode(); unsigned int rxFrequency = m_conf.getRxFrequency(); @@ -701,14 +703,15 @@ bool CMMDVMHost::createModem() LogInfo(" D-Star TX Level: %u%%", dstarTXLevel); LogInfo(" DMR TX Level: %u%%", dmrTXLevel); LogInfo(" YSF TX Level: %u%%", ysfTXLevel); + LogInfo(" P25 TX Level: %u%%", p25TXLevel); LogInfo(" RX Frequency: %uHz", rxFrequency); LogInfo(" TX Frequency: %uHz", txFrequency); LogInfo(" Osc. Offset: %dppm", oscOffset); m_modem = new CModem(port, m_duplex, rxInvert, txInvert, pttInvert, txDelay, dmrDelay, oscOffset, debug); - m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled); - m_modem->setLevels(rxLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel); + m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled, m_p25Enabled); + m_modem->setLevels(rxLevel, dstarTXLevel, dmrTXLevel, ysfTXLevel, p25TXLevel); m_modem->setRFParams(rxFrequency, txFrequency); m_modem->setDMRParams(colorCode); @@ -844,6 +847,7 @@ void CMMDVMHost::readParams() m_dstarEnabled = m_conf.getDStarEnabled(); m_dmrEnabled = m_conf.getDMREnabled(); m_ysfEnabled = m_conf.getFusionEnabled(); + m_p25Enabled = m_conf.getP25Enabled(); m_duplex = m_conf.getDuplex(); m_callsign = m_conf.getCallsign(); m_timeout = m_conf.getTimeout(); @@ -860,6 +864,7 @@ void CMMDVMHost::readParams() LogInfo(" D-Star: %s", m_dstarEnabled ? "enabled" : "disabled"); LogInfo(" DMR: %s", m_dmrEnabled ? "enabled" : "disabled"); LogInfo(" YSF: %s", m_ysfEnabled ? "enabled" : "disabled"); + LogInfo(" P25: %s", m_p25Enabled ? "enabled" : "disabled"); } void CMMDVMHost::createDisplay() @@ -989,6 +994,18 @@ void CMMDVMHost::setMode(unsigned char mode) m_modeTimer.start(); break; + case MODE_P25: + if (m_dstarNetwork != NULL) + m_dstarNetwork->enable(false); + if (m_dmrNetwork != NULL) + m_dmrNetwork->enable(false); + if (m_ysfNetwork != NULL) + m_ysfNetwork->enable(false); + m_modem->setMode(MODE_P25); + m_mode = MODE_P25; + m_modeTimer.start(); + break; + case MODE_LOCKOUT: LogMessage("Mode set to Lockout"); if (m_dstarNetwork != NULL) diff --git a/MMDVMHost.h b/MMDVMHost.h index 333780d..fbdb180 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -55,6 +55,7 @@ private: bool m_dstarEnabled; bool m_dmrEnabled; bool m_ysfEnabled; + bool m_p25Enabled; std::string m_callsign; void readParams(); diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 3939478..99088cc 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -181,6 +181,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index df4152c..78f7d0e 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -173,6 +173,9 @@ Header Files + + Header Files + diff --git a/Modem.cpp b/Modem.cpp index 05ac188..a5e58f8 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -19,6 +19,7 @@ #include "DStarDefines.h" #include "DMRDefines.h" #include "YSFDefines.h" +#include "P25Defines.h" #include "Thread.h" #include "Modem.h" #include "Utils.h" @@ -92,6 +93,7 @@ m_rxLevel(0U), m_dstarTXLevel(0U), m_dmrTXLevel(0U), m_ysfTXLevel(0U), +m_p25TXLevel(0U), m_oscOffset(oscOffset), m_debug(debug), m_rxFrequency(0U), @@ -99,6 +101,7 @@ m_txFrequency(0U), m_dstarEnabled(false), m_dmrEnabled(false), m_ysfEnabled(false), +m_p25Enabled(false), m_serial(port, SERIAL_115200, true), m_buffer(NULL), m_length(0U), @@ -111,6 +114,8 @@ m_txDMRData1(1000U, "Modem TX DMR1"), m_txDMRData2(1000U, "Modem TX DMR2"), m_rxYSFData(1000U, "Modem RX YSF"), m_txYSFData(1000U, "Modem TX YSF"), +m_rxP25Data(1000U, "Modem RX P25"), +m_txP25Data(1000U, "Modem TX P25"), m_statusTimer(1000U, 0U, 250U), m_inactivityTimer(1000U, 2U), m_playoutTimer(1000U, 0U, 10U), @@ -118,6 +123,7 @@ m_dstarSpace(0U), m_dmrSpace1(0U), m_dmrSpace2(0U), m_ysfSpace(0U), +m_p25Space(0U), m_tx(false), m_lockout(false), m_error(false), @@ -139,19 +145,21 @@ void CModem::setRFParams(unsigned int rxFrequency, unsigned int txFrequency) m_txFrequency = txFrequency; } -void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled) +void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled) { m_dstarEnabled = dstarEnabled; m_dmrEnabled = dmrEnabled; m_ysfEnabled = ysfEnabled; + m_p25Enabled = p25Enabled; } -void CModem::setLevels(unsigned int rxLevel, unsigned int dstarTXLevel, unsigned int dmrTXLevel, unsigned int ysfTXLevel) +void CModem::setLevels(unsigned int rxLevel, unsigned int dstarTXLevel, unsigned int dmrTXLevel, unsigned int ysfTXLevel, unsigned int p25TXLevel) { m_rxLevel = rxLevel; m_dstarTXLevel = dstarTXLevel; m_dmrTXLevel = dmrTXLevel; m_ysfTXLevel = ysfTXLevel; + m_p25TXLevel = p25TXLevel; } void CModem::setDMRParams(unsigned int colorCode) @@ -364,17 +372,45 @@ void CModem::clock(unsigned int ms) } break; - case MMDVM_P25_HDR: - CUtils::dump(2U, "RX P25 HDR", m_buffer, m_length); - break; + case MMDVM_P25_HDR: { + if (m_debug) + CUtils::dump(1U, "RX P25 Header", m_buffer, m_length); - case MMDVM_P25_LDU: - CUtils::dump(2U, "RX P25 LDU", m_buffer, m_length); - break; + unsigned char data = m_length - 2U; + m_rxP25Data.addData(&data, 1U); - case MMDVM_P25_LOST: - CUtils::dump(2U, "RX P25 Lost", m_buffer, m_length); - break; + data = TAG_HEADER; + m_rxP25Data.addData(&data, 1U); + + m_rxP25Data.addData(m_buffer + 3U, m_length - 3U); + } + break; + + case MMDVM_P25_LDU: { + if (m_debug) + CUtils::dump(1U, "RX P25 LDU", m_buffer, m_length); + + unsigned char data = m_length - 2U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_DATA; + m_rxP25Data.addData(&data, 1U); + + m_rxP25Data.addData(m_buffer + 3U, m_length - 3U); + } + break; + + case MMDVM_P25_LOST: { + if (m_debug) + CUtils::dump(1U, "RX P25 Lost", m_buffer, m_length); + + unsigned char data = 1U; + m_rxP25Data.addData(&data, 1U); + + data = TAG_LOST; + m_rxP25Data.addData(&data, 1U); + } + break; case MMDVM_GET_STATUS: { // if (m_debug) @@ -404,9 +440,10 @@ void CModem::clock(unsigned int ms) m_dmrSpace1 = m_buffer[7U]; m_dmrSpace2 = m_buffer[8U]; m_ysfSpace = m_buffer[9U]; + m_p25Space = m_buffer[10U]; m_inactivityTimer.start(); - // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u lockout=%d", m_buffer[5U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, int(m_lockout)); + // LogMessage("status=%02X, tx=%d, space=%u,%u,%u,%u,%u lockout=%d", m_buffer[5U], int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace, m_p25Space, int(m_lockout)); } break; @@ -416,14 +453,7 @@ void CModem::clock(unsigned int ms) break; case MMDVM_NAK: - if (m_buffer[3U] == MMDVM_DSTAR_HEADER && m_buffer[4U] == 5U) - LogWarning("Received a NAK from the MMDVM, MMDVM_DSTAR_HEADER, data overflow, space = %u", m_dstarSpace); - else if (m_buffer[3U] == MMDVM_DSTAR_DATA && m_buffer[4U] == 5U) - LogWarning("Received a NAK from the MMDVM, MMDVM_DSTAR_DATA, data overflow, space = %u", m_dstarSpace); - else if (m_buffer[3U] == MMDVM_DSTAR_EOT && m_buffer[4U] == 5U) - LogWarning("Received a NAK from the MMDVM, MMDVM_DSTAR_EOT, data overflow, space = %u", m_dstarSpace); - else - LogWarning("Received a NAK from the MMDVM, command = 0x%02X, reason = %u", m_buffer[3U], m_buffer[4U]); + LogWarning("Received a NAK from the MMDVM, command = 0x%02X, reason = %u", m_buffer[3U], m_buffer[4U]); break; default: @@ -525,6 +555,27 @@ void CModem::clock(unsigned int ms) m_ysfSpace--; } + + if (m_p25Space > 1U && !m_txP25Data.isEmpty()) { + unsigned char len = 0U; + m_txP25Data.getData(&len, 1U); + m_txP25Data.getData(m_buffer, len); + + if (m_debug) { + if (m_buffer[3U] == MMDVM_P25_HDR) + CUtils::dump(1U, "TX P25 HDR", m_buffer, len); + else + CUtils::dump(1U, "TX P25 LDU", m_buffer, len); + } + + int ret = m_serial.write(m_buffer, len); + if (ret != int(len)) + LogWarning("Error when writing P25 data to the MMDVM"); + + m_playoutTimer.start(); + + m_p25Space--; + } } void CModem::close() @@ -590,6 +641,20 @@ unsigned int CModem::readYSFData(unsigned char* data) return len; } +unsigned int CModem::readP25Data(unsigned char* data) +{ + assert(data != NULL); + + if (m_rxP25Data.isEmpty()) + return 0U; + + unsigned char len = 0U; + m_rxP25Data.getData(&len, 1U); + m_rxP25Data.getData(data, len); + + return len; +} + bool CModem::hasDStarSpace() const { unsigned int space = m_txDStarData.freeSpace() / (DSTAR_FRAME_LENGTH_BYTES + 4U); @@ -698,21 +763,6 @@ bool CModem::hasYSFSpace() const return space > 1U; } -bool CModem::hasTX() const -{ - return m_tx; -} - -bool CModem::hasLockout() const -{ - return m_lockout; -} - -bool CModem::hasError() const -{ - return m_error; -} - bool CModem::writeYSFData(const unsigned char* data, unsigned int length) { assert(data != NULL); @@ -736,6 +786,51 @@ bool CModem::writeYSFData(const unsigned char* data, unsigned int length) return true; } +bool CModem::hasP25Space() const +{ + unsigned int space = m_txP25Data.freeSpace() / (P25_LDU_FRAME_LENGTH_BYTES + 4U); + + return space > 1U; +} + +bool CModem::writeP25Data(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + assert(length > 0U); + + if (data[0U] != TAG_HEADER && data[0U] != TAG_DATA && data[0U] != TAG_EOT) + return false; + + unsigned char buffer[250U]; + + buffer[0U] = MMDVM_FRAME_START; + buffer[1U] = length + 2U; + buffer[2U] = (data[0U] == TAG_HEADER) ? MMDVM_P25_HDR : MMDVM_P25_LDU; + + ::memcpy(buffer + 3U, data + 1U, length - 1U); + + unsigned char len = length + 2U; + m_txP25Data.addData(&len, 1U); + m_txP25Data.addData(buffer, len); + + return true; +} + +bool CModem::hasTX() const +{ + return m_tx; +} + +bool CModem::hasLockout() const +{ + return m_lockout; +} + +bool CModem::hasError() const +{ + return m_error; +} + bool CModem::readVersion() { CThread::sleep(2000U); // 2s @@ -815,7 +910,8 @@ bool CModem::setConfig() buffer[4U] |= 0x02U; if (m_ysfEnabled) buffer[4U] |= 0x04U; - buffer[4U] |= 0x08U; // XXX P25 + if (m_p25Enabled) + buffer[4U] |= 0x08U; buffer[5U] = m_txDelay / 10U; // In 10ms units @@ -833,11 +929,12 @@ bool CModem::setConfig() buffer[12U] = (m_dstarTXLevel * 255U) / 100U; buffer[13U] = (m_dmrTXLevel * 255U) / 100U; buffer[14U] = (m_ysfTXLevel * 255U) / 100U; + buffer[15U] = (m_p25TXLevel * 255U) / 100U; - // CUtils::dump(1U, "Written", buffer, 15U); + // CUtils::dump(1U, "Written", buffer, 16U); - int ret = m_serial.write(buffer, 15U); - if (ret != 15) + int ret = m_serial.write(buffer, 16U); + if (ret != 16) return false; unsigned int count = 0U; diff --git a/Modem.h b/Modem.h index 3348c9a..97b1cb5 100644 --- a/Modem.h +++ b/Modem.h @@ -38,8 +38,8 @@ public: ~CModem(); void setRFParams(unsigned int rxFrequency, unsigned int txFrequency); - void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled); - void setLevels(unsigned int rxLevel, unsigned int dstarTXLevel, unsigned int dmrTXLevel, unsigned int ysfTXLevel); + void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled, bool p25Enabled); + void setLevels(unsigned int rxLevel, unsigned int dstarTXLevel, unsigned int dmrTXLevel, unsigned int ysfTXLevel, unsigned int p25Enabled); void setDMRParams(unsigned int colorCode); bool open(); @@ -48,11 +48,13 @@ public: unsigned int readDMRData1(unsigned char* data); unsigned int readDMRData2(unsigned char* data); unsigned int readYSFData(unsigned char* data); + unsigned int readP25Data(unsigned char* data); bool hasDStarSpace() const; bool hasDMRSpace1() const; bool hasDMRSpace2() const; bool hasYSFSpace() const; + bool hasP25Space() const; bool hasTX() const; @@ -63,6 +65,7 @@ public: bool writeDMRData1(const unsigned char* data, unsigned int length); bool writeDMRData2(const unsigned char* data, unsigned int length); bool writeYSFData(const unsigned char* data, unsigned int length); + bool writeP25Data(const unsigned char* data, unsigned int length); bool writeDMRStart(bool tx); bool writeDMRShortLC(const unsigned char* lc); @@ -91,6 +94,7 @@ private: unsigned int m_dstarTXLevel; unsigned int m_dmrTXLevel; unsigned int m_ysfTXLevel; + unsigned int m_p25TXLevel; int m_oscOffset; bool m_debug; unsigned int m_rxFrequency; @@ -98,6 +102,7 @@ private: bool m_dstarEnabled; bool m_dmrEnabled; bool m_ysfEnabled; + bool m_p25Enabled; CSerialController m_serial; unsigned char* m_buffer; unsigned int m_length; @@ -110,6 +115,8 @@ private: CRingBuffer m_txDMRData2; CRingBuffer m_rxYSFData; CRingBuffer m_txYSFData; + CRingBuffer m_rxP25Data; + CRingBuffer m_txP25Data; CTimer m_statusTimer; CTimer m_inactivityTimer; CTimer m_playoutTimer; @@ -117,6 +124,7 @@ private: unsigned int m_dmrSpace1; unsigned int m_dmrSpace2; unsigned int m_ysfSpace; + unsigned int m_p25Space; bool m_tx; bool m_lockout; bool m_error; diff --git a/P25Defines.h b/P25Defines.h new file mode 100644 index 0000000..21ce64d --- /dev/null +++ b/P25Defines.h @@ -0,0 +1,33 @@ +/* + * 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(P25DEFINES_H) +#define P25DEFINES_H + +const unsigned int P25_HDR_FRAME_LENGTH_BYTES = 99U; + +const unsigned int P25_LDU_FRAME_LENGTH_BYTES = 216U; + +const unsigned int P25_SYNC_LENGTH_BYTES = 6U; +const unsigned int P25_NID_LENGTH_BYTES = 8U; + +const unsigned char P25_SYNC_BYTES[] = {0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU}; +const unsigned char P25_SYNC_BYTES_LENGTH = 6U; + +#endif + diff --git a/Sync.cpp b/Sync.cpp index 88faad1..f5404db 100644 --- a/Sync.cpp +++ b/Sync.cpp @@ -21,6 +21,7 @@ #include "DStarDefines.h" #include "DMRDefines.h" #include "YSFDefines.h" +#include "P25Defines.h" #include #include @@ -66,3 +67,10 @@ void CSync::addYSFSync(unsigned char* data) ::memcpy(data, YSF_SYNC_BYTES, YSF_SYNC_LENGTH_BYTES); } + +void CSync::addP25Sync(unsigned char* data) +{ + assert(data != NULL); + + ::memcpy(data, P25_SYNC_BYTES, P25_SYNC_LENGTH_BYTES); +} diff --git a/Sync.h b/Sync.h index 92df8c0..3ee59d5 100644 --- a/Sync.h +++ b/Sync.h @@ -29,6 +29,8 @@ public: static void addYSFSync(unsigned char* data); + static void addP25Sync(unsigned char* data); + private: };