From 0c6fcaaa3db87312a5459e4a249bb5ee2d3eae5c Mon Sep 17 00:00:00 2001 From: it9gnj <56492235+it9gnj@users.noreply.github.com> Date: Sun, 13 Oct 2019 01:36:54 +0200 Subject: [PATCH 01/70] Update NXDNHosts.txt --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 6dbe8f6..68fb0f1 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -122,3 +122,6 @@ # 22245 IT PIEDMONT GDO 22245 nxdngdo.duckdns.org 41400 + +# 2249 IT SICILIA +2249 nxdn.digitalsicilia.it 41400 From 137fc0f9f71a09cd26f50af25242314ea012d4f2 Mon Sep 17 00:00:00 2001 From: Yakov Danilov Date: Tue, 15 Oct 2019 16:21:33 +0300 Subject: [PATCH 02/70] Update NXDNHosts.txt --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index b6d1c0a..84f97d6 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -12,6 +12,9 @@ # Florida, 1200 1200 florida.nxref.org 41400 +# RU DMR TG2503 +2503 nxdn.r1ik.ru 41400 + # VK7 TAS, 5057 5057 45.248.50.37 41400 From bc0e230813499dc081aac81aadb16dbbd66b41c7 Mon Sep 17 00:00:00 2001 From: n9krg <56365804+n9krg@users.noreply.github.com> Date: Thu, 17 Oct 2019 21:27:38 -0500 Subject: [PATCH 03/70] Update NXDNHosts.txt --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index c5ff950..0785e46 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -3,6 +3,9 @@ # The format of this file is the number of the Talk Group followed by the host name or address and port # +# Super Freq 420 +420 144.202.59.230 41400 + # VKCore, 505 505 43.229.63.42 41450 From 21a3c3e2dd6c8b36f04497775e3adf1cdbcec8b8 Mon Sep 17 00:00:00 2001 From: BudT Date: Wed, 30 Oct 2019 06:21:37 -0600 Subject: [PATCH 04/70] Update NXDNHosts.txt changed/updated address for New Zealand, 530 --- NXDNGateway/NXDNHosts.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 0785e46..af20d5c 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -10,7 +10,7 @@ 505 43.229.63.42 41450 # New Zealand, 530 -530 101.98.22.194 41400 +zldigitalreflectors.hopto.org 41400 # Florida, 1200 1200 florida.nxref.org 41400 From af2f2a3c12f6264f1c2a62fb6179b7ea38af6ad7 Mon Sep 17 00:00:00 2001 From: BudT Date: Wed, 30 Oct 2019 19:13:20 -0600 Subject: [PATCH 05/70] Update NXDNHosts.txt forgot the TG # in my last edit for 530. Sorry --- NXDNGateway/NXDNHosts.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index af20d5c..cbced82 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -10,7 +10,7 @@ 505 43.229.63.42 41450 # New Zealand, 530 -zldigitalreflectors.hopto.org 41400 +530 zldigitalreflectors.hopto.org 41400 # Florida, 1200 1200 florida.nxref.org 41400 From f7c8398b7071f1fa406de2b25dbb93c60ff71eee Mon Sep 17 00:00:00 2001 From: Russell Thomas Date: Fri, 1 Nov 2019 09:23:18 -0500 Subject: [PATCH 06/70] Update NXDNHost.txt updated IP address for DXLink --- NXDNGateway/NXDNHosts.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index cbced82..204c30d 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -94,7 +94,7 @@ 31672 nxdn-31672.pistar.uk 41400 # DX-LINK SYSTEM, 31777 -31777 45.77.204.214 41400 +31777 8.9.4.102 41400 # Fusion Canada Fr /Wires-x /Ysf /Nxdn Network 40721 38.110.97.161 41400 From 91fa3dca7641cb22929517195f951a27509f748d Mon Sep 17 00:00:00 2001 From: n9krg <56365804+n9krg@users.noreply.github.com> Date: Sat, 9 Nov 2019 02:58:25 -0600 Subject: [PATCH 07/70] Update NXDNHosts.txt --- NXDNGateway/NXDNHosts.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index a49080c..3fd5bf8 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -4,7 +4,7 @@ # # Super Freq 420 -420 144.202.59.230 41400 +420 nxdn.evsuperfreqs.com 41400 # VKCore, 505 505 43.229.63.42 41450 From 809353fcceeef46062370cf93605d5e2174837ea Mon Sep 17 00:00:00 2001 From: Merlinv2 <55551965+Merlinv2@users.noreply.github.com> Date: Thu, 14 Nov 2019 17:20:39 +0100 Subject: [PATCH 08/70] Update NXDNHosts.txt Please ADD New NXDN Reflector : # 914 Latin America 914 164.132.96.157 41400 --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 3fd5bf8..29a1e66 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -134,3 +134,6 @@ # 2249 IT SICILIA 2249 nxdn.digitalsicilia.it 41400 + +# 914 Latin America +914 164.132.96.157 41400 From 26e9e48b9c0bb8cc39cd3d2c61ef4b17263c5064 Mon Sep 17 00:00:00 2001 From: mm0hjx <58149737+mm0hjx@users.noreply.github.com> Date: Sun, 24 Nov 2019 20:54:43 +0000 Subject: [PATCH 09/70] Update NXDNHosts.txt # NXDN Scotland, 23551 23551 nxdnscotland.ddns.net 41400 --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 29a1e66..2532962 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -48,6 +48,9 @@ # Europe, German speaking, 20000 20000 89.185.97.38 41400 +# NXDN Scotland, 23551 +23551 nxdnscotland.ddns.net 41400 + # CT NXCore, 25000 25000 45.62.211.216 41425 From 2115b1631d1a2689a444b12b589edce62f04a8c1 Mon Sep 17 00:00:00 2001 From: awasser1 Date: Sat, 4 Jan 2020 11:31:12 +1000 Subject: [PATCH 10/70] Update NXDNHosts.txt 31137 restore after death of Steve whom ran the reflector previously. --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 2532962..d1cb058 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -75,6 +75,9 @@ # Connecticut Chat, 31092 31092 nxdn.alecwasserman.com 41400 +# Kingsland Digital Link +31137 74.91.119.94 41400 + # Illinois, 31171 31171 74.208.235.115 41400 From 7d36ffc7df1bd394b462431f21bc955e55153082 Mon Sep 17 00:00:00 2001 From: Merlinv2 <55551965+Merlinv2@users.noreply.github.com> Date: Fri, 10 Jan 2020 09:18:17 +0100 Subject: [PATCH 11/70] Update NXDNHosts.txt please add nxreflector # RED NXDN SPAIN 214 nxdn214.xreflector.es 41400 --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index d1cb058..14dcddb 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -143,3 +143,6 @@ # 914 Latin America 914 164.132.96.157 41400 + +# RED NXDN SPAIN +214 nxdn214.xreflector.es 41400 From 7151b058ce6b12251a1ad8ef570a1d8d0d099783 Mon Sep 17 00:00:00 2001 From: Michele <55660249+IU5HJU@users.noreply.github.com> Date: Sun, 19 Jan 2020 19:02:41 +0100 Subject: [PATCH 12/70] Update NXDNHost.txt Reflector in numerical order --- NXDNGateway/NXDNHosts.txt | 60 +++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 14dcddb..b7ac974 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -3,6 +3,9 @@ # The format of this file is the number of the Talk Group followed by the host name or address and port # +# RED NXDN SPAIN +214 nxdn214.xreflector.es 41400 + # Super Freq 420 420 nxdn.evsuperfreqs.com 41400 @@ -12,24 +15,33 @@ # New Zealand, 530 530 zldigitalreflectors.hopto.org 41400 +# 914 Latin America +914 164.132.96.157 41400 + # Florida, 1200 1200 florida.nxref.org 41400 +# 2140 DMRplus BM Multi +2140 94.177.235.81 41400 + +# 2225 IT Tuscany +2225 80.211.99.134 41400 + +# 2249 IT SICILIA +2249 nxdn.digitalsicilia.it 41400 + # RU DMR TG2503 2503 nxdn.r1ik.ru 41400 +# 3023 Ontario Crosslink +3023 ontxlink.hopto.org 41400 + # VK7 TAS, 5057 5057 45.248.50.37 41400 -# BM NXCore bridge, 50599 -50599 nxdn.duckdns.org 41490 - # North America, 10200 10200 dvswitch.org 42400 -# Portuguese speaking test, 10268 -26810 84.90.7.110 41400 - # Spanish speaking, 10301 10301 ea5gvk.duckdns.org 41400 @@ -48,6 +60,12 @@ # Europe, German speaking, 20000 20000 89.185.97.38 41400 +# 21465 ADER Multimode +21465 80.211.106.186 41400 + +# 22245 IT PIEDMONT GDO +22245 nxdngdo.duckdns.org 41400 + # NXDN Scotland, 23551 23551 nxdnscotland.ddns.net 41400 @@ -60,6 +78,9 @@ # Poland, 26000 26000 31.0.161.238 41400 +# Portuguese speaking test, 10268 +26810 84.90.7.110 41400 + # America-Ragchew, 28299 28299 65.101.7.52 41400 @@ -111,6 +132,9 @@ # DMR TG50525 bridge, 50525 50525 50525.nxref.org 41400 +# BM NXCore bridge, 50599 +50599 nxdn.duckdns.org 41490 + # Thailand DTDXA XLX520N, 52000 52000 nxdn.dtdxa.com 41400 @@ -122,27 +146,3 @@ # French-Test, 65208 65208 m55.evxonline.net 41400 - -# 3023 Ontario Crosslink -3023 ontxlink.hopto.org 41400 - -# 2140 DMRplus BM Multi -2140 94.177.235.81 41400 - -# 2225 IT Tuscany -2225 80.211.99.134 41400 - -# 21465 ADER Multimode -21465 80.211.106.186 41400 - -# 22245 IT PIEDMONT GDO -22245 nxdngdo.duckdns.org 41400 - -# 2249 IT SICILIA -2249 nxdn.digitalsicilia.it 41400 - -# 914 Latin America -914 164.132.96.157 41400 - -# RED NXDN SPAIN -214 nxdn214.xreflector.es 41400 From a1cf148965071d8c375b62f44ab801ffbc9e8061 Mon Sep 17 00:00:00 2001 From: Scott Evans Date: Sat, 25 Jan 2020 02:53:33 +1100 Subject: [PATCH 13/70] Update nxdn hosts.txt Added Canada 302 nxdn reflector --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index b7ac974..ec088c5 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -6,6 +6,9 @@ # RED NXDN SPAIN 214 nxdn214.xreflector.es 41400 +# Canada, 302 +302 p25canada.hopto.org 41400 + # Super Freq 420 420 nxdn.evsuperfreqs.com 41400 From 17b3e6eb965e5354201a9291a34d55b28c488a59 Mon Sep 17 00:00:00 2001 From: SV1CDR <60268646+sv1cdr@users.noreply.github.com> Date: Fri, 24 Jan 2020 22:24:16 +0100 Subject: [PATCH 14/70] Update NXDNHosts.txt --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index b7ac974..80e4165 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -2,6 +2,8 @@ # # The format of this file is the number of the Talk Group followed by the host name or address and port # +# HELLAS Zone TG202 +202 hellaszone.com 41400 # RED NXDN SPAIN 214 nxdn214.xreflector.es 41400 @@ -146,3 +148,4 @@ # French-Test, 65208 65208 m55.evxonline.net 41400 + From 37284f1561aeac2acf18a42fe51f8a63460c7517 Mon Sep 17 00:00:00 2001 From: Joaquin Madrid Belando Date: Sat, 25 Jan 2020 12:55:37 +0100 Subject: [PATCH 15/70] Update Update NXDNHosts.txt Add Reflector NXDN 7225 MULTIPROTOCOLO ARGENTINA --- Update NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Update NXDNHosts.txt b/Update NXDNHosts.txt index d0ef425..3e3bfe3 100644 --- a/Update NXDNHosts.txt +++ b/Update NXDNHosts.txt @@ -1,2 +1,5 @@ # 911 911 Cop Talk 911 NXDN.k2cop.com 41400 + +# 7225 MULTIPROTOCOLO ARGENTINA +7225 ysfarg.ddns.net 41400 From 18c92b6275fd983bc54d75dbd286d13ca79d094e Mon Sep 17 00:00:00 2001 From: Merlinv2 <55551965+Merlinv2@users.noreply.github.com> Date: Thu, 30 Jan 2020 15:46:39 +0100 Subject: [PATCH 16/70] Update NXDNHosts.txt Please Update NXDNHosts.txt add: # NXDN SPAIN 21410 21410 nxdn21410.nxdn.es 41400 --- NXDNGateway/NXDNHosts.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 51b3f8a..3d51a5a 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -147,8 +147,10 @@ 53099 203.86.206.49 41400 # World Wide, 65000 -65000 176.9.1.168 41400 +65000 176.9.1.168 41400 # French-Test, 65208 65208 m55.evxonline.net 41400 +# NXDN SPAIN 21410 +21410 nxdn21410.nxdn.es 41400 From 0cf784a14adc08afd674cfbb88b931a7a8fe0c5c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 2 Feb 2020 18:45:16 +0000 Subject: [PATCH 17/70] Added XLX545A and XLX545E --- NXDNGateway/NXDNHosts.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 3d51a5a..4d85417 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -20,6 +20,9 @@ # New Zealand, 530 530 zldigitalreflectors.hopto.org 41400 +# XLX545E PA NXDN +545 70.44.20.24 41401 + # 914 Latin America 914 164.132.96.157 41400 @@ -116,6 +119,9 @@ # Oklahoma Link, 31403 31403 3.208.70.29 41400 +# XLX545A Pennsylvania Cross Mode +31425 70.44.20.24 41400 + # Rhode Island Digital Link, 31444 31444 18.219.32.21 41400 From b113ef91e51ab91535ec2393513cdbe32750e401 Mon Sep 17 00:00:00 2001 From: Andrew Lynch Date: Wed, 5 Feb 2020 19:58:09 -0600 Subject: [PATCH 18/70] Update NXDNHosts Added 707nxdn.kd0ioe.com reflector, linked to TG707 on TGIF. --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 4d85417..df2dbf1 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -23,6 +23,9 @@ # XLX545E PA NXDN 545 70.44.20.24 41401 +# RuralMN Reflector 707 +707 707nxdn.kd0ioe.com 41400 + # 914 Latin America 914 164.132.96.157 41400 From f639251d5595814bf61ce2b7c2fc135a7d840b9b Mon Sep 17 00:00:00 2001 From: Scott Evans Date: Mon, 10 Feb 2020 07:31:15 +1100 Subject: [PATCH 19/70] NXDNHosts.txt I received an email from VA3CZK requesting that I removed the addition of the 302 Canada reflector from the NXDNHosts.txt listing. --- NXDNGateway/NXDNHosts.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index df2dbf1..436e23b 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -8,9 +8,6 @@ # RED NXDN SPAIN 214 nxdn214.xreflector.es 41400 -# Canada, 302 -302 p25canada.hopto.org 41400 - # Super Freq 420 420 nxdn.evsuperfreqs.com 41400 From 5a781db1f6ce7f21b0d131c080444be2aa293f21 Mon Sep 17 00:00:00 2001 From: n9krg <56365804+n9krg@users.noreply.github.com> Date: Mon, 10 Feb 2020 09:18:25 -0600 Subject: [PATCH 20/70] Update NXDNHosts.txt new dynamic dns --- NXDNGateway/NXDNHosts.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 436e23b..146c16a 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -9,7 +9,7 @@ 214 nxdn214.xreflector.es 41400 # Super Freq 420 -420 nxdn.evsuperfreqs.com 41400 +420 hb.superfreqdigital.com 41400 # VKCore, 505 505 43.229.63.42 41450 From f71231b2e61abb2eb2801e172ec62d72a17dc44a Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 14 Feb 2020 21:08:18 +0000 Subject: [PATCH 21/70] Added 7225 Multiprotocolo Argentina --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 146c16a..0198021 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -47,6 +47,9 @@ # VK7 TAS, 5057 5057 45.248.50.37 41400 +# Multiprotocolo Argentina +7225 ysfarg.ddns.net 41400 + # North America, 10200 10200 dvswitch.org 42400 From 98509ef2a91e8344f3c6314a7d493ae21fba00d5 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 14 Feb 2020 21:44:35 +0000 Subject: [PATCH 22/70] Update to VS2019. --- NXDNGateway/NXDNGateway.vcxproj | 10 +++++----- NXDNParrot/NXDNParrot.vcxproj | 10 +++++----- NXDNReflector/NXDNReflector.vcxproj | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/NXDNGateway/NXDNGateway.vcxproj b/NXDNGateway/NXDNGateway.vcxproj index 38995e9..97c3696 100644 --- a/NXDNGateway/NXDNGateway.vcxproj +++ b/NXDNGateway/NXDNGateway.vcxproj @@ -22,32 +22,32 @@ {8B7A5406-8560-4B40-ADDA-9B8EBF93E232} Win32Proj NXDNGateway - 10.0.15063.0 + 10.0 Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode diff --git a/NXDNParrot/NXDNParrot.vcxproj b/NXDNParrot/NXDNParrot.vcxproj index 053937b..a92087d 100644 --- a/NXDNParrot/NXDNParrot.vcxproj +++ b/NXDNParrot/NXDNParrot.vcxproj @@ -22,32 +22,32 @@ {2AE94EAA-FD57-45C9-8555-6425CFA777A3} Win32Proj NXDNParrot - 10.0.15063.0 + 10.0 Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode diff --git a/NXDNReflector/NXDNReflector.vcxproj b/NXDNReflector/NXDNReflector.vcxproj index d72db0b..37b05b1 100644 --- a/NXDNReflector/NXDNReflector.vcxproj +++ b/NXDNReflector/NXDNReflector.vcxproj @@ -52,32 +52,32 @@ {C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5} Win32Proj NXDNReflector - 10.0.16299.0 + 10.0 Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode From c78da747a0218c0c7f8982d830b48d82d4778709 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 24 Feb 2020 11:46:22 +0000 Subject: [PATCH 23/70] Add TG3142 --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 0198021..3c927cc 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -44,6 +44,9 @@ # 3023 Ontario Crosslink 3023 ontxlink.hopto.org 41400 +# 3142 Pennsylvania +3142 3.215.215.169 41402 + # VK7 TAS, 5057 5057 45.248.50.37 41400 From 3a1b556274b3d058564ffcf317a1f91aa43f10ec Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 29 Feb 2020 12:14:15 +0000 Subject: [PATCH 24/70] Added TG31264 --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 3c927cc..a71c889 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -119,6 +119,9 @@ # Southern Indiana, 31188 31188 w9windigital.org 41400 +# 31264 XLX625 The BROniverse www.wa8bro.com +31264 nxdn.dudetronics.com 41400 + # Central New Jersey, 31340 31340 cnjham.msmts.com 41400 From ea7a6f30065881442ebfba4c9b7e8607d96fa68d Mon Sep 17 00:00:00 2001 From: NN1D <61644341+NN1D@users.noreply.github.com> Date: Sun, 1 Mar 2020 11:48:30 -0500 Subject: [PATCH 25/70] Update Update NXDNHosts.txt --- Update NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Update NXDNHosts.txt b/Update NXDNHosts.txt index 3e3bfe3..3dab350 100644 --- a/Update NXDNHosts.txt +++ b/Update NXDNHosts.txt @@ -3,3 +3,6 @@ # 7225 MULTIPROTOCOLO ARGENTINA 7225 ysfarg.ddns.net 41400 + +# 25000 NE NXCore NXDNReflector +25000 173.166.94.77 41400 From 581b40c1b8190deac42acf1639b5597546f89961 Mon Sep 17 00:00:00 2001 From: JJ Cummings Date: Mon, 2 Mar 2020 15:21:17 -0700 Subject: [PATCH 26/70] Added WE0FUN NXDN host info --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index a71c889..84763e7 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -104,6 +104,9 @@ # Alabama-Link, 31010 31010 nxdn.alabamalink.info 41400 +# Colorado Fun Machine WE0FUN Bridge to C4FM, DMR, DStar, P25 and AllStarLink (Analog) http://www.we0fun.com +31081 nxdn.we0fun.com 41400 + # Colorado HD, 31088 31088 54.191.50.212 41400 From 77f55180afa643441a099498972eb4024fb77b8e Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 3 Mar 2020 15:31:59 +0000 Subject: [PATCH 27/70] Add a backoff timer for when the connection to aprs.fi fails. --- NXDNGateway/APRSWriter.cpp | 4 ++- NXDNGateway/APRSWriterThread.cpp | 45 +++++++++++++++++++++++++++----- NXDNGateway/APRSWriterThread.h | 8 +++++- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/NXDNGateway/APRSWriter.cpp b/NXDNGateway/APRSWriter.cpp index 4c88902..e5eb58e 100644 --- a/NXDNGateway/APRSWriter.cpp +++ b/NXDNGateway/APRSWriter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2010-2014,2016,2017,2018,2020 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 @@ -112,6 +112,8 @@ void CAPRSWriter::clock(unsigned int ms) { m_idTimer.clock(ms); + m_thread->clock(ms); + if (m_socket != NULL) { if (m_idTimer.hasExpired()) { pollGPS(); diff --git a/NXDNGateway/APRSWriterThread.cpp b/NXDNGateway/APRSWriterThread.cpp index 93e2e48..c388609 100644 --- a/NXDNGateway/APRSWriterThread.cpp +++ b/NXDNGateway/APRSWriterThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2010-2014,2016,2020 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 @@ -41,6 +41,8 @@ m_socket(address, port), m_queue(20U, "APRS Queue"), m_exit(false), m_connected(false), +m_reconnectTimer(1000U), +m_tries(1U), m_APRSReadCallback(NULL), m_filter(), m_clientName("YSFGateway") @@ -63,6 +65,8 @@ m_socket(address, port), m_queue(20U, "APRS Queue"), m_exit(false), m_connected(false), +m_reconnectTimer(1000U), +m_tries(1U), m_APRSReadCallback(NULL), m_filter(filter), m_clientName(clientName) @@ -94,19 +98,28 @@ void CAPRSWriterThread::entry() LogMessage("Starting the APRS Writer thread"); m_connected = connect(); + if (!m_connected) { + LogError("Connect attempt to the APRS server has failed"); + startReconnectionTimer(); + } try { while (!m_exit) { if (!m_connected) { - m_connected = connect(); + if (m_reconnectTimer.isRunning() && m_reconnectTimer.hasExpired()) { + m_reconnectTimer.stop(); - if (!m_connected){ - LogError("Reconnect attempt to the APRS server has failed"); - sleep(10000UL); // 10 secs + m_connected = connect(); + if (!m_connected) { + LogError("Reconnect attempt to the APRS server has failed"); + startReconnectionTimer(); + } } } if (m_connected) { + m_tries = 0U; + if (!m_queue.isEmpty()){ char* p = NULL; m_queue.getData(&p, 1U); @@ -115,11 +128,12 @@ void CAPRSWriterThread::entry() ::strcat(p, "\r\n"); - bool ret = m_socket.write((unsigned char*)p, ::strlen(p)); + bool ret = m_socket.write((unsigned char*)p, (unsigned int)::strlen(p)); if (!ret) { m_connected = false; m_socket.close(); LogError("Connection to the APRS thread has failed"); + startReconnectionTimer(); } delete[] p; @@ -132,6 +146,7 @@ void CAPRSWriterThread::entry() m_connected = false; m_socket.close(); LogError("Error when reading from the APRS server"); + startReconnectionTimer(); } if(length > 0 && line.at(0U) != '#'//check if we have something and if that something is an APRS frame @@ -176,7 +191,7 @@ void CAPRSWriterThread::write(const char* data) if (!m_connected) return; - unsigned int len = ::strlen(data); + unsigned int len = (unsigned int)::strlen(data); char* p = new char[len + 5U]; ::strcpy(p, data); @@ -196,6 +211,11 @@ void CAPRSWriterThread::stop() wait(); } +void CAPRSWriterThread::clock(unsigned int ms) +{ + m_reconnectTimer.clock(ms); +} + bool CAPRSWriterThread::connect() { bool ret = m_socket.open(); @@ -246,3 +266,14 @@ bool CAPRSWriterThread::connect() return true; } + +void CAPRSWriterThread::startReconnectionTimer() +{ + // Clamp at a ten minutes reconnect time + m_tries++; + if (m_tries > 10U) + m_tries = 10U; + + m_reconnectTimer.setTimeout(m_tries * 60U); + m_reconnectTimer.start(); +} diff --git a/NXDNGateway/APRSWriterThread.h b/NXDNGateway/APRSWriterThread.h index 42bfd67..c86c23a 100644 --- a/NXDNGateway/APRSWriterThread.h +++ b/NXDNGateway/APRSWriterThread.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010,2011,2012,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2010,2011,2012,2016,2020 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 @@ -21,6 +21,7 @@ #include "TCPSocket.h" #include "RingBuffer.h" +#include "Timer.h" #include "Thread.h" #include @@ -45,6 +46,8 @@ public: void setReadAPRSCallback(ReadAPRSFrameCallback cb); + void clock(unsigned int ms); + private: std::string m_username; std::string m_password; @@ -52,11 +55,14 @@ private: CRingBuffer m_queue; bool m_exit; bool m_connected; + CTimer m_reconnectTimer; + unsigned int m_tries; ReadAPRSFrameCallback m_APRSReadCallback; std::string m_filter; std::string m_clientName; bool connect(); + void startReconnectionTimer(); }; #endif From 0549fabbc1263134ac502b423f2b97d552e3abaf Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 9 Mar 2020 11:10:15 +0000 Subject: [PATCH 28/70] Add Deutschland 26200 --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 84763e7..3073f5b 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -92,6 +92,9 @@ # Poland, 26000 26000 31.0.161.238 41400 +# Deutschland, 26200 +26200 26200.ham-nxdn.de 41400 + # Portuguese speaking test, 10268 26810 84.90.7.110 41400 From 44ea6e7b68dbbc319699e579795a44eb200859d1 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 10 Mar 2020 12:29:55 +0000 Subject: [PATCH 29/70] Add Pennsylvania Cross Mode (alt), 31426 --- NXDNGateway/NXDNHosts.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 3073f5b..44f63fb 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -134,9 +134,12 @@ # Oklahoma Link, 31403 31403 3.208.70.29 41400 -# XLX545A Pennsylvania Cross Mode +# XLX545A Pennsylvania Cross Mode, 31425 31425 70.44.20.24 41400 +# XLX545A Pennsylvania Cross Mode (alt), 31426 +31426 3.215.215.169 41400 + # Rhode Island Digital Link, 31444 31444 18.219.32.21 41400 From f6df463b8e60d64fe3435f887ca16527204157eb Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 16 Mar 2020 14:28:23 +0000 Subject: [PATCH 30/70] Updated NX Core 25000 --- NXDNGateway/NXDNHosts.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 44f63fb..d680a32 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -83,8 +83,8 @@ # NXDN Scotland, 23551 23551 nxdnscotland.ddns.net 41400 -# CT NXCore, 25000 -25000 45.62.211.216 41425 +# NX Core, 25000 +25000 173.166.94.77 41400 # Russia NXDN Net, 25641 25641 194.182.85.217 41400 From 1dc51679d8d199e496ce854cf9493c10d8ef0190 Mon Sep 17 00:00:00 2001 From: Roby Date: Thu, 19 Mar 2020 00:15:39 +0100 Subject: [PATCH 31/70] Update NXDNHosts.txt add 22200 hblink ita reflector --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index d680a32..d2d55fe 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -77,6 +77,9 @@ # 21465 ADER Multimode 21465 80.211.106.186 41400 +# 22200 IT HBLINK ITALY +22200 nxdn.hblink.it 41400 + # 22245 IT PIEDMONT GDO 22245 nxdngdo.duckdns.org 41400 From ac1b481142f9fa1395a1804f5ba7fb9afc7dcbcf Mon Sep 17 00:00:00 2001 From: Roby Date: Thu, 26 Mar 2020 18:46:47 +0100 Subject: [PATCH 32/70] Update NXDNHosts.txt Echolink NXDN Reflector --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index d2d55fe..128cf9b 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -80,6 +80,9 @@ # 22200 IT HBLINK ITALY 22200 nxdn.hblink.it 41400 +# 22220 IT ECHOLINK ITALY +22220 dagobah.hblink.it 41400 + # 22245 IT PIEDMONT GDO 22245 nxdngdo.duckdns.org 41400 From 785faa7ad9173cda54f83a4e43683e5b96c4972f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 3 Apr 2020 17:59:40 +0100 Subject: [PATCH 33/70] First version of the remote commands handler. --- NXDNGateway/Conf.cpp | 25 ++++++++-- NXDNGateway/Conf.h | 15 ++++-- NXDNGateway/NXDNGateway.cpp | 91 ++++++++++++++++++++++++++++++++++++- NXDNGateway/NXDNGateway.ini | 3 ++ NXDNGateway/Version.h | 4 +- 5 files changed, 128 insertions(+), 10 deletions(-) diff --git a/NXDNGateway/Conf.cpp b/NXDNGateway/Conf.cpp index 92cba3c..0056c27 100644 --- a/NXDNGateway/Conf.cpp +++ b/NXDNGateway/Conf.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020 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 @@ -35,7 +35,8 @@ enum SECTION { SECTION_LOG, SECTION_APRS_FI, SECTION_NETWORK, - SECTION_MOBILE_GPS + SECTION_MOBILE_GPS, + SECTION_REMOTE_COMMANDS }; CConf::CConf(const std::string& file) : @@ -81,7 +82,9 @@ m_networkInactivityTimeout(0U), m_networkDebug(false), m_mobileGPSEnabled(false), m_mobileGPSAddress(), -m_mobileGPSPort(0U) +m_mobileGPSPort(0U), +m_remoteCommandsEnabled(false), +m_remoteCommandsPort(6075U) { } @@ -121,6 +124,8 @@ bool CConf::read() section = SECTION_NETWORK; else if (::strncmp(buffer, "[Mobile GPS]", 12U) == 0) section = SECTION_MOBILE_GPS; + else if (::strncmp(buffer, "[Remote Commands]", 17U) == 0) + section = SECTION_REMOTE_COMMANDS; else section = SECTION_NONE; @@ -230,6 +235,11 @@ bool CConf::read() m_mobileGPSAddress = value; else if (::strcmp(key, "Port") == 0) m_mobileGPSPort = (unsigned int)::atoi(value); + } else if (section == SECTION_REMOTE_COMMANDS) { + if (::strcmp(key, "Enable") == 0) + m_remoteCommandsEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Port") == 0) + m_remoteCommandsPort = (unsigned int)::atoi(value); } } @@ -448,3 +458,12 @@ unsigned int CConf::getMobileGPSPort() const return m_mobileGPSPort; } +bool CConf::getRemoteCommandsEnabled() const +{ + return m_remoteCommandsEnabled; +} + +unsigned int CConf::getRemoteCommandsPort() const +{ + return m_remoteCommandsPort; +} diff --git a/NXDNGateway/Conf.h b/NXDNGateway/Conf.h index 29dce87..d11307b 100644 --- a/NXDNGateway/Conf.h +++ b/NXDNGateway/Conf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020 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 @@ -84,9 +84,13 @@ public: bool getNetworkDebug() const; // The Mobile GPS section - bool getMobileGPSEnabled() const; - std::string getMobileGPSAddress() const; - unsigned int getMobileGPSPort() const; + bool getMobileGPSEnabled() const; + std::string getMobileGPSAddress() const; + unsigned int getMobileGPSPort() const; + + // The Remote Commands section + bool getRemoteCommandsEnabled() const; + unsigned int getRemoteCommandsPort() const; private: std::string m_file; @@ -139,6 +143,9 @@ private: bool m_mobileGPSEnabled; std::string m_mobileGPSAddress; unsigned int m_mobileGPSPort; + + bool m_remoteCommandsEnabled; + unsigned int m_remoteCommandsPort; }; #endif diff --git a/NXDNGateway/NXDNGateway.cpp b/NXDNGateway/NXDNGateway.cpp index b86fb9e..97cdb0b 100644 --- a/NXDNGateway/NXDNGateway.cpp +++ b/NXDNGateway/NXDNGateway.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2017,2018,2020 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 @@ -27,6 +27,7 @@ #include "Thread.h" #include "Voice.h" #include "Timer.h" +#include "Utils.h" #include "Log.h" #if defined(_WIN32) || defined(_WIN64) @@ -179,6 +180,16 @@ void CNXDNGateway::run() createGPS(); + CUDPSocket* remoteSocket = NULL; + if (m_conf.getRemoteCommandsEnabled()) { + remoteSocket = new CUDPSocket(m_conf.getRemoteCommandsPort()); + ret = remoteSocket->open(); + if (!ret) { + delete remoteSocket; + remoteSocket = NULL; + } + } + CIcomNetwork localNetwork(m_conf.getMyPort(), m_conf.getRptDebug()); ret = localNetwork.open(); if (!ret) { @@ -389,6 +400,79 @@ startupId = 9999U; reflectors.clock(ms); + if (remoteSocket != NULL) { + int res = remoteSocket->read(buffer, 200U, address, port); + if (res > 0) { + buffer[res] = '\0'; + if (::memcmp(buffer + 0U, "TalkGroup", 9U) == 0) { + unsigned int tg = (unsigned int)::atoi((char*)(buffer + 9U)); + + CNXDNReflector* reflector = NULL; + if (tg != 9999U) + reflector = reflectors.find(tg); + + if (reflector == NULL && currentId != 9999U) { + LogMessage("Unlinked from reflector %u by remote command", currentId); + + if (voice != NULL) + voice->unlinked(); + + remoteNetwork.writeUnlink(currentAddr, currentPort, currentId); + remoteNetwork.writeUnlink(currentAddr, currentPort, currentId); + remoteNetwork.writeUnlink(currentAddr, currentPort, currentId); + + inactivityTimer.stop(); + pollTimer.stop(); + lostTimer.stop(); + + currentId = 9999U; + } else if (reflector != NULL && currentId == 9999U) { + currentId = tg; + currentAddr = reflector->m_address; + currentPort = reflector->m_port; + + LogMessage("Linked to reflector %u by remote command", currentId); + + if (voice != NULL) + voice->linkedTo(currentId); + + remoteNetwork.writePoll(currentAddr, currentPort, currentId); + remoteNetwork.writePoll(currentAddr, currentPort, currentId); + remoteNetwork.writePoll(currentAddr, currentPort, currentId); + + inactivityTimer.start(); + pollTimer.start(); + lostTimer.start(); + } else if (reflector != NULL && currentId != 9999U) { + LogMessage("Unlinked from reflector %u by remote command", currentId); + + remoteNetwork.writeUnlink(currentAddr, currentPort, currentId); + remoteNetwork.writeUnlink(currentAddr, currentPort, currentId); + remoteNetwork.writeUnlink(currentAddr, currentPort, currentId); + + currentId = tg; + currentAddr = reflector->m_address; + currentPort = reflector->m_port; + + LogMessage("Linked to reflector %u by remote command", currentId); + + if (voice != NULL) + voice->linkedTo(currentId); + + remoteNetwork.writePoll(currentAddr, currentPort, currentId); + remoteNetwork.writePoll(currentAddr, currentPort, currentId); + remoteNetwork.writePoll(currentAddr, currentPort, currentId); + + inactivityTimer.start(); + pollTimer.start(); + lostTimer.start(); + } + } else { + CUtils::dump("Invalid remote command received", buffer, res); + } + } + } + if (voice != NULL) voice->clock(ms); @@ -469,6 +553,11 @@ startupId = 9999U; delete voice; + if (remoteSocket != NULL) { + remoteSocket->close(); + delete remoteSocket; + } + localNetwork.close(); remoteNetwork.close(); diff --git a/NXDNGateway/NXDNGateway.ini b/NXDNGateway/NXDNGateway.ini index 884d8bd..3aff870 100644 --- a/NXDNGateway/NXDNGateway.ini +++ b/NXDNGateway/NXDNGateway.ini @@ -57,3 +57,6 @@ Enable=0 Address=127.0.0.1 Port=7834 +[Remote Commands] +Enable=0 +Port=6075 diff --git a/NXDNGateway/Version.h b/NXDNGateway/Version.h index 53badbe..b366ff5 100644 --- a/NXDNGateway/Version.h +++ b/NXDNGateway/Version.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020 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 @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20180524"; +const char* VERSION = "20200403"; #endif From f51115c1d013999484031f0e7dde5bb13bc8f405 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 6 Apr 2020 16:43:53 +0100 Subject: [PATCH 34/70] Beginnings of Kenwood repeater support. --- NXDNGateway/IcomNetwork.cpp | 6 ++- NXDNGateway/IcomNetwork.h | 17 ++++---- NXDNGateway/Makefile | 2 +- NXDNGateway/NXDNGateway.cpp | 21 ++++++---- NXDNGateway/NXDNGateway.vcxproj | 2 + NXDNGateway/NXDNGateway.vcxproj.filters | 6 +++ NXDNGateway/RptNetwork.cpp | 23 +++++++++++ NXDNGateway/RptNetwork.h | 55 +++++++++++++++++++++++++ 8 files changed, 115 insertions(+), 17 deletions(-) create mode 100644 NXDNGateway/RptNetwork.cpp create mode 100644 NXDNGateway/RptNetwork.h diff --git a/NXDNGateway/IcomNetwork.cpp b/NXDNGateway/IcomNetwork.cpp index 655acb9..056eaae 100644 --- a/NXDNGateway/IcomNetwork.cpp +++ b/NXDNGateway/IcomNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2014,2016,2018,2020 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 @@ -121,3 +121,7 @@ void CIcomNetwork::close() LogMessage("Closing Icom connection"); } + +void CIcomNetwork::clock(unsigned int ms) +{ +} diff --git a/NXDNGateway/IcomNetwork.h b/NXDNGateway/IcomNetwork.h index 38923d1..1c8f02d 100644 --- a/NXDNGateway/IcomNetwork.h +++ b/NXDNGateway/IcomNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2014,2016,2018,2020 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 @@ -19,24 +19,27 @@ #ifndef IcomNetwork_H #define IcomNetwork_H +#include "RptNetwork.h" #include "UDPSocket.h" #include "Timer.h" #include #include -class CIcomNetwork { +class CIcomNetwork : public IRptNetwork { public: CIcomNetwork(unsigned int localPort, bool debug); - ~CIcomNetwork(); + virtual ~CIcomNetwork(); - bool open(); + virtual bool open(); - bool write(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port); + virtual bool write(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port); - bool read(unsigned char* data, in_addr& address, unsigned int& port); + virtual bool read(unsigned char* data, in_addr& address, unsigned int& port); - void close(); + virtual void close(); + + virtual void clock(unsigned int ms); private: CUDPSocket m_socket; diff --git a/NXDNGateway/Makefile b/NXDNGateway/Makefile index 881ee6d..c587deb 100644 --- a/NXDNGateway/Makefile +++ b/NXDNGateway/Makefile @@ -5,7 +5,7 @@ LIBS = -lpthread LDFLAGS = -g OBJECTS = APRSWriter.o APRSWriterThread.o Conf.o GPSHandler.o IcomNetwork.o Log.o Mutex.o NXDNCRC.o NXDNGateway.o NXDNLookup.o NXDNNetwork.o Reflectors.o \ - StopWatch.o TCPSocket.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o + RptNetwork.o StopWatch.o TCPSocket.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o all: NXDNGateway diff --git a/NXDNGateway/NXDNGateway.cpp b/NXDNGateway/NXDNGateway.cpp index b86fb9e..7483fb3 100644 --- a/NXDNGateway/NXDNGateway.cpp +++ b/NXDNGateway/NXDNGateway.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2017,2018,2020 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 @@ -19,6 +19,7 @@ #include "IcomNetwork.h" #include "NXDNNetwork.h" #include "NXDNGateway.h" +#include "RptNetwork.h" #include "NXDNLookup.h" #include "Reflectors.h" #include "GPSHandler.h" @@ -179,8 +180,8 @@ void CNXDNGateway::run() createGPS(); - CIcomNetwork localNetwork(m_conf.getMyPort(), m_conf.getRptDebug()); - ret = localNetwork.open(); + IRptNetwork* localNetwork = new CIcomNetwork(m_conf.getMyPort(), m_conf.getRptDebug()); + ret = localNetwork->open(); if (!ret) { ::LogFinalise(); return; @@ -189,7 +190,8 @@ void CNXDNGateway::run() CNXDNNetwork remoteNetwork(m_conf.getNetworkPort(), m_conf.getCallsign(), m_conf.getNetworkDebug()); ret = remoteNetwork.open(); if (!ret) { - localNetwork.close(); + localNetwork->close(); + delete localNetwork; ::LogFinalise(); return; } @@ -272,7 +274,7 @@ startupId = 9999U; bool grp = (buffer[9U] & 0x01U) == 0x01U; if (grp && currentId == dstId) - localNetwork.write(buffer + 10U, len - 10U, rptAddr, rptPort); + localNetwork->write(buffer + 10U, len - 10U, rptAddr, rptPort); } // Any network activity is proof that the reflector is alive @@ -281,7 +283,7 @@ startupId = 9999U; } // From the MMDVM to the reflector or control data - len = localNetwork.read(buffer, address, port); + len = localNetwork->read(buffer, address, port); if (len > 0U) { // Only process the beginning and ending voice blocks here if ((buffer[0U] == 0x81U || buffer[0U] == 0x83U) && (buffer[5U] == 0x01U || buffer[5U] == 0x08U)) { @@ -381,7 +383,7 @@ startupId = 9999U; if (voice != NULL) { unsigned int length = voice->read(buffer); if (length > 0U) - localNetwork.write(buffer, length, rptAddr, rptPort); + localNetwork->write(buffer, length, rptAddr, rptPort); } unsigned int ms = stopWatch.elapsed(); @@ -389,6 +391,8 @@ startupId = 9999U; reflectors.clock(ms); + localNetwork->clock(ms); + if (voice != NULL) voice->clock(ms); @@ -469,7 +473,8 @@ startupId = 9999U; delete voice; - localNetwork.close(); + localNetwork->close(); + delete localNetwork; remoteNetwork.close(); diff --git a/NXDNGateway/NXDNGateway.vcxproj b/NXDNGateway/NXDNGateway.vcxproj index 97c3696..658c58c 100644 --- a/NXDNGateway/NXDNGateway.vcxproj +++ b/NXDNGateway/NXDNGateway.vcxproj @@ -159,6 +159,7 @@ + @@ -181,6 +182,7 @@ + diff --git a/NXDNGateway/NXDNGateway.vcxproj.filters b/NXDNGateway/NXDNGateway.vcxproj.filters index 5013a7b..bc39c26 100644 --- a/NXDNGateway/NXDNGateway.vcxproj.filters +++ b/NXDNGateway/NXDNGateway.vcxproj.filters @@ -74,6 +74,9 @@ Header Files + + Header Files + @@ -133,5 +136,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/NXDNGateway/RptNetwork.cpp b/NXDNGateway/RptNetwork.cpp new file mode 100644 index 0000000..952ce99 --- /dev/null +++ b/NXDNGateway/RptNetwork.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 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 "RptNetwork.h" + +IRptNetwork::~IRptNetwork() +{ +} diff --git a/NXDNGateway/RptNetwork.h b/NXDNGateway/RptNetwork.h new file mode 100644 index 0000000..36ec99b --- /dev/null +++ b/NXDNGateway/RptNetwork.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 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. + */ + +#ifndef RptNetwork_H +#define RptNetwork_H + +#if !defined(_WIN32) && !defined(_WIN64) +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#endif + +#include +#include + +class IRptNetwork { +public: + virtual ~IRptNetwork() = 0; + + virtual bool open() = 0; + + virtual bool write(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port) = 0; + + virtual bool read(unsigned char* data, in_addr& address, unsigned int& port) = 0; + + virtual void close() = 0; + + virtual void clock(unsigned int ms) = 0; + +private: +}; + +#endif From 001bc4a83680c3dbd3cd4314aea7ab63d6b9d4cc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 6 Apr 2020 21:32:50 +0100 Subject: [PATCH 35/70] Add a basic Kenwood network handler. --- NXDNGateway/Conf.cpp | 12 +- NXDNGateway/Conf.h | 4 +- NXDNGateway/IcomNetwork.cpp | 22 +- NXDNGateway/IcomNetwork.h | 7 +- NXDNGateway/KenwoodNetwork.cpp | 644 ++++++++++++++++++++++++ NXDNGateway/KenwoodNetwork.h | 71 +++ NXDNGateway/Makefile | 4 +- NXDNGateway/NXDNGateway.cpp | 22 +- NXDNGateway/NXDNGateway.ini | 1 + NXDNGateway/NXDNGateway.vcxproj | 2 + NXDNGateway/NXDNGateway.vcxproj.filters | 6 + NXDNGateway/RptNetwork.h | 4 +- NXDNGateway/Version.h | 4 +- 13 files changed, 778 insertions(+), 25 deletions(-) create mode 100644 NXDNGateway/KenwoodNetwork.cpp create mode 100644 NXDNGateway/KenwoodNetwork.h diff --git a/NXDNGateway/Conf.cpp b/NXDNGateway/Conf.cpp index 92cba3c..f1bebb2 100644 --- a/NXDNGateway/Conf.cpp +++ b/NXDNGateway/Conf.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020 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 @@ -42,6 +42,7 @@ CConf::CConf(const std::string& file) : m_file(file), m_callsign(), m_suffix(), +m_rptProtocol("Icom"), m_rptAddress(), m_rptPort(0U), m_myPort(0U), @@ -143,7 +144,9 @@ bool CConf::read() for (unsigned int i = 0U; value[i] != 0; i++) value[i] = ::toupper(value[i]); m_suffix = value; - } else if (::strcmp(key, "RptAddress") == 0) + } else if (::strcmp(key, "RptProtocol") == 0) + m_rptProtocol = value; + else if (::strcmp(key, "RptAddress") == 0) m_rptAddress = value; else if (::strcmp(key, "RptPort") == 0) m_rptPort = (unsigned int)::atoi(value); @@ -248,6 +251,11 @@ std::string CConf::getSuffix() const return m_suffix; } +std::string CConf::getRptProtocol() const +{ + return m_rptProtocol; +} + std::string CConf::getRptAddress() const { return m_rptAddress; diff --git a/NXDNGateway/Conf.h b/NXDNGateway/Conf.h index 29dce87..b726a5a 100644 --- a/NXDNGateway/Conf.h +++ b/NXDNGateway/Conf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020 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 @@ -33,6 +33,7 @@ public: // The General section std::string getCallsign() const; std::string getSuffix() const; + std::string getRptProtocol() const; std::string getRptAddress() const; unsigned int getRptPort() const; unsigned int getMyPort() const; @@ -92,6 +93,7 @@ private: std::string m_file; std::string m_callsign; std::string m_suffix; + std::string m_rptProtocol; std::string m_rptAddress; unsigned int m_rptPort; unsigned int m_myPort; diff --git a/NXDNGateway/IcomNetwork.cpp b/NXDNGateway/IcomNetwork.cpp index 056eaae..557f155 100644 --- a/NXDNGateway/IcomNetwork.cpp +++ b/NXDNGateway/IcomNetwork.cpp @@ -26,10 +26,17 @@ const unsigned int BUFFER_LENGTH = 200U; -CIcomNetwork::CIcomNetwork(unsigned int localPort, bool debug) : +CIcomNetwork::CIcomNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug) : m_socket(localPort), +m_address(), +m_port(rptPort), m_debug(debug) { + assert(localPort > 0U); + assert(!rptAddress.empty()); + assert(rptPort > 0U); + + m_address = CUDPSocket::lookup(rptAddress); } CIcomNetwork::~CIcomNetwork() @@ -46,7 +53,7 @@ bool CIcomNetwork::open() return m_socket.open(); } -bool CIcomNetwork::write(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port) +bool CIcomNetwork::write(const unsigned char* data, unsigned int length) { assert(data != NULL); @@ -77,19 +84,26 @@ bool CIcomNetwork::write(const unsigned char* data, unsigned int length, const i if (m_debug) CUtils::dump(1U, "Icom Data Sent", buffer, 102U); - return m_socket.write(buffer, 102U, address, port); + return m_socket.write(buffer, 102U, m_address, m_port); } -bool CIcomNetwork::read(unsigned char* data, in_addr& address, unsigned int& port) +bool CIcomNetwork::read(unsigned char* data) { assert(data != NULL); unsigned char buffer[BUFFER_LENGTH]; + in_addr address; + unsigned int port; int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); if (length <= 0) return false; + if (m_address.s_addr != address.s_addr || m_port != port) { + LogWarning("Icom Data received from an unknown address or port - %08X:%u", ntohl(address.s_addr), port); + return false; + } + // Invalid packet type? if (::memcmp(buffer, "ICOM", 4U) != 0) return false; diff --git a/NXDNGateway/IcomNetwork.h b/NXDNGateway/IcomNetwork.h index 1c8f02d..6cb4d3a 100644 --- a/NXDNGateway/IcomNetwork.h +++ b/NXDNGateway/IcomNetwork.h @@ -21,21 +21,20 @@ #include "RptNetwork.h" #include "UDPSocket.h" -#include "Timer.h" #include #include class CIcomNetwork : public IRptNetwork { public: - CIcomNetwork(unsigned int localPort, bool debug); + CIcomNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug); virtual ~CIcomNetwork(); virtual bool open(); - virtual bool write(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port); + virtual bool write(const unsigned char* data, unsigned int length); - virtual bool read(unsigned char* data, in_addr& address, unsigned int& port); + virtual bool read(unsigned char* data); virtual void close(); diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp new file mode 100644 index 0000000..1421dd8 --- /dev/null +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -0,0 +1,644 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 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 "KenwoodNetwork.h" +#include "NXDNCRC.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) +#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +const unsigned int BUFFER_LENGTH = 200U; + +CKenwoodNetwork::CKenwoodNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug) : +m_rtcpSocket(localPort + 1U), +m_rtpSocket(localPort + 0U), +m_stopWatch(), +m_address(), +m_rtcpPort(rptPort + 1U), +m_rtpPort(rptPort + 0U), +m_seqNo(0U), +m_timeStamp(0U), +m_ssrc(0U), +m_debug(debug), +m_timer(1000U, 0U, 200U) +{ + assert(localPort > 0U); + assert(!rptAddress.empty()); + assert(rptPort > 0U); + + m_address = CUDPSocket::lookup(rptAddress); + + ::srand((unsigned int)m_stopWatch.time()); +} + +CKenwoodNetwork::~CKenwoodNetwork() +{ +} + +bool CKenwoodNetwork::open() +{ + LogMessage("Opening Kenwood connection"); + + if (m_address.s_addr == INADDR_NONE) + return false; + + if (!m_rtcpSocket.open()) + return false; + + if (!m_rtpSocket.open()) { + m_rtcpSocket.close(); + return false; + } + + m_timer.start(); + + m_ssrc = ::rand(); + + return true; +} + +bool CKenwoodNetwork::write(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + + switch (data[0U]) { + case 0x81U: // Voice header or trailer + case 0x83U: + return processIcomVoiceHeader(data); + case 0xACU: // Voice data + case 0xAEU: + return processIcomVoiceData(data); + default: + return false; + } +} + +bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[30U]; + ::memset(outData, 0x00U, 30U); + + // SACCH + outData[0U] = inData[2U]; + outData[1U] = inData[1U]; + outData[2U] = inData[4U] & 0xC0U; + outData[3U] = inData[3U]; + + // FACCH 1+2 + outData[4U] = outData[14U] = inData[6U]; + outData[5U] = outData[15U] = inData[5U]; + outData[6U] = outData[16U] = inData[8U]; + outData[7U] = outData[17U] = inData[7U]; + outData[8U] = outData[18U] = inData[10U]; + outData[9U] = outData[19U] = inData[9U]; + outData[10U] = outData[20U] = inData[12U]; + outData[11U] = outData[21U] = inData[11U]; + + switch (outData[4U] & 0x3FU) { + case 0x01U: { + uint16_t uid = (outData[7U] << 8) + (outData[8U] << 0); + uint16_t gid = (outData[9U] << 8) + (outData[10U] << 0); + return writeRTPVoiceHeader(outData); + } + case 0x08U: + return writeRTPVoiceTrailer(outData); + default: + return false; + } +} + +bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[40U], temp[10U]; + ::memset(outData, 0x00U, 40U); + + // SACCH + outData[0U] = inData[2U]; + outData[1U] = inData[1U]; + outData[2U] = inData[4U] & 0xC0U; + outData[3U] = inData[3U]; + + // Audio 1 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (5U * 8U) + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[4U] = temp[1U]; + outData[5U] = temp[0U]; + outData[6U] = temp[3U]; + outData[7U] = temp[2U]; + outData[8U] = temp[5U]; + outData[9U] = temp[4U]; + outData[10U] = temp[7U]; + outData[11U] = temp[6U]; + + // Audio 2 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (5U * 8U) + 49U + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[12U] = temp[1U]; + outData[13U] = temp[0U]; + outData[14U] = temp[3U]; + outData[15U] = temp[2U]; + outData[16U] = temp[5U]; + outData[17U] = temp[4U]; + outData[18U] = temp[7U]; + outData[19U] = temp[6U]; + + // Audio 3 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (19U * 8U) + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[20U] = temp[1U]; + outData[21U] = temp[0U]; + outData[22U] = temp[3U]; + outData[23U] = temp[2U]; + outData[24U] = temp[5U]; + outData[25U] = temp[4U]; + outData[26U] = temp[7U]; + outData[27U] = temp[6U]; + + // Audio 4 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (19U * 8U) + 49U + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[28U] = temp[1U]; + outData[29U] = temp[0U]; + outData[30U] = temp[3U]; + outData[31U] = temp[2U]; + outData[32U] = temp[5U]; + outData[33U] = temp[4U]; + outData[34U] = temp[7U]; + outData[35U] = temp[6U]; + + return writeRTPVoiceData(outData); +} + +bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + m_seqNo++; + + m_timeStamp = (unsigned long)m_stopWatch.time(); + + buffer[4U] = (m_timeStamp >> 24) & 0xFFU; + buffer[5U] = (m_timeStamp >> 16) & 0xFFU; + buffer[6U] = (m_timeStamp >> 8) & 0xFFU; + buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + m_timeStamp += 640U; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + buffer[16U] = 0x03U; + buffer[17U] = 0x03U; + buffer[18U] = 0x04U; + buffer[19U] = 0x04U; + buffer[20U] = 0x0AU; + buffer[21U] = 0x05U; + buffer[22U] = 0x0AU; + + ::memcpy(buffer + 23U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U); + + return m_rtpSocket.write(buffer, 47U, m_address, m_rtpPort); +} + +bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + + buffer[4U] = (m_timeStamp >> 24) & 0xFFU; + buffer[5U] = (m_timeStamp >> 16) & 0xFFU; + buffer[6U] = (m_timeStamp >> 8) & 0xFFU; + buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + buffer[16U] = 0x03U; + buffer[17U] = 0x03U; + buffer[18U] = 0x04U; + buffer[19U] = 0x04U; + buffer[20U] = 0x0AU; + buffer[21U] = 0x05U; + buffer[22U] = 0x0AU; + + ::memcpy(buffer + 23U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U); + + return m_rtpSocket.write(buffer, 47U, m_address, m_rtpPort); +} + +bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[60U]; + ::memset(buffer, 0x00U, 60U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + m_seqNo++; + + buffer[4U] = (m_timeStamp >> 24) & 0xFFU; + buffer[5U] = (m_timeStamp >> 16) & 0xFFU; + buffer[6U] = (m_timeStamp >> 8) & 0xFFU; + buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + m_timeStamp += 640U; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + buffer[16U] = 0x03U; + buffer[17U] = 0x02U; + buffer[18U] = 0x04U; + buffer[19U] = 0x07U; + buffer[20U] = 0x10U; + buffer[21U] = 0x08U; + buffer[22U] = 0x10U; + + ::memcpy(buffer + 23U, data, 36U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 59U); + + return m_rtpSocket.write(buffer, 59U, m_address, m_rtpPort); +} + +bool CKenwoodNetwork::writeRTCPPing() +{ + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); + + buffer[0U] = 0x8AU; + buffer[1U] = 0xCCU; + + buffer[3U] = 0x06U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[22U] = 0x02U; + + buffer[24U] = 0x01U; + buffer[25U] = 0x01U; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); + + return m_rtcpSocket.write(buffer, 28U, m_address, m_rtcpPort); +} + +bool CKenwoodNetwork::writeRTCPData(unsigned short src, unsigned short dst) +{ + unsigned char buffer[20U]; + ::memset(buffer, 0x00U, 20U); + + buffer[0U] = 0x8BU; + buffer[1U] = 0xCCU; + + buffer[3U] = 0x04U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[12U] = (src >> 8) & 0xFFU; + buffer[13U] = (src >> 0) & 0xFFU; + + buffer[14U] = (dst >> 8) & 0xFFU; + buffer[15U] = (dst >> 0) & 0xFFU; + + buffer[16U] = 0x01U; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U); + + return m_rtcpSocket.write(buffer, 20U, m_address, m_rtcpPort); +} + +bool CKenwoodNetwork::read(unsigned char* data) +{ + assert(data != NULL); + + unsigned char dummy[BUFFER_LENGTH]; + readRTCP(dummy); + + unsigned int len = readRTP(data); + + switch (data[9U]) { + case 0x05U: { // Voice header or trailer + bool ret = processKenwoodVoiceHeader(data); + if (!ret) + return false; + return true; + } + case 0x08U: // Voice data + processKenwoodVoiceData(data); + return true; + default: + CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); + return false; + } +} + +unsigned int CKenwoodNetwork::readRTP(unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[BUFFER_LENGTH]; + + in_addr address; + unsigned int port; + int length = m_rtpSocket.read(buffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return 0U; + + // Check if the data is for us + if (m_address.s_addr != address.s_addr || port != m_rtpPort) { + LogMessage("Kenwood RTP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_rtpPort, port); + return 0U; + } + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Received", buffer, length); + + if (length != 47 && length != 59) { + LogError("Invalid RTP length of %d", length); + return 0U; + } + + ::memcpy(data, buffer + 12U, length - 12U); + + return length - 12U; +} + +unsigned int CKenwoodNetwork::readRTCP(unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[BUFFER_LENGTH]; + + in_addr address; + unsigned int port; + int length = m_rtcpSocket.read(buffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return 0U; + + // Check if the data is for us + if (m_address.s_addr != address.s_addr || port != m_rtcpPort) { + LogMessage("Kenwood RTCP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_rtcpPort, port); + return 0U; + } + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Received", buffer, length); + + if (length != 20 && length != 28) { + LogError("Invalid RTCP length of %d", length); + return 0U; + } + + if (::memcmp(buffer + 8U, "KWNE", 4U) != 0) { + LogError("Missing RTCP KWNE signature"); + return 0U; + } + + ::memcpy(data, buffer + 12U, length - 12U); + + return length - 12U; +} + +void CKenwoodNetwork::close() +{ + m_rtcpSocket.close(); + m_rtpSocket.close(); + + LogMessage("Closing Kenwood connection"); +} + +void CKenwoodNetwork::clock(unsigned int ms) +{ + m_timer.clock(ms); + if (m_timer.hasExpired()) { + writeRTCPPing(); + m_timer.start(); + } +} + +bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[50U], temp[20U]; + ::memset(outData, 0x00U, 50U); + + // LICH + outData[0U] = 0x83U; + + // SACCH + ::memset(temp, 0x00U, 20U); + temp[0U] = inData[12U]; + temp[1U] = inData[11U]; + temp[2U] = inData[14U]; + temp[3U] = inData[13U]; + CNXDNCRC::encodeCRC6(temp, 26U); + ::memcpy(outData + 1U, temp, 4U); + + // FACCH 1+2 + ::memset(temp, 0x00U, 20U); + temp[0U] = inData[15U]; + temp[1U] = inData[14U]; + temp[2U] = inData[17U]; + temp[3U] = inData[16U]; + temp[4U] = inData[19U]; + temp[5U] = inData[18U]; + temp[6U] = inData[21U]; + temp[7U] = inData[20U]; + temp[8U] = inData[23U]; + temp[9U] = inData[22U]; + CNXDNCRC::encodeCRC12(temp, 80U); + ::memcpy(outData + 5U, temp, 12U); + ::memcpy(outData + 19U, temp, 12U); + + switch (outData[5U] & 0x3FU) { + case 0x01U: { + unsigned short uid = (outData[8U] << 8) + (outData[9U] << 0); + unsigned short gid = (outData[10U] << 8) + (outData[11U] << 0); + ::memcpy(inData, outData, 33U); + return true; + } + case 0x08U: + ::memcpy(inData, outData, 33U); + return true; + default: + return false; + } +} + +void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[50U], temp[20U]; + ::memset(outData, 0x00U, 50U); + + // LICH + outData[0U] = 0xAEU; + + // SACCH + ::memset(temp, 0x00U, 20U); + temp[0U] = inData[12U]; + temp[1U] = inData[11U]; + temp[2U] = inData[14U]; + temp[3U] = inData[13U]; + CNXDNCRC::encodeCRC6(temp, 26U); + ::memcpy(outData + 1U, temp, 4U); + + // AMBE 1+2 + unsigned int n = 5U * 8U; + + temp[0U] = inData[16U]; + temp[1U] = inData[15U]; + temp[2U] = inData[18U]; + temp[3U] = inData[17U]; + temp[4U] = inData[20U]; + temp[5U] = inData[19U]; + temp[6U] = inData[22U]; + temp[7U] = inData[21U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + temp[0U] = inData[16U]; + temp[1U] = inData[15U]; + temp[2U] = inData[18U]; + temp[3U] = inData[17U]; + temp[4U] = inData[20U]; + temp[5U] = inData[19U]; + temp[6U] = inData[22U]; + temp[7U] = inData[21U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + // AMBE 3+4 + n = 19U * 8U; + + temp[0U] = inData[24U]; + temp[1U] = inData[23U]; + temp[2U] = inData[26U]; + temp[3U] = inData[25U]; + temp[4U] = inData[28U]; + temp[5U] = inData[27U]; + temp[6U] = inData[30U]; + temp[7U] = inData[29U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + temp[0U] = inData[32U]; + temp[1U] = inData[31U]; + temp[2U] = inData[34U]; + temp[3U] = inData[33U]; + temp[4U] = inData[36U]; + temp[5U] = inData[35U]; + temp[6U] = inData[38U]; + temp[7U] = inData[37U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + ::memcpy(inData, outData, 33U); +} diff --git a/NXDNGateway/KenwoodNetwork.h b/NXDNGateway/KenwoodNetwork.h new file mode 100644 index 0000000..011e223 --- /dev/null +++ b/NXDNGateway/KenwoodNetwork.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 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. + */ + +#ifndef KenwoodNetwork_H +#define KenwoodNetwork_H + +#include "RptNetwork.h" +#include "StopWatch.h" +#include "UDPSocket.h" +#include "Timer.h" + +#include +#include + +class CKenwoodNetwork : public IRptNetwork { +public: + CKenwoodNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug); + virtual ~CKenwoodNetwork(); + + virtual bool open(); + + virtual bool write(const unsigned char* data, unsigned int length); + + virtual bool read(unsigned char* data); + + virtual void close(); + + virtual void clock(unsigned int ms); + +private: + CUDPSocket m_rtpSocket; + CUDPSocket m_rtcpSocket; + CStopWatch m_stopWatch; + in_addr m_address; + unsigned int m_rtcpPort; + unsigned int m_rtpPort; + unsigned short m_seqNo; + unsigned long m_timeStamp; + unsigned int m_ssrc; + bool m_debug; + CTimer m_timer; + + bool processIcomVoiceHeader(const unsigned char* data); + bool processIcomVoiceData(const unsigned char* data); + bool processKenwoodVoiceHeader(unsigned char* data); + void processKenwoodVoiceData(unsigned char* data); + bool writeRTPVoiceHeader(const unsigned char* data); + bool writeRTPVoiceData(const unsigned char* data); + bool writeRTPVoiceTrailer(const unsigned char* data); + bool writeRTCPPing(); + bool writeRTCPData(unsigned short src, unsigned short dst); + unsigned int readRTP(unsigned char* data); + unsigned int readRTCP(unsigned char* data); +}; + +#endif diff --git a/NXDNGateway/Makefile b/NXDNGateway/Makefile index c587deb..4ec984b 100644 --- a/NXDNGateway/Makefile +++ b/NXDNGateway/Makefile @@ -4,8 +4,8 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread LIBS = -lpthread LDFLAGS = -g -OBJECTS = APRSWriter.o APRSWriterThread.o Conf.o GPSHandler.o IcomNetwork.o Log.o Mutex.o NXDNCRC.o NXDNGateway.o NXDNLookup.o NXDNNetwork.o Reflectors.o \ - RptNetwork.o StopWatch.o TCPSocket.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o +OBJECTS = APRSWriter.o APRSWriterThread.o Conf.o GPSHandler.o IcomNetwork.o KenwoodNetwork.o Log.o Mutex.o NXDNCRC.o NXDNGateway.o NXDNLookup.o NXDNNetwork.o \ + Reflectors.o RptNetwork.o StopWatch.o TCPSocket.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o all: NXDNGateway diff --git a/NXDNGateway/NXDNGateway.cpp b/NXDNGateway/NXDNGateway.cpp index 7483fb3..8f896e3 100644 --- a/NXDNGateway/NXDNGateway.cpp +++ b/NXDNGateway/NXDNGateway.cpp @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "KenwoodNetwork.h" #include "IcomNetwork.h" #include "NXDNNetwork.h" #include "NXDNGateway.h" @@ -114,7 +115,8 @@ void CNXDNGateway::run() if (pid == -1) { ::fprintf(stderr, "Couldn't fork() , exiting\n"); return; - } else if (pid != 0) { + } + else if (pid != 0) { exit(EXIT_SUCCESS); } @@ -175,12 +177,16 @@ void CNXDNGateway::run() } #endif - in_addr rptAddr = CUDPSocket::lookup(m_conf.getRptAddress()); - unsigned int rptPort = m_conf.getRptPort(); - createGPS(); - IRptNetwork* localNetwork = new CIcomNetwork(m_conf.getMyPort(), m_conf.getRptDebug()); + IRptNetwork* localNetwork = NULL; + std::string protocol = m_conf.getRptProtocol(); + + if (protocol == "Kenwood") + localNetwork = new CKenwoodNetwork(m_conf.getMyPort(), m_conf.getRptAddress(), m_conf.getRptPort(), m_conf.getRptDebug()); + else + localNetwork = new CIcomNetwork(m_conf.getMyPort(), m_conf.getRptAddress(), m_conf.getRptPort(), m_conf.getRptDebug()); + ret = localNetwork->open(); if (!ret) { ::LogFinalise(); @@ -274,7 +280,7 @@ startupId = 9999U; bool grp = (buffer[9U] & 0x01U) == 0x01U; if (grp && currentId == dstId) - localNetwork->write(buffer + 10U, len - 10U, rptAddr, rptPort); + localNetwork->write(buffer + 10U, len - 10U); } // Any network activity is proof that the reflector is alive @@ -283,7 +289,7 @@ startupId = 9999U; } // From the MMDVM to the reflector or control data - len = localNetwork->read(buffer, address, port); + len = localNetwork->read(buffer); if (len > 0U) { // Only process the beginning and ending voice blocks here if ((buffer[0U] == 0x81U || buffer[0U] == 0x83U) && (buffer[5U] == 0x01U || buffer[5U] == 0x08U)) { @@ -383,7 +389,7 @@ startupId = 9999U; if (voice != NULL) { unsigned int length = voice->read(buffer); if (length > 0U) - localNetwork->write(buffer, length, rptAddr, rptPort); + localNetwork->write(buffer, length); } unsigned int ms = stopWatch.elapsed(); diff --git a/NXDNGateway/NXDNGateway.ini b/NXDNGateway/NXDNGateway.ini index 884d8bd..6e439d6 100644 --- a/NXDNGateway/NXDNGateway.ini +++ b/NXDNGateway/NXDNGateway.ini @@ -1,6 +1,7 @@ [General] Callsign=G4KLX Suffix=NXDN +Protocol=Icom RptAddress=127.0.0.1 RptPort=14021 LocalPort=14020 diff --git a/NXDNGateway/NXDNGateway.vcxproj b/NXDNGateway/NXDNGateway.vcxproj index 658c58c..e955110 100644 --- a/NXDNGateway/NXDNGateway.vcxproj +++ b/NXDNGateway/NXDNGateway.vcxproj @@ -151,6 +151,7 @@ + @@ -175,6 +176,7 @@ + diff --git a/NXDNGateway/NXDNGateway.vcxproj.filters b/NXDNGateway/NXDNGateway.vcxproj.filters index bc39c26..4215f7e 100644 --- a/NXDNGateway/NXDNGateway.vcxproj.filters +++ b/NXDNGateway/NXDNGateway.vcxproj.filters @@ -77,6 +77,9 @@ Header Files + + Header Files + @@ -139,5 +142,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/NXDNGateway/RptNetwork.h b/NXDNGateway/RptNetwork.h index 36ec99b..0ec1a06 100644 --- a/NXDNGateway/RptNetwork.h +++ b/NXDNGateway/RptNetwork.h @@ -41,9 +41,9 @@ public: virtual bool open() = 0; - virtual bool write(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port) = 0; + virtual bool write(const unsigned char* data, unsigned int length) = 0; - virtual bool read(unsigned char* data, in_addr& address, unsigned int& port) = 0; + virtual bool read(unsigned char* data) = 0; virtual void close() = 0; diff --git a/NXDNGateway/Version.h b/NXDNGateway/Version.h index 53badbe..b6d79f8 100644 --- a/NXDNGateway/Version.h +++ b/NXDNGateway/Version.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2017,2018,2020 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 @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20180524"; +const char* VERSION = "20200406"; #endif From 768e1a3c1436c5742cd127da32b8ef4baa8c2cc5 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 8 Apr 2020 22:23:20 +0100 Subject: [PATCH 36/70] Add P25 Canada TG302. --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 128cf9b..8f29852 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -8,6 +8,9 @@ # RED NXDN SPAIN 214 nxdn214.xreflector.es 41400 +# 302, P25 Canada +302 p25canada.hopto.org 41400 + # Super Freq 420 420 hb.superfreqdigital.com 41400 From 9304e653c1b44c33108b8f33a5bd24d69dc47935 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 9 Apr 2020 17:21:07 +0100 Subject: [PATCH 37/70] Fix bugs in the Kenwood protocol implementation. --- NXDNGateway/KenwoodNetwork.cpp | 84 +++++++++++++++++----------------- NXDNGateway/NXDNGateway.ini | 2 +- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 1421dd8..2bf5c26 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -119,8 +119,9 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) outData[10U] = outData[20U] = inData[12U]; outData[11U] = outData[21U] = inData[11U]; - switch (outData[4U] & 0x3FU) { + switch (outData[5U] & 0x3FU) { case 0x01U: { + // XXX uint16_t uid = (outData[7U] << 8) + (outData[8U] << 0); uint16_t gid = (outData[9U] << 8) + (outData[10U] << 0); return writeRTPVoiceHeader(outData); @@ -408,20 +409,21 @@ bool CKenwoodNetwork::read(unsigned char* data) readRTCP(dummy); unsigned int len = readRTP(data); - - switch (data[9U]) { - case 0x05U: { // Voice header or trailer - bool ret = processKenwoodVoiceHeader(data); - if (!ret) + if (len > 0U) { + switch (data[9U]) { + case 0x05U: { // Voice header or trailer + bool ret = processKenwoodVoiceHeader(data); + if (!ret) + return false; + return true; + } + case 0x08U: // Voice data + processKenwoodVoiceData(data); + return true; + default: + CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); return false; - return true; - } - case 0x08U: // Voice data - processKenwoodVoiceData(data); - return true; - default: - CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); - return false; + } } } @@ -530,16 +532,16 @@ bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) // FACCH 1+2 ::memset(temp, 0x00U, 20U); - temp[0U] = inData[15U]; - temp[1U] = inData[14U]; - temp[2U] = inData[17U]; - temp[3U] = inData[16U]; - temp[4U] = inData[19U]; - temp[5U] = inData[18U]; - temp[6U] = inData[21U]; - temp[7U] = inData[20U]; - temp[8U] = inData[23U]; - temp[9U] = inData[22U]; + temp[0U] = inData[16U]; + temp[1U] = inData[15U]; + temp[2U] = inData[18U]; + temp[3U] = inData[17U]; + temp[4U] = inData[20U]; + temp[5U] = inData[19U]; + temp[6U] = inData[22U]; + temp[7U] = inData[21U]; + temp[8U] = inData[24U]; + temp[9U] = inData[23U]; CNXDNCRC::encodeCRC12(temp, 80U); ::memcpy(outData + 5U, temp, 12U); ::memcpy(outData + 19U, temp, 12U); @@ -595,23 +597,6 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) WRITE_BIT(outData, n, b); } - temp[0U] = inData[16U]; - temp[1U] = inData[15U]; - temp[2U] = inData[18U]; - temp[3U] = inData[17U]; - temp[4U] = inData[20U]; - temp[5U] = inData[19U]; - temp[6U] = inData[22U]; - temp[7U] = inData[21U]; - - for (unsigned int i = 0U; i < 49U; i++, n++) { - bool b = READ_BIT(temp, i); - WRITE_BIT(outData, n, b); - } - - // AMBE 3+4 - n = 19U * 8U; - temp[0U] = inData[24U]; temp[1U] = inData[23U]; temp[2U] = inData[26U]; @@ -626,6 +611,9 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) WRITE_BIT(outData, n, b); } + // AMBE 3+4 + n = 19U * 8U; + temp[0U] = inData[32U]; temp[1U] = inData[31U]; temp[2U] = inData[34U]; @@ -640,5 +628,19 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) WRITE_BIT(outData, n, b); } + temp[0U] = inData[40U]; + temp[1U] = inData[39U]; + temp[2U] = inData[42U]; + temp[3U] = inData[41U]; + temp[4U] = inData[44U]; + temp[5U] = inData[43U]; + temp[6U] = inData[46U]; + temp[7U] = inData[45U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + ::memcpy(inData, outData, 33U); } diff --git a/NXDNGateway/NXDNGateway.ini b/NXDNGateway/NXDNGateway.ini index 6e439d6..5f18973 100644 --- a/NXDNGateway/NXDNGateway.ini +++ b/NXDNGateway/NXDNGateway.ini @@ -1,7 +1,7 @@ [General] Callsign=G4KLX Suffix=NXDN -Protocol=Icom +RptProtocol=Icom RptAddress=127.0.0.1 RptPort=14021 LocalPort=14020 From 2ce25c2d7c6bf0486c943723515925e179f8d2ce Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 9 Apr 2020 19:57:59 +0100 Subject: [PATCH 38/70] Change behaviour of RTCP packets. --- NXDNGateway/KenwoodNetwork.cpp | 43 +++++++++++++++------------------- NXDNGateway/KenwoodNetwork.h | 2 +- NXDNGateway/Version.h | 2 +- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 2bf5c26..96187dc 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -73,8 +73,6 @@ bool CKenwoodNetwork::open() return false; } - m_timer.start(); - m_ssrc = ::rand(); return true; @@ -119,14 +117,18 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) outData[10U] = outData[20U] = inData[12U]; outData[11U] = outData[21U] = inData[11U]; - switch (outData[5U] & 0x3FU) { - case 0x01U: { - // XXX - uint16_t uid = (outData[7U] << 8) + (outData[8U] << 0); - uint16_t gid = (outData[9U] << 8) + (outData[10U] << 0); + unsigned short src = (inData[8U] << 8) + (inData[9U] << 0); + unsigned short dst = (inData[10U] << 8) + (inData[11U] << 0); + unsigned char type = (inData[7U] >> 5) & 0x07U; + + switch (inData[5U] & 0x3FU) { + case 0x01U: + m_timer.start(); + writeRTCPData(type, src, dst); return writeRTPVoiceHeader(outData); - } case 0x08U: + m_timer.stop(); + writeRTCPData(type, src, dst); return writeRTPVoiceTrailer(outData); default: return false; @@ -367,7 +369,7 @@ bool CKenwoodNetwork::writeRTCPPing() return m_rtcpSocket.write(buffer, 28U, m_address, m_rtcpPort); } -bool CKenwoodNetwork::writeRTCPData(unsigned short src, unsigned short dst) +bool CKenwoodNetwork::writeRTCPData(unsigned char type, unsigned short src, unsigned short dst) { unsigned char buffer[20U]; ::memset(buffer, 0x00U, 20U); @@ -393,7 +395,7 @@ bool CKenwoodNetwork::writeRTCPData(unsigned short src, unsigned short dst) buffer[14U] = (dst >> 8) & 0xFFU; buffer[15U] = (dst >> 0) & 0xFFU; - buffer[16U] = 0x01U; + buffer[16U] = type; if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U); @@ -411,20 +413,18 @@ bool CKenwoodNetwork::read(unsigned char* data) unsigned int len = readRTP(data); if (len > 0U) { switch (data[9U]) { - case 0x05U: { // Voice header or trailer - bool ret = processKenwoodVoiceHeader(data); - if (!ret) - return false; - return true; - } + case 0x05U: // Voice header or trailer + return processKenwoodVoiceHeader(data); case 0x08U: // Voice data processKenwoodVoiceData(data); return true; default: - CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); - return false; + break; } } + + CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); + return false; } unsigned int CKenwoodNetwork::readRTP(unsigned char* data) @@ -547,12 +547,7 @@ bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) ::memcpy(outData + 19U, temp, 12U); switch (outData[5U] & 0x3FU) { - case 0x01U: { - unsigned short uid = (outData[8U] << 8) + (outData[9U] << 0); - unsigned short gid = (outData[10U] << 8) + (outData[11U] << 0); - ::memcpy(inData, outData, 33U); - return true; - } + case 0x01U: case 0x08U: ::memcpy(inData, outData, 33U); return true; diff --git a/NXDNGateway/KenwoodNetwork.h b/NXDNGateway/KenwoodNetwork.h index 011e223..8a3389f 100644 --- a/NXDNGateway/KenwoodNetwork.h +++ b/NXDNGateway/KenwoodNetwork.h @@ -63,7 +63,7 @@ private: bool writeRTPVoiceData(const unsigned char* data); bool writeRTPVoiceTrailer(const unsigned char* data); bool writeRTCPPing(); - bool writeRTCPData(unsigned short src, unsigned short dst); + bool writeRTCPData(unsigned char type, unsigned short src, unsigned short dst); unsigned int readRTP(unsigned char* data); unsigned int readRTCP(unsigned char* data); }; diff --git a/NXDNGateway/Version.h b/NXDNGateway/Version.h index b6d79f8..0ebde8d 100644 --- a/NXDNGateway/Version.h +++ b/NXDNGateway/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200406"; +const char* VERSION = "20200409"; #endif From 91c35166d5a79ec7b9f55cd900f4fdc792cc4958 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 10 Apr 2020 13:54:22 +0100 Subject: [PATCH 39/70] Stop the timeout if the timer isn't running. --- NXDNGateway/KenwoodNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 96187dc..6149c4f 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -505,7 +505,7 @@ void CKenwoodNetwork::close() void CKenwoodNetwork::clock(unsigned int ms) { m_timer.clock(ms); - if (m_timer.hasExpired()) { + if (m_timer.isRunning() && m_timer.hasExpired()) { writeRTCPPing(); m_timer.start(); } From 0db7036caf0488d1fc73f55419d633534eeeb633 Mon Sep 17 00:00:00 2001 From: iu7igu <39775345+iu7igu@users.noreply.github.com> Date: Sat, 11 Apr 2020 19:05:08 +0200 Subject: [PATCH 40/70] Update NXDNHosts.txt Add 2007-DXGROUP ti reflectors --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 128cf9b..c45f6e0 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -182,5 +182,8 @@ # French-Test, 65208 65208 m55.evxonline.net 41400 +# NXDN - 2007DXGROUP +68800 89.46.75.115 41400 + # NXDN SPAIN 21410 21410 nxdn21410.nxdn.es 41400 From 7d529b6c2da7e9e0ca7d40687e59dbec5dcba6a6 Mon Sep 17 00:00:00 2001 From: wb6dtb <62869527+wb6dtb@users.noreply.github.com> Date: Sat, 11 Apr 2020 13:04:59 -0700 Subject: [PATCH 41/70] Update NXDNHosts.txt --- NXDNGateway/NXDNHosts.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 128cf9b..fedb8c3 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -158,6 +158,12 @@ # DX-LINK SYSTEM, 31777 31777 8.9.4.102 41400 +# CW-Ops Academy, NXDN Reflector 32103 +32103 cwops.dyndns.org 41400 + +# OMISS Group, NXDN Reflector 33581 +33581 omiss.dyndns.org 41400 + # Fusion Canada Fr /Wires-x /Ysf /Nxdn Network 40721 38.110.97.161 41400 From afbb819a68e002d9e5ef0e2e56b8cb96261428ae Mon Sep 17 00:00:00 2001 From: K2COP <39566434+K2COP@users.noreply.github.com> Date: Mon, 13 Apr 2020 19:13:59 -0400 Subject: [PATCH 42/70] Update NXDNHosts.txt # 911 Cop Talk, Multimode TG for Police and First Responders 911 nxdn.k2cop.com 41400 --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 3cdf983..f3c1313 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -23,6 +23,9 @@ # RuralMN Reflector 707 707 707nxdn.kd0ioe.com 41400 +# 911 Cop Talk, Multimode TG for Police and First Responders +911 nxdn.k2cop.com 41400 + # 914 Latin America 914 164.132.96.157 41400 From bd93454ad60f6de30e566f17873f63cdfe4f648e Mon Sep 17 00:00:00 2001 From: hb9tvw <33429099+hb9tvw@users.noreply.github.com> Date: Thu, 16 Apr 2020 23:12:06 +0200 Subject: [PATCH 43/70] Update NXDNHosts.txt Add NXDN Swiss Reflector --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 3cdf983..dd5e64d 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -86,6 +86,9 @@ # 22245 IT PIEDMONT GDO 22245 nxdngdo.duckdns.org 41400 +# 22825 Swiss NXDN Reflerctor +22825 212.237.33.114 41400 + # NXDN Scotland, 23551 23551 nxdnscotland.ddns.net 41400 From 06cee5c7442207c39f5fb96d7eac72cd6f8029be Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 20 Apr 2020 16:02:10 +0100 Subject: [PATCH 44/70] Add the Kenwood protocol. --- NXDNReflector/Conf.cpp | 10 +- NXDNReflector/Conf.h | 4 +- NXDNReflector/CoreNetwork.cpp | 23 + NXDNReflector/CoreNetwork.h | 55 ++ .../{NXCoreNetwork.cpp => IcomNetwork.cpp} | 38 +- .../{NXCoreNetwork.h => IcomNetwork.h} | 23 +- NXDNReflector/KenwoodNetwork.cpp | 645 ++++++++++++++++++ NXDNReflector/KenwoodNetwork.h | 69 ++ NXDNReflector/Makefile | 2 +- NXDNReflector/NXDNCRC.cpp | 185 +++++ NXDNReflector/NXDNCRC.h | 42 ++ NXDNReflector/NXDNReflector.cpp | 13 +- NXDNReflector/NXDNReflector.h | 6 +- NXDNReflector/NXDNReflector.ini | 1 + NXDNReflector/NXDNReflector.vcxproj | 10 +- NXDNReflector/NXDNReflector.vcxproj.filters | 22 +- NXDNReflector/Version.h | 4 +- 17 files changed, 1111 insertions(+), 41 deletions(-) create mode 100644 NXDNReflector/CoreNetwork.cpp create mode 100644 NXDNReflector/CoreNetwork.h rename NXDNReflector/{NXCoreNetwork.cpp => IcomNetwork.cpp} (67%) rename NXDNReflector/{NXCoreNetwork.h => IcomNetwork.h} (66%) create mode 100644 NXDNReflector/KenwoodNetwork.cpp create mode 100644 NXDNReflector/KenwoodNetwork.h create mode 100644 NXDNReflector/NXDNCRC.cpp create mode 100644 NXDNReflector/NXDNCRC.h diff --git a/NXDNReflector/Conf.cpp b/NXDNReflector/Conf.cpp index 0564d15..f1e1cf8 100644 --- a/NXDNReflector/Conf.cpp +++ b/NXDNReflector/Conf.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2018,2020 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 @@ -48,6 +48,7 @@ m_logFileRoot(), m_networkPort(0U), m_networkDebug(false), m_nxCoreEnabled(false), +m_nxCoreProtocol("Icom"), m_nxCoreAddress(), m_nxCoreTGEnable(0U), m_nxCoreTGDisable(0U), @@ -123,6 +124,8 @@ bool CConf::read() } else if (section == SECTION_NXCORE) { if (::strcmp(key, "Enabled") == 0) m_nxCoreEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Protocol") == 0) + m_nxCoreProtocol = value; else if (::strcmp(key, "Address") == 0) m_nxCoreAddress = value; else if (::strcmp(key, "TGEnable") == 0) @@ -194,6 +197,11 @@ bool CConf::getNXCoreEnabled() const return m_nxCoreEnabled; } +std::string CConf::getNXCoreProtocol() const +{ + return m_nxCoreProtocol; +} + std::string CConf::getNXCoreAddress() const { return m_nxCoreAddress; diff --git a/NXDNReflector/Conf.h b/NXDNReflector/Conf.h index d5c4c2e..57156ed 100644 --- a/NXDNReflector/Conf.h +++ b/NXDNReflector/Conf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2018,2020 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 @@ -50,6 +50,7 @@ public: // The NXCore section bool getNXCoreEnabled() const; + std::string getNXCoreProtocol() const; std::string getNXCoreAddress() const; unsigned short getNXCoreTGEnable() const; unsigned short getNXCoreTGDisable() const; @@ -72,6 +73,7 @@ private: bool m_networkDebug; bool m_nxCoreEnabled; + std::string m_nxCoreProtocol; std::string m_nxCoreAddress; unsigned short m_nxCoreTGEnable; unsigned short m_nxCoreTGDisable; diff --git a/NXDNReflector/CoreNetwork.cpp b/NXDNReflector/CoreNetwork.cpp new file mode 100644 index 0000000..c842dc7 --- /dev/null +++ b/NXDNReflector/CoreNetwork.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 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 "CoreNetwork.h" + +ICoreNetwork::~ICoreNetwork() +{ +} diff --git a/NXDNReflector/CoreNetwork.h b/NXDNReflector/CoreNetwork.h new file mode 100644 index 0000000..d991b81 --- /dev/null +++ b/NXDNReflector/CoreNetwork.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 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. + */ + +#ifndef CoreNetwork_H +#define CoreNetwork_H + +#if !defined(_WIN32) && !defined(_WIN64) +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#endif + +#include +#include + +class ICoreNetwork { +public: + virtual ~ICoreNetwork() = 0; + + virtual bool open() = 0; + + virtual bool write(const unsigned char* data, unsigned int length) = 0; + + virtual unsigned int read(unsigned char* data) = 0; + + virtual void close() = 0; + + virtual void clock(unsigned int ms) = 0; + +private: +}; + +#endif diff --git a/NXDNReflector/NXCoreNetwork.cpp b/NXDNReflector/IcomNetwork.cpp similarity index 67% rename from NXDNReflector/NXCoreNetwork.cpp rename to NXDNReflector/IcomNetwork.cpp index e676710..08d68ec 100644 --- a/NXDNReflector/NXCoreNetwork.cpp +++ b/NXDNReflector/IcomNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2014,2016,2018,2020 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "NXCoreNetwork.h" +#include "IcomNetwork.h" #include "Utils.h" #include "Log.h" @@ -26,10 +26,10 @@ const unsigned int BUFFER_LENGTH = 200U; -const unsigned int NXCORE_PORT = 41300U; +const unsigned int ICOM_PORT = 41300U; -CNXCoreNetwork::CNXCoreNetwork(const std::string& address, bool debug) : -m_socket(NXCORE_PORT), +CIcomNetwork::CIcomNetwork(const std::string& address, bool debug) : +m_socket(ICOM_PORT), m_address(), m_debug(debug) { @@ -38,13 +38,13 @@ m_debug(debug) m_address = CUDPSocket::lookup(address); } -CNXCoreNetwork::~CNXCoreNetwork() +CIcomNetwork::~CIcomNetwork() { } -bool CNXCoreNetwork::open() +bool CIcomNetwork::open() { - LogMessage("Opening NXCore network connection"); + LogMessage("Opening Icom network connection"); if (m_address.s_addr == INADDR_NONE) return false; @@ -52,7 +52,7 @@ bool CNXCoreNetwork::open() return m_socket.open(); } -bool CNXCoreNetwork::write(const unsigned char* data, unsigned int len) +bool CIcomNetwork::write(const unsigned char* data, unsigned int len) { assert(data != NULL); @@ -81,12 +81,12 @@ bool CNXCoreNetwork::write(const unsigned char* data, unsigned int len) ::memcpy(buffer + 40U, data + 10U, 33U); if (m_debug) - CUtils::dump(1U, "NXCore Network Data Sent", buffer, 102U); + CUtils::dump(1U, "Icom Network Data Sent", buffer, 102U); - return m_socket.write(buffer, 102U, m_address, NXCORE_PORT); + return m_socket.write(buffer, 102U, m_address, ICOM_PORT); } -unsigned int CNXCoreNetwork::read(unsigned char* data) +unsigned int CIcomNetwork::read(unsigned char* data) { unsigned char buffer[BUFFER_LENGTH]; @@ -97,8 +97,8 @@ unsigned int CNXCoreNetwork::read(unsigned char* data) return 0U; // Check if the data is for us - if (m_address.s_addr != address.s_addr || port != NXCORE_PORT) { - LogMessage("NXCore packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, NXCORE_PORT, port); + if (m_address.s_addr != address.s_addr || port != ICOM_PORT) { + LogMessage("Icom packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, ICOM_PORT, port); return 0U; } @@ -110,16 +110,20 @@ unsigned int CNXCoreNetwork::read(unsigned char* data) return 0U; if (m_debug) - CUtils::dump(1U, "NXCore Network Data Received", buffer, length); + CUtils::dump(1U, "Icom Network Data Received", buffer, length); ::memcpy(data, buffer + 40U, 33U); return 33U; } -void CNXCoreNetwork::close() +void CIcomNetwork::clock(unsigned int ms) +{ +} + +void CIcomNetwork::close() { m_socket.close(); - LogMessage("Closing NXCore network connection"); + LogMessage("Closing Icom network connection"); } diff --git a/NXDNReflector/NXCoreNetwork.h b/NXDNReflector/IcomNetwork.h similarity index 66% rename from NXDNReflector/NXCoreNetwork.h rename to NXDNReflector/IcomNetwork.h index 78c896c..704b12b 100644 --- a/NXDNReflector/NXCoreNetwork.h +++ b/NXDNReflector/IcomNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2014,2016,2018,2020 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 @@ -16,27 +16,30 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef NXCoreNetwork_H -#define NXCoreNetwork_H +#ifndef IcomNetwork_H +#define IcomNetwork_H +#include "CoreNetwork.h" #include "UDPSocket.h" #include "Timer.h" #include #include -class CNXCoreNetwork { +class CIcomNetwork : public ICoreNetwork { public: - CNXCoreNetwork(const std::string& address, bool debug); - ~CNXCoreNetwork(); + CIcomNetwork(const std::string& address, bool debug); + virtual ~CIcomNetwork(); - bool open(); + virtual bool open(); - bool write(const unsigned char* data, unsigned int len); + virtual bool write(const unsigned char* data, unsigned int len); - unsigned int read(unsigned char* data); + virtual unsigned int read(unsigned char* data); - void close(); + virtual void close(); + + virtual void clock(unsigned int ms); private: CUDPSocket m_socket; diff --git a/NXDNReflector/KenwoodNetwork.cpp b/NXDNReflector/KenwoodNetwork.cpp new file mode 100644 index 0000000..979c021 --- /dev/null +++ b/NXDNReflector/KenwoodNetwork.cpp @@ -0,0 +1,645 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 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 "KenwoodNetwork.h" +#include "NXDNCRC.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) +#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +const unsigned int BUFFER_LENGTH = 200U; + +const unsigned int RTP_PORT = 64000U; +const unsigned int RTCP_PORT = 64001U; + +CKenwoodNetwork::CKenwoodNetwork(const std::string& address, bool debug) : +m_rtcpSocket(RTCP_PORT), +m_rtpSocket(RTP_PORT), +m_stopWatch(), +m_address(), +m_seqNo(0U), +m_timeStamp(0U), +m_ssrc(0U), +m_debug(debug), +m_timer(1000U, 0U, 200U) +{ + assert(!address.empty()); + + m_address = CUDPSocket::lookup(address); + + ::srand((unsigned int)m_stopWatch.time()); +} + +CKenwoodNetwork::~CKenwoodNetwork() +{ +} + +bool CKenwoodNetwork::open() +{ + LogMessage("Opening Kenwood connection"); + + if (m_address.s_addr == INADDR_NONE) + return false; + + if (!m_rtcpSocket.open()) + return false; + + if (!m_rtpSocket.open()) { + m_rtcpSocket.close(); + return false; + } + + m_ssrc = ::rand(); + + return true; +} + +bool CKenwoodNetwork::write(const unsigned char* data, unsigned int length) +{ + assert(data != NULL); + + switch (data[0U]) { + case 0x81U: // Voice header or trailer + case 0x83U: + return processIcomVoiceHeader(data); + case 0xACU: // Voice data + case 0xAEU: + return processIcomVoiceData(data); + default: + return false; + } +} + +bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[30U]; + ::memset(outData, 0x00U, 30U); + + // SACCH + outData[0U] = inData[2U]; + outData[1U] = inData[1U]; + outData[2U] = inData[4U] & 0xC0U; + outData[3U] = inData[3U]; + + // FACCH 1+2 + outData[4U] = outData[14U] = inData[6U]; + outData[5U] = outData[15U] = inData[5U]; + outData[6U] = outData[16U] = inData[8U]; + outData[7U] = outData[17U] = inData[7U]; + outData[8U] = outData[18U] = inData[10U]; + outData[9U] = outData[19U] = inData[9U]; + outData[10U] = outData[20U] = inData[12U]; + outData[11U] = outData[21U] = inData[11U]; + + unsigned short src = (inData[8U] << 8) + (inData[9U] << 0); + unsigned short dst = (inData[10U] << 8) + (inData[11U] << 0); + unsigned char type = (inData[7U] >> 5) & 0x07U; + + switch (inData[5U] & 0x3FU) { + case 0x01U: + m_timer.start(); + writeRTCPData(type, src, dst); + return writeRTPVoiceHeader(outData); + case 0x08U: + m_timer.stop(); + writeRTCPData(type, src, dst); + return writeRTPVoiceTrailer(outData); + default: + return false; + } +} + +bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[40U], temp[10U]; + ::memset(outData, 0x00U, 40U); + + // SACCH + outData[0U] = inData[2U]; + outData[1U] = inData[1U]; + outData[2U] = inData[4U] & 0xC0U; + outData[3U] = inData[3U]; + + // Audio 1 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (5U * 8U) + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[4U] = temp[1U]; + outData[5U] = temp[0U]; + outData[6U] = temp[3U]; + outData[7U] = temp[2U]; + outData[8U] = temp[5U]; + outData[9U] = temp[4U]; + outData[10U] = temp[7U]; + outData[11U] = temp[6U]; + + // Audio 2 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (5U * 8U) + 49U + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[12U] = temp[1U]; + outData[13U] = temp[0U]; + outData[14U] = temp[3U]; + outData[15U] = temp[2U]; + outData[16U] = temp[5U]; + outData[17U] = temp[4U]; + outData[18U] = temp[7U]; + outData[19U] = temp[6U]; + + // Audio 3 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (19U * 8U) + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[20U] = temp[1U]; + outData[21U] = temp[0U]; + outData[22U] = temp[3U]; + outData[23U] = temp[2U]; + outData[24U] = temp[5U]; + outData[25U] = temp[4U]; + outData[26U] = temp[7U]; + outData[27U] = temp[6U]; + + // Audio 4 + ::memset(temp, 0x00U, 10U); + for (unsigned int i = 0U; i < 49U; i++) { + unsigned int offset = (19U * 8U) + 49U + i; + bool b = READ_BIT(inData, offset); + WRITE_BIT(temp, i, b); + } + outData[28U] = temp[1U]; + outData[29U] = temp[0U]; + outData[30U] = temp[3U]; + outData[31U] = temp[2U]; + outData[32U] = temp[5U]; + outData[33U] = temp[4U]; + outData[34U] = temp[7U]; + outData[35U] = temp[6U]; + + return writeRTPVoiceData(outData); +} + +bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + m_seqNo++; + + m_timeStamp = (unsigned long)m_stopWatch.time(); + + buffer[4U] = (m_timeStamp >> 24) & 0xFFU; + buffer[5U] = (m_timeStamp >> 16) & 0xFFU; + buffer[6U] = (m_timeStamp >> 8) & 0xFFU; + buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + m_timeStamp += 640U; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + buffer[16U] = 0x03U; + buffer[17U] = 0x03U; + buffer[18U] = 0x04U; + buffer[19U] = 0x04U; + buffer[20U] = 0x0AU; + buffer[21U] = 0x05U; + buffer[22U] = 0x0AU; + + ::memcpy(buffer + 23U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U); + + return m_rtpSocket.write(buffer, 47U, m_address, RTP_PORT); +} + +bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + + buffer[4U] = (m_timeStamp >> 24) & 0xFFU; + buffer[5U] = (m_timeStamp >> 16) & 0xFFU; + buffer[6U] = (m_timeStamp >> 8) & 0xFFU; + buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + buffer[16U] = 0x03U; + buffer[17U] = 0x03U; + buffer[18U] = 0x04U; + buffer[19U] = 0x04U; + buffer[20U] = 0x0AU; + buffer[21U] = 0x05U; + buffer[22U] = 0x0AU; + + ::memcpy(buffer + 23U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 47U); + + return m_rtpSocket.write(buffer, 47U, m_address, RTP_PORT); +} + +bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[60U]; + ::memset(buffer, 0x00U, 60U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 0) & 0xFFU; + m_seqNo++; + + buffer[4U] = (m_timeStamp >> 24) & 0xFFU; + buffer[5U] = (m_timeStamp >> 16) & 0xFFU; + buffer[6U] = (m_timeStamp >> 8) & 0xFFU; + buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + m_timeStamp += 640U; + + buffer[8U] = (m_ssrc >> 24) & 0xFFU; + buffer[9U] = (m_ssrc >> 16) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + + buffer[16U] = 0x03U; + buffer[17U] = 0x02U; + buffer[18U] = 0x04U; + buffer[19U] = 0x07U; + buffer[20U] = 0x10U; + buffer[21U] = 0x08U; + buffer[22U] = 0x10U; + + ::memcpy(buffer + 23U, data, 36U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 59U); + + return m_rtpSocket.write(buffer, 59U, m_address, RTP_PORT); +} + +bool CKenwoodNetwork::writeRTCPPing() +{ + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); + + buffer[0U] = 0x8AU; + buffer[1U] = 0xCCU; + + buffer[3U] = 0x06U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[22U] = 0x02U; + + buffer[24U] = 0x01U; + buffer[25U] = 0x01U; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); + + return m_rtcpSocket.write(buffer, 28U, m_address, RTCP_PORT); +} + +bool CKenwoodNetwork::writeRTCPData(unsigned char type, unsigned short src, unsigned short dst) +{ + unsigned char buffer[20U]; + ::memset(buffer, 0x00U, 20U); + + buffer[0U] = 0x8BU; + buffer[1U] = 0xCCU; + + buffer[3U] = 0x04U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[12U] = (src >> 8) & 0xFFU; + buffer[13U] = (src >> 0) & 0xFFU; + + buffer[14U] = (dst >> 8) & 0xFFU; + buffer[15U] = (dst >> 0) & 0xFFU; + + buffer[16U] = type; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U); + + return m_rtcpSocket.write(buffer, 20U, m_address, RTCP_PORT); +} + +unsigned int CKenwoodNetwork::read(unsigned char* data) +{ + assert(data != NULL); + + unsigned char dummy[BUFFER_LENGTH]; + readRTCP(dummy); + + bool ret; + + unsigned int len = readRTP(data); + if (len > 0U) { + switch (data[9U]) { + case 0x05U: // Voice header or trailer + ret = processKenwoodVoiceHeader(data); + if (!ret) + return 0U; + return 33U; + case 0x08U: // Voice data + processKenwoodVoiceData(data); + return 33U; + default: + break; + } + } + + CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); + return 0U; +} + +unsigned int CKenwoodNetwork::readRTP(unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[BUFFER_LENGTH]; + + in_addr address; + unsigned int port; + int length = m_rtpSocket.read(buffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return 0U; + + // Check if the data is for us + if (m_address.s_addr != address.s_addr || port != RTP_PORT) { + LogMessage("Kenwood RTP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, RTP_PORT, port); + return 0U; + } + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Received", buffer, length); + + if (length != 47 && length != 59) { + LogError("Invalid RTP length of %d", length); + return 0U; + } + + ::memcpy(data, buffer + 12U, length - 12U); + + return length - 12U; +} + +unsigned int CKenwoodNetwork::readRTCP(unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[BUFFER_LENGTH]; + + in_addr address; + unsigned int port; + int length = m_rtcpSocket.read(buffer, BUFFER_LENGTH, address, port); + if (length <= 0) + return 0U; + + // Check if the data is for us + if (m_address.s_addr != address.s_addr || port != RTCP_PORT) { + LogMessage("Kenwood RTCP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, RTCP_PORT, port); + return 0U; + } + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Received", buffer, length); + + if (length != 20 && length != 28) { + LogError("Invalid RTCP length of %d", length); + return 0U; + } + + if (::memcmp(buffer + 8U, "KWNE", 4U) != 0) { + LogError("Missing RTCP KWNE signature"); + return 0U; + } + + ::memcpy(data, buffer + 12U, length - 12U); + + return length - 12U; +} + +void CKenwoodNetwork::close() +{ + m_rtcpSocket.close(); + m_rtpSocket.close(); + + LogMessage("Closing Kenwood connection"); +} + +void CKenwoodNetwork::clock(unsigned int ms) +{ + m_timer.clock(ms); + if (m_timer.isRunning() && m_timer.hasExpired()) { + writeRTCPPing(); + m_timer.start(); + } +} + +bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[50U], temp[20U]; + ::memset(outData, 0x00U, 50U); + + // LICH + outData[0U] = 0x83U; + + // SACCH + ::memset(temp, 0x00U, 20U); + temp[0U] = inData[12U]; + temp[1U] = inData[11U]; + temp[2U] = inData[14U]; + temp[3U] = inData[13U]; + CNXDNCRC::encodeCRC6(temp, 26U); + ::memcpy(outData + 1U, temp, 4U); + + // FACCH 1+2 + ::memset(temp, 0x00U, 20U); + temp[0U] = inData[16U]; + temp[1U] = inData[15U]; + temp[2U] = inData[18U]; + temp[3U] = inData[17U]; + temp[4U] = inData[20U]; + temp[5U] = inData[19U]; + temp[6U] = inData[22U]; + temp[7U] = inData[21U]; + temp[8U] = inData[24U]; + temp[9U] = inData[23U]; + CNXDNCRC::encodeCRC12(temp, 80U); + ::memcpy(outData + 5U, temp, 12U); + ::memcpy(outData + 19U, temp, 12U); + + switch (outData[5U] & 0x3FU) { + case 0x01U: + case 0x08U: + ::memcpy(inData, outData, 33U); + return true; + default: + return false; + } +} + +void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[50U], temp[20U]; + ::memset(outData, 0x00U, 50U); + + // LICH + outData[0U] = 0xAEU; + + // SACCH + ::memset(temp, 0x00U, 20U); + temp[0U] = inData[12U]; + temp[1U] = inData[11U]; + temp[2U] = inData[14U]; + temp[3U] = inData[13U]; + CNXDNCRC::encodeCRC6(temp, 26U); + ::memcpy(outData + 1U, temp, 4U); + + // AMBE 1+2 + unsigned int n = 5U * 8U; + + temp[0U] = inData[16U]; + temp[1U] = inData[15U]; + temp[2U] = inData[18U]; + temp[3U] = inData[17U]; + temp[4U] = inData[20U]; + temp[5U] = inData[19U]; + temp[6U] = inData[22U]; + temp[7U] = inData[21U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + temp[0U] = inData[24U]; + temp[1U] = inData[23U]; + temp[2U] = inData[26U]; + temp[3U] = inData[25U]; + temp[4U] = inData[28U]; + temp[5U] = inData[27U]; + temp[6U] = inData[30U]; + temp[7U] = inData[29U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + // AMBE 3+4 + n = 19U * 8U; + + temp[0U] = inData[32U]; + temp[1U] = inData[31U]; + temp[2U] = inData[34U]; + temp[3U] = inData[33U]; + temp[4U] = inData[36U]; + temp[5U] = inData[35U]; + temp[6U] = inData[38U]; + temp[7U] = inData[37U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + temp[0U] = inData[40U]; + temp[1U] = inData[39U]; + temp[2U] = inData[42U]; + temp[3U] = inData[41U]; + temp[4U] = inData[44U]; + temp[5U] = inData[43U]; + temp[6U] = inData[46U]; + temp[7U] = inData[45U]; + + for (unsigned int i = 0U; i < 49U; i++, n++) { + bool b = READ_BIT(temp, i); + WRITE_BIT(outData, n, b); + } + + ::memcpy(inData, outData, 33U); +} diff --git a/NXDNReflector/KenwoodNetwork.h b/NXDNReflector/KenwoodNetwork.h new file mode 100644 index 0000000..4c0ded9 --- /dev/null +++ b/NXDNReflector/KenwoodNetwork.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009-2014,2016,2018,2020 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. + */ + +#ifndef KenwoodNetwork_H +#define KenwoodNetwork_H + +#include "CoreNetwork.h" +#include "StopWatch.h" +#include "UDPSocket.h" +#include "Timer.h" + +#include +#include + +class CKenwoodNetwork : public ICoreNetwork { +public: + CKenwoodNetwork(const std::string& address, bool debug); + virtual ~CKenwoodNetwork(); + + virtual bool open(); + + virtual bool write(const unsigned char* data, unsigned int length); + + virtual unsigned int read(unsigned char* data); + + virtual void close(); + + virtual void clock(unsigned int ms); + +private: + CUDPSocket m_rtpSocket; + CUDPSocket m_rtcpSocket; + CStopWatch m_stopWatch; + in_addr m_address; + unsigned short m_seqNo; + unsigned long m_timeStamp; + unsigned int m_ssrc; + bool m_debug; + CTimer m_timer; + + bool processIcomVoiceHeader(const unsigned char* data); + bool processIcomVoiceData(const unsigned char* data); + bool processKenwoodVoiceHeader(unsigned char* data); + void processKenwoodVoiceData(unsigned char* data); + bool writeRTPVoiceHeader(const unsigned char* data); + bool writeRTPVoiceData(const unsigned char* data); + bool writeRTPVoiceTrailer(const unsigned char* data); + bool writeRTCPPing(); + bool writeRTCPData(unsigned char type, unsigned short src, unsigned short dst); + unsigned int readRTP(unsigned char* data); + unsigned int readRTCP(unsigned char* data); +}; + +#endif diff --git a/NXDNReflector/Makefile b/NXDNReflector/Makefile index 8cd4048..43c534b 100644 --- a/NXDNReflector/Makefile +++ b/NXDNReflector/Makefile @@ -4,7 +4,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread LIBS = -lpthread LDFLAGS = -g -OBJECTS = Conf.o Log.o Mutex.o NXCoreNetwork.o NXDNLookup.o NXDNNetwork.o NXDNReflector.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o +OBJECTS = Conf.o CoreNetwork.o IcomNetwork.o KenwoodNetwork.o Log.o Mutex.o NXDNCRC.o NXDNLookup.o NXDNNetwork.o NXDNReflector.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o all: NXDNReflector diff --git a/NXDNReflector/NXDNCRC.cpp b/NXDNReflector/NXDNCRC.cpp new file mode 100644 index 0000000..60278ae --- /dev/null +++ b/NXDNReflector/NXDNCRC.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2018 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 "NXDNCRC.h" + +#include +#include + +const uint8_t BIT_MASK_TABLE1[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE1[(i)&7]) +#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7]) + +bool CNXDNCRC::checkCRC6(const unsigned char* in, unsigned int length) +{ + assert(in != NULL); + + uint8_t crc = createCRC6(in, length); + + uint8_t temp[1U]; + temp[0U] = 0x00U; + unsigned int j = length; + for (unsigned int i = 2U; i < 8U; i++, j++) { + bool b = READ_BIT1(in, j); + WRITE_BIT1(temp, i, b); + } + + return crc == temp[0U]; +} + +void CNXDNCRC::encodeCRC6(unsigned char* in, unsigned int length) +{ + assert(in != NULL); + + uint8_t crc[1U]; + crc[0U] = createCRC6(in, length); + + unsigned int n = length; + for (unsigned int i = 2U; i < 8U; i++, n++) { + bool b = READ_BIT1(crc, i); + WRITE_BIT1(in, n, b); + } +} + +bool CNXDNCRC::checkCRC12(const unsigned char* in, unsigned int length) +{ + assert(in != NULL); + + uint16_t crc = createCRC12(in, length); + uint8_t temp1[2U]; + temp1[0U] = (crc >> 8) & 0xFFU; + temp1[1U] = (crc >> 0) & 0xFFU; + + uint8_t temp2[2U]; + temp2[0U] = 0x00U; + temp2[1U] = 0x00U; + unsigned int j = length; + for (unsigned int i = 4U; i < 16U; i++, j++) { + bool b = READ_BIT1(in, j); + WRITE_BIT1(temp2, i, b); + } + + return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U]; +} + +void CNXDNCRC::encodeCRC12(unsigned char* in, unsigned int length) +{ + assert(in != NULL); + + uint16_t crc = createCRC12(in, length); + + uint8_t temp[2U]; + temp[0U] = (crc >> 8) & 0xFFU; + temp[1U] = (crc >> 0) & 0xFFU; + + unsigned int n = length; + for (unsigned int i = 4U; i < 16U; i++, n++) { + bool b = READ_BIT1(temp, i); + WRITE_BIT1(in, n, b); + } +} + +bool CNXDNCRC::checkCRC15(const unsigned char* in, unsigned int length) +{ + assert(in != NULL); + + uint16_t crc = createCRC15(in, length); + uint8_t temp1[2U]; + temp1[0U] = (crc >> 8) & 0xFFU; + temp1[1U] = (crc >> 0) & 0xFFU; + + uint8_t temp2[2U]; + temp2[0U] = 0x00U; + temp2[1U] = 0x00U; + unsigned int j = length; + for (unsigned int i = 1U; i < 16U; i++, j++) { + bool b = READ_BIT1(in, j); + WRITE_BIT1(temp2, i, b); + } + + return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U]; +} + +void CNXDNCRC::encodeCRC15(unsigned char* in, unsigned int length) +{ + assert(in != NULL); + + uint16_t crc = createCRC15(in, length); + + uint8_t temp[2U]; + temp[0U] = (crc >> 8) & 0xFFU; + temp[1U] = (crc >> 0) & 0xFFU; + + unsigned int n = length; + for (unsigned int i = 1U; i < 16U; i++, n++) { + bool b = READ_BIT1(temp, i); + WRITE_BIT1(in, n, b); + } +} + +uint8_t CNXDNCRC::createCRC6(const unsigned char* in, unsigned int length) +{ + uint8_t crc = 0x3FU; + + for (unsigned int i = 0U; i < length; i++) { + bool bit1 = READ_BIT1(in, i) != 0x00U; + bool bit2 = (crc & 0x20U) == 0x20U; + + crc <<= 1; + + if (bit1 ^ bit2) + crc ^= 0x27U; + } + + return crc & 0x3FU; +} + +uint16_t CNXDNCRC::createCRC12(const unsigned char* in, unsigned int length) +{ + uint16_t crc = 0x0FFFU; + + for (unsigned int i = 0U; i < length; i++) { + bool bit1 = READ_BIT1(in, i) != 0x00U; + bool bit2 = (crc & 0x0800U) == 0x0800U; + + crc <<= 1; + + if (bit1 ^ bit2) + crc ^= 0x080FU; + } + + return crc & 0x0FFFU; +} + +uint16_t CNXDNCRC::createCRC15(const unsigned char* in, unsigned int length) +{ + uint16_t crc = 0x7FFFU; + + for (unsigned int i = 0U; i < length; i++) { + bool bit1 = READ_BIT1(in, i) != 0x00U; + bool bit2 = (crc & 0x4000U) == 0x4000U; + + crc <<= 1; + + if (bit1 ^ bit2) + crc ^= 0x4CC5U; + } + + return crc & 0x7FFFU; +} diff --git a/NXDNReflector/NXDNCRC.h b/NXDNReflector/NXDNCRC.h new file mode 100644 index 0000000..12e2e40 --- /dev/null +++ b/NXDNReflector/NXDNCRC.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 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(NXDNCRC_H) +#define NXDNCRC_H + +#include + +class CNXDNCRC +{ +public: + static bool checkCRC6(const unsigned char* in, unsigned int length); + static void encodeCRC6(unsigned char* in, unsigned int length); + + static bool checkCRC12(const unsigned char* in, unsigned int length); + static void encodeCRC12(unsigned char* in, unsigned int length); + + static bool checkCRC15(const unsigned char* in, unsigned int length); + static void encodeCRC15(unsigned char* in, unsigned int length); + +private: + static uint8_t createCRC6(const unsigned char* in, unsigned int length); + static uint16_t createCRC12(const unsigned char* in, unsigned int length); + static uint16_t createCRC15(const unsigned char* in, unsigned int length); +}; + +#endif diff --git a/NXDNReflector/NXDNReflector.cpp b/NXDNReflector/NXDNReflector.cpp index 0e078a2..f8115f2 100644 --- a/NXDNReflector/NXDNReflector.cpp +++ b/NXDNReflector/NXDNReflector.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2018,2020 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 @@ -16,8 +16,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "KenwoodNetwork.h" #include "NXDNReflector.h" #include "NXDNNetwork.h" +#include "IcomNetwork.h" #include "NXDNLookup.h" #include "StopWatch.h" #include "Version.h" @@ -410,6 +412,9 @@ void CNXDNReflector::run() dumpTimer.start(); } + if (m_nxCoreNetwork != NULL) + m_nxCoreNetwork->clock(ms); + if (ms < 5U) CThread::sleep(5U); } @@ -454,7 +459,11 @@ void CNXDNReflector::dumpRepeaters() const bool CNXDNReflector::openNXCore() { - m_nxCoreNetwork = new CNXCoreNetwork(m_conf.getNXCoreAddress(), m_conf.getNXCoreDebug()); + std::string protocol = m_conf.getNXCoreProtocol(); + if (protocol == "Kenwood") + m_nxCoreNetwork = new CKenwoodNetwork(m_conf.getNXCoreAddress(), m_conf.getNXCoreDebug()); + else + m_nxCoreNetwork = new CIcomNetwork(m_conf.getNXCoreAddress(), m_conf.getNXCoreDebug()); bool ret = m_nxCoreNetwork->open(); if (!ret) { delete m_nxCoreNetwork; diff --git a/NXDNReflector/NXDNReflector.h b/NXDNReflector/NXDNReflector.h index 4dcafe8..7b7ca65 100644 --- a/NXDNReflector/NXDNReflector.h +++ b/NXDNReflector/NXDNReflector.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX +* Copyright (C) 2016,2018,2020 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 @@ -19,7 +19,7 @@ #if !defined(NXDNReflector_H) #define NXDNReflector_H -#include "NXCoreNetwork.h" +#include "CoreNetwork.h" #include "Timer.h" #include "Conf.h" @@ -65,7 +65,7 @@ public: private: CConf m_conf; - CNXCoreNetwork* m_nxCoreNetwork; + ICoreNetwork* m_nxCoreNetwork; std::vector m_repeaters; CNXDNRepeater* findRepeater(const in_addr& address, unsigned int port) const; diff --git a/NXDNReflector/NXDNReflector.ini b/NXDNReflector/NXDNReflector.ini index a59ccd5..bc0e4b6 100644 --- a/NXDNReflector/NXDNReflector.ini +++ b/NXDNReflector/NXDNReflector.ini @@ -19,6 +19,7 @@ Debug=0 [NXCore] Enabled=0 +Protocol=Icom # Address=208.111.3.45 Address=44.131.4.1 # TGEnable=1234 diff --git a/NXDNReflector/NXDNReflector.vcxproj b/NXDNReflector/NXDNReflector.vcxproj index 37b05b1..73d79ac 100644 --- a/NXDNReflector/NXDNReflector.vcxproj +++ b/NXDNReflector/NXDNReflector.vcxproj @@ -20,7 +20,10 @@ - + + + + @@ -35,7 +38,10 @@ - + + + + diff --git a/NXDNReflector/NXDNReflector.vcxproj.filters b/NXDNReflector/NXDNReflector.vcxproj.filters index e361874..4f06cff 100644 --- a/NXDNReflector/NXDNReflector.vcxproj.filters +++ b/NXDNReflector/NXDNReflector.vcxproj.filters @@ -47,7 +47,16 @@ Header Files - + + Header Files + + + Header Files + + + Header Files + + Header Files @@ -85,7 +94,16 @@ Source Files - + + Source Files + + + Source Files + + + Source Files + + Source Files diff --git a/NXDNReflector/Version.h b/NXDNReflector/Version.h index 2bd351f..301ae35 100644 --- a/NXDNReflector/Version.h +++ b/NXDNReflector/Version.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 2015,2016,2018,2020 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 @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20180517"; +const char* VERSION = "20200420"; #endif From c31a2a7cfe94096537b3491d7f2ae7c075eeb869 Mon Sep 17 00:00:00 2001 From: iu7igu <39775345+iu7igu@users.noreply.github.com> Date: Mon, 27 Apr 2020 22:12:12 +0200 Subject: [PATCH 45/70] Modified 2007dxgroup tg Number --- NXDNGateway/NXDNHosts.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 37adbfd..87b44ea 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -195,7 +195,7 @@ 65208 m55.evxonline.net 41400 # NXDN - 2007DXGROUP -68800 89.46.75.115 41400 +65100 89.46.75.115 41400 # NXDN SPAIN 21410 21410 nxdn21410.nxdn.es 41400 From 99e13114a8f3894fd6a60a4adaf3503f2a54c142 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 29 Apr 2020 12:49:03 +0100 Subject: [PATCH 46/70] Initial attempt at decoding Kenwood GPS data. --- NXDNGateway/GPSHandler.cpp | 118 +++++++++++++++++++++++++++++++++---- NXDNGateway/GPSHandler.h | 5 +- NXDNGateway/Version.h | 2 +- 3 files changed, 112 insertions(+), 13 deletions(-) diff --git a/NXDNGateway/GPSHandler.cpp b/NXDNGateway/GPSHandler.cpp index 696f5ff..650d1f7 100644 --- a/NXDNGateway/GPSHandler.cpp +++ b/NXDNGateway/GPSHandler.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2018 by Jonathan Naylor G4KLX +* Copyright (C) 2018,2020 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 @@ -64,7 +64,9 @@ void CGPSHandler::processData(const unsigned char* data) m_length += NXDN_DATA_LENGTH; if (data[0U] == 0x00U) { - processNMEA(); + bool ret = processIcom(); + if (!ret) + processKenwood(); reset(); } } @@ -81,23 +83,25 @@ void CGPSHandler::reset() m_source.clear(); } -void CGPSHandler::processNMEA() +bool CGPSHandler::processIcom() { if (m_data[0U] != NXDN_DATA_TYPE_GPS) - return; + return false; if (::memcmp(m_data + 1U, "$G", 2U) != 0) - return; + return false; if (::strchr((char*)(m_data + 1U), '*') == NULL) - return; + return false; + + // From here onwards we have something that looks like Icom GPS data if (!checkXOR()) - return; + return true; if (::memcmp(m_data + 4U, "RMC", 3U) != 0) { CUtils::dump("Unhandled NMEA sentence", (unsigned char*)(m_data + 1U), m_length - 1U); - return; + return true; } // Parse the $GxRMC string into tokens @@ -114,11 +118,11 @@ void CGPSHandler::processNMEA() // Is there any position data? if (pRMC[3U] == NULL || pRMC[4U] == NULL || pRMC[5U] == NULL || pRMC[6U] == NULL || ::strlen(pRMC[3U]) == 0U || ::strlen(pRMC[4U]) == 0U || ::strlen(pRMC[5U]) == 0 || ::strlen(pRMC[6U]) == 0) - return; + return true; // Is it a valid GPS fix? if (::strcmp(pRMC[2U], "A") != 0) - return; + return true; double latitude = ::atof(pRMC[3U]); double longitude = ::atof(pRMC[5U]); @@ -142,6 +146,8 @@ void CGPSHandler::processNMEA() } m_writer->write(output); + + return true; } bool CGPSHandler::checkXOR() const @@ -158,3 +164,95 @@ bool CGPSHandler::checkXOR() const return ::memcmp(buffer, p2 + 1U, 2U) == 0; } + +void CGPSHandler::processKenwood() +{ + enum { + GPS_FULL, + GPS_SHORT, + GPS_VERY_SHORT + } type; + + switch (m_data[0U]) { + case 0x00U: + type = GPS_FULL; + break; + case 0x01U: + type = GPS_SHORT; + break; + case 0x02U: + type = GPS_VERY_SHORT; + break; + default: + return; + } + + unsigned char UTCss = m_data[1U] & 0x3FU; + unsigned char UTCmm = ((m_data[1U] & 0xC0U) >> 2) | (m_data[2U] & 0x0FU); + unsigned char UTChh = ((m_data[3U] & 0x01U) << 4) | (m_data[2U] & 0xF0U) >> 4; + + unsigned char UTCday = 0x1FU; + unsigned char UTCmonth = 0x0FU; + unsigned char UTCyear = 0x7FU; + if (type == GPS_FULL) { + UTCday = m_data[15U] & 0x1FU; + UTCmonth = ((m_data[15U] & 0xE0U) >> 3) | (m_data[16] & 0x01U); + UTCyear = (m_data[16U] & 0xFEU) >> 1; + } + + unsigned char north = 'N'; + unsigned int latAfter = 0x7FFFU; + unsigned int latBefore = 0xFFFFU; + unsigned char east = 'E'; + unsigned int longAfter = 0x7FFFU; + unsigned int longBefore = 0xFFFFU; + if (type == GPS_VERY_SHORT) { + north = (m_data[5U] & 0x01U) == 0x00U ? 'N' : 'S'; + latAfter = ((m_data[5U] & 0xFEU) >> 1) | (m_data[6U] << 7); + latBefore = (m_data[8U] << 8) | m_data[7U]; + + east = (m_data[9U] & 0x01U) == 0x00U ? 'E' : 'W'; + longAfter = ((m_data[9U] & 0xFEU) >> 1) | (m_data[10U] << 7); + longBefore = (m_data[12U] << 8) | m_data[11U]; + } else { + north = (m_data[7U] & 0x01U) == 0x00U ? 'N' : 'S'; + latAfter = ((m_data[7U] & 0xFEU) >> 1) | (m_data[8U] << 7); + latBefore = (m_data[10U] << 8) | m_data[9U]; + + east = (m_data[11U] & 0x01U) == 0x00U ? 'E' : 'W'; + longAfter = ((m_data[11U] & 0xFEU) >> 1) | (m_data[12U] << 7); + longBefore = (m_data[14U] << 8) | m_data[13U]; + } + + if (latAfter == 0x7FFFU || latBefore == 0xFFFFU || longAfter == 0x7FFFU || longBefore == 0xFFFFU) + return; + + unsigned int course = 0xFFFFU; + unsigned int speedBefore = 0x3FFU; + unsigned int speedAfter = 0x0FU; + if (type == GPS_FULL) { + course = (m_data[21U] << 4) | (m_data[22U] & 0x0FU); + speedBefore = ((m_data[23U] & 0xF0U) << 2) | (m_data[24U] & 0x3FU); + speedAfter = m_data[23U] & 0x0FU; + } + + std::string source = m_source; + if (!m_suffix.empty()) { + source.append("-"); + source.append(m_suffix.substr(0U, 1U)); + } + + char output[300U]; + if (course != 0xFFFFU && speedBefore != 0x3FFU && speedAfter != 0x0FU) { + ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07u.%02lu%c/%08u.%02u%cr%03d/%03d via MMDVM", + source.c_str(), m_callsign.c_str(), latBefore, latAfter, north, longBefore, longAfter, east, course / 10U, speedBefore); + } + else { + ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07u.%02u%c/%08u.%02u%cr via MMDVM", + source.c_str(), m_callsign.c_str(), latBefore, latAfter, north, longBefore, longAfter, east); + } + + LogMessage("Kenwood APRS message = %s", output); + + // m_writer->write(output); +} diff --git a/NXDNGateway/GPSHandler.h b/NXDNGateway/GPSHandler.h index 44cdb34..cd46936 100644 --- a/NXDNGateway/GPSHandler.h +++ b/NXDNGateway/GPSHandler.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2018 by Jonathan Naylor G4KLX +* Copyright (C) 2018,2020 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 @@ -42,7 +42,8 @@ private: std::string m_source; std::string m_suffix; - void processNMEA(); + bool processIcom(); + void processKenwood(); bool checkXOR() const; void reset(); }; diff --git a/NXDNGateway/Version.h b/NXDNGateway/Version.h index 0ebde8d..96e2fee 100644 --- a/NXDNGateway/Version.h +++ b/NXDNGateway/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200409"; +const char* VERSION = "20200429"; #endif From 948fa8bfbf6741767ebab1ae6a68a4aef80e9fa8 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 1 May 2020 18:44:52 +0100 Subject: [PATCH 47/70] Kenwood work in progress. --- NXDNGateway/GPSHandler.cpp | 26 +++++++--- NXDNGateway/GPSHandler.h | 2 +- NXDNGateway/KenwoodNetwork.cpp | 95 ++++++++++++++++++++++++---------- NXDNGateway/KenwoodNetwork.h | 1 + 4 files changed, 89 insertions(+), 35 deletions(-) diff --git a/NXDNGateway/GPSHandler.cpp b/NXDNGateway/GPSHandler.cpp index 650d1f7..e231948 100644 --- a/NXDNGateway/GPSHandler.cpp +++ b/NXDNGateway/GPSHandler.cpp @@ -60,14 +60,17 @@ void CGPSHandler::processData(const unsigned char* data) { assert(data != NULL); + CUtils::dump(4U, "processData GPS Data", data, 21U); + ::memcpy(m_data + m_length, data + 1U, NXDN_DATA_LENGTH); m_length += NXDN_DATA_LENGTH; if (data[0U] == 0x00U) { bool ret = processIcom(); if (!ret) - processKenwood(); - reset(); + ret = processKenwood(); + if (ret) + reset(); } } @@ -165,7 +168,7 @@ bool CGPSHandler::checkXOR() const return ::memcmp(buffer, p2 + 1U, 2U) == 0; } -void CGPSHandler::processKenwood() +bool CGPSHandler::processKenwood() { enum { GPS_FULL, @@ -175,18 +178,26 @@ void CGPSHandler::processKenwood() switch (m_data[0U]) { case 0x00U: + if (m_length < 38U) + return false; type = GPS_FULL; break; case 0x01U: + if (m_length < 17U) + return false; type = GPS_SHORT; break; case 0x02U: + if (m_length < 15U) + return false; type = GPS_VERY_SHORT; break; default: - return; + return true; } + CUtils::dump("Kenwood GPS Data", m_data, m_length); + unsigned char UTCss = m_data[1U] & 0x3FU; unsigned char UTCmm = ((m_data[1U] & 0xC0U) >> 2) | (m_data[2U] & 0x0FU); unsigned char UTChh = ((m_data[3U] & 0x01U) << 4) | (m_data[2U] & 0xF0U) >> 4; @@ -225,7 +236,7 @@ void CGPSHandler::processKenwood() } if (latAfter == 0x7FFFU || latBefore == 0xFFFFU || longAfter == 0x7FFFU || longBefore == 0xFFFFU) - return; + return true; unsigned int course = 0xFFFFU; unsigned int speedBefore = 0x3FFU; @@ -246,8 +257,7 @@ void CGPSHandler::processKenwood() if (course != 0xFFFFU && speedBefore != 0x3FFU && speedAfter != 0x0FU) { ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07u.%02lu%c/%08u.%02u%cr%03d/%03d via MMDVM", source.c_str(), m_callsign.c_str(), latBefore, latAfter, north, longBefore, longAfter, east, course / 10U, speedBefore); - } - else { + } else { ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07u.%02u%c/%08u.%02u%cr via MMDVM", source.c_str(), m_callsign.c_str(), latBefore, latAfter, north, longBefore, longAfter, east); } @@ -255,4 +265,6 @@ void CGPSHandler::processKenwood() LogMessage("Kenwood APRS message = %s", output); // m_writer->write(output); + + return true; } diff --git a/NXDNGateway/GPSHandler.h b/NXDNGateway/GPSHandler.h index cd46936..1a03eac 100644 --- a/NXDNGateway/GPSHandler.h +++ b/NXDNGateway/GPSHandler.h @@ -43,7 +43,7 @@ private: std::string m_suffix; bool processIcom(); - void processKenwood(); + bool processKenwood(); bool checkXOR() const; void reset(); }; diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 6149c4f..5b99f7e 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -411,20 +411,21 @@ bool CKenwoodNetwork::read(unsigned char* data) readRTCP(dummy); unsigned int len = readRTP(data); - if (len > 0U) { - switch (data[9U]) { - case 0x05U: // Voice header or trailer - return processKenwoodVoiceHeader(data); - case 0x08U: // Voice data - processKenwoodVoiceData(data); - return true; - default: - break; - } + switch (len) { + case 0U: // Nothing received + return false; + case 35U: // Voice header or trailer + return processKenwoodVoiceHeader(data); + case 47U: // Voice data + processKenwoodVoiceData(data); + return true; + case 31U: // Data + processKenwoodData(data); + return true; + default: + CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); + return false; } - - CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); - return false; } unsigned int CKenwoodNetwork::readRTP(unsigned char* data) @@ -440,19 +441,14 @@ unsigned int CKenwoodNetwork::readRTP(unsigned char* data) return 0U; // Check if the data is for us - if (m_address.s_addr != address.s_addr || port != m_rtpPort) { - LogMessage("Kenwood RTP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_rtpPort, port); + if (m_address.s_addr != address.s_addr) { + LogMessage("Kenwood RTP packet received from an invalid source, %08X != %08X", m_address.s_addr, address.s_addr); return 0U; } if (m_debug) CUtils::dump(1U, "Kenwood Network RTP Data Received", buffer, length); - if (length != 47 && length != 59) { - LogError("Invalid RTP length of %d", length); - return 0U; - } - ::memcpy(data, buffer + 12U, length - 12U); return length - 12U; @@ -471,19 +467,14 @@ unsigned int CKenwoodNetwork::readRTCP(unsigned char* data) return 0U; // Check if the data is for us - if (m_address.s_addr != address.s_addr || port != m_rtcpPort) { - LogMessage("Kenwood RTCP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_rtcpPort, port); + if (m_address.s_addr != address.s_addr) { + LogMessage("Kenwood RTCP packet received from an invalid source, %08X != %08X", m_address.s_addr, address.s_addr); return 0U; } if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Received", buffer, length); - if (length != 20 && length != 28) { - LogError("Invalid RTCP length of %d", length); - return 0U; - } - if (::memcmp(buffer + 8U, "KWNE", 4U) != 0) { LogError("Missing RTCP KWNE signature"); return 0U; @@ -548,6 +539,8 @@ bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) switch (outData[5U] & 0x3FU) { case 0x01U: + ::memcpy(inData, outData, 33U); + return true; case 0x08U: ::memcpy(inData, outData, 33U); return true; @@ -639,3 +632,51 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) ::memcpy(inData, outData, 33U); } + +void CKenwoodNetwork::processKenwoodData(unsigned char* inData) +{ + if (inData[7U] != 0x09U && inData[7U] != 0x0BU && inData[7U] != 0x08U) + return; + + unsigned char outData[50U]; + + if (inData[7U] == 0x09U || inData[7U] == 0x08U) { + outData[0U] = 0x90U; + outData[1U] = inData[8U]; + outData[2U] = inData[7U]; + outData[3U] = inData[10U]; + outData[4U] = inData[9U]; + outData[5U] = inData[12U]; + outData[6U] = inData[11U]; + ::memcpy(inData, outData, 7U); + CUtils::dump(4U, "Outgoing Kenwood GPS Data Header/Trailer", inData, 7U); + } else { + CUtils::dump(4U, "Incoming Kenwood GPS Data", inData, 31U); + outData[0U] = 0x90U; + outData[1U] = inData[8U]; + outData[2U] = inData[7U]; + outData[3U] = inData[10U]; + outData[4U] = inData[9U]; + outData[5U] = inData[12U]; + outData[6U] = inData[11U]; + outData[7U] = inData[14U]; + outData[8U] = inData[13U]; + outData[9U] = inData[16U]; + outData[10U] = inData[15U]; + outData[11U] = inData[18U]; + outData[12U] = inData[17U]; + outData[13U] = inData[20U]; + outData[14U] = inData[19U]; + outData[15U] = inData[22U]; + outData[16U] = inData[21U]; + outData[17U] = inData[24U]; + outData[18U] = inData[23U]; + outData[19U] = inData[26U]; + outData[20U] = inData[25U]; + outData[21U] = inData[28U]; + outData[22U] = inData[27U]; + outData[23U] = inData[29U]; + ::memcpy(inData, outData, 24U); + CUtils::dump(4U, "Outgoing Kenwood GPS Data Body", inData, 24U); + } +} diff --git a/NXDNGateway/KenwoodNetwork.h b/NXDNGateway/KenwoodNetwork.h index 8a3389f..0ae16b7 100644 --- a/NXDNGateway/KenwoodNetwork.h +++ b/NXDNGateway/KenwoodNetwork.h @@ -59,6 +59,7 @@ private: bool processIcomVoiceData(const unsigned char* data); bool processKenwoodVoiceHeader(unsigned char* data); void processKenwoodVoiceData(unsigned char* data); + void processKenwoodData(unsigned char* data); bool writeRTPVoiceHeader(const unsigned char* data); bool writeRTPVoiceData(const unsigned char* data); bool writeRTPVoiceTrailer(const unsigned char* data); From f1b69c530285cd0ee75198eb6ac973badb9dd1de Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 2 May 2020 17:50:39 +0100 Subject: [PATCH 48/70] ZZ --- NXDNGateway/GPSHandler.cpp | 76 +++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/NXDNGateway/GPSHandler.cpp b/NXDNGateway/GPSHandler.cpp index e231948..c98a851 100644 --- a/NXDNGateway/GPSHandler.cpp +++ b/NXDNGateway/GPSHandler.cpp @@ -65,12 +65,13 @@ void CGPSHandler::processData(const unsigned char* data) ::memcpy(m_data + m_length, data + 1U, NXDN_DATA_LENGTH); m_length += NXDN_DATA_LENGTH; + // The packet frame number and block number are zero to indicate the last section of the + // data transmission. if (data[0U] == 0x00U) { bool ret = processIcom(); if (!ret) - ret = processKenwood(); - if (ret) - reset(); + processKenwood(); + reset(); } } @@ -198,53 +199,60 @@ bool CGPSHandler::processKenwood() CUtils::dump("Kenwood GPS Data", m_data, m_length); - unsigned char UTCss = m_data[1U] & 0x3FU; - unsigned char UTCmm = ((m_data[1U] & 0xC0U) >> 2) | (m_data[2U] & 0x0FU); - unsigned char UTChh = ((m_data[3U] & 0x01U) << 4) | (m_data[2U] & 0xF0U) >> 4; + unsigned char UTCss = m_data[3U] & 0x3FU; + unsigned char UTCmm = ((m_data[3U] & 0xC0U) >> 6) | ((m_data[4U] & 0x0FU) << 2); + unsigned char UTChh = ((m_data[5U] & 0x01U) << 4) | ((m_data[4U] & 0xF0U) >> 4); + + LogMessage("UTC hh:%u mm:%u ss:%u", UTChh, UTCmm, UTCss); unsigned char UTCday = 0x1FU; unsigned char UTCmonth = 0x0FU; unsigned char UTCyear = 0x7FU; if (type == GPS_FULL) { - UTCday = m_data[15U] & 0x1FU; - UTCmonth = ((m_data[15U] & 0xE0U) >> 3) | (m_data[16] & 0x01U); - UTCyear = (m_data[16U] & 0xFEU) >> 1; + UTCday = m_data[17U] & 0x1FU; + UTCmonth = ((m_data[17U] & 0xE0U) >> 5) | ((m_data[18U] & 0x01U) << 4); + UTCyear = (m_data[18U] & 0xFEU) >> 1; + + LogMessage("UTC dd:%u mm:%u yy:%u", UTCday, UTCmonth, UTCyear); } - unsigned char north = 'N'; - unsigned int latAfter = 0x7FFFU; - unsigned int latBefore = 0xFFFFU; - unsigned char east = 'E'; - unsigned int longAfter = 0x7FFFU; - unsigned int longBefore = 0xFFFFU; + unsigned char north = 'N'; + unsigned int latAfter = 0x7FFFU; + unsigned int latBefore = 0xFFFFU; + unsigned char east = 'E'; + unsigned int lonAfter = 0x7FFFU; + unsigned int lonBefore = 0xFFFFU; if (type == GPS_VERY_SHORT) { - north = (m_data[5U] & 0x01U) == 0x00U ? 'N' : 'S'; - latAfter = ((m_data[5U] & 0xFEU) >> 1) | (m_data[6U] << 7); - latBefore = (m_data[8U] << 8) | m_data[7U]; - - east = (m_data[9U] & 0x01U) == 0x00U ? 'E' : 'W'; - longAfter = ((m_data[9U] & 0xFEU) >> 1) | (m_data[10U] << 7); - longBefore = (m_data[12U] << 8) | m_data[11U]; - } else { north = (m_data[7U] & 0x01U) == 0x00U ? 'N' : 'S'; latAfter = ((m_data[7U] & 0xFEU) >> 1) | (m_data[8U] << 7); latBefore = (m_data[10U] << 8) | m_data[9U]; - east = (m_data[11U] & 0x01U) == 0x00U ? 'E' : 'W'; - longAfter = ((m_data[11U] & 0xFEU) >> 1) | (m_data[12U] << 7); - longBefore = (m_data[14U] << 8) | m_data[13U]; + east = (m_data[11U] & 0x01U) == 0x00U ? 'E' : 'W'; + lonAfter = ((m_data[11U] & 0xFEU) >> 1) | (m_data[12U] << 7); + lonBefore = (m_data[13U] << 8) | m_data[13U]; + } else { + north = (m_data[9U] & 0x01U) == 0x00U ? 'N' : 'S'; + latAfter = ((m_data[9U] & 0xFEU) >> 1) | (m_data[10U] << 7); + latBefore = (m_data[12U] << 8) | m_data[11U]; + + east = (m_data[13U] & 0x01U) == 0x00U ? 'E' : 'W'; + lonAfter = ((m_data[13U] & 0xFEU) >> 1) | (m_data[14U] << 7); + lonBefore = (m_data[16U] << 8) | m_data[15U]; } - if (latAfter == 0x7FFFU || latBefore == 0xFFFFU || longAfter == 0x7FFFU || longBefore == 0xFFFFU) + LogMessage("Latitude: %u . %u %c", latBefore, latAfter, north); + LogMessage("Longitude: %u . %u %c", lonBefore, lonAfter, east); + + if (latAfter == 0x7FFFU || latBefore == 0xFFFFU || lonAfter == 0x7FFFU || lonBefore == 0xFFFFU) return true; unsigned int course = 0xFFFFU; unsigned int speedBefore = 0x3FFU; unsigned int speedAfter = 0x0FU; if (type == GPS_FULL) { - course = (m_data[21U] << 4) | (m_data[22U] & 0x0FU); - speedBefore = ((m_data[23U] & 0xF0U) << 2) | (m_data[24U] & 0x3FU); - speedAfter = m_data[23U] & 0x0FU; + course = (m_data[23U] << 4) | (m_data[24U] & 0x0FU); + speedBefore = ((m_data[25U] & 0xF0U) << 2) | (m_data[26U] & 0x3FU); + speedAfter = m_data[25U] & 0x0FU; } std::string source = m_source; @@ -255,11 +263,11 @@ bool CGPSHandler::processKenwood() char output[300U]; if (course != 0xFFFFU && speedBefore != 0x3FFU && speedAfter != 0x0FU) { - ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07u.%02lu%c/%08u.%02u%cr%03d/%03d via MMDVM", - source.c_str(), m_callsign.c_str(), latBefore, latAfter, north, longBefore, longAfter, east, course / 10U, speedBefore); + ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr%03d/%03d via MMDVM", + source.c_str(), m_callsign.c_str(), latBefore, latAfter / 100U, north, lonBefore, lonAfter / 100U, east, course / 10U, speedBefore); } else { - ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07u.%02u%c/%08u.%02u%cr via MMDVM", - source.c_str(), m_callsign.c_str(), latBefore, latAfter, north, longBefore, longAfter, east); + ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr via MMDVM", + source.c_str(), m_callsign.c_str(), latBefore, latAfter / 100U, north, lonBefore, lonAfter / 100U, east); } LogMessage("Kenwood APRS message = %s", output); From f85975f4c1b52cd38aa9425a2451138d6bd7ba57 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 2 May 2020 17:52:12 +0100 Subject: [PATCH 49/70] Make the GPS description more accurate. --- NXDNGateway/GPSHandler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NXDNGateway/GPSHandler.cpp b/NXDNGateway/GPSHandler.cpp index c98a851..3d04239 100644 --- a/NXDNGateway/GPSHandler.cpp +++ b/NXDNGateway/GPSHandler.cpp @@ -142,10 +142,10 @@ bool CGPSHandler::processIcom() int bearing = ::atoi(pRMC[8U]); int speed = ::atoi(pRMC[7U]); - ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07.2lf%s/%08.2lf%sr%03d/%03d via MMDVM", + ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07.2lf%s/%08.2lf%sr%03d/%03d Icom IDAS via MMDVM", source.c_str(), m_callsign.c_str(), latitude, pRMC[4U], longitude, pRMC[6U], bearing, speed); } else { - ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07.2lf%s/%08.2lf%sr via MMDVM", + ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07.2lf%s/%08.2lf%sr Icom IDAS via MMDVM", source.c_str(), m_callsign.c_str(), latitude, pRMC[4U], longitude, pRMC[6U]); } @@ -263,10 +263,10 @@ bool CGPSHandler::processKenwood() char output[300U]; if (course != 0xFFFFU && speedBefore != 0x3FFU && speedAfter != 0x0FU) { - ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr%03d/%03d via MMDVM", + ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr%03d/%03d Kenwood NEXEDGE via MMDVM", source.c_str(), m_callsign.c_str(), latBefore, latAfter / 100U, north, lonBefore, lonAfter / 100U, east, course / 10U, speedBefore); } else { - ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr via MMDVM", + ::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr Kenwood NEXEDGE via MMDVM", source.c_str(), m_callsign.c_str(), latBefore, latAfter / 100U, north, lonBefore, lonAfter / 100U, east); } From e83aa6142867331d6c98af522a94f8b74ee5cf90 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 4 May 2020 13:48:54 +0100 Subject: [PATCH 50/70] Tested Kenwood GPS data decoding. --- NXDNGateway/GPSHandler.cpp | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/NXDNGateway/GPSHandler.cpp b/NXDNGateway/GPSHandler.cpp index 3d04239..e0a511f 100644 --- a/NXDNGateway/GPSHandler.cpp +++ b/NXDNGateway/GPSHandler.cpp @@ -60,8 +60,6 @@ void CGPSHandler::processData(const unsigned char* data) { assert(data != NULL); - CUtils::dump(4U, "processData GPS Data", data, 21U); - ::memcpy(m_data + m_length, data + 1U, NXDN_DATA_LENGTH); m_length += NXDN_DATA_LENGTH; @@ -197,25 +195,6 @@ bool CGPSHandler::processKenwood() return true; } - CUtils::dump("Kenwood GPS Data", m_data, m_length); - - unsigned char UTCss = m_data[3U] & 0x3FU; - unsigned char UTCmm = ((m_data[3U] & 0xC0U) >> 6) | ((m_data[4U] & 0x0FU) << 2); - unsigned char UTChh = ((m_data[5U] & 0x01U) << 4) | ((m_data[4U] & 0xF0U) >> 4); - - LogMessage("UTC hh:%u mm:%u ss:%u", UTChh, UTCmm, UTCss); - - unsigned char UTCday = 0x1FU; - unsigned char UTCmonth = 0x0FU; - unsigned char UTCyear = 0x7FU; - if (type == GPS_FULL) { - UTCday = m_data[17U] & 0x1FU; - UTCmonth = ((m_data[17U] & 0xE0U) >> 5) | ((m_data[18U] & 0x01U) << 4); - UTCyear = (m_data[18U] & 0xFEU) >> 1; - - LogMessage("UTC dd:%u mm:%u yy:%u", UTCday, UTCmonth, UTCyear); - } - unsigned char north = 'N'; unsigned int latAfter = 0x7FFFU; unsigned int latBefore = 0xFFFFU; @@ -240,9 +219,6 @@ bool CGPSHandler::processKenwood() lonBefore = (m_data[16U] << 8) | m_data[15U]; } - LogMessage("Latitude: %u . %u %c", latBefore, latAfter, north); - LogMessage("Longitude: %u . %u %c", lonBefore, lonAfter, east); - if (latAfter == 0x7FFFU || latBefore == 0xFFFFU || lonAfter == 0x7FFFU || lonBefore == 0xFFFFU) return true; @@ -270,9 +246,7 @@ bool CGPSHandler::processKenwood() source.c_str(), m_callsign.c_str(), latBefore, latAfter / 100U, north, lonBefore, lonAfter / 100U, east); } - LogMessage("Kenwood APRS message = %s", output); - - // m_writer->write(output); + m_writer->write(output); return true; } From 4f34393a639569a3cd18101a44688dbae2747dec Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 4 May 2020 13:57:47 +0100 Subject: [PATCH 51/70] Remove debugging messages. --- NXDNGateway/KenwoodNetwork.cpp | 3 --- NXDNGateway/Version.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 5b99f7e..28d7fa0 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -649,9 +649,7 @@ void CKenwoodNetwork::processKenwoodData(unsigned char* inData) outData[5U] = inData[12U]; outData[6U] = inData[11U]; ::memcpy(inData, outData, 7U); - CUtils::dump(4U, "Outgoing Kenwood GPS Data Header/Trailer", inData, 7U); } else { - CUtils::dump(4U, "Incoming Kenwood GPS Data", inData, 31U); outData[0U] = 0x90U; outData[1U] = inData[8U]; outData[2U] = inData[7U]; @@ -677,6 +675,5 @@ void CKenwoodNetwork::processKenwoodData(unsigned char* inData) outData[22U] = inData[27U]; outData[23U] = inData[29U]; ::memcpy(inData, outData, 24U); - CUtils::dump(4U, "Outgoing Kenwood GPS Data Body", inData, 24U); } } diff --git a/NXDNGateway/Version.h b/NXDNGateway/Version.h index 96e2fee..22c80f6 100644 --- a/NXDNGateway/Version.h +++ b/NXDNGateway/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200429"; +const char* VERSION = "20200504"; #endif From d6e28630ff4a05d51ddd3833f67a0a97a836bce7 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 5 May 2020 14:48:13 +0100 Subject: [PATCH 52/70] Clean up the Kenwood control data. --- NXDNGateway/KenwoodNetwork.cpp | 155 ++++++++++++++++++++++++++------- NXDNGateway/KenwoodNetwork.h | 8 +- NXDNGateway/Version.h | 2 +- 3 files changed, 132 insertions(+), 33 deletions(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 28d7fa0..d0c31fc 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -24,6 +24,7 @@ #include #include #include +#include const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; @@ -39,11 +40,14 @@ m_stopWatch(), m_address(), m_rtcpPort(rptPort + 1U), m_rtpPort(rptPort + 0U), +m_sessionId(0U), m_seqNo(0U), m_timeStamp(0U), m_ssrc(0U), m_debug(debug), -m_timer(1000U, 0U, 200U) +m_timer(1000U, 0U, 200U), +m_startSecs(0U), +m_startMSecs(0U) { assert(localPort > 0U); assert(!rptAddress.empty()); @@ -108,12 +112,12 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) outData[3U] = inData[3U]; // FACCH 1+2 - outData[4U] = outData[14U] = inData[6U]; - outData[5U] = outData[15U] = inData[5U]; - outData[6U] = outData[16U] = inData[8U]; - outData[7U] = outData[17U] = inData[7U]; - outData[8U] = outData[18U] = inData[10U]; - outData[9U] = outData[19U] = inData[9U]; + outData[4U] = outData[14U] = inData[6U]; + outData[5U] = outData[15U] = inData[5U]; + outData[6U] = outData[16U] = inData[8U]; + outData[7U] = outData[17U] = inData[7U]; + outData[8U] = outData[18U] = inData[10U]; + outData[9U] = outData[19U] = inData[9U]; outData[10U] = outData[20U] = inData[12U]; outData[11U] = outData[21U] = inData[11U]; @@ -124,11 +128,11 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) switch (inData[5U] & 0x3FU) { case 0x01U: m_timer.start(); - writeRTCPData(type, src, dst); + writeRTCPStart(); return writeRTPVoiceHeader(outData); case 0x08U: m_timer.stop(); - writeRTCPData(type, src, dst); + writeRTCPHang(type, src, dst); return writeRTPVoiceTrailer(outData); default: return false; @@ -225,23 +229,28 @@ bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) buffer[0U] = 0x80U; buffer[1U] = 0x66U; + m_seqNo++; buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - m_seqNo++; m_timeStamp = (unsigned long)m_stopWatch.time(); buffer[4U] = (m_timeStamp >> 24) & 0xFFU; buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; - m_timeStamp += 640U; + buffer[6U] = (m_timeStamp >> 8) & 0xFFU; + buffer[7U] = (m_timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; buffer[10U] = (m_ssrc >> 8) & 0xFFU; buffer[11U] = (m_ssrc >> 0) & 0xFFU; + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; buffer[16U] = 0x03U; buffer[17U] = 0x03U; buffer[18U] = 0x04U; @@ -268,9 +277,11 @@ bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) buffer[0U] = 0x80U; buffer[1U] = 0x66U; + m_seqNo++; buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; + m_timeStamp += 640U; buffer[4U] = (m_timeStamp >> 24) & 0xFFU; buffer[5U] = (m_timeStamp >> 16) & 0xFFU; buffer[6U] = (m_timeStamp >> 8) & 0xFFU; @@ -281,6 +292,11 @@ bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) buffer[10U] = (m_ssrc >> 8) & 0xFFU; buffer[11U] = (m_ssrc >> 0) & 0xFFU; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; buffer[16U] = 0x03U; buffer[17U] = 0x03U; buffer[18U] = 0x04U; @@ -307,21 +323,26 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) buffer[0U] = 0x80U; buffer[1U] = 0x66U; + m_seqNo++; buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - m_seqNo++; + m_timeStamp += 640U; buffer[4U] = (m_timeStamp >> 24) & 0xFFU; buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; - m_timeStamp += 640U; + buffer[6U] = (m_timeStamp >> 8) & 0xFFU; + buffer[7U] = (m_timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; - buffer[10U] = (m_ssrc >> 8) & 0xFFU; - buffer[11U] = (m_ssrc >> 0) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; buffer[16U] = 0x03U; buffer[17U] = 0x02U; buffer[18U] = 0x04U; @@ -338,30 +359,58 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) return m_rtpSocket.write(buffer, 59U, m_address, m_rtpPort); } -bool CKenwoodNetwork::writeRTCPPing() +bool CKenwoodNetwork::writeRTCPStart() { + time_t now; + ::time(&now); + + m_startSecs = uint32_t(now); + +#if defined(_WIN32) || defined(_WIN64) + SYSTEMTIME st; + ::GetSystemTime(&st); + + m_startMSecs = st.wMilliseconds; +#else + struct timeval tod; + ::gettimeofday(&tod, NULL); + + m_startMSecs = tod.tv_usec / 1000U; +#endif + unsigned char buffer[30U]; ::memset(buffer, 0x00U, 30U); buffer[0U] = 0x8AU; buffer[1U] = 0xCCU; - + buffer[2U] = 0x00U; buffer[3U] = 0x06U; buffer[4U] = (m_ssrc >> 24) & 0xFFU; buffer[5U] = (m_ssrc >> 16) & 0xFFU; - buffer[6U] = (m_ssrc >> 8) & 0xFFU; - buffer[7U] = (m_ssrc >> 0) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; buffer[8U] = 'K'; buffer[9U] = 'W'; buffer[10U] = 'N'; buffer[11U] = 'E'; + buffer[12U] = (m_startSecs >> 24) & 0xFFU; + buffer[13U] = (m_startSecs >> 16) & 0xFFU; + buffer[14U] = (m_startSecs >> 8) & 0xFFU; + buffer[15U] = (m_startSecs >> 0) & 0xFFU; + + buffer[16U] = (m_startMSecs >> 24) & 0xFFU; + buffer[17U] = (m_startMSecs >> 16) & 0xFFU; + buffer[18U] = (m_startMSecs >> 8) & 0xFFU; + buffer[19U] = (m_startMSecs >> 0) & 0xFFU; + buffer[22U] = 0x02U; buffer[24U] = 0x01U; - buffer[25U] = 0x01U; + + buffer[27U] = 0x0AU; if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); @@ -369,20 +418,62 @@ bool CKenwoodNetwork::writeRTCPPing() return m_rtcpSocket.write(buffer, 28U, m_address, m_rtcpPort); } -bool CKenwoodNetwork::writeRTCPData(unsigned char type, unsigned short src, unsigned short dst) +bool CKenwoodNetwork::writeRTCPPing() { - unsigned char buffer[20U]; - ::memset(buffer, 0x00U, 20U); + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); + + buffer[0U] = 0x8AU; + buffer[1U] = 0xCCU; + buffer[2U] = 0x00U; + buffer[3U] = 0x06U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[12U] = (m_startSecs >> 24) & 0xFFU; + buffer[13U] = (m_startSecs >> 16) & 0xFFU; + buffer[14U] = (m_startSecs >> 8) & 0xFFU; + buffer[15U] = (m_startSecs >> 0) & 0xFFU; + + buffer[16U] = (m_startMSecs >> 24) & 0xFFU; + buffer[17U] = (m_startMSecs >> 16) & 0xFFU; + buffer[18U] = (m_startMSecs >> 8) & 0xFFU; + buffer[19U] = (m_startMSecs >> 0) & 0xFFU; + + buffer[22U] = 0x02U; + + buffer[24U] = 0x01U; + + buffer[27U] = 0x7BU; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); + + return m_rtcpSocket.write(buffer, 28U, m_address, m_rtcpPort); +} + +bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst) +{ + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); buffer[0U] = 0x8BU; buffer[1U] = 0xCCU; - + buffer[2U] = 0x00U; buffer[3U] = 0x04U; buffer[4U] = (m_ssrc >> 24) & 0xFFU; buffer[5U] = (m_ssrc >> 16) & 0xFFU; - buffer[6U] = (m_ssrc >> 8) & 0xFFU; - buffer[7U] = (m_ssrc >> 0) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; buffer[8U] = 'K'; buffer[9U] = 'W'; @@ -397,6 +488,10 @@ bool CKenwoodNetwork::writeRTCPData(unsigned char type, unsigned short src, unsi buffer[16U] = type; + buffer[17U] = 0x00U; + buffer[18U] = 0x00U; + buffer[19U] = 0x00U; + if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U); diff --git a/NXDNGateway/KenwoodNetwork.h b/NXDNGateway/KenwoodNetwork.h index 0ae16b7..b30f5de 100644 --- a/NXDNGateway/KenwoodNetwork.h +++ b/NXDNGateway/KenwoodNetwork.h @@ -49,11 +49,14 @@ private: in_addr m_address; unsigned int m_rtcpPort; unsigned int m_rtpPort; - unsigned short m_seqNo; + uint8_t m_sessionId; + uint16_t m_seqNo; unsigned long m_timeStamp; unsigned int m_ssrc; bool m_debug; CTimer m_timer; + uint32_t m_startSecs; + uint32_t m_startMSecs; bool processIcomVoiceHeader(const unsigned char* data); bool processIcomVoiceData(const unsigned char* data); @@ -63,8 +66,9 @@ private: bool writeRTPVoiceHeader(const unsigned char* data); bool writeRTPVoiceData(const unsigned char* data); bool writeRTPVoiceTrailer(const unsigned char* data); + bool writeRTCPStart(); bool writeRTCPPing(); - bool writeRTCPData(unsigned char type, unsigned short src, unsigned short dst); + bool writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst); unsigned int readRTP(unsigned char* data); unsigned int readRTCP(unsigned char* data); }; diff --git a/NXDNGateway/Version.h b/NXDNGateway/Version.h index 22c80f6..bc8508c 100644 --- a/NXDNGateway/Version.h +++ b/NXDNGateway/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200504"; +const char* VERSION = "20200505"; #endif From bfa111872668b38d19e867e3c50cb3ccd9dd89db Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sat, 9 May 2020 15:08:24 +0100 Subject: [PATCH 53/70] Latest changes for Kenwood repeater support. --- NXDNGateway/KenwoodNetwork.cpp | 81 +++++++++++++++++++++++++++------- NXDNGateway/KenwoodNetwork.h | 7 ++- NXDNGateway/UDPSocket.cpp | 31 ++++++++++++- NXDNGateway/UDPSocket.h | 4 +- NXDNGateway/Version.h | 2 +- 5 files changed, 105 insertions(+), 20 deletions(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index d0c31fc..40822c3 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -45,17 +45,19 @@ m_seqNo(0U), m_timeStamp(0U), m_ssrc(0U), m_debug(debug), -m_timer(1000U, 0U, 200U), m_startSecs(0U), -m_startMSecs(0U) +m_startMSecs(0U), +m_rtcpTimer(1000U, 0U, 200U), +m_hangTimer(1000U, 5U), +m_hangType(0U), +m_hangSrc(0U), +m_hangDst(0U) { assert(localPort > 0U); assert(!rptAddress.empty()); assert(rptPort > 0U); m_address = CUDPSocket::lookup(rptAddress); - - ::srand((unsigned int)m_stopWatch.time()); } CKenwoodNetwork::~CKenwoodNetwork() @@ -77,7 +79,7 @@ bool CKenwoodNetwork::open() return false; } - m_ssrc = ::rand(); + m_ssrc = m_rtpSocket.getLocalAddress(); return true; } @@ -127,11 +129,12 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) switch (inData[5U] & 0x3FU) { case 0x01U: - m_timer.start(); + m_hangTimer.stop(); + m_rtcpTimer.start(); writeRTCPStart(); return writeRTPVoiceHeader(outData); case 0x08U: - m_timer.stop(); + m_hangTimer.start(); writeRTCPHang(type, src, dst); return writeRTPVoiceTrailer(outData); default: @@ -152,6 +155,10 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[2U] = inData[4U] & 0xC0U; outData[3U] = inData[3U]; + CUtils::dump(4U, "Icom Audio 1 + 2 + 3 + 4", inData + 5U, 28U); + + CUtils::dump(4U, "Icom Audio 1 + 2", inData + 5U, 14U); + // Audio 1 ::memset(temp, 0x00U, 10U); for (unsigned int i = 0U; i < 49U; i++) { @@ -168,6 +175,8 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[10U] = temp[7U]; outData[11U] = temp[6U]; + CUtils::dump(4U, "Kenwood unswapped Audio 1", temp, 8U); + // Audio 2 ::memset(temp, 0x00U, 10U); for (unsigned int i = 0U; i < 49U; i++) { @@ -184,6 +193,10 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[18U] = temp[7U]; outData[19U] = temp[6U]; + CUtils::dump(4U, "Kenwood unswapped Audio 2", temp, 8U); + + CUtils::dump(4U, "Icom Audio 3 + 4", inData + 19U, 14U); + // Audio 3 ::memset(temp, 0x00U, 10U); for (unsigned int i = 0U; i < 49U; i++) { @@ -200,6 +213,8 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[26U] = temp[7U]; outData[27U] = temp[6U]; + CUtils::dump(4U, "Kenwood unswapped Audio 3", temp, 8U); + // Audio 4 ::memset(temp, 0x00U, 10U); for (unsigned int i = 0U; i < 49U; i++) { @@ -216,6 +231,8 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[34U] = temp[7U]; outData[35U] = temp[6U]; + CUtils::dump(4U, "Kenwood unswapped Audio 4", temp, 8U); + return writeRTPVoiceData(outData); } @@ -461,6 +478,15 @@ bool CKenwoodNetwork::writeRTCPPing() } bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst) +{ + m_hangType = type; + m_hangSrc = src; + m_hangDst = dst; + + return writeRTCPHang(); +} + +bool CKenwoodNetwork::writeRTCPHang() { unsigned char buffer[30U]; ::memset(buffer, 0x00U, 30U); @@ -480,13 +506,13 @@ bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsi buffer[10U] = 'N'; buffer[11U] = 'E'; - buffer[12U] = (src >> 8) & 0xFFU; - buffer[13U] = (src >> 0) & 0xFFU; + buffer[12U] = (m_hangSrc >> 8) & 0xFFU; + buffer[13U] = (m_hangSrc >> 0) & 0xFFU; - buffer[14U] = (dst >> 8) & 0xFFU; - buffer[15U] = (dst >> 0) & 0xFFU; + buffer[14U] = (m_hangDst >> 8) & 0xFFU; + buffer[15U] = (m_hangDst >> 0) & 0xFFU; - buffer[16U] = type; + buffer[16U] = m_hangType; buffer[17U] = 0x00U; buffer[18U] = 0x00U; @@ -590,10 +616,19 @@ void CKenwoodNetwork::close() void CKenwoodNetwork::clock(unsigned int ms) { - m_timer.clock(ms); - if (m_timer.isRunning() && m_timer.hasExpired()) { - writeRTCPPing(); - m_timer.start(); + m_rtcpTimer.clock(ms); + if (m_rtcpTimer.isRunning() && m_rtcpTimer.hasExpired()) { + if (m_hangTimer.isRunning()) + writeRTCPHang(); + else + writeRTCPPing(); + m_rtcpTimer.start(); + } + + m_hangTimer.clock(ms); + if (m_hangTimer.isRunning() && m_hangTimer.hasExpired()) { + m_rtcpTimer.stop(); + m_hangTimer.stop(); } } @@ -675,6 +710,8 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) temp[6U] = inData[22U]; temp[7U] = inData[21U]; + CUtils::dump(4U, "Kenwood unswapped Audio 1", temp, 8U); + for (unsigned int i = 0U; i < 49U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(outData, n, b); @@ -689,11 +726,15 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) temp[6U] = inData[30U]; temp[7U] = inData[29U]; + CUtils::dump(4U, "Kenwood unswapped Audio 2", temp, 8U); + for (unsigned int i = 0U; i < 49U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(outData, n, b); } + CUtils::dump(4U, "Icom Audio 1 + 2", outData + 5U, 14U); + // AMBE 3+4 n = 19U * 8U; @@ -706,6 +747,8 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) temp[6U] = inData[38U]; temp[7U] = inData[37U]; + CUtils::dump(4U, "Kenwood unswapped Audio 3", temp, 8U); + for (unsigned int i = 0U; i < 49U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(outData, n, b); @@ -720,11 +763,17 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) temp[6U] = inData[46U]; temp[7U] = inData[45U]; + CUtils::dump(4U, "Kenwood unswapped Audio 4", temp, 8U); + for (unsigned int i = 0U; i < 49U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(outData, n, b); } + CUtils::dump(4U, "Icom Audio 3 + 4", outData + 19U, 14U); + + CUtils::dump(4U, "Icom Audio 1 + 2 + 3 + 4", outData + 5U, 28U); + ::memcpy(inData, outData, 33U); } diff --git a/NXDNGateway/KenwoodNetwork.h b/NXDNGateway/KenwoodNetwork.h index b30f5de..bf59c2f 100644 --- a/NXDNGateway/KenwoodNetwork.h +++ b/NXDNGateway/KenwoodNetwork.h @@ -54,9 +54,13 @@ private: unsigned long m_timeStamp; unsigned int m_ssrc; bool m_debug; - CTimer m_timer; uint32_t m_startSecs; uint32_t m_startMSecs; + CTimer m_rtcpTimer; + CTimer m_hangTimer; + unsigned char m_hangType; + unsigned short m_hangSrc; + unsigned short m_hangDst; bool processIcomVoiceHeader(const unsigned char* data); bool processIcomVoiceData(const unsigned char* data); @@ -69,6 +73,7 @@ private: bool writeRTCPStart(); bool writeRTCPPing(); bool writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst); + bool writeRTCPHang(); unsigned int readRTP(unsigned char* data); unsigned int readRTCP(unsigned char* data); }; diff --git a/NXDNGateway/UDPSocket.cpp b/NXDNGateway/UDPSocket.cpp index 396f1f7..c105b0b 100644 --- a/NXDNGateway/UDPSocket.cpp +++ b/NXDNGateway/UDPSocket.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2006-2016,2020 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 @@ -24,6 +24,7 @@ #if !defined(_WIN32) && !defined(_WIN64) #include #include +#include #endif @@ -260,3 +261,31 @@ void CUDPSocket::close() ::close(m_fd); #endif } + +unsigned long CUDPSocket::getLocalAddress() const +{ + unsigned long address = 0UL; + + char hostname[80U]; + int ret = ::gethostname(hostname, 80); + if (ret == -1) + return 0UL; + + struct hostent* phe = ::gethostbyname(hostname); + if (phe == NULL) + return 0UL; + + if (phe->h_addrtype != AF_INET) + return 0UL; + + for (unsigned int i = 0U; phe->h_addr_list[i] != NULL; i++) { + struct in_addr addr; + ::memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); + if (addr.s_addr != INADDR_LOOPBACK) { + address = addr.s_addr; + break; + } + } + + return address; +} diff --git a/NXDNGateway/UDPSocket.h b/NXDNGateway/UDPSocket.h index e0af272..ffc3b92 100644 --- a/NXDNGateway/UDPSocket.h +++ b/NXDNGateway/UDPSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2011,2013,2015,2016,2020 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 @@ -47,6 +47,8 @@ public: void close(); + unsigned long getLocalAddress() const; + static in_addr lookup(const std::string& hostName); private: diff --git a/NXDNGateway/Version.h b/NXDNGateway/Version.h index bc8508c..4344528 100644 --- a/NXDNGateway/Version.h +++ b/NXDNGateway/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200505"; +const char* VERSION = "20200509"; #endif From 6e028eda6a02f4a0d0550cf30fb3f5eedf87ac0e Mon Sep 17 00:00:00 2001 From: Roby Date: Sat, 9 May 2020 16:52:17 +0200 Subject: [PATCH 54/70] Update NXDNHosts.txt --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 87b44ea..e5d8cab 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -83,6 +83,9 @@ # 22200 IT HBLINK ITALY 22200 nxdn.hblink.it 41400 +# 22202 IT NXDN Sardegna +22202 nxdn.is0hha.hblink.it 41400 + # 22220 IT ECHOLINK ITALY 22220 dagobah.hblink.it 41400 From df6db324fab641c91be9025e3d17a4482708afeb Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 11 May 2020 16:14:26 +0100 Subject: [PATCH 55/70] Change the way the timestamp is calculated. --- NXDNGateway/KenwoodNetwork.cpp | 27 ++++++++++++++++++++++++--- NXDNGateway/KenwoodNetwork.h | 2 -- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 40822c3..bbf9241 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -36,7 +36,6 @@ const unsigned int BUFFER_LENGTH = 200U; CKenwoodNetwork::CKenwoodNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug) : m_rtcpSocket(localPort + 1U), m_rtpSocket(localPort + 0U), -m_stopWatch(), m_address(), m_rtcpPort(rptPort + 1U), m_rtpPort(rptPort + 0U), @@ -240,6 +239,30 @@ bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) { assert(data != NULL); +#if defined(_WIN32) || defined(_WIN64) + SYSTEMTIME st; + ::GetSystemTime(&st); + + unsigned int hh = st.wHour; + unsigned int mm = st.wMinute; + unsigned int ss = st.wSecond; + unsigned int ms = st.wMilliseconds; + + m_timeStamp = hh * 3600U * 1000U * 80U; + m_timeStamp += mm * 60U * 1000U * 80U; + m_timeStamp += ss * 1000U * 80U; + m_timeStamp += ms * 80U; +#else + struct timeval tod; + ::gettimeofday(&tod, NULL); + + unsigned int ss = tod.tv_sec; + unsigned int ms = tod.tv_usec / 1000U; + + m_timeStamp = ss * 1000U * 80U; + m_timeStamp += ms * 80U; +#endif + unsigned char buffer[50U]; ::memset(buffer, 0x00U, 50U); @@ -250,8 +273,6 @@ bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - m_timeStamp = (unsigned long)m_stopWatch.time(); - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; buffer[5U] = (m_timeStamp >> 16) & 0xFFU; buffer[6U] = (m_timeStamp >> 8) & 0xFFU; diff --git a/NXDNGateway/KenwoodNetwork.h b/NXDNGateway/KenwoodNetwork.h index bf59c2f..ac16618 100644 --- a/NXDNGateway/KenwoodNetwork.h +++ b/NXDNGateway/KenwoodNetwork.h @@ -20,7 +20,6 @@ #define KenwoodNetwork_H #include "RptNetwork.h" -#include "StopWatch.h" #include "UDPSocket.h" #include "Timer.h" @@ -45,7 +44,6 @@ public: private: CUDPSocket m_rtpSocket; CUDPSocket m_rtcpSocket; - CStopWatch m_stopWatch; in_addr m_address; unsigned int m_rtcpPort; unsigned int m_rtpPort; From 9ebcca5b56b0a19893c845d55d8611245b28541f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 12 May 2020 14:06:53 +0100 Subject: [PATCH 56/70] Change the timestamp calculation. --- NXDNGateway/KenwoodNetwork.cpp | 85 ++++++++++++++++++---------------- NXDNGateway/KenwoodNetwork.h | 2 +- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index bbf9241..05b9433 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -41,7 +41,6 @@ m_rtcpPort(rptPort + 1U), m_rtpPort(rptPort + 0U), m_sessionId(0U), m_seqNo(0U), -m_timeStamp(0U), m_ssrc(0U), m_debug(debug), m_startSecs(0U), @@ -239,30 +238,6 @@ bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) { assert(data != NULL); -#if defined(_WIN32) || defined(_WIN64) - SYSTEMTIME st; - ::GetSystemTime(&st); - - unsigned int hh = st.wHour; - unsigned int mm = st.wMinute; - unsigned int ss = st.wSecond; - unsigned int ms = st.wMilliseconds; - - m_timeStamp = hh * 3600U * 1000U * 80U; - m_timeStamp += mm * 60U * 1000U * 80U; - m_timeStamp += ss * 1000U * 80U; - m_timeStamp += ms * 80U; -#else - struct timeval tod; - ::gettimeofday(&tod, NULL); - - unsigned int ss = tod.tv_sec; - unsigned int ms = tod.tv_usec / 1000U; - - m_timeStamp = ss * 1000U * 80U; - m_timeStamp += ms * 80U; -#endif - unsigned char buffer[50U]; ::memset(buffer, 0x00U, 50U); @@ -273,10 +248,11 @@ bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; - buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; @@ -319,11 +295,11 @@ bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - m_timeStamp += 640U; - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; - buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; @@ -365,11 +341,11 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - m_timeStamp += 640U; - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; - buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; @@ -842,3 +818,34 @@ void CKenwoodNetwork::processKenwoodData(unsigned char* inData) ::memcpy(inData, outData, 24U); } } + +unsigned long CKenwoodNetwork::getTimeStamp() const +{ + unsigned long timeStamp = 0UL; + +#if defined(_WIN32) || defined(_WIN64) + SYSTEMTIME st; + ::GetSystemTime(&st); + + unsigned int hh = st.wHour; + unsigned int mm = st.wMinute; + unsigned int ss = st.wSecond; + unsigned int ms = st.wMilliseconds; + + timeStamp += hh * 3600U * 1000U * 80U; + timeStamp += mm * 60U * 1000U * 80U; + timeStamp += ss * 1000U * 80U; + timeStamp += ms * 80U; +#else + struct timeval tod; + ::gettimeofday(&tod, NULL); + + unsigned int ss = tod.tv_sec; + unsigned int ms = tod.tv_usec / 1000U; + + timeStamp += ss * 1000U * 80U; + timeStamp += ms * 80U; +#endif + + return timeStamp; +} diff --git a/NXDNGateway/KenwoodNetwork.h b/NXDNGateway/KenwoodNetwork.h index ac16618..5486a1a 100644 --- a/NXDNGateway/KenwoodNetwork.h +++ b/NXDNGateway/KenwoodNetwork.h @@ -49,7 +49,6 @@ private: unsigned int m_rtpPort; uint8_t m_sessionId; uint16_t m_seqNo; - unsigned long m_timeStamp; unsigned int m_ssrc; bool m_debug; uint32_t m_startSecs; @@ -74,6 +73,7 @@ private: bool writeRTCPHang(); unsigned int readRTP(unsigned char* data); unsigned int readRTCP(unsigned char* data); + unsigned long getTimeStamp() const; }; #endif From f4205228622d81ed38ad53e19cdb32357ee25edc Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 14 May 2020 11:16:54 +0100 Subject: [PATCH 57/70] Optimise the timestamp handling. --- NXDNGateway/KenwoodNetwork.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 05b9433..2e521c8 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -375,12 +375,12 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) bool CKenwoodNetwork::writeRTCPStart() { +#if defined(_WIN32) || defined(_WIN64) time_t now; ::time(&now); m_startSecs = uint32_t(now); -#if defined(_WIN32) || defined(_WIN64) SYSTEMTIME st; ::GetSystemTime(&st); @@ -389,6 +389,7 @@ bool CKenwoodNetwork::writeRTCPStart() struct timeval tod; ::gettimeofday(&tod, NULL); + m_startSecs = tod.tv_sec; m_startMSecs = tod.tv_usec / 1000U; #endif From f7d2ce0016eef6fc12ede58d77a993226d8eea2c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 15 May 2020 16:37:53 +0100 Subject: [PATCH 58/70] Rename 10301. --- NXDNGateway/NXDNHosts.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index e5d8cab..8f72895 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -59,7 +59,7 @@ # North America, 10200 10200 dvswitch.org 42400 -# Spanish speaking, 10301 +# HBLINK Espana, 10301 10301 ea5gvk.duckdns.org 41400 # NXDN 10302 Multimode BM 21461 EA Spain From e9f1fbb1bd3fc78194bc3698bb482fde1cdb2437 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 15 May 2020 16:41:13 +0100 Subject: [PATCH 59/70] Add 20945 --- NXDNGateway/NXDNHosts.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 8f72895..17244b4 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -77,6 +77,9 @@ # Europe, German speaking, 20000 20000 89.185.97.38 41400 +# 20945 Deutschland DL1BH +20945 dl1bh.ddns.net 41400 + # 21465 ADER Multimode 21465 80.211.106.186 41400 @@ -88,7 +91,6 @@ # 22220 IT ECHOLINK ITALY 22220 dagobah.hblink.it 41400 - # 22245 IT PIEDMONT GDO 22245 nxdngdo.duckdns.org 41400 From a1b4a00c32ceb8ac9ca414b1f19914ef624451df Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 18 May 2020 11:13:37 +0100 Subject: [PATCH 60/70] Fix the initialisation order. --- NXDNGateway/KenwoodNetwork.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 2e521c8..0ed30b9 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -34,8 +34,8 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04 const unsigned int BUFFER_LENGTH = 200U; CKenwoodNetwork::CKenwoodNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug) : -m_rtcpSocket(localPort + 1U), m_rtpSocket(localPort + 0U), +m_rtcpSocket(localPort + 1U), m_address(), m_rtcpPort(rptPort + 1U), m_rtpPort(rptPort + 0U), From 9941df13c2cb524776a7fb004e8d87787f62f3a3 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 19 May 2020 16:45:20 +0100 Subject: [PATCH 61/70] Add network late entry. --- NXDNGateway/IcomNetwork.cpp | 14 +-- NXDNGateway/IcomNetwork.h | 2 +- NXDNGateway/KenwoodNetwork.cpp | 167 ++++++++++++++++++++++++--------- NXDNGateway/KenwoodNetwork.h | 15 ++- NXDNGateway/RptNetwork.h | 2 +- NXDNGateway/Version.h | 2 +- 6 files changed, 143 insertions(+), 59 deletions(-) diff --git a/NXDNGateway/IcomNetwork.cpp b/NXDNGateway/IcomNetwork.cpp index 557f155..6cbd9b2 100644 --- a/NXDNGateway/IcomNetwork.cpp +++ b/NXDNGateway/IcomNetwork.cpp @@ -87,7 +87,7 @@ bool CIcomNetwork::write(const unsigned char* data, unsigned int length) return m_socket.write(buffer, 102U, m_address, m_port); } -bool CIcomNetwork::read(unsigned char* data) +unsigned int CIcomNetwork::read(unsigned char* data) { assert(data != NULL); @@ -97,16 +97,16 @@ bool CIcomNetwork::read(unsigned char* data) int length = m_socket.read(buffer, BUFFER_LENGTH, address, port); if (length <= 0) - return false; + return 0U; if (m_address.s_addr != address.s_addr || m_port != port) { LogWarning("Icom Data received from an unknown address or port - %08X:%u", ntohl(address.s_addr), port); - return false; + return 0U; } // Invalid packet type? if (::memcmp(buffer, "ICOM", 4U) != 0) - return false; + return 0U; // An Icom repeater connect request if (buffer[4U] == 0x01U && buffer[5U] == 0x61U) { @@ -115,18 +115,18 @@ bool CIcomNetwork::read(unsigned char* data) buffer[38U] = 0x4FU; buffer[39U] = 0x4BU; m_socket.write(buffer, length, address, port); - return false; + return 0U; } if (length != 102) - return false; + return 0U; if (m_debug) CUtils::dump(1U, "Icom Data Received", buffer, length); ::memcpy(data, buffer + 40U, 33U); - return true; + return 33U; } void CIcomNetwork::close() diff --git a/NXDNGateway/IcomNetwork.h b/NXDNGateway/IcomNetwork.h index 6cb4d3a..e2aec93 100644 --- a/NXDNGateway/IcomNetwork.h +++ b/NXDNGateway/IcomNetwork.h @@ -34,7 +34,7 @@ public: virtual bool write(const unsigned char* data, unsigned int length); - virtual bool read(unsigned char* data); + virtual unsigned int read(unsigned char* data); virtual void close(); diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 0ed30b9..3f36334 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -39,7 +39,13 @@ m_rtcpSocket(localPort + 1U), m_address(), m_rtcpPort(rptPort + 1U), m_rtpPort(rptPort + 0U), -m_sessionId(0U), +m_headerSeen(false), +m_seen1(false), +m_seen2(false), +m_seen3(false), +m_seen4(false), +m_sacch(NULL), +m_sessionId(1U), m_seqNo(0U), m_ssrc(0U), m_debug(debug), @@ -55,11 +61,14 @@ m_hangDst(0U) assert(!rptAddress.empty()); assert(rptPort > 0U); + m_sacch = new unsigned char[10U]; + m_address = CUDPSocket::lookup(rptAddress); } CKenwoodNetwork::~CKenwoodNetwork() { + delete[] m_sacch; } bool CKenwoodNetwork::open() @@ -131,10 +140,12 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) m_rtcpTimer.start(); writeRTCPStart(); return writeRTPVoiceHeader(outData); - case 0x08U: + case 0x08U: { m_hangTimer.start(); + bool ret = writeRTPVoiceTrailer(outData); writeRTCPHang(type, src, dst); - return writeRTPVoiceTrailer(outData); + return ret; + } default: return false; } @@ -153,10 +164,6 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[2U] = inData[4U] & 0xC0U; outData[3U] = inData[3U]; - CUtils::dump(4U, "Icom Audio 1 + 2 + 3 + 4", inData + 5U, 28U); - - CUtils::dump(4U, "Icom Audio 1 + 2", inData + 5U, 14U); - // Audio 1 ::memset(temp, 0x00U, 10U); for (unsigned int i = 0U; i < 49U; i++) { @@ -173,8 +180,6 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[10U] = temp[7U]; outData[11U] = temp[6U]; - CUtils::dump(4U, "Kenwood unswapped Audio 1", temp, 8U); - // Audio 2 ::memset(temp, 0x00U, 10U); for (unsigned int i = 0U; i < 49U; i++) { @@ -191,10 +196,6 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[18U] = temp[7U]; outData[19U] = temp[6U]; - CUtils::dump(4U, "Kenwood unswapped Audio 2", temp, 8U); - - CUtils::dump(4U, "Icom Audio 3 + 4", inData + 19U, 14U); - // Audio 3 ::memset(temp, 0x00U, 10U); for (unsigned int i = 0U; i < 49U; i++) { @@ -211,8 +212,6 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[26U] = temp[7U]; outData[27U] = temp[6U]; - CUtils::dump(4U, "Kenwood unswapped Audio 3", temp, 8U); - // Audio 4 ::memset(temp, 0x00U, 10U); for (unsigned int i = 0U; i < 49U; i++) { @@ -229,8 +228,6 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) outData[34U] = temp[7U]; outData[35U] = temp[6U]; - CUtils::dump(4U, "Kenwood unswapped Audio 4", temp, 8U); - return writeRTPVoiceData(outData); } @@ -522,7 +519,7 @@ bool CKenwoodNetwork::writeRTCPHang() return m_rtcpSocket.write(buffer, 20U, m_address, m_rtcpPort); } -bool CKenwoodNetwork::read(unsigned char* data) +unsigned int CKenwoodNetwork::read(unsigned char* data) { assert(data != NULL); @@ -532,18 +529,19 @@ bool CKenwoodNetwork::read(unsigned char* data) unsigned int len = readRTP(data); switch (len) { case 0U: // Nothing received - return false; + return 0U; case 35U: // Voice header or trailer return processKenwoodVoiceHeader(data); case 47U: // Voice data - processKenwoodVoiceData(data); - return true; + if (m_headerSeen) + return processKenwoodVoiceData(data); + else + return processKenwoodVoiceLateEntry(data); case 31U: // Data - processKenwoodData(data); - return true; + return processKenwoodData(data); default: CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); - return false; + return 0U; } } @@ -630,7 +628,7 @@ void CKenwoodNetwork::clock(unsigned int ms) } } -bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) +unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) { assert(inData != NULL); @@ -668,16 +666,26 @@ bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) switch (outData[5U] & 0x3FU) { case 0x01U: ::memcpy(inData, outData, 33U); - return true; + m_headerSeen = true; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; + return 33U; case 0x08U: ::memcpy(inData, outData, 33U); - return true; + m_headerSeen = false; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; + return 33U; default: - return false; + return 0U; } } -void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) +unsigned int CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) { assert(inData != NULL); @@ -708,8 +716,6 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) temp[6U] = inData[22U]; temp[7U] = inData[21U]; - CUtils::dump(4U, "Kenwood unswapped Audio 1", temp, 8U); - for (unsigned int i = 0U; i < 49U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(outData, n, b); @@ -724,15 +730,11 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) temp[6U] = inData[30U]; temp[7U] = inData[29U]; - CUtils::dump(4U, "Kenwood unswapped Audio 2", temp, 8U); - for (unsigned int i = 0U; i < 49U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(outData, n, b); } - CUtils::dump(4U, "Icom Audio 1 + 2", outData + 5U, 14U); - // AMBE 3+4 n = 19U * 8U; @@ -745,8 +747,6 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) temp[6U] = inData[38U]; temp[7U] = inData[37U]; - CUtils::dump(4U, "Kenwood unswapped Audio 3", temp, 8U); - for (unsigned int i = 0U; i < 49U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(outData, n, b); @@ -761,24 +761,20 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) temp[6U] = inData[46U]; temp[7U] = inData[45U]; - CUtils::dump(4U, "Kenwood unswapped Audio 4", temp, 8U); - for (unsigned int i = 0U; i < 49U; i++, n++) { bool b = READ_BIT(temp, i); WRITE_BIT(outData, n, b); } - CUtils::dump(4U, "Icom Audio 3 + 4", outData + 19U, 14U); - - CUtils::dump(4U, "Icom Audio 1 + 2 + 3 + 4", outData + 5U, 28U); - ::memcpy(inData, outData, 33U); + + return 33U; } -void CKenwoodNetwork::processKenwoodData(unsigned char* inData) +unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData) { if (inData[7U] != 0x09U && inData[7U] != 0x0BU && inData[7U] != 0x08U) - return; + return 0U; unsigned char outData[50U]; @@ -791,6 +787,7 @@ void CKenwoodNetwork::processKenwoodData(unsigned char* inData) outData[5U] = inData[12U]; outData[6U] = inData[11U]; ::memcpy(inData, outData, 7U); + return 7U; } else { outData[0U] = 0x90U; outData[1U] = inData[8U]; @@ -817,6 +814,7 @@ void CKenwoodNetwork::processKenwoodData(unsigned char* inData) outData[22U] = inData[27U]; outData[23U] = inData[29U]; ::memcpy(inData, outData, 24U); + return 24U; } } @@ -850,3 +848,82 @@ unsigned long CKenwoodNetwork::getTimeStamp() const return timeStamp; } + +unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char sacch[4U]; + sacch[0U] = inData[12U]; + sacch[1U] = inData[11U]; + sacch[2U] = inData[14U]; + sacch[3U] = inData[13U]; + + switch (sacch[0U] & 0xC0U) { + case 0xC0U: + if (!m_seen1) { + unsigned int offset = 0U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen1 = true; + } + break; + case 0x80U: + if (!m_seen2) { + unsigned int offset = 18U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen2 = true; + } + break; + case 0x40U: + if (!m_seen3) { + unsigned int offset = 36U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen3 = true; + } + break; + case 0x00U: + if (!m_seen4) { + unsigned int offset = 54U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen4 = true; + } + break; + } + + if (!m_seen1 || !m_seen2 || !m_seen3 || !m_seen4) + return 0U; + + m_headerSeen = true; + + // Create a dummy header + // Header SACCH + inData[11U] = 0x10U; + inData[12U] = 0x01U; + inData[13U] = 0x00U; + inData[14U] = 0x00U; + + inData[15U] = m_sacch[1U]; + inData[16U] = m_sacch[0U]; + inData[17U] = m_sacch[3U]; + inData[18U] = m_sacch[2U]; + inData[19U] = m_sacch[5U]; + inData[20U] = m_sacch[4U]; + inData[21U] = m_sacch[7U]; + inData[22U] = m_sacch[6U]; + inData[23U] = 0x00U; + inData[24U] = m_sacch[8U]; + + return processKenwoodVoiceHeader(inData); +} diff --git a/NXDNGateway/KenwoodNetwork.h b/NXDNGateway/KenwoodNetwork.h index 5486a1a..c7c2d69 100644 --- a/NXDNGateway/KenwoodNetwork.h +++ b/NXDNGateway/KenwoodNetwork.h @@ -35,7 +35,7 @@ public: virtual bool write(const unsigned char* data, unsigned int length); - virtual bool read(unsigned char* data); + virtual unsigned int read(unsigned char* data); virtual void close(); @@ -47,6 +47,12 @@ private: in_addr m_address; unsigned int m_rtcpPort; unsigned int m_rtpPort; + bool m_headerSeen; + bool m_seen1; + bool m_seen2; + bool m_seen3; + bool m_seen4; + unsigned char* m_sacch; uint8_t m_sessionId; uint16_t m_seqNo; unsigned int m_ssrc; @@ -61,9 +67,10 @@ private: bool processIcomVoiceHeader(const unsigned char* data); bool processIcomVoiceData(const unsigned char* data); - bool processKenwoodVoiceHeader(unsigned char* data); - void processKenwoodVoiceData(unsigned char* data); - void processKenwoodData(unsigned char* data); + unsigned int processKenwoodVoiceHeader(unsigned char* data); + unsigned int processKenwoodVoiceData(unsigned char* data); + unsigned int processKenwoodVoiceLateEntry(unsigned char* data); + unsigned int processKenwoodData(unsigned char* data); bool writeRTPVoiceHeader(const unsigned char* data); bool writeRTPVoiceData(const unsigned char* data); bool writeRTPVoiceTrailer(const unsigned char* data); diff --git a/NXDNGateway/RptNetwork.h b/NXDNGateway/RptNetwork.h index 0ec1a06..44f86d8 100644 --- a/NXDNGateway/RptNetwork.h +++ b/NXDNGateway/RptNetwork.h @@ -43,7 +43,7 @@ public: virtual bool write(const unsigned char* data, unsigned int length) = 0; - virtual bool read(unsigned char* data) = 0; + virtual unsigned int read(unsigned char* data) = 0; virtual void close() = 0; diff --git a/NXDNGateway/Version.h b/NXDNGateway/Version.h index 4344528..1c4898c 100644 --- a/NXDNGateway/Version.h +++ b/NXDNGateway/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200509"; +const char* VERSION = "20200519"; #endif From 03d70ba43d5f5be911334e9df7b0babf2b4745a7 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 19 May 2020 18:06:13 +0100 Subject: [PATCH 62/70] Minor cleanups. --- NXDNGateway/KenwoodNetwork.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 3f36334..55b4149 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -509,10 +509,6 @@ bool CKenwoodNetwork::writeRTCPHang() buffer[16U] = m_hangType; - buffer[17U] = 0x00U; - buffer[18U] = 0x00U; - buffer[19U] = 0x00U; - if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U); @@ -905,8 +901,6 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData if (!m_seen1 || !m_seen2 || !m_seen3 || !m_seen4) return 0U; - m_headerSeen = true; - // Create a dummy header // Header SACCH inData[11U] = 0x10U; @@ -914,6 +908,7 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData inData[13U] = 0x00U; inData[14U] = 0x00U; + // Header FACCH inData[15U] = m_sacch[1U]; inData[16U] = m_sacch[0U]; inData[17U] = m_sacch[3U]; From b39354613d76506dd073cd1d95ad248b1d4ee215 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 19 May 2020 18:08:34 +0100 Subject: [PATCH 63/70] Updated ini file for Kenwood, Icom and MMDVM repeaters. --- NXDNGateway/NXDNGateway.ini | 11 +++++ NXDNGateway/NXDNGateway.sav.ini | 78 +++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 NXDNGateway/NXDNGateway.sav.ini diff --git a/NXDNGateway/NXDNGateway.ini b/NXDNGateway/NXDNGateway.ini index aa2b2ab..205857c 100644 --- a/NXDNGateway/NXDNGateway.ini +++ b/NXDNGateway/NXDNGateway.ini @@ -1,6 +1,17 @@ [General] Callsign=G4KLX Suffix=NXDN +# The next four lines are for a Kenwood repeater +# RptProtocol=Kenwood +# RptAddress=1.2.3.4 +# RptPort=64000 +# LocalPort=64000 +# The next four lines are for an Icom repeater +# RptProtocol=Icom +# RptAddress=1.2.3.4 +# RptPort=41300 +# LocalPort=41300 +# The next four lines are for an MMDVM RptProtocol=Icom RptAddress=127.0.0.1 RptPort=14021 diff --git a/NXDNGateway/NXDNGateway.sav.ini b/NXDNGateway/NXDNGateway.sav.ini new file mode 100644 index 0000000..dd6d752 --- /dev/null +++ b/NXDNGateway/NXDNGateway.sav.ini @@ -0,0 +1,78 @@ +[General] +Callsign=G4KLX +Suffix=NXDN +# The next four lines are for a Kenwood repeater +# RptProtocol=Kenwood +# RptAddress=1.2.3.4 +# RptPort=64000 +# LocalPort=64000 +# The next four lines are for an Icom repeater +# RptProtocol=Icom +# RptAddress=1.2.3.4 +# RptPort=41300 +# LocalPort=41300 +# The next four lines are for an MMDVM +# RptProtocol=Icom +# RptAddress=127.0.0.1 +# RptPort=14021 +# LocalPort=14020 +RptProtocol=Kenwood +RptAddress=10.10.148.40 +RptPort=64000 +LocalPort=64000 +Debug=1 +Daemon=1 + +[Info] +RXFrequency=430475000 +TXFrequency=439475000 +Power=1 +Latitude=0.0 +Longitude=0.0 +Height=0 +Name=Nowhere +Description=Multi-Mode Repeater + +[Voice] +Enabled=1 +Language=en_GB +Directory=Audio + +[aprs.fi] +Enable=0 +# Server=noam.aprs2.net +Server=euro.aprs2.net +Port=14580 +Password=9999 +Description=APRS Description +Suffix=N + +[Id Lookup] +Name=NXDN.csv +Time=24 + +[Log] +FilePath=. +FileRoot=NXDNGateway + +[Network] +Port=14050 +HostsFile1=NXDNHosts.txt +HostsFile2=./private/NXDNHosts.txt +ReloadTime=60 +ParrotAddress=127.0.0.1 +ParrotPort=42021 +NXDN2DMRAddress=127.0.0.1 +NXDN2DMRPort=42022 +Startup=10 +InactivityTimeout=10 +Debug=0 + +[Mobile GPS] +Enable=0 +Address=127.0.0.1 +Port=7834 + +[Remote Commands] +Enable=0 +Port=6075 From aeffaf80c2a3f4873701c9baecc5d591985d2f1e Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 19 May 2020 18:09:29 +0100 Subject: [PATCH 64/70] Delete unwanted file. --- NXDNGateway/NXDNGateway.sav.ini | 78 --------------------------------- 1 file changed, 78 deletions(-) delete mode 100644 NXDNGateway/NXDNGateway.sav.ini diff --git a/NXDNGateway/NXDNGateway.sav.ini b/NXDNGateway/NXDNGateway.sav.ini deleted file mode 100644 index dd6d752..0000000 --- a/NXDNGateway/NXDNGateway.sav.ini +++ /dev/null @@ -1,78 +0,0 @@ -[General] -Callsign=G4KLX -Suffix=NXDN -# The next four lines are for a Kenwood repeater -# RptProtocol=Kenwood -# RptAddress=1.2.3.4 -# RptPort=64000 -# LocalPort=64000 -# The next four lines are for an Icom repeater -# RptProtocol=Icom -# RptAddress=1.2.3.4 -# RptPort=41300 -# LocalPort=41300 -# The next four lines are for an MMDVM -# RptProtocol=Icom -# RptAddress=127.0.0.1 -# RptPort=14021 -# LocalPort=14020 -RptProtocol=Kenwood -RptAddress=10.10.148.40 -RptPort=64000 -LocalPort=64000 -Debug=1 -Daemon=1 - -[Info] -RXFrequency=430475000 -TXFrequency=439475000 -Power=1 -Latitude=0.0 -Longitude=0.0 -Height=0 -Name=Nowhere -Description=Multi-Mode Repeater - -[Voice] -Enabled=1 -Language=en_GB -Directory=Audio - -[aprs.fi] -Enable=0 -# Server=noam.aprs2.net -Server=euro.aprs2.net -Port=14580 -Password=9999 -Description=APRS Description -Suffix=N - -[Id Lookup] -Name=NXDN.csv -Time=24 - -[Log] -FilePath=. -FileRoot=NXDNGateway - -[Network] -Port=14050 -HostsFile1=NXDNHosts.txt -HostsFile2=./private/NXDNHosts.txt -ReloadTime=60 -ParrotAddress=127.0.0.1 -ParrotPort=42021 -NXDN2DMRAddress=127.0.0.1 -NXDN2DMRPort=42022 -Startup=10 -InactivityTimeout=10 -Debug=0 - -[Mobile GPS] -Enable=0 -Address=127.0.0.1 -Port=7834 - -[Remote Commands] -Enable=0 -Port=6075 From 7e69b7dd64c973e1ac0a0b18a7cbf536723352b7 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 19 May 2020 18:10:23 +0100 Subject: [PATCH 65/70] Remove unwanted file. --- Update NXDNHosts.txt | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 Update NXDNHosts.txt diff --git a/Update NXDNHosts.txt b/Update NXDNHosts.txt deleted file mode 100644 index 3dab350..0000000 --- a/Update NXDNHosts.txt +++ /dev/null @@ -1,8 +0,0 @@ -# 911 911 Cop Talk -911 NXDN.k2cop.com 41400 - -# 7225 MULTIPROTOCOLO ARGENTINA -7225 ysfarg.ddns.net 41400 - -# 25000 NE NXCore NXDNReflector -25000 173.166.94.77 41400 From c16da142cf97010b4bd2146ab0b7c1a8ddd56d00 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 19 May 2020 20:47:11 +0100 Subject: [PATCH 66/70] Convert to using microseconds. --- NXDNGateway/KenwoodNetwork.cpp | 22 +++++++++++----------- NXDNGateway/KenwoodNetwork.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index 55b4149..c5a4a20 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -50,7 +50,7 @@ m_seqNo(0U), m_ssrc(0U), m_debug(debug), m_startSecs(0U), -m_startMSecs(0U), +m_startUSecs(0U), m_rtcpTimer(1000U, 0U, 200U), m_hangTimer(1000U, 5U), m_hangType(0U), @@ -381,13 +381,13 @@ bool CKenwoodNetwork::writeRTCPStart() SYSTEMTIME st; ::GetSystemTime(&st); - m_startMSecs = st.wMilliseconds; + m_startUSecs = st.wMilliseconds * 1000U; #else struct timeval tod; ::gettimeofday(&tod, NULL); m_startSecs = tod.tv_sec; - m_startMSecs = tod.tv_usec / 1000U; + m_startUSecs = tod.tv_usec; #endif unsigned char buffer[30U]; @@ -413,10 +413,10 @@ bool CKenwoodNetwork::writeRTCPStart() buffer[14U] = (m_startSecs >> 8) & 0xFFU; buffer[15U] = (m_startSecs >> 0) & 0xFFU; - buffer[16U] = (m_startMSecs >> 24) & 0xFFU; - buffer[17U] = (m_startMSecs >> 16) & 0xFFU; - buffer[18U] = (m_startMSecs >> 8) & 0xFFU; - buffer[19U] = (m_startMSecs >> 0) & 0xFFU; + buffer[16U] = (m_startUSecs >> 24) & 0xFFU; + buffer[17U] = (m_startUSecs >> 16) & 0xFFU; + buffer[18U] = (m_startUSecs >> 8) & 0xFFU; + buffer[19U] = (m_startUSecs >> 0) & 0xFFU; buffer[22U] = 0x02U; @@ -455,10 +455,10 @@ bool CKenwoodNetwork::writeRTCPPing() buffer[14U] = (m_startSecs >> 8) & 0xFFU; buffer[15U] = (m_startSecs >> 0) & 0xFFU; - buffer[16U] = (m_startMSecs >> 24) & 0xFFU; - buffer[17U] = (m_startMSecs >> 16) & 0xFFU; - buffer[18U] = (m_startMSecs >> 8) & 0xFFU; - buffer[19U] = (m_startMSecs >> 0) & 0xFFU; + buffer[16U] = (m_startUSecs >> 24) & 0xFFU; + buffer[17U] = (m_startUSecs >> 16) & 0xFFU; + buffer[18U] = (m_startUSecs >> 8) & 0xFFU; + buffer[19U] = (m_startUSecs >> 0) & 0xFFU; buffer[22U] = 0x02U; diff --git a/NXDNGateway/KenwoodNetwork.h b/NXDNGateway/KenwoodNetwork.h index c7c2d69..aa52d64 100644 --- a/NXDNGateway/KenwoodNetwork.h +++ b/NXDNGateway/KenwoodNetwork.h @@ -58,7 +58,7 @@ private: unsigned int m_ssrc; bool m_debug; uint32_t m_startSecs; - uint32_t m_startMSecs; + uint32_t m_startUSecs; CTimer m_rtcpTimer; CTimer m_hangTimer; unsigned char m_hangType; From 76bfc9c59294308e674732a998d75c5140709d97 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 21 May 2020 11:21:43 +0100 Subject: [PATCH 67/70] Update README --- README.md | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6f32ee5..ed437e2 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,28 @@ -These programs are clients for the NXDN networking now built into the MMDVM Host. +These programs are clients for the NXDN networking built into the MMDVM Host. -The Parrot is very simple minded and can only handle one client at a time and is therefore not suitable for use as a shared resource via the Internet. +The Parrot is very simple minded and can only handle one client at a time and +is therefore not suitable for use as a shared resource via the Internet. -The Reflector is used as a single talk group in the same way that it is with P25. It also includes the option to link it to NXCore to allow for interchange of audio between the two. At the NXCore end, it should be set up to receive the traffic from only one talk group. +The Reflector is used as a single talk group in the same way that it is with +P25. It also includes the option to link it to NXCore to allow for interchange +of audio between the two. At the NXCore end, it should be set up to receive the +traffic from only one talk group. -The Gateway allows for use of NXDN Talk Groups to control the access to the various NXDN reflectors. It speaks the same language as Icom repeaters to the MMDVM so could theoretically be used as a gateway for a real Icom NXDN repeater. This has not been tested. +The Gateway allows for use of NXDN Talk Groups to control the access to the +various NXDN reflectors. It speaks the same language as Icom repeaters to the +MMDVM so can be used as a gateway for Icom NXDN repeaters. It also +includes experimental support for Kenwood NXDN repeaters. -The Gateway has an ini file that contain the parameters for running the software. The filename of the ini file is passed as a parameter on the command line. The Parrot takes the UDP port number to listen on as an argument. +The Gateway has an ini file that contain the parameters for running the +software. The filename of the ini file is passed as a parameter on the command +line. The Parrot takes the UDP port number to listen on as an argument. -The MMDVM .ini file should have the IP address and port number of the client in the [NXDN Network] settings. +The MMDVM .ini file should have the IP address and port number of the client in +the [NXDN Network] settings. -They build on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2017 on x86 and x64. +These programs build on 32-bit and 64-bit Linux as well as on Windows using +Visual Studio 2019 on x86 and x64. -This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden. +This software is licenced under the GPL v2 and is intended for amateur and +educational use only. Use of this software for commercial purposes is strictly +forbidden. From fc08cf95f360b3a6000e503a7f66e93ff02f6164 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 27 May 2020 13:49:55 +0100 Subject: [PATCH 68/70] Update to the latest Kenwood protocol handler. --- NXDNReflector/KenwoodNetwork.cpp | 472 ++++++++++++++++++++++++------- NXDNReflector/KenwoodNetwork.h | 31 +- NXDNReflector/UDPSocket.cpp | 30 +- NXDNReflector/UDPSocket.h | 6 +- NXDNReflector/Version.h | 2 +- 5 files changed, 432 insertions(+), 109 deletions(-) diff --git a/NXDNReflector/KenwoodNetwork.cpp b/NXDNReflector/KenwoodNetwork.cpp index 979c021..8a872c0 100644 --- a/NXDNReflector/KenwoodNetwork.cpp +++ b/NXDNReflector/KenwoodNetwork.cpp @@ -24,6 +24,7 @@ #include #include #include +#include const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; @@ -36,25 +37,37 @@ const unsigned int RTP_PORT = 64000U; const unsigned int RTCP_PORT = 64001U; CKenwoodNetwork::CKenwoodNetwork(const std::string& address, bool debug) : -m_rtcpSocket(RTCP_PORT), m_rtpSocket(RTP_PORT), -m_stopWatch(), +m_rtcpSocket(RTCP_PORT), m_address(), +m_headerSeen(false), +m_seen1(false), +m_seen2(false), +m_seen3(false), +m_seen4(false), +m_sacch(NULL), +m_sessionId(1U), m_seqNo(0U), -m_timeStamp(0U), m_ssrc(0U), m_debug(debug), -m_timer(1000U, 0U, 200U) +m_startSecs(0U), +m_startUSecs(0U), +m_rtcpTimer(1000U, 0U, 200U), +m_hangTimer(1000U, 5U), +m_hangType(0U), +m_hangSrc(0U), +m_hangDst(0U) { assert(!address.empty()); - m_address = CUDPSocket::lookup(address); + m_sacch = new unsigned char[10U]; - ::srand((unsigned int)m_stopWatch.time()); + m_address = CUDPSocket::lookup(address); } CKenwoodNetwork::~CKenwoodNetwork() { + delete[] m_sacch; } bool CKenwoodNetwork::open() @@ -72,7 +85,7 @@ bool CKenwoodNetwork::open() return false; } - m_ssrc = ::rand(); + m_ssrc = m_rtpSocket.getLocalAddress(); return true; } @@ -107,12 +120,12 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) outData[3U] = inData[3U]; // FACCH 1+2 - outData[4U] = outData[14U] = inData[6U]; - outData[5U] = outData[15U] = inData[5U]; - outData[6U] = outData[16U] = inData[8U]; - outData[7U] = outData[17U] = inData[7U]; - outData[8U] = outData[18U] = inData[10U]; - outData[9U] = outData[19U] = inData[9U]; + outData[4U] = outData[14U] = inData[6U]; + outData[5U] = outData[15U] = inData[5U]; + outData[6U] = outData[16U] = inData[8U]; + outData[7U] = outData[17U] = inData[7U]; + outData[8U] = outData[18U] = inData[10U]; + outData[9U] = outData[19U] = inData[9U]; outData[10U] = outData[20U] = inData[12U]; outData[11U] = outData[21U] = inData[11U]; @@ -122,13 +135,16 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) switch (inData[5U] & 0x3FU) { case 0x01U: - m_timer.start(); - writeRTCPData(type, src, dst); + m_hangTimer.stop(); + m_rtcpTimer.start(); + writeRTCPStart(); return writeRTPVoiceHeader(outData); - case 0x08U: - m_timer.stop(); - writeRTCPData(type, src, dst); - return writeRTPVoiceTrailer(outData); + case 0x08U: { + m_hangTimer.start(); + bool ret = writeRTPVoiceTrailer(outData); + writeRTCPHang(type, src, dst); + return ret; + } default: return false; } @@ -224,23 +240,27 @@ bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) buffer[0U] = 0x80U; buffer[1U] = 0x66U; + m_seqNo++; buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - m_seqNo++; - m_timeStamp = (unsigned long)m_stopWatch.time(); - - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; - buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; - m_timeStamp += 640U; + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; buffer[10U] = (m_ssrc >> 8) & 0xFFU; buffer[11U] = (m_ssrc >> 0) & 0xFFU; + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; buffer[16U] = 0x03U; buffer[17U] = 0x03U; buffer[18U] = 0x04U; @@ -267,19 +287,26 @@ bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) buffer[0U] = 0x80U; buffer[1U] = 0x66U; + m_seqNo++; buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; - buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; buffer[10U] = (m_ssrc >> 8) & 0xFFU; buffer[11U] = (m_ssrc >> 0) & 0xFFU; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; buffer[16U] = 0x03U; buffer[17U] = 0x03U; buffer[18U] = 0x04U; @@ -306,21 +333,26 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) buffer[0U] = 0x80U; buffer[1U] = 0x66U; + m_seqNo++; buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - m_seqNo++; - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; - buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; - m_timeStamp += 640U; + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; - buffer[10U] = (m_ssrc >> 8) & 0xFFU; - buffer[11U] = (m_ssrc >> 0) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; buffer[16U] = 0x03U; buffer[17U] = 0x02U; buffer[18U] = 0x04U; @@ -337,30 +369,59 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) return m_rtpSocket.write(buffer, 59U, m_address, RTP_PORT); } -bool CKenwoodNetwork::writeRTCPPing() +bool CKenwoodNetwork::writeRTCPStart() { +#if defined(_WIN32) || defined(_WIN64) + time_t now; + ::time(&now); + + m_startSecs = uint32_t(now); + + SYSTEMTIME st; + ::GetSystemTime(&st); + + m_startUSecs = st.wMilliseconds * 1000U; +#else + struct timeval tod; + ::gettimeofday(&tod, NULL); + + m_startSecs = tod.tv_sec; + m_startUSecs = tod.tv_usec; +#endif + unsigned char buffer[30U]; ::memset(buffer, 0x00U, 30U); buffer[0U] = 0x8AU; buffer[1U] = 0xCCU; - + buffer[2U] = 0x00U; buffer[3U] = 0x06U; buffer[4U] = (m_ssrc >> 24) & 0xFFU; buffer[5U] = (m_ssrc >> 16) & 0xFFU; - buffer[6U] = (m_ssrc >> 8) & 0xFFU; - buffer[7U] = (m_ssrc >> 0) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; buffer[8U] = 'K'; buffer[9U] = 'W'; buffer[10U] = 'N'; buffer[11U] = 'E'; + buffer[12U] = (m_startSecs >> 24) & 0xFFU; + buffer[13U] = (m_startSecs >> 16) & 0xFFU; + buffer[14U] = (m_startSecs >> 8) & 0xFFU; + buffer[15U] = (m_startSecs >> 0) & 0xFFU; + + buffer[16U] = (m_startUSecs >> 24) & 0xFFU; + buffer[17U] = (m_startUSecs >> 16) & 0xFFU; + buffer[18U] = (m_startUSecs >> 8) & 0xFFU; + buffer[19U] = (m_startUSecs >> 0) & 0xFFU; + buffer[22U] = 0x02U; buffer[24U] = 0x01U; - buffer[25U] = 0x01U; + + buffer[27U] = 0x0AU; if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); @@ -368,33 +429,84 @@ bool CKenwoodNetwork::writeRTCPPing() return m_rtcpSocket.write(buffer, 28U, m_address, RTCP_PORT); } -bool CKenwoodNetwork::writeRTCPData(unsigned char type, unsigned short src, unsigned short dst) +bool CKenwoodNetwork::writeRTCPPing() { - unsigned char buffer[20U]; - ::memset(buffer, 0x00U, 20U); + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); - buffer[0U] = 0x8BU; + buffer[0U] = 0x8AU; buffer[1U] = 0xCCU; - - buffer[3U] = 0x04U; + buffer[2U] = 0x00U; + buffer[3U] = 0x06U; buffer[4U] = (m_ssrc >> 24) & 0xFFU; buffer[5U] = (m_ssrc >> 16) & 0xFFU; - buffer[6U] = (m_ssrc >> 8) & 0xFFU; - buffer[7U] = (m_ssrc >> 0) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; buffer[8U] = 'K'; buffer[9U] = 'W'; buffer[10U] = 'N'; buffer[11U] = 'E'; - buffer[12U] = (src >> 8) & 0xFFU; - buffer[13U] = (src >> 0) & 0xFFU; + buffer[12U] = (m_startSecs >> 24) & 0xFFU; + buffer[13U] = (m_startSecs >> 16) & 0xFFU; + buffer[14U] = (m_startSecs >> 8) & 0xFFU; + buffer[15U] = (m_startSecs >> 0) & 0xFFU; - buffer[14U] = (dst >> 8) & 0xFFU; - buffer[15U] = (dst >> 0) & 0xFFU; + buffer[16U] = (m_startUSecs >> 24) & 0xFFU; + buffer[17U] = (m_startUSecs >> 16) & 0xFFU; + buffer[18U] = (m_startUSecs >> 8) & 0xFFU; + buffer[19U] = (m_startUSecs >> 0) & 0xFFU; - buffer[16U] = type; + buffer[22U] = 0x02U; + + buffer[24U] = 0x01U; + + buffer[27U] = 0x7BU; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); + + return m_rtcpSocket.write(buffer, 28U, m_address, RTCP_PORT); +} + +bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst) +{ + m_hangType = type; + m_hangSrc = src; + m_hangDst = dst; + + return writeRTCPHang(); +} + +bool CKenwoodNetwork::writeRTCPHang() +{ + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); + + buffer[0U] = 0x8BU; + buffer[1U] = 0xCCU; + buffer[2U] = 0x00U; + buffer[3U] = 0x04U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[12U] = (m_hangSrc >> 8) & 0xFFU; + buffer[13U] = (m_hangSrc >> 0) & 0xFFU; + + buffer[14U] = (m_hangDst >> 8) & 0xFFU; + buffer[15U] = (m_hangDst >> 0) & 0xFFU; + + buffer[16U] = m_hangType; if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U); @@ -409,26 +521,23 @@ unsigned int CKenwoodNetwork::read(unsigned char* data) unsigned char dummy[BUFFER_LENGTH]; readRTCP(dummy); - bool ret; - unsigned int len = readRTP(data); - if (len > 0U) { - switch (data[9U]) { - case 0x05U: // Voice header or trailer - ret = processKenwoodVoiceHeader(data); - if (!ret) - return 0U; - return 33U; - case 0x08U: // Voice data - processKenwoodVoiceData(data); - return 33U; - default: - break; - } + switch (len) { + case 0U: // Nothing received + return 0U; + case 35U: // Voice header or trailer + return processKenwoodVoiceHeader(data); + case 47U: // Voice data + if (m_headerSeen) + return processKenwoodVoiceData(data); + else + return processKenwoodVoiceLateEntry(data); + case 31U: // Data + return processKenwoodData(data); + default: + CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); + return 0U; } - - CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); - return 0U; } unsigned int CKenwoodNetwork::readRTP(unsigned char* data) @@ -444,19 +553,14 @@ unsigned int CKenwoodNetwork::readRTP(unsigned char* data) return 0U; // Check if the data is for us - if (m_address.s_addr != address.s_addr || port != RTP_PORT) { - LogMessage("Kenwood RTP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, RTP_PORT, port); + if (m_address.s_addr != address.s_addr) { + LogMessage("Kenwood RTP packet received from an invalid source, %08X != %08X", m_address.s_addr, address.s_addr); return 0U; } if (m_debug) CUtils::dump(1U, "Kenwood Network RTP Data Received", buffer, length); - if (length != 47 && length != 59) { - LogError("Invalid RTP length of %d", length); - return 0U; - } - ::memcpy(data, buffer + 12U, length - 12U); return length - 12U; @@ -475,19 +579,14 @@ unsigned int CKenwoodNetwork::readRTCP(unsigned char* data) return 0U; // Check if the data is for us - if (m_address.s_addr != address.s_addr || port != RTCP_PORT) { - LogMessage("Kenwood RTCP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, RTCP_PORT, port); + if (m_address.s_addr != address.s_addr) { + LogMessage("Kenwood RTCP packet received from an invalid source, %08X != %08X", m_address.s_addr, address.s_addr); return 0U; } if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Received", buffer, length); - if (length != 20 && length != 28) { - LogError("Invalid RTCP length of %d", length); - return 0U; - } - if (::memcmp(buffer + 8U, "KWNE", 4U) != 0) { LogError("Missing RTCP KWNE signature"); return 0U; @@ -508,14 +607,23 @@ void CKenwoodNetwork::close() void CKenwoodNetwork::clock(unsigned int ms) { - m_timer.clock(ms); - if (m_timer.isRunning() && m_timer.hasExpired()) { - writeRTCPPing(); - m_timer.start(); + m_rtcpTimer.clock(ms); + if (m_rtcpTimer.isRunning() && m_rtcpTimer.hasExpired()) { + if (m_hangTimer.isRunning()) + writeRTCPHang(); + else + writeRTCPPing(); + m_rtcpTimer.start(); + } + + m_hangTimer.clock(ms); + if (m_hangTimer.isRunning() && m_hangTimer.hasExpired()) { + m_rtcpTimer.stop(); + m_hangTimer.stop(); } } -bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) +unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) { assert(inData != NULL); @@ -552,15 +660,27 @@ bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) switch (outData[5U] & 0x3FU) { case 0x01U: + ::memcpy(inData, outData, 33U); + m_headerSeen = true; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; + return 33U; case 0x08U: ::memcpy(inData, outData, 33U); - return true; + m_headerSeen = false; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; + return 33U; default: - return false; + return 0U; } } -void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) +unsigned int CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) { assert(inData != NULL); @@ -642,4 +762,162 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) } ::memcpy(inData, outData, 33U); + + return 33U; +} + +unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData) +{ + if (inData[7U] != 0x09U && inData[7U] != 0x0BU && inData[7U] != 0x08U) + return 0U; + + unsigned char outData[50U]; + + if (inData[7U] == 0x09U || inData[7U] == 0x08U) { + outData[0U] = 0x90U; + outData[1U] = inData[8U]; + outData[2U] = inData[7U]; + outData[3U] = inData[10U]; + outData[4U] = inData[9U]; + outData[5U] = inData[12U]; + outData[6U] = inData[11U]; + ::memcpy(inData, outData, 7U); + return 7U; + } else { + outData[0U] = 0x90U; + outData[1U] = inData[8U]; + outData[2U] = inData[7U]; + outData[3U] = inData[10U]; + outData[4U] = inData[9U]; + outData[5U] = inData[12U]; + outData[6U] = inData[11U]; + outData[7U] = inData[14U]; + outData[8U] = inData[13U]; + outData[9U] = inData[16U]; + outData[10U] = inData[15U]; + outData[11U] = inData[18U]; + outData[12U] = inData[17U]; + outData[13U] = inData[20U]; + outData[14U] = inData[19U]; + outData[15U] = inData[22U]; + outData[16U] = inData[21U]; + outData[17U] = inData[24U]; + outData[18U] = inData[23U]; + outData[19U] = inData[26U]; + outData[20U] = inData[25U]; + outData[21U] = inData[28U]; + outData[22U] = inData[27U]; + outData[23U] = inData[29U]; + ::memcpy(inData, outData, 24U); + return 24U; + } +} + +unsigned long CKenwoodNetwork::getTimeStamp() const +{ + unsigned long timeStamp = 0UL; + +#if defined(_WIN32) || defined(_WIN64) + SYSTEMTIME st; + ::GetSystemTime(&st); + + unsigned int hh = st.wHour; + unsigned int mm = st.wMinute; + unsigned int ss = st.wSecond; + unsigned int ms = st.wMilliseconds; + + timeStamp += hh * 3600U * 1000U * 80U; + timeStamp += mm * 60U * 1000U * 80U; + timeStamp += ss * 1000U * 80U; + timeStamp += ms * 80U; +#else + struct timeval tod; + ::gettimeofday(&tod, NULL); + + unsigned int ss = tod.tv_sec; + unsigned int ms = tod.tv_usec / 1000U; + + timeStamp += ss * 1000U * 80U; + timeStamp += ms * 80U; +#endif + + return timeStamp; +} + +unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char sacch[4U]; + sacch[0U] = inData[12U]; + sacch[1U] = inData[11U]; + sacch[2U] = inData[14U]; + sacch[3U] = inData[13U]; + + switch (sacch[0U] & 0xC0U) { + case 0xC0U: + if (!m_seen1) { + unsigned int offset = 0U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen1 = true; + } + break; + case 0x80U: + if (!m_seen2) { + unsigned int offset = 18U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen2 = true; + } + break; + case 0x40U: + if (!m_seen3) { + unsigned int offset = 36U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen3 = true; + } + break; + case 0x00U: + if (!m_seen4) { + unsigned int offset = 54U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen4 = true; + } + break; + } + + if (!m_seen1 || !m_seen2 || !m_seen3 || !m_seen4) + return 0U; + + // Create a dummy header + // Header SACCH + inData[11U] = 0x10U; + inData[12U] = 0x01U; + inData[13U] = 0x00U; + inData[14U] = 0x00U; + + // Header FACCH + inData[15U] = m_sacch[1U]; + inData[16U] = m_sacch[0U]; + inData[17U] = m_sacch[3U]; + inData[18U] = m_sacch[2U]; + inData[19U] = m_sacch[5U]; + inData[20U] = m_sacch[4U]; + inData[21U] = m_sacch[7U]; + inData[22U] = m_sacch[6U]; + inData[23U] = 0x00U; + inData[24U] = m_sacch[8U]; + + return processKenwoodVoiceHeader(inData); } diff --git a/NXDNReflector/KenwoodNetwork.h b/NXDNReflector/KenwoodNetwork.h index 4c0ded9..0543efe 100644 --- a/NXDNReflector/KenwoodNetwork.h +++ b/NXDNReflector/KenwoodNetwork.h @@ -20,7 +20,6 @@ #define KenwoodNetwork_H #include "CoreNetwork.h" -#include "StopWatch.h" #include "UDPSocket.h" #include "Timer.h" @@ -45,25 +44,41 @@ public: private: CUDPSocket m_rtpSocket; CUDPSocket m_rtcpSocket; - CStopWatch m_stopWatch; in_addr m_address; - unsigned short m_seqNo; - unsigned long m_timeStamp; + bool m_headerSeen; + bool m_seen1; + bool m_seen2; + bool m_seen3; + bool m_seen4; + unsigned char* m_sacch; + uint8_t m_sessionId; + uint16_t m_seqNo; unsigned int m_ssrc; bool m_debug; - CTimer m_timer; + uint32_t m_startSecs; + uint32_t m_startUSecs; + CTimer m_rtcpTimer; + CTimer m_hangTimer; + unsigned char m_hangType; + unsigned short m_hangSrc; + unsigned short m_hangDst; bool processIcomVoiceHeader(const unsigned char* data); bool processIcomVoiceData(const unsigned char* data); - bool processKenwoodVoiceHeader(unsigned char* data); - void processKenwoodVoiceData(unsigned char* data); + unsigned int processKenwoodVoiceHeader(unsigned char* data); + unsigned int processKenwoodVoiceData(unsigned char* data); + unsigned int processKenwoodVoiceLateEntry(unsigned char* data); + unsigned int processKenwoodData(unsigned char* data); bool writeRTPVoiceHeader(const unsigned char* data); bool writeRTPVoiceData(const unsigned char* data); bool writeRTPVoiceTrailer(const unsigned char* data); + bool writeRTCPStart(); bool writeRTCPPing(); - bool writeRTCPData(unsigned char type, unsigned short src, unsigned short dst); + bool writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst); + bool writeRTCPHang(); unsigned int readRTP(unsigned char* data); unsigned int readRTCP(unsigned char* data); + unsigned long getTimeStamp() const; }; #endif diff --git a/NXDNReflector/UDPSocket.cpp b/NXDNReflector/UDPSocket.cpp index 396f1f7..d651ab8 100644 --- a/NXDNReflector/UDPSocket.cpp +++ b/NXDNReflector/UDPSocket.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2006-2016,2020 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 @@ -260,3 +260,31 @@ void CUDPSocket::close() ::close(m_fd); #endif } + +unsigned long CUDPSocket::getLocalAddress() const +{ + unsigned long address = 0UL; + + char hostname[80U]; + int ret = ::gethostname(hostname, 80); + if (ret == -1) + return 0UL; + + struct hostent* phe = ::gethostbyname(hostname); + if (phe == NULL) + return 0UL; + + if (phe->h_addrtype != AF_INET) + return 0UL; + + for (unsigned int i = 0U; phe->h_addr_list[i] != NULL; i++) { + struct in_addr addr; + ::memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); + if (addr.s_addr != INADDR_LOOPBACK) { + address = addr.s_addr; + break; + } + } + + return address; +} diff --git a/NXDNReflector/UDPSocket.h b/NXDNReflector/UDPSocket.h index e0af272..4c21a43 100644 --- a/NXDNReflector/UDPSocket.h +++ b/NXDNReflector/UDPSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2011,2013,2015,2016,2020 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 @@ -47,7 +47,9 @@ public: void close(); - static in_addr lookup(const std::string& hostName); + unsigned long getLocalAddress() const; + + static in_addr lookup(const std::string& hostName); private: std::string m_address; diff --git a/NXDNReflector/Version.h b/NXDNReflector/Version.h index 301ae35..0a67dd6 100644 --- a/NXDNReflector/Version.h +++ b/NXDNReflector/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200420"; +const char* VERSION = "20200427"; #endif From 51b2158736192fcac7e0ab975f15e832e71357d3 Mon Sep 17 00:00:00 2001 From: sp4feu <56378304+sp4feu@users.noreply.github.com> Date: Tue, 2 Jun 2020 10:24:24 +0200 Subject: [PATCH 69/70] Update NXDNHosts.txt --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 06208ca..887bbf1 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -8,6 +8,9 @@ # RED NXDN SPAIN 214 nxdn214.xreflector.es 41400 +# HBLink Poland ,TG260 +260 nxdn.hblink.pl 41400 + # 302, P25 Canada 302 p25canada.hopto.org 41400 From bd431e614958bd1b377aaa4e8843add3c008dd62 Mon Sep 17 00:00:00 2001 From: Jeffrey <2723529+JeffreyKopcak@users.noreply.github.com> Date: Thu, 4 Jun 2020 23:02:58 -0400 Subject: [PATCH 70/70] Added TG31983 - K8JTK Hub --- NXDNGateway/NXDNHosts.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NXDNGateway/NXDNHosts.txt b/NXDNGateway/NXDNHosts.txt index 887bbf1..cb16ad1 100644 --- a/NXDNGateway/NXDNHosts.txt +++ b/NXDNGateway/NXDNHosts.txt @@ -175,6 +175,9 @@ # DX-LINK SYSTEM, 31777 31777 8.9.4.102 41400 +# K8JTK Hub Multimode ILS/DVMIS (K8JTK.org), 31983 +31983 NXDNReflector31983.K8JTK.org 41400 + # CW-Ops Academy, NXDN Reflector 32103 32103 cwops.dyndns.org 41400