From 8110a3c64ca864043bf7bdf25410758063d67de6 Mon Sep 17 00:00:00 2001 From: Doug McLain Date: Thu, 5 Jan 2023 19:10:07 -0500 Subject: [PATCH] Add native P25 Reflector and IMBE transcoding --- dashboard/pgs/class.reflector.php | 12 + dashboard/pgs/repeaters.php | 136 ++++++-- reflector/DVFramePacket.cpp | 22 ++ reflector/DVFramePacket.h | 2 + reflector/DVHeaderPacket.h | 2 +- reflector/GateKeeper.cpp | 4 + reflector/Main.h | 15 +- reflector/Makefile | 2 +- reflector/P25Client.cpp | 47 +++ reflector/P25Client.h | 41 +++ reflector/P25Protocol.cpp | 527 ++++++++++++++++++++++++++++++ reflector/P25Protocol.h | 75 +++++ reflector/Packet.cpp | 17 + reflector/Packet.h | 1 + reflector/Protocols.cpp | 5 + reflector/TCPacketDef.h | 3 +- 16 files changed, 879 insertions(+), 32 deletions(-) create mode 100644 reflector/P25Client.cpp create mode 100644 reflector/P25Client.h create mode 100644 reflector/P25Protocol.cpp create mode 100644 reflector/P25Protocol.h diff --git a/dashboard/pgs/class.reflector.php b/dashboard/pgs/class.reflector.php index d066819..c660d15 100644 --- a/dashboard/pgs/class.reflector.php +++ b/dashboard/pgs/class.reflector.php @@ -27,6 +27,7 @@ class xReflector { public $Interlinks = null; private $InterlinkXML = null; private $ReflectorXML = null; + public $TotalNodeCount = null; public function __construct() { $this->Nodes = array(); @@ -34,6 +35,7 @@ class xReflector { $this->Peers = array(); $this->Interlinks = array(); $this->Transferinterlink = false; + $this->TotalNodeCount = 5; } public function LoadXML() { @@ -457,6 +459,16 @@ class xReflector { } return -1; } + + public function SetTotalNodes($n) { + $this->TotalNodeCount = $n; + //error_log(print_r("SetTotalNodes() ".$this->TotalNodeCount.":".$n."\n", TRUE)); + } + + public function GetTotalNodes() { + //error_log(print_r("GetTotalNodes() ".$this->TotalNodeCount."\n", TRUE)); + return $this->TotalNodeCount; + } } diff --git a/dashboard/pgs/repeaters.php b/dashboard/pgs/repeaters.php index d82e49a..e4118d3 100644 --- a/dashboard/pgs/repeaters.php +++ b/dashboard/pgs/repeaters.php @@ -3,11 +3,10 @@ # Flag DV Station - Band Last Heard Linked for Protocol - Module $val) { + if ($val[$field] === $needle) { + return $key; + } + } + return null; +} + +function getLinkedGateways($logLines) { + + $gateways = Array(); + for ($i = count($logLines); $i>0; $i--) { + if(isset($logLines[$i])){ + $logLine = $logLines[$i]; + + if (strpos($logLine, "Starting P25Reflector")) { + return $gateways; + } + if (strpos($logLine, "No repeaters/gateways linked")) { + return $gateways; + } + if (strpos($logLine, "Currently linked repeaters")) { + for ($j = $i+1; $j <= count($logLines); $j++) { + if(isset($logLines[$j])){ + $logLine = $logLines[$j]; + if (!startsWith(substr($logLine,27), " ")) { + return $gateways; + } else { + //$Reflector->SetTotalNodes($Reflector->GetTotalNodes() + 1); + $timestamp = substr($logLine, 3, 19); + $callsign = substr($logLine, 31, 11); + //$callsign = explode(" ", $callsign); + $ipport = substr($logLine, 43); + //$ipport = explode(":", $ipport); + $key1 = searchForKey("ipport",$ipport, $gateways); + $key2 = searchForKey("callsign",$callsign, $gateways); + if (($key1 === NULL) && ($key2 == NULL)) { + array_push($gateways, Array('callsign'=>$callsign,'timestamp'=>$timestamp,'ipport'=>$ipport)); + } + } + } + } + } + } + } + return $gateways; +} + $Reflector->LoadFlags(); +$i = 0; for ($i=0;$i<$Reflector->NodeCount();$i++) { @@ -29,33 +82,11 @@ for ($i=0;$i<$Reflector->NodeCount();$i++) { echo ''.$Name.''.$Name.''; } echo ' - Nodes[$i]->GetSuffix(); - echo '" class="pl" target="_blank">'.$Reflector->Nodes[$i]->GetCallSign(); - if ($Reflector->Nodes[$i]->GetSuffix() != "") { echo '-'.$Reflector->Nodes[$i]->GetSuffix(); } - echo ' - '; - if (($Reflector->Nodes[$i]->GetPrefix() == 'REF') || ($Reflector->Nodes[$i]->GetPrefix() == 'XRF')) { - switch ($Reflector->Nodes[$i]->GetPrefix()) { - case 'REF' : echo 'REF-Link'; break; - case 'XRF' : echo 'XRF-Link'; break; - } - } - else { - switch ($Reflector->Nodes[$i]->GetSuffix()) { - case 'A' : echo '23cm'; break; - case 'B' : echo '70cm'; break; - case 'C' : echo '2m'; break; - case 'D' : echo 'Dongle'; break; - case 'G' : echo 'Internet-Gateway'; break; - default : echo ''; - } - } + '.$Reflector->Nodes[$i]->GetCallSign(); echo ' '.date("d.m.Y H:i", $Reflector->Nodes[$i]->GetLastHeardTime()).' '.FormatSeconds(time()-$Reflector->Nodes[$i]->GetConnectTime()).' s - '.$Reflector->Nodes[$i]->GetProtocol().' - '.$Reflector->Nodes[$i]->GetLinkedModule().''; + '.$Reflector->Nodes[$i]->GetProtocol().''; if ($PageOptions['RepeatersPage']['IPModus'] != 'HideIP') { echo ''; $Bytes = explode(".", $Reflector->Nodes[$i]->GetIP()); @@ -88,9 +119,62 @@ for ($i=0;$i<$Reflector->NodeCount();$i++) { echo ''; } echo ''; + + if ($i == $PageOptions['RepeatersPage']['LimitTo']) { $i = $Reflector->NodeCount()+1; } } +//$Reflector->SetTotalNodes($Reflector->NodeCount()); + +$logLines = array(); +//error_log(print_r("logLines ".count($logLines)."\n", TRUE)); +if ($log = fopen("/var/log/reflectors/P25-9846-".date("Y-m-d").".log", 'r')) { + while ($logLine = fgets($log)) { + array_push($logLines, $logLine); + } + fclose($log); +} +//error_log(print_r("logLines ".count($logLines)."\n", TRUE)); +$gateways = getLinkedGateways($logLines) ; +//error_log(print_r("gateways ".count($gateways)."\n", TRUE)); +//$Reflector->SetTotalNodes($Reflector->NodeCount() + count($p25gateways)); + +foreach ($gateways as $gateway) { + $i += 1; + echo ''; + echo "$i"; + list ($Flag, $Name) = $Reflector->GetFlag($gateway['callsign']); + if (file_exists("./img/flags/".$Flag.".png")) { + echo ''.$Name.''.$Name.''; + } + $cs = explode(" ", $gateway['callsign']); + $ip = explode(":", $gateway['ipport']); + + echo "$cs[0]P25$ip[0]"; +} + +if ($log = fopen("/var/log/reflectors/NXDNReflector-".date("Y-m-d").".log", 'r')) { + while ($logLine = fgets($log)) { + array_push($logLines, $logLine); + } + fclose($log); +} +$gateways = getLinkedGateways($logLines); + +foreach ($gateways as $gateway) { + $i += 1; + echo ''; + echo "$i"; + list ($Flag, $Name) = $Reflector->GetFlag($gateway['callsign']); + if (file_exists("./img/flags/".$Flag.".png")) { + echo ''.$Name.''.$Name.''; + } + $cs = explode(" ", $gateway['callsign']); + $ip = explode(":", $gateway['ipport']); + + echo "$cs[0]NXDN$ip[0]"; +} + ?> diff --git a/reflector/DVFramePacket.cpp b/reflector/DVFramePacket.cpp index 376bac3..eb58f6c 100644 --- a/reflector/DVFramePacket.cpp +++ b/reflector/DVFramePacket.cpp @@ -28,6 +28,7 @@ CDvFramePacket::CDvFramePacket() memset(m_TCPack.dmr, 0, 9); memset(m_uiDvSync, 0, 7); memset(m_TCPack.m17, 0, 16); + memset(m_TCPack.p25, 0, 11); memset(m_Nonce, 0, 14); m_TCPack.codec_in = ECodecType::none; }; @@ -41,6 +42,7 @@ CDvFramePacket::CDvFramePacket(const SDStarFrame *dvframe, uint16_t sid, uint8_t memset(m_TCPack.dmr, 0, 9); memset(m_uiDvSync, 0, 7); memset(m_TCPack.m17, 0, 16); + memset(m_TCPack.p25, 0, 11); memset(m_Nonce, 0, 14); m_TCPack.codec_in = ECodecType::dstar; } @@ -54,6 +56,7 @@ CDvFramePacket::CDvFramePacket(const uint8_t *ambe, const uint8_t *sync, uint16_ memset(m_TCPack.dstar, 0, 9); memset(m_uiDvData, 0, 3); memset(m_TCPack.m17, 0, 16); + memset(m_TCPack.p25, 0, 11); memset(m_Nonce, 0, 14); m_TCPack.codec_in = ECodecType::dmr; } @@ -67,6 +70,7 @@ CDvFramePacket::CDvFramePacket(const uint8_t *ambe, uint16_t sid, uint8_t pid, u memset(m_TCPack.dstar, 0, 9); memset(m_uiDvData, 0, 3); memset(m_TCPack.m17, 0, 16); + memset(m_TCPack.p25, 0, 11); memset(m_Nonce, 0, 14); m_TCPack.codec_in = ECodecType::dmr; uint8_t c[12]; @@ -96,6 +100,7 @@ CDvFramePacket::CDvFramePacket(const CM17Packet &m17) : CPacket(m17) memset(m_uiDvSync, 0, 7); memcpy(m_TCPack.m17, m17.GetPayload(), 16); memcpy(m_Nonce, m17.GetNonce(), 14); + memset(m_TCPack.p25, 0, 11); switch (0x6U & m17.GetFrameType()) { case 0x4U: @@ -110,6 +115,21 @@ CDvFramePacket::CDvFramePacket(const CM17Packet &m17) : CPacket(m17) } } +// p25 constructor +CDvFramePacket::CDvFramePacket(const uint8_t *imbe, uint16_t streamid, bool islast) + : CPacket(streamid, islast) +{ + memcpy(m_TCPack.p25, imbe, 11); + memset(m_TCPack.dmr, 0, 9); + memset(m_uiDvSync, 0, 7); + memset(m_TCPack.dstar, 0, 9); + memset(m_uiDvData, 0, 3); + memset(m_TCPack.m17, 0, 16); + memset(m_Nonce, 0, 14); + m_TCPack.codec_in = ECodecType::p25; +} + + // Network unsigned int CDvFramePacket::GetNetworkSize() { @@ -178,6 +198,8 @@ const uint8_t *CDvFramePacket::GetCodecData(ECodecType type) const case ECodecType::c2_1600: case ECodecType::c2_3200: return m_TCPack.m17; + case ECodecType::p25: + return m_TCPack.p25; default: return nullptr; } diff --git a/reflector/DVFramePacket.h b/reflector/DVFramePacket.h index 5946f08..26d7a1c 100644 --- a/reflector/DVFramePacket.h +++ b/reflector/DVFramePacket.h @@ -51,6 +51,8 @@ public: CDvFramePacket(uint16_t streamid, uint8_t counter, const uint8_t *ambe, const uint8_t *dvdata, uint8_t counter1, uint8_t counter2, const uint8_t *ambe2, const uint8_t *dmrsync, ECodecType type, bool islast); // M17 Frame CDvFramePacket(const CM17Packet &m17); + // P25 Frame + CDvFramePacket(const uint8_t *imbe, uint16_t streamid, bool islast); // URF Network CDvFramePacket(const CBuffer &buf); static unsigned int GetNetworkSize(); diff --git a/reflector/DVHeaderPacket.h b/reflector/DVHeaderPacket.h index ce2bd94..75b70ee 100644 --- a/reflector/DVHeaderPacket.h +++ b/reflector/DVHeaderPacket.h @@ -20,7 +20,7 @@ #include "Callsign.h" #include "Packet.h" - + //////////////////////////////////////////////////////////////////////////////////////// // implementation details diff --git a/reflector/GateKeeper.cpp b/reflector/GateKeeper.cpp index 69e0efd..4e7f7bd 100644 --- a/reflector/GateKeeper.cpp +++ b/reflector/GateKeeper.cpp @@ -89,6 +89,7 @@ bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, EProtocol pr case EProtocol::dmrmmdvm: case EProtocol::ysf: case EProtocol::m17: + case EProtocol::p25: #ifndef NO_G3 case EProtocol::g3: #endif @@ -135,6 +136,7 @@ bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, const EP case EProtocol::dmrmmdvm: case EProtocol::ysf: case EProtocol::m17: + case EProtocol::p25: #ifndef NO_G3 case EProtocol::g3: #endif @@ -286,6 +288,8 @@ const std::string CGateKeeper::ProtocolName(const EProtocol p) const return "URF"; case EProtocol::ysf: return "YSF"; + case EProtocol::p25: + return "P25"; case EProtocol::bm: return "Brandmeister"; #ifndef NO_G3 diff --git a/reflector/Main.h b/reflector/Main.h index 9886c88..78f4c87 100644 --- a/reflector/Main.h +++ b/reflector/Main.h @@ -50,13 +50,15 @@ #define YSF_IPV4 true #define XLX_IPV4 true #define M17_IPV4 true +#define P25_IPV4 true #define URF_IPV4 true -#define DSTAR_IPV6 true +#define DSTAR_IPV6 false #define DMR_IPV6 false #define YSF_IPV6 false #define XLX_IPV6 false #define M17_IPV6 true +#define P25_IPV6 false #define URF_IPV6 true // version ----------------------------------------------------- @@ -77,9 +79,9 @@ // protocols --------------------------------------------------- #ifndef NO_G3 -enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17, g3 }; +enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17, g3, p25 }; #else -enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17 }; +enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17, p25 }; #endif // DExtra @@ -145,6 +147,13 @@ enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm #define M17_KEEPALIVE_TIMEOUT (M17_KEEPALIVE_PERIOD*10) #define M17_RECONNECT_PERIOD 5 +// P25 +#define P25_PORT 41000 // UDP port +#define P25_KEEPALIVE_PERIOD 1 // in seconds +#define P25_KEEPALIVE_TIMEOUT (P25_KEEPALIVE_PERIOD*10) // in seconds +#define P25_AUTOLINK_ENABLE 1 // 1 = enable, 0 = disable auto-link +#define P25_AUTOLINK_MODULE 'A' // module for client to auto-link to + #ifndef NO_G3 // G3 Terminal #define G3_PRESENCE_PORT 12346 // UDP port diff --git a/reflector/Makefile b/reflector/Makefile index 802e027..26b9c46 100644 --- a/reflector/Makefile +++ b/reflector/Makefile @@ -35,7 +35,7 @@ endif LDFLAGS=-pthread -URFSRCS = Buffer.cpp Callsign.cpp CallsignList.cpp CallsignListItem.cpp Client.cpp Clients.cpp DCSClient.cpp DCSProtocol.cpp DExtraClient.cpp DExtraPeer.cpp DExtraProtocol.cpp DPlusClient.cpp DPlusProtocol.cpp DVFramePacket.cpp DVHeaderPacket.cpp GateKeeper.cpp IP.cpp Notification.cpp Packet.cpp PacketStream.cpp PeerCallsignList.cpp Peer.cpp Peers.cpp Protocol.cpp Protocols.cpp Reflector.cpp SEProtocol.cpp UDPSocket.cpp User.cpp Users.cpp Version.cpp Main.cpp BMClient.cpp BMPeer.cpp BMProtocol.cpp BPTC19696.cpp CRC.cpp DMRIdDir.cpp DMRIdDirFile.cpp DMRIdDirHttp.cpp DMRMMDVMClient.cpp DMRMMDVMProtocol.cpp DMRPlusClient.cpp DMRPlusProtocol.cpp Golay2087.cpp Golay24128.cpp Hamming.cpp M17Client.cpp M17CRC.cpp M17Packet.cpp M17Client.cpp M17Protocol.cpp QR1676.cpp RS129.cpp Semaphore.cpp Utils.cpp WiresXCmd.cpp WiresXCmdHandler.cpp WiresXInfo.cpp URFClient.cpp URFProtocol.cpp URFPeer.cpp YSFClient.cpp YSFConvolution.cpp YSFFich.cpp YSFNode.cpp YSFNodeDir.cpp YSFNodeDirFile.cpp YSFNodeDirHttp.cpp YSFPayload.cpp YSFProtocol.cpp YSFUtils.cpp +URFSRCS = Buffer.cpp Callsign.cpp CallsignList.cpp CallsignListItem.cpp Client.cpp Clients.cpp DCSClient.cpp DCSProtocol.cpp DExtraClient.cpp DExtraPeer.cpp DExtraProtocol.cpp DPlusClient.cpp DPlusProtocol.cpp DVFramePacket.cpp DVHeaderPacket.cpp GateKeeper.cpp IP.cpp Notification.cpp Packet.cpp PacketStream.cpp PeerCallsignList.cpp Peer.cpp Peers.cpp Protocol.cpp Protocols.cpp Reflector.cpp SEProtocol.cpp UDPSocket.cpp User.cpp Users.cpp Version.cpp Main.cpp BMClient.cpp BMPeer.cpp BMProtocol.cpp BPTC19696.cpp CRC.cpp DMRIdDir.cpp DMRIdDirFile.cpp DMRIdDirHttp.cpp DMRMMDVMClient.cpp DMRMMDVMProtocol.cpp DMRPlusClient.cpp DMRPlusProtocol.cpp Golay2087.cpp Golay24128.cpp Hamming.cpp M17Client.cpp M17CRC.cpp M17Packet.cpp M17Client.cpp M17Protocol.cpp P25Client.cpp P25Protocol.cpp QR1676.cpp RS129.cpp Semaphore.cpp Utils.cpp WiresXCmd.cpp WiresXCmdHandler.cpp WiresXInfo.cpp URFClient.cpp URFProtocol.cpp URFPeer.cpp YSFClient.cpp YSFConvolution.cpp YSFFich.cpp YSFNode.cpp YSFNodeDir.cpp YSFNodeDirFile.cpp YSFNodeDirHttp.cpp YSFPayload.cpp YSFProtocol.cpp YSFUtils.cpp G3SRCS = G3Client.cpp G3Protocol.cpp RawSocket.cpp UDPMsgSocket.cpp diff --git a/reflector/P25Client.cpp b/reflector/P25Client.cpp new file mode 100644 index 0000000..18a0bcb --- /dev/null +++ b/reflector/P25Client.cpp @@ -0,0 +1,47 @@ +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP +// +// 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 3 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, see . + +#include "Main.h" +#include "P25Client.h" + + +//////////////////////////////////////////////////////////////////////////////////////// +// constructors + +CP25Client::CP25Client() +{ +} + +CP25Client::CP25Client(const CCallsign &callsign, const CIp &ip, char reflectorModule) + : CClient(callsign, ip, reflectorModule) +{ +} + +CP25Client::CP25Client(const CP25Client &client) + : CClient(client) +{ +} + +//////////////////////////////////////////////////////////////////////////////////////// +// status + +bool CP25Client::IsAlive(void) const +{ + return (m_LastKeepaliveTime.time() < P25_KEEPALIVE_TIMEOUT); +} diff --git a/reflector/P25Client.h b/reflector/P25Client.h new file mode 100644 index 0000000..7532a92 --- /dev/null +++ b/reflector/P25Client.h @@ -0,0 +1,41 @@ +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP +// +// 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 3 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, see . + +#pragma once + +#include "Client.h" +class CP25Client : public CClient +{ +public: + // constructors + CP25Client(); + CP25Client(const CCallsign &, const CIp &, char = ' '); + CP25Client(const CP25Client &); + + // destructor + virtual ~CP25Client() {}; + + // identity + EProtocol GetProtocol(void) const { return EProtocol::p25; } + const char *GetProtocolName(void) const { return "P25"; } + bool IsNode(void) const { return true; } + + // status + bool IsAlive(void) const; +}; diff --git a/reflector/P25Protocol.cpp b/reflector/P25Protocol.cpp new file mode 100644 index 0000000..e154f92 --- /dev/null +++ b/reflector/P25Protocol.cpp @@ -0,0 +1,527 @@ +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP +// +// 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 3 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, see . + +#include "Main.h" +#include +#include "P25Client.h" +#include "P25Protocol.h" + +#include "Reflector.h" +#include "GateKeeper.h" + +const uint8_t REC62[] = {0x62U, 0x02U, 0x02U, 0x0CU, 0x0BU, 0x12U, 0x64U, 0x00U, 0x00U, 0x80U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; +const uint8_t REC63[] = {0x63U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC64[] = {0x64U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC65[] = {0x65U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC66[] = {0x66U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC67[] = {0x67U, 0xF0U, 0x9DU, 0x6AU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC68[] = {0x68U, 0x19U, 0xD4U, 0x26U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC69[] = {0x69U, 0xE0U, 0xEBU, 0x7BU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC6A[] = {0x6AU, 0x00U, 0x00U, 0x02U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; +const uint8_t REC6B[] = {0x6BU, 0x02U, 0x02U, 0x0CU, 0x0BU, 0x12U, 0x64U, 0x00U, 0x00U, 0x80U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; +const uint8_t REC6C[] = {0x6CU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC6D[] = {0x6DU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC6E[] = {0x6EU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC6F[] = {0x6FU, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC70[] = {0x70U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC71[] = {0x71U, 0xACU, 0xB8U, 0xA4U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC72[] = {0x72U, 0x9BU, 0xDCU, 0x75U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x02U}; +const uint8_t REC73[] = {0x73U, 0x00U, 0x00U, 0x02U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; +const uint8_t REC80[] = {0x80U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}; + +//////////////////////////////////////////////////////////////////////////////////////// +// operation + +bool CP25Protocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6) +{ + m_uiStreamId = 0; + // base class + if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6)) + return false; + + // update time + m_LastKeepaliveTime.start(); + + // done + return true; +} + + + +//////////////////////////////////////////////////////////////////////////////////////// +// task + +void CP25Protocol::Task(void) +{ + CBuffer Buffer; + CIp Ip; + CCallsign Callsign; + char ToLinkModule; + std::unique_ptr Header; + std::unique_ptr Frame; + + // handle incoming packets +#if P25_IPV6==true +#if P25_IPV4==true + if ( ReceiveDS(Buffer, Ip, 20) ) +#else + if ( Receive6(Buffer, Ip, 20) ) +#endif +#else + if ( Receive4(Buffer, Ip, 20) ) +#endif + { + // crack the packet + if ( IsValidDvPacket(Ip, Buffer, Frame) ) + { + if( !m_uiStreamId && IsValidDvHeaderPacket(Ip, Buffer, Header) ) + { + // callsign muted? + if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::p25) ) + { + OnDvHeaderPacketIn(Header, Ip); + } + } + // push the packet + OnDvFramePacketIn(Frame, &Ip); + } + else if ( IsValidConnectPacket(Buffer, &Callsign) ) + { + // callsign authorized? + if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::p25) ) + { + // add client if needed + CClients *clients = g_Reflector.GetClients(); + std::shared_ptrclient = clients->FindClient(Callsign, Ip, EProtocol::p25); + // client already connected ? + if ( client == nullptr ) + { + std::cout << "P25 connect packet from " << Callsign << " at " << Ip << std::endl; + + // create the client + auto newclient = std::make_shared(Callsign, Ip); + + // aautolink, if enabled +#if P25_AUTOLINK_ENABLE + newclient->SetReflectorModule(P25_AUTOLINK_MODULE); +#endif + + // and append + clients->AddClient(newclient); + } + else + { + client->Alive(); + } + + // acknowledge the request -- P25Reflector simply echoes the packet + Send(Buffer, Ip); + // and done + g_Reflector.ReleaseClients(); + } + } + else if ( IsValidDisconnectPacket(Buffer, &Callsign) ) + { + std::cout << "P25 disconnect packet from " << Callsign << " at " << Ip << std::endl; + + // find client + CClients *clients = g_Reflector.GetClients(); + std::shared_ptrclient = clients->FindClient(Ip, EProtocol::m17); + if ( client != nullptr ) + { + // remove it + clients->RemoveClient(client); + } + g_Reflector.ReleaseClients(); + } + else + { + // invalid packet + std::string title("Unknown P25 packet from "); + title += Ip.GetAddress(); + Buffer.Dump(title); + } + } + + // handle end of streaming timeout + CheckStreamsTimeout(); + + // handle queue from reflector + HandleQueue(); + + // keep client alive + if ( m_LastKeepaliveTime.time() > P25_KEEPALIVE_PERIOD ) + { + // + HandleKeepalives(); + + // update time + m_LastKeepaliveTime.start(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// streams helpers + +void CP25Protocol::OnDvHeaderPacketIn(std::unique_ptr &Header, const CIp &Ip) +{ + // find the stream + auto stream = GetStream(Header->GetStreamId(), &Ip); + if ( stream ) + { + // stream already open + // skip packet, but tickle the stream + stream->Tickle(); + } + else + { + // no stream open yet, open a new one + CCallsign my(Header->GetMyCallsign()); + CCallsign rpt1(Header->GetRpt1Callsign()); + CCallsign rpt2(Header->GetRpt2Callsign()); + + // find this client + std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::p25); + if ( client ) + { + // get client callsign + rpt1 = client->GetCallsign(); + auto m = client->GetReflectorModule(); + Header->SetRpt2Module(m); + rpt2.SetCSModule(m); + // and try to open the stream + if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + { + // keep the handle + m_Streams[stream->GetStreamId()] = stream; + } + } + // release + g_Reflector.ReleaseClients(); + + // update last heard + g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); + g_Reflector.ReleaseUsers(); + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// queue helper + +void CP25Protocol::HandleQueue(void) +{ + m_Queue.Lock(); + while ( !m_Queue.empty() ) + { + // get the packet + auto packet = m_Queue.pop(); + + // get our sender's id + const auto module = packet->GetPacketModule(); + + // check if it's header and update cache + if ( packet->IsDvHeader() ) + { + // this relies on queue feeder setting valid module id + // m_StreamsCache[module] will be created if it doesn't exist + m_StreamsCache[module].m_dvHeader = CDvHeaderPacket((const CDvHeaderPacket &)*packet.get()); + m_StreamsCache[module].m_iSeqCounter = 0; + } + else + { + // encode it + CBuffer buffer; + if ( packet->IsDvFrame() ) + { + EncodeP25Packet(m_StreamsCache[module].m_dvHeader, (const CDvFramePacket &)*packet.get(), m_StreamsCache[module].m_iSeqCounter++, buffer, packet->IsLastPacket()); + } + + // send it + if ( buffer.size() > 0 ) + { + // and push it to all our clients linked to the module and who are not streaming in + CClients *clients = g_Reflector.GetClients(); + auto it = clients->begin(); + std::shared_ptrclient = nullptr; + while ( (client = clients->FindNextClient(EProtocol::p25, it)) != nullptr ) + { + // is this client busy ? + if ( !client->IsAMaster() && (client->GetReflectorModule() == module) ) + { + // no, send the packet + Send(buffer, client->GetIp()); + + } + } + g_Reflector.ReleaseClients(); + } + } + } + m_Queue.Unlock(); +} + + +//////////////////////////////////////////////////////////////////////////////////////// +// packet decoding helpers + +bool CP25Protocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsign) +{ + bool valid = false; + if ( (Buffer.size() == 11) && (Buffer.data()[0] == 0xF0) ) + { + callsign->SetCallsign(Buffer.data()+1, 10); + valid = (callsign->IsValid()); + } + return valid; +} + +bool CP25Protocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign *callsign) +{ + bool valid = false; + if ( (Buffer.size() == 11) && (Buffer.data()[0] == 0xF1) ) + { + callsign->SetCallsign(Buffer.data()+1, 10); + valid = (callsign->IsValid()); + } + return valid; +} + +bool CP25Protocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::unique_ptr &frame) +{ + if ( (Buffer.size() >= 14) ) + { + int offset = 0; + bool last = false; + + switch (Buffer.data()[0U]) { + case 0x62U: + offset = 10U; + break; + case 0x63U: + offset = 1U; + break; + case 0x64U: + offset = 5U; + break; + case 0x65U: + offset = 5U; + break; + case 0x66U: + offset = 5U; + break; + case 0x67U: + case 0x68U: + case 0x69U: + offset = 5U; + break; + case 0x6AU: + offset = 4U; + break; + case 0x6BU: + offset = 10U; + break; + case 0x6CU: + offset = 1U; + break; + case 0x6DU: + case 0x6EU: + case 0x6FU: + case 0x70U: + case 0x71U: + case 0x72U: + offset = 5U; + break; + case 0x73U: + offset = 4U; + break; + case 0x80U: + last = true; + m_uiStreamId = 0; + break; + default: + break; + } + + frame = std::unique_ptr(new CDvFramePacket(&(Buffer.data()[offset]), m_uiStreamId, last)); + return true; + } + return false; +} + +bool CP25Protocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffer, std::unique_ptr &header) +{ + if(Buffer.data()[0] == 0x66){ + auto stream = GetStream(m_uiStreamId, &Ip); + if ( !stream ) + { + uint32_t uiSrcId = ((Buffer.data()[1] << 16) | ((Buffer.data()[2] << 8) & 0xff00) | (Buffer.data()[3] & 0xff)); + m_uiStreamId = static_cast(::rand()); + CCallsign csMY = CCallsign("", uiSrcId); + CCallsign rpt1 = CCallsign("", uiSrcId); + CCallsign rpt2 = m_ReflectorCallsign; + rpt1.SetCSModule(P25_MODULE_ID); + rpt2.SetCSModule(' '); + header = std::unique_ptr(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, 0)); + } + return true; + } + return false; +} + +void CP25Protocol::EncodeP25Packet(const CDvHeaderPacket &Header, const CDvFramePacket &DvFrame, uint32_t iSeq, CBuffer &Buffer, bool islast) const +{ + uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid(); + uint32_t uiRptrId = Header.GetRpt1Callsign().GetDmrid(); + + if(islast) + { + Buffer.resize(17); + ::memcpy(Buffer.data(), REC80, 17U); + return; + } + + switch (iSeq % 18) { + case 0x00U: + Buffer.resize(22); + ::memcpy(Buffer.data(), REC62, 22U); + ::memcpy(Buffer.data() + 10U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x01U: + Buffer.resize(14); + ::memcpy(Buffer.data(), REC63, 14U); + ::memcpy(Buffer.data() + 1U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x02U: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC64, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x03U: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC65, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + Buffer.data()[1U] = (uiRptrId >> 16) & 0xFFU; + Buffer.data()[2U] = (uiRptrId >> 8) & 0xFFU; + Buffer.data()[3U] = (uiRptrId >> 0) & 0xFFU; + break; + case 0x04U: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC66, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + Buffer.data()[1U] = (uiSrcId >> 16) & 0xFFU; + Buffer.data()[2U] = (uiSrcId >> 8) & 0xFFU; + Buffer.data()[3U] = (uiSrcId >> 0) & 0xFFU; + break; + case 0x05U: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC67, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x06U: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC68, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x07U: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC69, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x08U: + Buffer.resize(16); + ::memcpy(Buffer.data(), REC6A, 16U); + ::memcpy(Buffer.data() + 4U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x09U: + Buffer.resize(22); + ::memcpy(Buffer.data(), REC6B, 22U); + ::memcpy(Buffer.data() + 10U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x0AU: + Buffer.resize(14); + ::memcpy(Buffer.data(), REC6C, 14U); + ::memcpy(Buffer.data() + 1U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x0BU: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC6D, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x0CU: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC6E, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x0DU: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC6F, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x0EU: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC70, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x0FU: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC71, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x10U: + Buffer.resize(17); + ::memcpy(Buffer.data(), REC72, 17U); + ::memcpy(Buffer.data() + 5U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + case 0x11U: + Buffer.resize(16); + ::memcpy(Buffer.data(), REC73, 16U); + ::memcpy(Buffer.data() + 4U, DvFrame.GetCodecData(ECodecType::p25), 11U); + break; + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +// keepalive helpers + +void CP25Protocol::HandleKeepalives(void) +{ + // iterate on clients + CClients *clients = g_Reflector.GetClients(); + auto it = clients->begin(); + std::shared_ptrclient = nullptr; + while ( (client = clients->FindNextClient(EProtocol::p25, it)) != nullptr ) + { + // is this client busy ? + if ( client->IsAMaster() ) + { + // yes, just tickle it + client->Alive(); + } + // check it's still with us + else if ( !client->IsAlive() ) + { + // no, remove it + std::cout << "P25 client " << client->GetCallsign() << " keepalive timeout" << std::endl; + clients->RemoveClient(client); + } + + } + g_Reflector.ReleaseClients(); +} + diff --git a/reflector/P25Protocol.h b/reflector/P25Protocol.h new file mode 100644 index 0000000..38f7a36 --- /dev/null +++ b/reflector/P25Protocol.h @@ -0,0 +1,75 @@ +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. + +// urfd -- The universal reflector +// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2021 Doug McLain AD8DP +// +// 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 3 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, see . + +#pragma once + +#include "Timer.h" +#include "Protocol.h" +#include "DVHeaderPacket.h" +#include "DVFramePacket.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// define + +#define P25_MODULE_ID 'B' +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CP25StreamCacheItem +{ +public: + CP25StreamCacheItem() : m_iSeqCounter(0) {} + + CDvHeaderPacket m_dvHeader; + uint32_t m_iSeqCounter; +}; + +class CP25Protocol : public CProtocol +{ +public: + // initialization + bool Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6); + + // task + void Task(void); + +protected: + // queue helper + void HandleQueue(void); + void HandleKeepalives(void); + + // stream helpers + void OnDvHeaderPacketIn(std::unique_ptr &, const CIp &); + + // packet decoding helpers + bool IsValidConnectPacket(const CBuffer &, CCallsign *); + bool IsValidDisconnectPacket(const CBuffer &, CCallsign *); + bool IsValidDvPacket(const CIp &, const CBuffer &, std::unique_ptr &); + bool IsValidDvHeaderPacket(const CIp &, const CBuffer &, std::unique_ptr &); + + // packet encoding helpers + void EncodeP25Packet(const CDvHeaderPacket &, const CDvFramePacket &, uint32_t, CBuffer &Buffer, bool) const; + + // for keep alive + CTimer m_LastKeepaliveTime; + + // for queue header caches + std::unordered_map m_StreamsCache; + uint32_t m_uiStreamId; +}; diff --git a/reflector/Packet.cpp b/reflector/Packet.cpp index e7909d4..2ac6d42 100644 --- a/reflector/Packet.cpp +++ b/reflector/Packet.cpp @@ -138,6 +138,23 @@ CPacket::CPacket(uint16_t sid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysffri m_bLastPacket = lastpacket; } +// p25 constructor +CPacket::CPacket(uint16_t sid, bool lastpacket) +{ + m_uiStreamId = sid; + m_uiDstarPacketId = 0xFF; + m_uiDmrPacketId = 0xFF; + m_uiDmrPacketSubid = 0xFF; + m_uiYsfPacketId = 0xFF; + m_uiYsfPacketSubId = 0xFF; + m_uiYsfPacketFrameId = 0xFF; + m_uiM17FrameNumber = 0xFFFFFFFFU; + m_cModule = ' '; + m_eOrigin = EOrigin::local; + m_eCodecIn = ECodecType::p25; + m_bLastPacket = lastpacket; +}; + // bm constructor CPacket::CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubpid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysffrid, ECodecType codecIn, bool lastpacket) { diff --git a/reflector/Packet.h b/reflector/Packet.h index 49a865d..f48370f 100644 --- a/reflector/Packet.h +++ b/reflector/Packet.h @@ -34,6 +34,7 @@ public: CPacket(const CBuffer &Buffer); CPacket(uint16_t sid, uint8_t dstarpid); CPacket(uint16_t sid, uint8_t dmrpid, uint8_t dmrsubpid, bool lastpacket); + CPacket(uint16_t sid, bool lastpacket); CPacket(uint16_t sid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysfsubpidmax, bool lastpacket); CPacket(uint16_t sid, uint8_t dstarpid, uint8_t dmrpid, uint8_t dmrsubpid, uint8_t ysfpid, uint8_t ysfsubpid, uint8_t ysfsubpidmax, ECodecType, bool lastpacket); CPacket(const CM17Packet &); diff --git a/reflector/Protocols.cpp b/reflector/Protocols.cpp index 10649a6..facda65 100644 --- a/reflector/Protocols.cpp +++ b/reflector/Protocols.cpp @@ -26,6 +26,7 @@ #include "YSFProtocol.h" #include "M17Protocol.h" #include "BMProtocol.h" +#include "P25Protocol.h" #ifndef NO_G3 #include "G3Protocol.h" #endif @@ -77,6 +78,10 @@ bool CProtocols::Init(void) m_Protocols.emplace_back(std::unique_ptr(new CM17Protocol)); if (! m_Protocols.back()->Initialize("URF", EProtocol::m17, M17_PORT, M17_IPV4, M17_IPV6)) return false; + + m_Protocols.emplace_back(std::unique_ptr(new CP25Protocol)); + if (! m_Protocols.back()->Initialize("P25", EProtocol::p25, P25_PORT, P25_IPV4, P25_IPV6)) + return false; m_Protocols.emplace_back(std::unique_ptr(new CURFProtocol)); if (! m_Protocols.back()->Initialize("URF", EProtocol::urf, URF_PORT, URF_IPV4, URF_IPV6)) diff --git a/reflector/TCPacketDef.h b/reflector/TCPacketDef.h index 006fe8f..1585842 100644 --- a/reflector/TCPacketDef.h +++ b/reflector/TCPacketDef.h @@ -23,7 +23,7 @@ #define TC2REF "TC2URFMod" #define REF2TC "URF2TC" -enum class ECodecType : std::uint8_t { none = 0, dstar = 1, dmr = 2, c2_1600 = 3, c2_3200 = 4 }; +enum class ECodecType : std::uint8_t { none = 0, dstar = 1, dmr = 2, c2_1600 = 3, c2_3200 = 4, p25 = 5 }; using STCPacket = struct tcpacket_tag { CTimer rt_timer; @@ -35,4 +35,5 @@ using STCPacket = struct tcpacket_tag { uint8_t dstar[9]; uint8_t dmr[9]; uint8_t m17[16]; + uint8_t p25[11]; };