From 26243c024775a14aa2311f24c5b74b168207c57d Mon Sep 17 00:00:00 2001 From: m0vse Date: Mon, 25 May 2020 20:29:49 +0100 Subject: [PATCH 1/7] Update RemoteCommand to disable/enable network modes --- MMDVMHost.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 40f954c..d344409 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -1997,22 +1997,32 @@ void CMMDVMHost::remoteControl() case RCD_ENABLE_DSTAR: if (m_dstar != NULL && m_dstarEnabled==false) processEnableCommand(m_dstarEnabled, true); + if (m_dstarNetwork != NULL) + m_dstarNetwork->enable(true); break; case RCD_ENABLE_DMR: if (m_dmr != NULL && m_dmrEnabled==false) processEnableCommand(m_dmrEnabled, true); + if (m_dmrNetwork != NULL) + m_dmrNetwork->enable(true); break; case RCD_ENABLE_YSF: if (m_ysf != NULL && m_ysfEnabled==false) processEnableCommand(m_ysfEnabled, true); + if (m_ysfNetwork != NULL) + m_ysfNetwork->enable(true); break; case RCD_ENABLE_P25: if (m_p25 != NULL && m_p25Enabled==false) processEnableCommand(m_p25Enabled, true); + if (m_p25Network != NULL) + m_p25Network->enable(true); break; case RCD_ENABLE_NXDN: if (m_nxdn != NULL && m_nxdnEnabled==false) processEnableCommand(m_nxdnEnabled, true); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(true); break; case RCD_ENABLE_FM: if (m_fmEnabled==false) @@ -2021,22 +2031,32 @@ void CMMDVMHost::remoteControl() case RCD_DISABLE_DSTAR: if (m_dstar != NULL && m_dstarEnabled==true) processEnableCommand(m_dstarEnabled, false); + if (m_dstarNetwork != NULL) + m_dstarNetwork->enable(false); break; case RCD_DISABLE_DMR: if (m_dmr != NULL && m_dmrEnabled==true) processEnableCommand(m_dmrEnabled, false); + if (m_dmrNetwork != NULL) + m_dmrNetwork->enable(false); break; case RCD_DISABLE_YSF: if (m_ysf != NULL && m_ysfEnabled==true) processEnableCommand(m_ysfEnabled, false); + if (m_ysfNetwork != NULL) + m_ysfNetwork->enable(false); break; case RCD_DISABLE_P25: if (m_p25 != NULL && m_p25Enabled==true) processEnableCommand(m_p25Enabled, false); + if (m_p25Network != NULL) + m_p25Network->enable(false); break; case RCD_DISABLE_NXDN: if (m_nxdn != NULL && m_nxdnEnabled==true) processEnableCommand(m_nxdnEnabled, false); + if (m_nxdnNetwork != NULL) + m_nxdnNetwork->enable(false); break; case RCD_DISABLE_FM: if (m_fmEnabled == true) From 45eafe3672025b7285fd6b4adec95835f6af29e2 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 27 May 2020 11:38:46 +0100 Subject: [PATCH 2/7] Start adding the Kenwood protocol as an option. --- MMDVM.ini | 1 + MMDVMHost.h | 2 +- MMDVMHost.vcxproj | 4 + MMDVMHost.vcxproj.filters | 12 + Makefile | 9 +- Makefile.Pi | 9 +- Makefile.Pi.Adafruit | 9 +- Makefile.Pi.HD44780 | 9 +- Makefile.Pi.OLED | 9 +- Makefile.Pi.PCF8574 | 9 +- Makefile.Solaris | 9 +- NXDNIcomNetwork.cpp | 169 +++++++ NXDNIcomNetwork.h | 59 +++ NXDNKenwoodNetwork.cpp | 924 ++++++++++++++++++++++++++++++++++++++ NXDNKenwoodNetwork.h | 86 ++++ NXDNNetwork.cpp | 150 +------ NXDNNetwork.h | 31 +- 17 files changed, 1303 insertions(+), 198 deletions(-) create mode 100644 NXDNIcomNetwork.cpp create mode 100644 NXDNIcomNetwork.h create mode 100644 NXDNKenwoodNetwork.cpp create mode 100644 NXDNKenwoodNetwork.h diff --git a/MMDVM.ini b/MMDVM.ini index 12f2b73..9b02e83 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -215,6 +215,7 @@ Debug=0 [NXDN Network] Enable=1 +Protocol=Icom LocalAddress=127.0.0.1 LocalPort=14021 GatewayAddress=127.0.0.1 diff --git a/MMDVMHost.h b/MMDVMHost.h index 17d6786..6b1e078 100644 --- a/MMDVMHost.h +++ b/MMDVMHost.h @@ -66,7 +66,7 @@ private: CDMRNetwork* m_dmrNetwork; CYSFNetwork* m_ysfNetwork; CP25Network* m_p25Network; - CNXDNNetwork* m_nxdnNetwork; + INXDNNetwork* m_nxdnNetwork; CPOCSAGNetwork* m_pocsagNetwork; CDisplay* m_display; CUMP* m_ump; diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 812c7a4..44b50f2 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -203,6 +203,8 @@ + + @@ -297,6 +299,8 @@ + + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index fb8a362..01fcd3f 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -299,6 +299,12 @@ Header Files + + Header Files + + + Header Files + @@ -562,5 +568,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index efdaba6..33cc689 100644 --- a/Makefile +++ b/Makefile @@ -10,10 +10,11 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o \ - NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o \ - POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o \ - TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \ + NXDNKenwoodNetwork.oNXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \ + P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ + SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o \ + YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi b/Makefile.Pi index 640c07f..d9c1acd 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -10,10 +10,11 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o \ - UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 24c2907..a9c0b35 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -11,10 +11,11 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index c2faad2..a0127af 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -10,10 +10,11 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index d2db40c..5629489 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -10,10 +10,11 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o OLED.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 4c5d3a3..cd6b67f 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -11,10 +11,11 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ - NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o \ - NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o \ - POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o \ - Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o \ + NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ + P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o \ + SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/Makefile.Solaris b/Makefile.Solaris index c50d41e..4d46985 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -10,10 +10,11 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o CASTInfo.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ - NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o \ - NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o \ - QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o \ - UMP.o UserDB.o UserDBebtry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o + NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o NXDNKenwoodNetwork.o NXDNLayer3.o \ + NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o \ + P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o \ + StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBebtry.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \ + YSFNetwork.o YSFPayload.o all: MMDVMHost RemoteCommand diff --git a/NXDNIcomNetwork.cpp b/NXDNIcomNetwork.cpp new file mode 100644 index 0000000..2f3767b --- /dev/null +++ b/NXDNIcomNetwork.cpp @@ -0,0 +1,169 @@ +/* + * 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 "NXDNIcomNetwork.h" +#include "NXDNDefines.h" +#include "Defines.h" +#include "Utils.h" +#include "Log.h" + +#include +#include +#include + +const unsigned int BUFFER_LENGTH = 200U; + +CNXDNIcomNetwork::CNXDNIcomNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : +m_socket(localAddress, localPort), +m_address(), +m_port(gatewayPort), +m_debug(debug), +m_enabled(false), +m_buffer(1000U, "NXDN Network") +{ + assert(gatewayPort > 0U); + assert(!gatewayAddress.empty()); + + m_address = CUDPSocket::lookup(gatewayAddress); +} + +CNXDNIcomNetwork::~CNXDNIcomNetwork() +{ +} + +bool CNXDNIcomNetwork::open() +{ + LogMessage("Opening NXDN network connection"); + + if (m_address.s_addr == INADDR_NONE) + return false; + + return m_socket.open(); +} + +bool CNXDNIcomNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type) +{ + assert(data != NULL); + + unsigned char buffer[110U]; + ::memset(buffer, 0x00U, 110U); + + buffer[0U] = 'I'; + buffer[1U] = 'C'; + buffer[2U] = 'O'; + buffer[3U] = 'M'; + buffer[4U] = 0x01U; + buffer[5U] = 0x01U; + buffer[6U] = 0x08U; + buffer[7U] = 0xE0U; + + switch (type) { + case NNMT_VOICE_HEADER: + case NNMT_VOICE_TRAILER: + buffer[37U] = 0x23U; + buffer[38U] = 0x1CU; + buffer[39U] = 0x21U; + break; + case NNMT_VOICE_BODY: + buffer[37U] = 0x23U; + buffer[38U] = 0x10U; + buffer[39U] = 0x21U; + break; + case NNMT_DATA_HEADER: + case NNMT_DATA_BODY: + case NNMT_DATA_TRAILER: + buffer[37U] = 0x23U; + buffer[38U] = 0x02U; + buffer[39U] = 0x18U; + break; + default: + return false; + } + + ::memcpy(buffer + 40U, data, 33U); + + if (m_debug) + CUtils::dump(1U, "NXDN Network Data Sent", buffer, 102U); + + return m_socket.write(buffer, 102U, m_address, m_port); +} + +void CNXDNIcomNetwork::clock(unsigned int ms) +{ + 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; + + // Check if the data is for us + if (m_address.s_addr != address.s_addr || port != m_port) { + LogMessage("NXDN packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port); + return; + } + + // Invalid packet type? + if (::memcmp(buffer, "ICOM", 4U) != 0) + return; + + if (length != 102) + return; + + if (!m_enabled) + return; + + if (m_debug) + CUtils::dump(1U, "NXDN Network Data Received", buffer, length); + + m_buffer.addData(buffer + 40U, 33U); +} + +bool CNXDNIcomNetwork::read(unsigned char* data) +{ + assert(data != NULL); + + if (m_buffer.isEmpty()) + return false; + + m_buffer.getData(data, 33U); + + return true; +} + +void CNXDNIcomNetwork::reset() +{ +} + +void CNXDNIcomNetwork::close() +{ + m_socket.close(); + + LogMessage("Closing NXDN network connection"); +} + +void CNXDNIcomNetwork::enable(bool enabled) +{ + if (enabled && !m_enabled) + reset(); + else if (!enabled && m_enabled) + m_buffer.clear(); + + m_enabled = enabled; +} diff --git a/NXDNIcomNetwork.h b/NXDNIcomNetwork.h new file mode 100644 index 0000000..05fb023 --- /dev/null +++ b/NXDNIcomNetwork.h @@ -0,0 +1,59 @@ +/* + * 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 NXDNIcomNetwork_H +#define NXDNIcomNetwork_H + +#include "NXDNNetwork.h" +#include "NXDNDefines.h" +#include "RingBuffer.h" +#include "UDPSocket.h" +#include "Timer.h" + +#include +#include + +class CNXDNIcomNetwork : public INXDNNetwork { +public: + CNXDNIcomNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug); + virtual ~CNXDNIcomNetwork(); + + virtual bool open(); + + virtual void enable(bool enabled); + + virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type); + + virtual bool read(unsigned char* data); + + virtual void reset(); + + virtual void close(); + + virtual void clock(unsigned int ms); + +private: + CUDPSocket m_socket; + in_addr m_address; + unsigned int m_port; + bool m_debug; + bool m_enabled; + CRingBuffer m_buffer; +}; + +#endif diff --git a/NXDNKenwoodNetwork.cpp b/NXDNKenwoodNetwork.cpp new file mode 100644 index 0000000..c5a4a20 --- /dev/null +++ b/NXDNKenwoodNetwork.cpp @@ -0,0 +1,924 @@ +/* + * 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 +#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_rtpSocket(localPort + 0U), +m_rtcpSocket(localPort + 1U), +m_address(), +m_rtcpPort(rptPort + 1U), +m_rtpPort(rptPort + 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), +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(localPort > 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() +{ + 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 = m_rtpSocket.getLocalAddress(); + + 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_hangTimer.stop(); + m_rtcpTimer.start(); + writeRTCPStart(); + return writeRTPVoiceHeader(outData); + case 0x08U: { + m_hangTimer.start(); + bool ret = writeRTPVoiceTrailer(outData); + writeRTCPHang(type, src, dst); + return ret; + } + 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; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 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; + + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + 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; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 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; + 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; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 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] = 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::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[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[27U] = 0x0AU; + + 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::writeRTCPPing() +{ + 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_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[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) +{ + 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); + + return m_rtcpSocket.write(buffer, 20U, m_address, m_rtcpPort); +} + +unsigned int CKenwoodNetwork::read(unsigned char* data) +{ + assert(data != NULL); + + unsigned char dummy[BUFFER_LENGTH]; + readRTCP(dummy); + + unsigned int len = readRTP(data); + 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; + } +} + +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) { + 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); + + ::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) { + 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 (::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_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(); + } +} + +unsigned int 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: + ::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); + m_headerSeen = false; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; + return 33U; + default: + return 0U; + } +} + +unsigned int 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); + + 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/NXDNKenwoodNetwork.h b/NXDNKenwoodNetwork.h new file mode 100644 index 0000000..aa52d64 --- /dev/null +++ b/NXDNKenwoodNetwork.h @@ -0,0 +1,86 @@ +/* + * 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 "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 unsigned int read(unsigned char* data); + + virtual void close(); + + virtual void clock(unsigned int ms); + +private: + CUDPSocket m_rtpSocket; + CUDPSocket m_rtcpSocket; + 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; + bool m_debug; + 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); + 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 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/NXDNNetwork.cpp b/NXDNNetwork.cpp index 9e26900..0f55011 100644 --- a/NXDNNetwork.cpp +++ b/NXDNNetwork.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2018,2019 by Jonathan Naylor G4KLX + * Copyright (C) 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,154 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "NXDNDefines.h" #include "NXDNNetwork.h" -#include "Defines.h" -#include "Utils.h" -#include "Log.h" -#include -#include -#include - -const unsigned int BUFFER_LENGTH = 200U; - -CNXDNNetwork::CNXDNNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) : -m_socket(localAddress, localPort), -m_address(), -m_port(gatewayPort), -m_debug(debug), -m_enabled(false), -m_buffer(1000U, "NXDN Network") -{ - assert(gatewayPort > 0U); - assert(!gatewayAddress.empty()); - - m_address = CUDPSocket::lookup(gatewayAddress); -} - -CNXDNNetwork::~CNXDNNetwork() +INXDNNetwork::~INXDNNetwork() { } - -bool CNXDNNetwork::open() -{ - LogMessage("Opening NXDN network connection"); - - if (m_address.s_addr == INADDR_NONE) - return false; - - return m_socket.open(); -} - -bool CNXDNNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type) -{ - assert(data != NULL); - - unsigned char buffer[110U]; - ::memset(buffer, 0x00U, 110U); - - buffer[0U] = 'I'; - buffer[1U] = 'C'; - buffer[2U] = 'O'; - buffer[3U] = 'M'; - buffer[4U] = 0x01U; - buffer[5U] = 0x01U; - buffer[6U] = 0x08U; - buffer[7U] = 0xE0U; - - switch (type) { - case NNMT_VOICE_HEADER: - case NNMT_VOICE_TRAILER: - buffer[37U] = 0x23U; - buffer[38U] = 0x1CU; - buffer[39U] = 0x21U; - break; - case NNMT_VOICE_BODY: - buffer[37U] = 0x23U; - buffer[38U] = 0x10U; - buffer[39U] = 0x21U; - break; - case NNMT_DATA_HEADER: - case NNMT_DATA_BODY: - case NNMT_DATA_TRAILER: - buffer[37U] = 0x23U; - buffer[38U] = 0x02U; - buffer[39U] = 0x18U; - break; - default: - return false; - } - - ::memcpy(buffer + 40U, data, 33U); - - if (m_debug) - CUtils::dump(1U, "NXDN Network Data Sent", buffer, 102U); - - return m_socket.write(buffer, 102U, m_address, m_port); -} - -void CNXDNNetwork::clock(unsigned int ms) -{ - 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; - - // Check if the data is for us - if (m_address.s_addr != address.s_addr || port != m_port) { - LogMessage("NXDN packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port); - return; - } - - // Invalid packet type? - if (::memcmp(buffer, "ICOM", 4U) != 0) - return; - - if (length != 102) - return; - - if (!m_enabled) - return; - - if (m_debug) - CUtils::dump(1U, "NXDN Network Data Received", buffer, length); - - m_buffer.addData(buffer + 40U, 33U); -} - -bool CNXDNNetwork::read(unsigned char* data) -{ - assert(data != NULL); - - if (m_buffer.isEmpty()) - return false; - - m_buffer.getData(data, 33U); - - return true; -} - -void CNXDNNetwork::reset() -{ -} - -void CNXDNNetwork::close() -{ - m_socket.close(); - - LogMessage("Closing NXDN network connection"); -} - -void CNXDNNetwork::enable(bool enabled) -{ - if (enabled && !m_enabled) - reset(); - else if (!enabled && m_enabled) - m_buffer.clear(); - - m_enabled = enabled; -} diff --git a/NXDNNetwork.h b/NXDNNetwork.h index 3a5b784..564196b 100644 --- a/NXDNNetwork.h +++ b/NXDNNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX + * Copyright (C) 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 @@ -20,12 +20,8 @@ #define NXDNNetwork_H #include "NXDNDefines.h" -#include "RingBuffer.h" -#include "UDPSocket.h" -#include "Timer.h" #include -#include enum NXDN_NETWORK_MESSAGE_TYPE { NNMT_VOICE_HEADER, @@ -36,32 +32,25 @@ enum NXDN_NETWORK_MESSAGE_TYPE { NNMT_DATA_TRAILER }; -class CNXDNNetwork { +class INXDNNetwork { public: - CNXDNNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug); - ~CNXDNNetwork(); + virtual ~INXDNNetwork() = 0; - bool open(); + virtual bool open() = 0; - void enable(bool enabled); + virtual void enable(bool enabled) = 0; - bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type); + virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type) = 0; - bool read(unsigned char* data); + virtual bool read(unsigned char* data) = 0; - void reset(); + virtual void reset() = 0; - void close(); + virtual void close() = 0; - void clock(unsigned int ms); + virtual void clock(unsigned int ms) = 0; private: - CUDPSocket m_socket; - in_addr m_address; - unsigned int m_port; - bool m_debug; - bool m_enabled; - CRingBuffer m_buffer; }; #endif From 924baeacd1bf55dc77e33e766caf19a7a6f41008 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 27 May 2020 12:07:21 +0100 Subject: [PATCH 3/7] More work on integrating the Kenwood NXDN protocol. --- Conf.cpp | 8 ++++ Conf.h | 2 + MMDVMHost.cpp | 9 +++- NXDNControl.cpp | 4 +- NXDNControl.h | 6 +-- NXDNKenwoodNetwork.cpp | 101 ++++++++++++++++++++++------------------- NXDNKenwoodNetwork.h | 32 +++++++------ UDPSocket.cpp | 30 +++++++++++- UDPSocket.h | 6 ++- 9 files changed, 130 insertions(+), 68 deletions(-) diff --git a/Conf.cpp b/Conf.cpp index ee4034b..8d61b30 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -236,6 +236,7 @@ m_p25LocalPort(0U), m_p25NetworkModeHang(3U), m_p25NetworkDebug(false), m_nxdnNetworkEnabled(false), +m_nxdnNetworkProtocol("Icom"), m_nxdnGatewayAddress(), m_nxdnGatewayPort(0U), m_nxdnLocalAddress(), @@ -842,6 +843,8 @@ bool CConf::read() } else if (section == SECTION_NXDN_NETWORK) { if (::strcmp(key, "Enable") == 0) m_nxdnNetworkEnabled = ::atoi(value) == 1; + else if (::strcmp(key, "Protocol") == 0) + m_nxdnNetworkProtocol = value; else if (::strcmp(key, "LocalAddress") == 0) m_nxdnLocalAddress = value; else if (::strcmp(key, "LocalPort") == 0) @@ -1832,6 +1835,11 @@ bool CConf::getNXDNNetworkEnabled() const return m_nxdnNetworkEnabled; } +std::string CConf::getNXDNNetworkProtocol() const +{ + return m_nxdnNetworkProtocol; +} + std::string CConf::getNXDNGatewayAddress() const { return m_nxdnGatewayAddress; diff --git a/Conf.h b/Conf.h index 40e81a0..77cff6c 100644 --- a/Conf.h +++ b/Conf.h @@ -244,6 +244,7 @@ public: // The NXDN Network section bool getNXDNNetworkEnabled() const; + std::string getNXDNNetworkProtocol() const; std::string getNXDNGatewayAddress() const; unsigned int getNXDNGatewayPort() const; std::string getNXDNLocalAddress() const; @@ -509,6 +510,7 @@ private: bool m_p25NetworkDebug; bool m_nxdnNetworkEnabled; + std::string m_nxdnNetworkProtocol; std::string m_nxdnGatewayAddress; unsigned int m_nxdnGatewayPort; std::string m_nxdnLocalAddress; diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index d344409..3213959 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -17,6 +17,8 @@ */ #include "MMDVMHost.h" +#include "NXDNKenwoodNetwork.h" +#include "NXDNIcomNetwork.h" #include "RSSIInterpolator.h" #include "SerialController.h" #include "Version.h" @@ -1472,6 +1474,7 @@ bool CMMDVMHost::createP25Network() bool CMMDVMHost::createNXDNNetwork() { + std::string protocol = m_conf.getNXDNNetworkProtocol(); std::string gatewayAddress = m_conf.getNXDNGatewayAddress(); unsigned int gatewayPort = m_conf.getNXDNGatewayPort(); std::string localAddress = m_conf.getNXDNLocalAddress(); @@ -1480,13 +1483,17 @@ bool CMMDVMHost::createNXDNNetwork() bool debug = m_conf.getNXDNNetworkDebug(); LogInfo("NXDN Network Parameters"); + LogInfo(" Protocol: %s", protocol.c_str()); LogInfo(" Gateway Address: %s", gatewayAddress.c_str()); LogInfo(" Gateway Port: %u", gatewayPort); LogInfo(" Local Address: %s", localAddress.c_str()); LogInfo(" Local Port: %u", localPort); LogInfo(" Mode Hang: %us", m_nxdnNetModeHang); - m_nxdnNetwork = new CNXDNNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug); + if (protocol == "Kenwood") + m_nxdnNetwork = new CNXDNKenwoodNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug); + else + m_nxdnNetwork = new CNXDNIcomNetwork(localAddress, localPort, gatewayAddress, gatewayPort, debug); bool ret = m_nxdnNetwork->open(); if (!ret) { diff --git a/NXDNControl.cpp b/NXDNControl.cpp index 1f3fa4c..1e200c4 100644 --- a/NXDNControl.cpp +++ b/NXDNControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 Jonathan Naylor, G4KLX + * Copyright (C) 2015-2020 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 @@ -39,7 +39,7 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04 #define WRITE_BIT1(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_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) -CNXDNControl::CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, CNXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper) : +CNXDNControl::CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, INXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper) : m_ran(ran), m_id(id), m_selfOnly(selfOnly), diff --git a/NXDNControl.h b/NXDNControl.h index 5c441e2..af2fba1 100644 --- a/NXDNControl.h +++ b/NXDNControl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 by Jonathan Naylor G4KLX + * Copyright (C) 2015-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 @@ -36,7 +36,7 @@ class CNXDNControl { public: - CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, CNXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper); + CNXDNControl(unsigned int ran, unsigned int id, bool selfOnly, INXDNNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CNXDNLookup* lookup, CRSSIInterpolator* rssiMapper); ~CNXDNControl(); bool writeModem(unsigned char* data, unsigned int len); @@ -53,7 +53,7 @@ private: unsigned int m_ran; unsigned int m_id; bool m_selfOnly; - CNXDNNetwork* m_network; + INXDNNetwork* m_network; CDisplay* m_display; bool m_duplex; bool m_remoteGateway; diff --git a/NXDNKenwoodNetwork.cpp b/NXDNKenwoodNetwork.cpp index c5a4a20..e294d96 100644 --- a/NXDNKenwoodNetwork.cpp +++ b/NXDNKenwoodNetwork.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "KenwoodNetwork.h" +#include "NXDNKenwoodNetwork.h" #include "NXDNCRC.h" #include "Utils.h" #include "Log.h" @@ -33,12 +33,12 @@ 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_rtpSocket(localPort + 0U), -m_rtcpSocket(localPort + 1U), +CNXDNKenwoodNetwork::CNXDNKenwoodNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gwyAddress, unsigned int gwyPort, bool debug) : +m_rtpSocket(localAddress, localPort + 0U), +m_rtcpSocket(localAddress, localPort + 1U), m_address(), -m_rtcpPort(rptPort + 1U), -m_rtpPort(rptPort + 0U), +m_rtcpPort(gwyPort + 1U), +m_rtpPort(gwyPort + 0U), m_headerSeen(false), m_seen1(false), m_seen2(false), @@ -58,20 +58,20 @@ m_hangSrc(0U), m_hangDst(0U) { assert(localPort > 0U); - assert(!rptAddress.empty()); - assert(rptPort > 0U); + assert(!gwyAddress.empty()); + assert(gwyPort > 0U); m_sacch = new unsigned char[10U]; - m_address = CUDPSocket::lookup(rptAddress); + m_address = CUDPSocket::lookup(gwyAddress); } -CKenwoodNetwork::~CKenwoodNetwork() +CNXDNKenwoodNetwork::~CNXDNKenwoodNetwork() { delete[] m_sacch; } -bool CKenwoodNetwork::open() +bool CNXDNKenwoodNetwork::open() { LogMessage("Opening Kenwood connection"); @@ -91,23 +91,27 @@ bool CKenwoodNetwork::open() return true; } -bool CKenwoodNetwork::write(const unsigned char* data, unsigned int length) +bool CNXDNKenwoodNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type) { assert(data != NULL); - switch (data[0U]) { - case 0x81U: // Voice header or trailer - case 0x83U: + switch (type) { + case NNMT_VOICE_HEADER: // Voice header or trailer + case NNMT_VOICE_TRAILER: + case NNMT_DATA_TRAILER: // Data trailer return processIcomVoiceHeader(data); - case 0xACU: // Voice data - case 0xAEU: + case NNMT_VOICE_BODY: // Voice data return processIcomVoiceData(data); + case NNMT_DATA_HEADER: // Voice header or trailer + return processIcomDataHeader(data); + case NNMT_DATA_BODY: // Voice data + return processIcomDataData(data); default: return false; } } -bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) +bool CNXDNKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) { assert(inData != NULL); @@ -151,7 +155,7 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) } } -bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) +bool CNXDNKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) { assert(inData != NULL); @@ -231,7 +235,7 @@ bool CKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) return writeRTPVoiceData(outData); } -bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) +bool CNXDNKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) { assert(data != NULL); @@ -278,7 +282,7 @@ bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) return m_rtpSocket.write(buffer, 47U, m_address, m_rtpPort); } -bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) +bool CNXDNKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) { assert(data != NULL); @@ -324,7 +328,7 @@ bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) return m_rtpSocket.write(buffer, 47U, m_address, m_rtpPort); } -bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) +bool CNXDNKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) { assert(data != NULL); @@ -370,7 +374,7 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) return m_rtpSocket.write(buffer, 59U, m_address, m_rtpPort); } -bool CKenwoodNetwork::writeRTCPStart() +bool CNXDNKenwoodNetwork::writeRTCPStart() { #if defined(_WIN32) || defined(_WIN64) time_t now; @@ -430,7 +434,7 @@ bool CKenwoodNetwork::writeRTCPStart() return m_rtcpSocket.write(buffer, 28U, m_address, m_rtcpPort); } -bool CKenwoodNetwork::writeRTCPPing() +bool CNXDNKenwoodNetwork::writeRTCPPing() { unsigned char buffer[30U]; ::memset(buffer, 0x00U, 30U); @@ -472,7 +476,7 @@ bool CKenwoodNetwork::writeRTCPPing() return m_rtcpSocket.write(buffer, 28U, m_address, m_rtcpPort); } -bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst) +bool CNXDNKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst) { m_hangType = type; m_hangSrc = src; @@ -481,7 +485,7 @@ bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsi return writeRTCPHang(); } -bool CKenwoodNetwork::writeRTCPHang() +bool CNXDNKenwoodNetwork::writeRTCPHang() { unsigned char buffer[30U]; ::memset(buffer, 0x00U, 30U); @@ -515,7 +519,7 @@ bool CKenwoodNetwork::writeRTCPHang() return m_rtcpSocket.write(buffer, 20U, m_address, m_rtcpPort); } -unsigned int CKenwoodNetwork::read(unsigned char* data) +bool CNXDNKenwoodNetwork::read(unsigned char* data) { assert(data != NULL); @@ -525,7 +529,7 @@ unsigned int CKenwoodNetwork::read(unsigned char* data) unsigned int len = readRTP(data); switch (len) { case 0U: // Nothing received - return 0U; + return false; case 35U: // Voice header or trailer return processKenwoodVoiceHeader(data); case 47U: // Voice data @@ -537,11 +541,11 @@ unsigned int CKenwoodNetwork::read(unsigned char* data) return processKenwoodData(data); default: CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); - return 0U; + return false; } } -unsigned int CKenwoodNetwork::readRTP(unsigned char* data) +unsigned int CNXDNKenwoodNetwork::readRTP(unsigned char* data) { assert(data != NULL); @@ -567,7 +571,7 @@ unsigned int CKenwoodNetwork::readRTP(unsigned char* data) return length - 12U; } -unsigned int CKenwoodNetwork::readRTCP(unsigned char* data) +unsigned int CNXDNKenwoodNetwork::readRTCP(unsigned char* data) { assert(data != NULL); @@ -598,7 +602,11 @@ unsigned int CKenwoodNetwork::readRTCP(unsigned char* data) return length - 12U; } -void CKenwoodNetwork::close() +void CNXDNKenwoodNetwork::reset() +{ +} + +void CNXDNKenwoodNetwork::close() { m_rtcpSocket.close(); m_rtpSocket.close(); @@ -606,7 +614,7 @@ void CKenwoodNetwork::close() LogMessage("Closing Kenwood connection"); } -void CKenwoodNetwork::clock(unsigned int ms) +void CNXDNKenwoodNetwork::clock(unsigned int ms) { m_rtcpTimer.clock(ms); if (m_rtcpTimer.isRunning() && m_rtcpTimer.hasExpired()) { @@ -624,7 +632,7 @@ void CKenwoodNetwork::clock(unsigned int ms) } } -unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) +bool CNXDNKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) { assert(inData != NULL); @@ -667,7 +675,7 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) m_seen2 = false; m_seen3 = false; m_seen4 = false; - return 33U; + return true; case 0x08U: ::memcpy(inData, outData, 33U); m_headerSeen = false; @@ -675,13 +683,13 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) m_seen2 = false; m_seen3 = false; m_seen4 = false; - return 33U; + return true; default: - return 0U; + return false; } } -unsigned int CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) +bool CNXDNKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) { assert(inData != NULL); @@ -764,17 +772,18 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) ::memcpy(inData, outData, 33U); - return 33U; + return true; } -unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData) +bool CNXDNKenwoodNetwork::processKenwoodData(unsigned char* inData) { if (inData[7U] != 0x09U && inData[7U] != 0x0BU && inData[7U] != 0x08U) - return 0U; + return false; unsigned char outData[50U]; if (inData[7U] == 0x09U || inData[7U] == 0x08U) { + // XXX outData[0U] = 0x90U; outData[1U] = inData[8U]; outData[2U] = inData[7U]; @@ -783,7 +792,7 @@ unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData) outData[5U] = inData[12U]; outData[6U] = inData[11U]; ::memcpy(inData, outData, 7U); - return 7U; + return true; } else { outData[0U] = 0x90U; outData[1U] = inData[8U]; @@ -810,11 +819,11 @@ unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData) outData[22U] = inData[27U]; outData[23U] = inData[29U]; ::memcpy(inData, outData, 24U); - return 24U; + return true; } } -unsigned long CKenwoodNetwork::getTimeStamp() const +unsigned long CNXDNKenwoodNetwork::getTimeStamp() const { unsigned long timeStamp = 0UL; @@ -845,7 +854,7 @@ unsigned long CKenwoodNetwork::getTimeStamp() const return timeStamp; } -unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData) +bool CNXDNKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData) { assert(inData != NULL); @@ -899,7 +908,7 @@ unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData } if (!m_seen1 || !m_seen2 || !m_seen3 || !m_seen4) - return 0U; + return false; // Create a dummy header // Header SACCH diff --git a/NXDNKenwoodNetwork.h b/NXDNKenwoodNetwork.h index aa52d64..96da4f3 100644 --- a/NXDNKenwoodNetwork.h +++ b/NXDNKenwoodNetwork.h @@ -16,28 +16,32 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef KenwoodNetwork_H -#define KenwoodNetwork_H +#ifndef NXDNKenwoodNetwork_H +#define NXDNKenwoodNetwork_H -#include "RptNetwork.h" +#include "NXDNNetwork.h" #include "UDPSocket.h" #include "Timer.h" #include #include -class CKenwoodNetwork : public IRptNetwork { +class CNXDNKenwoodNetwork : public INXDNNetwork { public: - CKenwoodNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug); - virtual ~CKenwoodNetwork(); + CNXDNKenwoodNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gwyAddress, unsigned int gwyPort, bool debug); + virtual ~CNXDNKenwoodNetwork(); virtual bool open(); - virtual bool write(const unsigned char* data, unsigned int length); + virtual void enable(bool enabled); - virtual unsigned int read(unsigned char* data); + virtual bool write(const unsigned char* data, NXDN_NETWORK_MESSAGE_TYPE type); - virtual void close(); + virtual bool read(unsigned char* data); + + virtual void reset(); + + virtual void close(); virtual void clock(unsigned int ms); @@ -67,10 +71,12 @@ private: bool processIcomVoiceHeader(const unsigned char* data); bool processIcomVoiceData(const 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 processIcomDataHeader(const unsigned char* data); + bool processIcomDataData(const unsigned char* data); + bool processKenwoodVoiceHeader(unsigned char* data); + bool processKenwoodVoiceData(unsigned char* data); + bool processKenwoodVoiceLateEntry(unsigned char* data); + bool 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/UDPSocket.cpp b/UDPSocket.cpp index ba0e35f..2899faf 100644 --- a/UDPSocket.cpp +++ b/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 @@ -258,3 +258,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/UDPSocket.h b/UDPSocket.h index e0af272..4c21a43 100644 --- a/UDPSocket.h +++ b/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; From 0b7efee2a76eeed256118bcc9cf95f826274e592 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 27 May 2020 12:47:21 +0100 Subject: [PATCH 4/7] Upgrade the Kenwood protocol to pass data calls. --- NXDNKenwoodNetwork.cpp | 270 ++++++++++++++++++++++++++++++++++++++--- NXDNKenwoodNetwork.h | 5 + Version.h | 2 +- 3 files changed, 260 insertions(+), 17 deletions(-) diff --git a/NXDNKenwoodNetwork.cpp b/NXDNKenwoodNetwork.cpp index e294d96..8531f90 100644 --- a/NXDNKenwoodNetwork.cpp +++ b/NXDNKenwoodNetwork.cpp @@ -39,6 +39,7 @@ m_rtcpSocket(localAddress, localPort + 1U), m_address(), m_rtcpPort(gwyPort + 1U), m_rtpPort(gwyPort + 0U), +m_enabled(false), m_headerSeen(false), m_seen1(false), m_seen2(false), @@ -98,13 +99,13 @@ bool CNXDNKenwoodNetwork::write(const unsigned char* data, NXDN_NETWORK_MESSAGE_ switch (type) { case NNMT_VOICE_HEADER: // Voice header or trailer case NNMT_VOICE_TRAILER: - case NNMT_DATA_TRAILER: // Data trailer return processIcomVoiceHeader(data); case NNMT_VOICE_BODY: // Voice data return processIcomVoiceData(data); - case NNMT_DATA_HEADER: // Voice header or trailer + case NNMT_DATA_HEADER: // Data header or trailer + case NNMT_DATA_TRAILER: return processIcomDataHeader(data); - case NNMT_DATA_BODY: // Voice data + case NNMT_DATA_BODY: // Data data return processIcomDataData(data); default: return false; @@ -235,6 +236,83 @@ bool CNXDNKenwoodNetwork::processIcomVoiceData(const unsigned char* inData) return writeRTPVoiceData(outData); } +bool CNXDNKenwoodNetwork::processIcomDataHeader(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 0x09U: + m_hangTimer.stop(); + m_rtcpTimer.start(); + writeRTCPStart(); + return writeRTPDataHeader(outData); + case 0x08U: { + m_hangTimer.start(); + bool ret = writeRTPDataTrailer(outData); + writeRTCPHang(type, src, dst); + return ret; + } + default: + return false; + } +} + +bool CNXDNKenwoodNetwork::processIcomDataData(const unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char outData[40U]; + ::memset(outData, 0x00U, 40U); + + outData[0U] = inData[2U]; + outData[1U] = inData[1U]; + outData[2U] = inData[4U]; + outData[3U] = inData[3U]; + outData[4U] = inData[6U]; + outData[5U] = inData[5U]; + outData[6U] = inData[8U]; + outData[7U] = inData[7U]; + outData[8U] = inData[10U]; + outData[9U] = inData[9U]; + outData[10U] = inData[12U]; + outData[11U] = inData[11U]; + outData[12U] = inData[14U]; + outData[13U] = inData[13U]; + outData[14U] = inData[16U]; + outData[15U] = inData[15U]; + outData[16U] = inData[18U]; + outData[17U] = inData[17U]; + outData[18U] = inData[20U]; + outData[19U] = inData[19U]; + outData[20U] = inData[22U]; + outData[21U] = inData[21U]; + + return writeRTPDataData(outData); +} + bool CNXDNKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) { assert(data != NULL); @@ -252,11 +330,11 @@ bool CNXDNKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) 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[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; - buffer[8U] = (m_ssrc >> 24) & 0xFFU; - buffer[9U] = (m_ssrc >> 16) & 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; @@ -374,6 +452,132 @@ bool CNXDNKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) return m_rtpSocket.write(buffer, 59U, m_address, m_rtpPort); } +bool CNXDNKenwoodNetwork::writeRTPDataHeader(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 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; + + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + buffer[16U] = 0x01U; + buffer[17U] = 0x01U; + + ::memcpy(buffer + 18U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 42U); + + return m_rtpSocket.write(buffer, 42U, m_address, m_rtpPort); +} + +bool CNXDNKenwoodNetwork::writeRTPDataTrailer(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 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; + + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + buffer[16U] = 0x01U; + buffer[17U] = 0x06U; + + ::memcpy(buffer + 18U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 42U); + + return m_rtpSocket.write(buffer, 42U, m_address, m_rtpPort); +} + +bool CNXDNKenwoodNetwork::writeRTPDataData(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char buffer[50U]; + ::memset(buffer, 0x00U, 50U); + + buffer[0U] = 0x80U; + buffer[1U] = 0x66U; + + m_seqNo++; + buffer[2U] = (m_seqNo >> 8) & 0xFFU; + buffer[3U] = (m_seqNo >> 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; + + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; + buffer[16U] = 0x01U; + buffer[17U] = 0x01U; + + ::memcpy(buffer + 18U, data, 24U); + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTP Data Sent", buffer, 42U); + + return m_rtpSocket.write(buffer, 42U, m_address, m_rtpPort); +} + bool CNXDNKenwoodNetwork::writeRTCPStart() { #if defined(_WIN32) || defined(_WIN64) @@ -563,6 +767,9 @@ unsigned int CNXDNKenwoodNetwork::readRTP(unsigned char* data) return 0U; } + if (!m_enabled) + return 0U; + if (m_debug) CUtils::dump(1U, "Kenwood Network RTP Data Received", buffer, length); @@ -589,6 +796,9 @@ unsigned int CNXDNKenwoodNetwork::readRTCP(unsigned char* data) return 0U; } + if (!m_enabled) + return 0U; + if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Received", buffer, length); @@ -604,6 +814,14 @@ unsigned int CNXDNKenwoodNetwork::readRTCP(unsigned char* data) void CNXDNKenwoodNetwork::reset() { + m_rtcpTimer.stop(); + m_hangTimer.stop(); + + m_headerSeen = false; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; } void CNXDNKenwoodNetwork::close() @@ -783,15 +1001,27 @@ bool CNXDNKenwoodNetwork::processKenwoodData(unsigned char* inData) unsigned char outData[50U]; if (inData[7U] == 0x09U || inData[7U] == 0x08U) { - // XXX - 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); + 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]; + ::memcpy(inData, outData, 20U); return true; } else { outData[0U] = 0x90U; @@ -931,3 +1161,11 @@ bool CNXDNKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData) return processKenwoodVoiceHeader(inData); } + +void CNXDNKenwoodNetwork::enable(bool enabled) +{ + if (enabled && !m_enabled) + reset(); + + m_enabled = enabled; +} diff --git a/NXDNKenwoodNetwork.h b/NXDNKenwoodNetwork.h index 96da4f3..e0c1099 100644 --- a/NXDNKenwoodNetwork.h +++ b/NXDNKenwoodNetwork.h @@ -51,6 +51,7 @@ private: in_addr m_address; unsigned int m_rtcpPort; unsigned int m_rtpPort; + bool m_enabled; bool m_headerSeen; bool m_seen1; bool m_seen2; @@ -73,6 +74,7 @@ private: bool processIcomVoiceData(const unsigned char* data); bool processIcomDataHeader(const unsigned char* data); bool processIcomDataData(const unsigned char* data); + bool processIcomDataTrailer(const unsigned char* data); bool processKenwoodVoiceHeader(unsigned char* data); bool processKenwoodVoiceData(unsigned char* data); bool processKenwoodVoiceLateEntry(unsigned char* data); @@ -80,6 +82,9 @@ private: bool writeRTPVoiceHeader(const unsigned char* data); bool writeRTPVoiceData(const unsigned char* data); bool writeRTPVoiceTrailer(const unsigned char* data); + bool writeRTPDataHeader(const unsigned char* data); + bool writeRTPDataData(const unsigned char* data); + bool writeRTPDataTrailer(const unsigned char* data); bool writeRTCPStart(); bool writeRTCPPing(); bool writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst); diff --git a/Version.h b/Version.h index 19a3d8e..fe64411 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200518"; +const char* VERSION = "20200527"; #endif From 7bfe2f2b2fbe532e68962000f4b09a4632db13ff Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 27 May 2020 12:52:15 +0100 Subject: [PATCH 5/7] Fix Linux compile. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 33cc689..e14f51c 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ OBJECTS = \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTA.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ DStarSlowData.o Golay2087.o Golay24128.o Hamming.o I2CController.o LCDproc.o Log.o MMDVMHost.o MobileGPS.o Modem.o ModemSerialPort.o Mutex.o \ NetworkInfo.o Nextion.o NullDisplay.o NullModem.o NXDNAudio.o NXDNControl.o NXDNConvolution.o NXDNCRC.o NXDNFACCH1.o NXDNIcomNetwork.o \ - NXDNKenwoodNetwork.oNXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \ + NXDNKenwoodNetwork.o NXDNLayer3.o NXDNLICH.o NXDNLookup.o NXDNNetwork.o NXDNSACCH.o NXDNUDCH.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o \ P25Network.o P25NID.o P25Trellis.o P25Utils.o POCSAGControl.o POCSAGNetwork.o QR1676.o RemoteControl.o RS129.o RS241213.o RSSIInterpolator.o \ SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o TFTSurenoo.o Thread.o Timer.o UDPSocket.o UMP.o UserDB.o UserDBentry.o Utils.o \ YSFControl.o YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o From 36a852b38bc07e2cbec783440617c03f82258bcd Mon Sep 17 00:00:00 2001 From: SASANO Takayoshi Date: Sun, 14 Jun 2020 16:00:20 +0900 Subject: [PATCH 6/7] change ScreenLayout definition for Nextion to add new feature easily, the definition of ScreenLayout in [Nextion] has changed like this. ScreenLayout < 8: compatibile setting for old config file 0: G4KLX @ 9600bps 1: (reserved) 2: ON7LDS @ 9600bps 3: ON7LDS-DIY @ 9600bps 4: ON7LDS-DIY @ 115200bps ScreenLayout >= 8: new world, set the bit to enable each feature bit3 (8) use 115200bps bit4 (16) Display DMR Talker Alias bit5 (32) Colour change when displaying TA bit6 (64) Font size change when displaying long TA text bit7 (128) Display DIY status when MMDVM IDLE old settings are same as: 0 -> 0 2 -> 112 (16+32+64) 3 -> 144 (16+128) 4 -> 152 (8+16+128) --- Display.cpp | 2 +- Nextion.cpp | 106 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 76 insertions(+), 32 deletions(-) diff --git a/Display.cpp b/Display.cpp index 0b47b64..d0e6fd0 100644 --- a/Display.cpp +++ b/Display.cpp @@ -566,7 +566,7 @@ CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem) } } else { SERIAL_SPEED baudrate = SERIAL_9600; - if (screenLayout==4U) + if (screenLayout&0x0cU) baudrate = SERIAL_115200; LogInfo(" Display baudrate: %u ",baudrate); diff --git a/Nextion.cpp b/Nextion.cpp index f15d6cf..adb8e76 100644 --- a/Nextion.cpp +++ b/Nextion.cpp @@ -38,6 +38,16 @@ const unsigned int P25_BER_COUNT = 7U; // 7 * 180ms = 1260ms const unsigned int NXDN_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms const unsigned int NXDN_BER_COUNT = 28U; // 28 * 40ms = 1120ms +#define LAYOUT_COMPAT_MASK (7 << 0) // compatibility for old setting +#define LAYOUT_TA_ENABLE (1 << 4) // enable Talker Alias (TA) display +#define LAYOUT_TA_COLOUR (1 << 5) // TA display with font colour change +#define LAYOUT_TA_FONTSIZE (1 << 6) // TA display with font size change +#define LAYOUT_DIY (1 << 7) // use ON7LDS-DIY layout + +// bit[3:2] is used in Display.cpp to set connection speed for LCD panel. +// 00:low, others:high-speed. bit[2] is overlapped with LAYOUT_COMPAT_MASK. +#define LAYOUT_HIGHSPEED (3 << 2) + CNextion::CNextion(const std::string& callsign, unsigned int dmrid, ISerialPort* serial, unsigned int brightness, bool displayClock, bool utc, unsigned int idleBrightness, unsigned int screenLayout, unsigned int txFrequency, unsigned int rxFrequency, bool displayTempInF, const std::string& location) : CDisplay(), m_callsign(callsign), @@ -49,7 +59,7 @@ m_mode(MODE_IDLE), m_displayClock(displayClock), m_utc(utc), m_idleBrightness(idleBrightness), -m_screenLayout(screenLayout), +m_screenLayout(0), m_clockDisplayTimer(1000U, 0U, 400U), m_rssiAccum1(0U), m_rssiAccum2(0U), @@ -68,6 +78,23 @@ m_location(location) { assert(serial != NULL); assert(brightness >= 0U && brightness <= 100U); + + static const unsigned int feature_set[] = { + 0, // 0: G4KLX + 0, // 1: (reserved, low speed) + // 2: ON7LDS + LAYOUT_TA_ENABLE | LAYOUT_TA_COLOUR | LAYOUT_TA_FONTSIZE, + LAYOUT_TA_ENABLE | LAYOUT_DIY, // 3: ON7LDS-DIY + LAYOUT_TA_ENABLE | LAYOUT_DIY, // 4: ON7LDS-DIY (high speed) + 0, // 5: (reserved, high speed) + 0, // 6: (reserved, high speed) + 0, // 7: (reserved, high speed) + }; + + if (screenLayout & ~LAYOUT_COMPAT_MASK) + m_screenLayout = screenLayout & ~LAYOUT_COMPAT_MASK; + else + m_screenLayout = feature_set[screenLayout]; } CNextion::~CNextion() @@ -118,7 +145,7 @@ void CNextion::setIdleInt() ::sprintf(command, "t0.txt=\"%s/%u\"", m_callsign.c_str(), m_dmrid); sendCommand(command); - if (m_screenLayout > 2U) { + if (m_screenLayout & LAYOUT_DIY) { ::sprintf(command, "t4.txt=\"%s\"", m_callsign.c_str()); sendCommand(command); ::sprintf(command, "t5.txt=\"%u\"", m_dmrid); @@ -350,17 +377,21 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro if (slotNo == 1U) { - if (m_screenLayout == 2U) { - sendCommand("t2.pco=0"); - sendCommand("t2.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t2.font=4"); } sendCommand("t2.txt=\"2 Listening\""); sendCommandAction(69U); } else { - if (m_screenLayout == 2U) { - sendCommand("t0.pco=0"); - sendCommand("t0.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t0.font=4"); } sendCommand("t0.txt=\"1 Listening\""); @@ -377,9 +408,11 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro if (slotNo == 1U) { ::sprintf(text, "t0.txt=\"1 %s %s\"", type, src.c_str()); - if (m_screenLayout == 2U) { - sendCommand("t0.pco=0"); - sendCommand("t0.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t0.font=4"); } sendCommand(text); @@ -391,9 +424,11 @@ void CNextion::writeDMRInt(unsigned int slotNo, const std::string& src, bool gro } else { ::sprintf(text, "t2.txt=\"2 %s %s\"", type, src.c_str()); - if (m_screenLayout == 2U) { - sendCommand("t2.pco=0"); - sendCommand("t2.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t2.font=4"); } sendCommand(text); @@ -448,15 +483,17 @@ void CNextion::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi) void CNextion::writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type) { - if (m_screenLayout < 2U) + if (!(m_screenLayout & LAYOUT_TA_ENABLE)) return; if (type[0] == ' ') { if (slotNo == 1U) { - if (m_screenLayout == 2U) sendCommand("t0.pco=33808"); + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=33808"); sendCommandAction(64U); } else { - if (m_screenLayout == 2U) sendCommand("t2.pco=33808"); + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=33808"); sendCommandAction(72U); } @@ -467,33 +504,36 @@ void CNextion::writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, co char text[50U]; ::sprintf(text, "t0.txt=\"1 %s %s\"", type, talkerAlias); - if (m_screenLayout == 2U) { + if (m_screenLayout & LAYOUT_TA_FONTSIZE) { if (::strlen((char*)talkerAlias) > (16U-4U)) sendCommand("t0.font=3"); if (::strlen((char*)talkerAlias) > (20U-4U)) sendCommand("t0.font=2"); if (::strlen((char*)talkerAlias) > (24U-4U)) sendCommand("t0.font=1"); - - sendCommand("t0.pco=1024"); } + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=1024"); + sendCommand(text); sendCommandAction(63U); } else { char text[50U]; ::sprintf(text, "t2.txt=\"2 %s %s\"", type, talkerAlias); - if (m_screenLayout == 2U) { + if (m_screenLayout & LAYOUT_TA_FONTSIZE) { if (::strlen((char*)talkerAlias) > (16U-4U)) sendCommand("t2.font=3"); if (::strlen((char*)talkerAlias) > (20U-4U)) sendCommand("t2.font=2"); if (::strlen((char*)talkerAlias) > (24U-4U)) sendCommand("t2.font=1"); - - sendCommand("t2.pco=1024"); } + + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=1024"); + sendCommand(text); sendCommandAction(71U); } @@ -535,9 +575,11 @@ void CNextion::clearDMRInt(unsigned int slotNo) sendCommand("t0.txt=\"1 Listening\""); sendCommandAction(61U); - if (m_screenLayout == 2U) { - sendCommand("t0.pco=0"); - sendCommand("t0.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t0.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t0.font=4"); } sendCommand("t1.txt=\"\""); @@ -547,9 +589,11 @@ void CNextion::clearDMRInt(unsigned int slotNo) sendCommand("t2.txt=\"2 Listening\""); sendCommandAction(69U); - if (m_screenLayout == 2U) { - sendCommand("t2.pco=0"); - sendCommand("t2.font=4"); + if (m_screenLayout & LAYOUT_TA_ENABLE) { + if (m_screenLayout & LAYOUT_TA_COLOUR) + sendCommand("t2.pco=0"); + if (m_screenLayout & LAYOUT_TA_FONTSIZE) + sendCommand("t2.font=4"); } sendCommand("t3.txt=\"\""); @@ -862,7 +906,7 @@ void CNextion::close() void CNextion::sendCommandAction(unsigned int status) { - if (m_screenLayout<3U) + if (!(m_screenLayout & LAYOUT_DIY)) return; char text[30U]; @@ -881,4 +925,4 @@ void CNextion::sendCommand(const char* command) // we must add a bit of a delay to allow the display to process the commands, else some are getting mangled. // 10 ms is just a guess, but seems to be sufficient. CThread::sleep(10U); - } +} From 3313fe8ec3528f107172855a240a8d7839e881cf Mon Sep 17 00:00:00 2001 From: Andy Taylor Date: Mon, 15 Jun 2020 17:00:37 +0100 Subject: [PATCH 7/7] Update OLED.cpp Modify the OLED code to only allow scroll commands when scrolling is enabled --- OLED.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/OLED.cpp b/OLED.cpp index 6f9b4ec..02afc2d 100644 --- a/OLED.cpp +++ b/OLED.cpp @@ -240,7 +240,8 @@ void COLED::setIdleInt() // m_display.print("Idle"); // m_display.setTextSize(1); - m_display.startscrolldiagright(0x00,0x0f); //the MMDVM logo scrolls the whole screen + if (m_displayScroll && m_displayLogoScreensaver) + m_display.startscrolldiagright(0x00,0x0f); //the MMDVM logo scrolls the whole screen m_display.display(); unsigned char info[100U]; @@ -568,7 +569,8 @@ void COLED::writeCWInt() m_display.setTextSize(1); m_display.display(); - m_display.startscrollright(0x02,0x0f); + if (m_displayScroll) + m_display.startscrollright(0x02,0x0f); } void COLED::clearCWInt() @@ -581,14 +583,16 @@ void COLED::clearCWInt() m_display.setTextSize(1); m_display.display(); - m_display.startscrollleft(0x02,0x0f); + if (m_displayScroll) + m_display.startscrollleft(0x02,0x0f); } void COLED::close() { m_display.clearDisplay(); m_display.fillRect(0, 0, m_display.width(), 16, BLACK); - m_display.startscrollright(0x00,0x01); + if (m_displayScroll) + m_display.startscrollright(0x00,0x01); m_display.setCursor(0,00); m_display.setTextSize(2); m_display.print("-CLOSE-");