diff --git a/Config.cpp b/Config.cpp
index ad03176..f660aaa 100644
--- a/Config.cpp
+++ b/Config.cpp
@@ -54,6 +54,7 @@ extern int CWIDLeft;
 extern int CWIDRight;
 extern int CWIDType;
 extern bool afterTraffic;
+extern bool darkTheme;
 
 extern "C" int RSID_SABM[4];
 extern "C" int RSID_UI[4];
@@ -115,6 +116,7 @@ void GetPortSettings(int Chan)
 
 	fx25_mode[Chan] = getAX25Param("FX25", FX25_MODE_RX).toInt();
 	il2p_mode[Chan] = getAX25Param("IL2P", IL2P_MODE_NONE).toInt();
+	il2p_crc[Chan] = getAX25Param("IL2PCRC", 0).toInt();
 	RSID_UI[Chan] = getAX25Param("RSID_UI", 0).toInt();
 	RSID_SABM[Chan] = getAX25Param("RSID_SABM", 0).toInt();
 	RSID_SetModem[Chan] = getAX25Param("RSID_SetModem", 0).toInt();
@@ -303,6 +305,8 @@ void getSettings()
 
 	}
 
+	darkTheme = settings->value("Init/darkTheme", false).toBool();
+
 	delete(settings);
 }
 
@@ -347,6 +351,7 @@ void SavePortSettings(int Chan)
 	saveAX25Param("MyDigiCall", MyDigiCall[Chan]);
 	saveAX25Param("FX25", fx25_mode[Chan]);
 	saveAX25Param("IL2P", il2p_mode[Chan]);
+	saveAX25Param("IL2PCRC", il2p_crc[Chan]);
 	saveAX25Param("RSID_UI", RSID_UI[Chan]);
 	saveAX25Param("RSID_SABM", RSID_SABM[Chan]);
 	saveAX25Param("RSID_SetModem", RSID_SetModem[Chan]);
@@ -463,6 +468,8 @@ void saveSettings()
 	settings->setValue("Modem/CWIDType", CWIDType);
 	settings->setValue("Modem/afterTraffic", afterTraffic);
 
+	settings->setValue("Init/darkTheme", darkTheme);
+
 	saveAX25Params(0);
 	saveAX25Params(1);
 	saveAX25Params(2);
diff --git a/ModemDialog.ui b/ModemDialog.ui
index e8f7903..9b5b856 100644
--- a/ModemDialog.ui
+++ b/ModemDialog.ui
@@ -737,6 +737,19 @@
          Retries
         
        
+       
+        
+         
+          200
+          280
+          53
+          21
+         
+        
+        
+         CRC
+        
+       
       
      
     
@@ -1445,6 +1458,19 @@
          
         
        
+       
+        
+         
+          200
+          280
+          53
+          21
+         
+        
+        
+         CRC
+        
+       
       
       
        
@@ -2202,6 +2228,19 @@
          
         
        
+       
+        
+         
+          200
+          280
+          53
+          21
+         
+        
+        
+         CRC
+        
+       
       
       
        
@@ -2956,6 +2995,19 @@
          
         
        
+       
+        
+         
+          200
+          280
+          53
+          21
+         
+        
+        
+         CRC
+        
+       
       
       
        
@@ -3041,6 +3093,9 @@
       
        Save
       
+      
+       true
+      
      
     
     - 
diff --git a/QtSoundModem-DESKTOP-MHE5LO8.vcxproj b/QtSoundModem-DESKTOP-MHE5LO8.vcxproj
deleted file mode 100644
index adcd4b6..0000000
--- a/QtSoundModem-DESKTOP-MHE5LO8.vcxproj
+++ /dev/null
@@ -1,292 +0,0 @@
-
-
-  
-    
-      Release
-      Win32
-    
-    
-      Debug
-      Win32
-    
-  
-  
-    {4EDE958E-D0AC-37B4-81F7-78313A262DCD}
-    QtSoundModem
-    QtVS_v304
-    10.0.17763.0
-    10.0.19041.0
-    $(MSBuildProjectDirectory)\QtMsBuild
-  
-  
-  
-    v141
-    release\
-    false
-    NotSet
-    Application
-    release\
-    QtSoundModem
-  
-  
-    v141
-    debug\
-    false
-    NotSet
-    Application
-    debug\
-    QtSoundModem
-  
-  
-  
-    
-  
-  
-  
-    
-  
-  
-    
-  
-  
-  
-    
-  
-  
-    $(SolutionDir)$(Platform)\$(Configuration)\
-    $(SolutionDir)Intermed\$(Platform)\$(Configuration)\
-    QtSoundModem
-    true
-    true
-  
-  
-    $(SolutionDir)$(Platform)\$(Configuration)\
-    $(SolutionDir)Intermed\$(Platform)\$(Configuration)\\
-    QtSoundModem
-    true
-    false
-  
-  
-    5.14
-    core;network;gui;widgets;serialport
-  
-  
-    5.14.2
-    core;network;gui;widgets;serialport
-  
-  
-    
-  
-  
-    
-      rsid;.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;release;/include;%(AdditionalIncludeDirectories)
-      -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)
-      $(IntDir)
-      false
-      None
-      4577;4467;%(DisableSpecificWarnings)
-      Sync
-      $(IntDir)
-      MaxSpeed
-      _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)
-      false
-      $(OutDir)
-      MultiThreadedDLL
-      true
-      true
-      Level3
-      true
-    
-    
-      libfftw3f-3.lib;shell32.lib;setupapi.lib;WS2_32.Lib;%(AdditionalDependencies)
-      C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories)
-      "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
-      true
-      false
-      true
-      false
-      true
-      $(OutDir)QtSoundModem.exe
-      true
-      Windows
-      true
-    
-    
-      Unsigned
-      None
-      0
-    
-    
-      _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)
-    
-    
-      msvc
-      ./$(Configuration)/moc_predefs.h
-      Moc'ing %(Identity)...
-      output
-      $(IntDir)
-      moc_%(Filename).cpp
-    
-    
-      QtSoundModem
-      default
-      Rcc'ing %(Identity)...
-      $(IntDir)
-      qrc_%(Filename).cpp
-    
-    
-      Uic'ing %(Identity)...
-      $(IntDir)
-      ui_%(Filename).h
-    
-  
-  
-    
-      .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;debug;/include;rsid;%(AdditionalIncludeDirectories)
-      -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)
-      $(IntDir)
-      false
-      EditAndContinue
-      4577;4467;%(DisableSpecificWarnings)
-      Sync
-      $(IntDir)
-      Disabled
-      _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;%(PreprocessorDefinitions)
-      false
-      MultiThreadedDebugDLL
-      true
-      true
-      Level3
-      true
-      $(OutDir)
-    
-    
-      libfftw3f-3.lib;shell32.lib;setupapi.lib;WS2_32.Lib;%(AdditionalDependencies)
-      C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories)
-      "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
-      true
-      true
-      true
-      $(OutDir)\QtSoundModem.exe
-      true
-      Windows
-      true
-      false
-    
-    
-      Unsigned
-      None
-      0
-    
-    
-      _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)
-    
-    
-      msvc
-      ./$(Configuration)/moc_predefs.h
-      Moc'ing %(Identity)...
-      output
-      $(IntDir)
-      moc_%(Filename).cpp
-    
-    
-      QtSoundModem
-      default
-      Rcc'ing %(Identity)...
-      $(IntDir)
-      qrc_%(Filename).cpp
-    
-    
-      Uic'ing %(Identity)...
-      $(IntDir)
-      ui_%(Filename).h
-    
-  
-  
-    
-    
-    
-    
-    
-    
-      CompileAsC
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-  
-  
-    
-    
-    
-    
-    
-  
-  
-    
-      Document
-      true
-      $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)
-      cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h
-      Generate moc_predefs.h
-      debug\moc_predefs.h;%(Outputs)
-    
-    
-      Document
-      $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)
-      cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h
-      Generate moc_predefs.h
-      release\moc_predefs.h;%(Outputs)
-      true
-    
-  
-  
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-  
-  
-    
-    
-  
-  
-    
-  
-  
-    
-  
-  
-  
-    
-  
-  
-
\ No newline at end of file
diff --git a/QtSoundModem-HPLaptop.vcxproj b/QtSoundModem-HPLaptop.vcxproj
deleted file mode 100644
index 3b99dd0..0000000
--- a/QtSoundModem-HPLaptop.vcxproj
+++ /dev/null
@@ -1,288 +0,0 @@
-
-
-  
-    
-      Release
-      Win32
-    
-    
-      Debug
-      Win32
-    
-  
-  
-    {4EDE958E-D0AC-37B4-81F7-78313A262DCD}
-    QtSoundModem
-    QtVS_v304
-    10.0.19041.0
-    10.0.19041.0
-    $(MSBuildProjectDirectory)\QtMsBuild
-  
-  
-  
-    v141
-    release\
-    false
-    NotSet
-    Application
-    release\
-    QtSoundModem
-  
-  
-    v141
-    debug\
-    false
-    NotSet
-    Application
-    debug\
-    QtSoundModem
-  
-  
-  
-    
-  
-  
-  
-    
-  
-  
-    
-  
-  
-  
-    
-  
-  
-    C:\Dev\Msdev2005\projects\QT\QtSoundModem\Win32\Debug\
-    C:\Dev\Msdev2005\projects\QT\QtSoundModem\Intermed\Win32\Debug\
-    QtSoundModem
-    true
-    true
-  
-  
-    C:\Dev\Msdev2005\projects\QT\QtSoundModem\Win32\Release\
-    C:\Dev\Msdev2005\projects\QT\QtSoundModem\Intermed\Win32\Release\
-    QtSoundModem
-    true
-    false
-  
-  
-    5.14.2_msvc2017
-    core;network;gui;widgets;serialport
-  
-  
-    5.14.2_msvc2017
-    core;network;gui;widgets;serialport
-  
-  
-    
-  
-  
-    
-      rsid;.\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;release;/include;%(AdditionalIncludeDirectories)
-      -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)
-      $(IntDir)
-      false
-      None
-      4577;4467;%(DisableSpecificWarnings)
-      Sync
-      $(IntDir)
-      MaxSpeed
-      _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions)
-      false
-      $(OutDir)
-      MultiThreadedDLL
-      true
-      true
-      Level3
-      true
-    
-    
-      libfftw3f-3.lib;shell32.lib;setupapi.lib;WS2_32.Lib;%(AdditionalDependencies)
-      C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories)
-      "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
-      true
-      false
-      true
-      false
-      true
-      $(OutDir)\QtSoundModem.exe
-      true
-      Windows
-      true
-    
-    
-      Unsigned
-      None
-      0
-    
-    
-      _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;%(PreprocessorDefinitions)
-    
-    
-      msvc
-      ./$(Configuration)/moc_predefs.h
-      Moc'ing %(Identity)...
-      output
-      $(IntDir)
-      moc_%(Filename).cpp
-    
-    
-      QtSoundModem
-      default
-      Rcc'ing %(Identity)...
-      $(IntDir)
-      qrc_%(Filename).cpp
-    
-    
-      Uic'ing %(Identity)...
-      $(IntDir)
-      ui_%(Filename).h
-    
-  
-  
-    
-      .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;debug;/include;rsid;%(AdditionalIncludeDirectories)
-      -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions)
-      $(IntDir)
-      false
-      EditAndContinue
-      4577;4467;%(DisableSpecificWarnings)
-      Sync
-      $(IntDir)
-      Disabled
-      _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;%(PreprocessorDefinitions)
-      false
-      MultiThreadedDebugDLL
-      true
-      true
-      Level3
-      true
-      $(OutDir)
-    
-    
-      libfftw3f-3.lib;shell32.lib;setupapi.lib;WS2_32.Lib;%(AdditionalDependencies)
-      C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories)
-      "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
-      true
-      true
-      true
-      $(OutDir)\QtSoundModem.exe
-      true
-      Windows
-      true
-      false
-    
-    
-      Unsigned
-      None
-      0
-    
-    
-      _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions)
-    
-    
-      msvc
-      ./$(Configuration)/moc_predefs.h
-      Moc'ing %(Identity)...
-      output
-      $(IntDir)
-      moc_%(Filename).cpp
-    
-    
-      QtSoundModem
-      default
-      Rcc'ing %(Identity)...
-      $(IntDir)
-      qrc_%(Filename).cpp
-    
-    
-      Uic'ing %(Identity)...
-      $(IntDir)
-      ui_%(Filename).h
-    
-  
-  
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-  
-  
-    
-    
-    
-    
-    
-  
-  
-    
-      Document
-      true
-      $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)
-      cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h
-      Generate moc_predefs.h
-      debug\moc_predefs.h;%(Outputs)
-    
-    
-      Document
-      $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs)
-      cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h
-      Generate moc_predefs.h
-      release\moc_predefs.h;%(Outputs)
-      true
-    
-  
-  
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-  
-  
-    
-    
-  
-  
-    
-  
-  
-    
-  
-  
-  
-    
-  
-  
-
\ No newline at end of file
diff --git a/QtSoundModem.cpp b/QtSoundModem.cpp
index cadb3fb..976ca95 100644
--- a/QtSoundModem.cpp
+++ b/QtSoundModem.cpp
@@ -51,17 +51,18 @@ along with QtSoundModem.  If not, see http://www.gnu.org/licenses
 
 
 QImage *Constellation[4];
-QImage *Waterfall[4] = { 0,0,0,0 };
-QImage *Header[4];
+QImage *Waterfall = 0;
 QLabel *DCDLabel[4];
 QLineEdit *chanOffsetLabel[4];
 QImage *DCDLed[4];
 
 QImage *RXLevel;
+QImage *RXLevel2;
+
+QLabel *WaterfallCopy;
 
-QLabel *WaterfallCopy[2];
-QLabel *HeaderCopy[2];
 QLabel * RXLevelCopy;
+QLabel * RXLevel2Copy;
 
 QTextEdit * monWindowCopy;
 
@@ -73,6 +74,8 @@ QList Ports = QSerialPortInfo::availablePorts();
 
 void saveSettings();
 void getSettings();
+void DrawModemFreqRange();
+
 extern "C" void CloseSound();
 extern "C" void GetSoundDevices();
 extern "C" char modes_name[modes_count][21];
@@ -120,11 +123,10 @@ extern "C"
 	int Freq_Change(int Chan, int Freq);
 	void set_speed(int snd_ch, int Modem);
 	void init_speed(int snd_ch);
-	void wf_pointer(int snd_ch);
 	void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform);
 	void dofft(short * in, float * outr, float * outi);
 	void init_raduga();
-	void wf_Scale(int Chan);
+	void DrawFreqTicks();
 	void AGW_Report_Modem_Change(int port);
 	char * strlop(char * buf, char delim);
 	void sendRSID(int Chan, int dropTX);
@@ -157,7 +159,10 @@ int WaterfallMin = 00;
 int WaterfallMax = 6000;
 
 int Configuring = 0;
+bool lockWaterfall = false;
+bool inWaterfall = false;
 
+extern "C" int NeedWaterfallHeaders;
 extern "C" float BinSize;
 
 extern "C" { int RSID_SABM[4]; }
@@ -175,6 +180,12 @@ QRgb red = qRgb(255, 0, 0);
 QRgb yellow = qRgb(255, 255, 0);
 QRgb cyan = qRgb(0, 255, 255);
 
+QRgb txText = qRgb(192, 0, 0);
+QRgb rxText = qRgb(0, 0, 192);
+
+bool darkTheme = true;
+bool minimizeonStart = true;
+
 // Indexed colour list from ARDOPC
 
 #define WHITE 0
@@ -198,7 +209,7 @@ QRgb vbColours[16] = { qRgb(255, 255, 255), qRgb(255, 99, 71), qRgb(255, 215, 0)
 						qRgb(218, 165, 32), qRgb(255, 0, 255) };
 
 unsigned char  WaterfallLines[2][80][4096] = { 0 };
-int NextWaterfallLine[2] = { 0 };
+int NextWaterfallLine[2] = {0, 0};
 
 unsigned int LastLevel = 255;
 unsigned int LastBusy = 255;
@@ -307,8 +318,20 @@ void QtSoundModem::resizeEvent(QResizeEvent* event)
 
 	QRect r = geometry();
 
-	int A, B, C, W;
-	int modemBoxHeight = 30;
+	QRect r1 = ui.monWindow->geometry();
+	QRect r2 = ui.centralWidget->geometry();
+
+	int modemBoxHeight = 34;
+	
+	int Width = r.width();
+	int Height = r.height() - 25;
+
+	int monitorTop;
+	int monitorHeight;
+	int sessionTop;
+	int sessionHeight = 0;
+	int waterfallsTop;
+	int waterfallsHeight = WaterfallImageHeight;
 
 	ui.modeB->setVisible(soundChannel[1]);
 	ui.centerB->setVisible(soundChannel[1]);
@@ -331,78 +354,46 @@ void QtSoundModem::resizeEvent(QResizeEvent* event)
 	if (soundChannel[2] || soundChannel[3])
 		modemBoxHeight = 60;
 
+	ui.Waterfall->setVisible(0);
 
-	A = r.height() - 25;   // No waterfalls
+	monitorTop = modemBoxHeight + 1;
 
-	if (UsingBothChannels && Secondwaterfall)
+	// Now have one waterfall label containing headers and waterfalls
+
+		if (Firstwaterfall || Secondwaterfall)
+			ui.Waterfall->setVisible(1);
+
+	if (AGWServ)
 	{
-		// Two waterfalls
-
-		ui.WaterfallA->setVisible(1);
-		ui.HeaderA->setVisible(1);
-		ui.WaterfallB->setVisible(1);
-		ui.HeaderB->setVisible(1);
-
-		A = r.height() - 258;   // Top of Waterfall A
-		B = A + 115;			// Top of Waterfall B
+		sessionTable->setVisible(true);
+		sessionHeight = 150;
 	}
 	else
 	{
-		// One waterfall
-
-		// Could be Left or Right
-
-		if (Firstwaterfall)
-		{
-			if (soundChannel[0] == RIGHT)
-			{
-				ui.WaterfallA->setVisible(0);
-				ui.HeaderA->setVisible(0);
-				ui.WaterfallB->setVisible(1);
-				ui.HeaderB->setVisible(1);
-			}
-			else
-			{
-				ui.WaterfallA->setVisible(1);
-				ui.HeaderA->setVisible(1);
-				ui.WaterfallB->setVisible(0);
-				ui.HeaderB->setVisible(0);
-			}
-
-			A = r.height() - 145;   // Top of Waterfall A
-		}
-		else
-			A = r.height() - 25;   // Top of Waterfall A
+		sessionTable->setVisible(false);
 	}
 
-	C = A - 150;			// Bottom of Monitor, Top of connection list
-	W = r.width();
+	// if only displaying one Waterfall, change height of waterfall area
 
-	// Calc Positions of Waterfalls
-
-	ui.monWindow->setGeometry(QRect(0, modemBoxHeight, W, C - (modemBoxHeight + 26)));
-	sessionTable->setGeometry(QRect(0, C, W, 175));
-
-	if (UsingBothChannels)
+	if (UsingBothChannels == 0  || (Firstwaterfall == 0) || (Secondwaterfall == 0))
 	{
-		ui.HeaderA->setGeometry(QRect(0, A, W, 38));
-		ui.WaterfallA->setGeometry(QRect(0, A + 38, W, 80));
-		ui.HeaderB->setGeometry(QRect(0, B, W, 38));
-		ui.WaterfallB->setGeometry(QRect(0, B + 38, W, 80));
-	}
-	else
-	{
-		if (soundChannel[0] == RIGHT)
-		{
-			ui.HeaderB->setGeometry(QRect(0, A, W, 38));
-			ui.WaterfallB->setGeometry(QRect(0, A + 38, W, 80));
-		}
-		else
-		{
-			ui.HeaderA->setGeometry(QRect(0, A, W, 38));
-			ui.WaterfallA->setGeometry(QRect(0, A + 38, W, 80));
-		}
+		waterfallsHeight /= 2;
 	}
+
+	if ((Firstwaterfall == 0) && (Secondwaterfall == 0))
+		waterfallsHeight = 0;
+
+	monitorHeight = Height - sessionHeight - waterfallsHeight - modemBoxHeight;
+	waterfallsTop = Height - waterfallsHeight;
+	sessionTop = Height - (sessionHeight + waterfallsHeight);
+
+	ui.monWindow->setGeometry(QRect(0, monitorTop, Width, monitorHeight));
+
+	if (AGWServ)
+		sessionTable->setGeometry(QRect(0, sessionTop, Width, sessionHeight));
+
+	if (waterfallsHeight)
+		ui.Waterfall->setGeometry(QRect(0, waterfallsTop, Width, waterfallsHeight + 2));
 }
 
 QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State)
@@ -426,50 +417,40 @@ void QtSoundModem::menuChecked()
 	int state = Act->isChecked();
 
 	if (Act == actWaterfall1)
-	{
-		int oldstate = Firstwaterfall;
 		Firstwaterfall = state;
 
-		if (state != oldstate)
-			initWaterfall(0, state);
-
-	}
 	else if (Act == actWaterfall2)
-	{
-		int oldstate = Secondwaterfall;
 		Secondwaterfall = state;
 
-		if (state != oldstate)
-			initWaterfall(1, state);
+	initWaterfall(Firstwaterfall | Secondwaterfall);
 
-	}
 	saveSettings();
 }
 
-void QtSoundModem::initWaterfall(int chan, int state)
+void QtSoundModem::initWaterfall(int state)
 {
 	if (state == 1)
 	{
-		if (chan == 0)
-		{
-			ui.WaterfallA = new QLabel(ui.centralWidget);
-			WaterfallCopy[0] = ui.WaterfallA;
-		}
-		else
-		{
-			ui.WaterfallB = new QLabel(ui.centralWidget);
-			WaterfallCopy[1] = ui.WaterfallB;
-		}
-		Waterfall[chan] = new QImage(1024, 80, QImage::Format_RGB32);
-		Waterfall[chan]->fill(black);
+	//	if (ui.Waterfall)
+	//	{
+	//		delete ui.Waterfall;
+	//		ui.Waterfall = new QLabel(ui.centralWidget);
+	//	}
+		WaterfallCopy = ui.Waterfall;
+
+		Waterfall = new QImage(1024, WaterfallImageHeight + 2, QImage::Format_RGB32);
+
+		NeedWaterfallHeaders = 1;
+
 	}
 	else
 	{
-		delete(Waterfall[chan]);
-		Waterfall[chan] = 0;
+		delete(Waterfall);
+		Waterfall = 0;
 	}
 
 	QSize Size(800, 602);						// Not actually used, but Event constructor needs it
+
 	QResizeEvent *event = new QResizeEvent(Size, Size);
 	QApplication::sendEvent(this, event);
 }
@@ -518,7 +499,7 @@ void DoPSKWindows()
 	constellationDialog->resize(NextX, 140);
 }
 
-
+QTimer *wftimer;
 
 QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
 {
@@ -530,6 +511,8 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
 
 	mythis = this;
 
+	getSettings();
+
 	QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat);
 
 	family = mysettings.value("FontFamily", "Courier New").toString();
@@ -606,7 +589,7 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
 	restoreGeometry(mysettings.value("geometry").toByteArray());
 	restoreState(mysettings.value("windowState").toByteArray());
 
-	sessionTable = new QTableWidget(this);
+	sessionTable = new QTableWidget(ui.centralWidget);
 
 	sessionTable->verticalHeader()->setVisible(FALSE);
 	sessionTable->verticalHeader()->setDefaultSectionSize(20);
@@ -615,7 +598,7 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
 	sessionTable->setColumnCount(12);
 	m_TableHeader << "MyCall" << "DestCall" << "Status" << "Sent pkts" << "Sent Bytes" << "Rcvd pkts" << "Rcvd bytes" << "Rcvd FC" << "FEC corr" << "CPS TX" << "CPS RX" << "Direction";
 
-	sessionTable->setStyleSheet("QHeaderView::section { background-color:rgb(224, 224, 224) }");
+	mysetstyle();
 
 	sessionTable->setHorizontalHeaderLabels(m_TableHeader);
 	sessionTable->setColumnWidth(0, 80);
@@ -672,14 +655,11 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
 	actAbout = ui.menuBar->addAction("&About");
 	connect(actAbout, SIGNAL(triggered()), this, SLOT(doAbout()));
 
-	Header[0] = new QImage(1024, 38, QImage::Format_RGB32);
-	Header[1] = new QImage(1024, 38, QImage::Format_RGB32);
 	RXLevel = new QImage(150, 10, QImage::Format_RGB32);
 	RXLevel->fill(white);
 	ui.RXLevel->setPixmap(QPixmap::fromImage(*RXLevel));
 	RXLevelCopy = ui.RXLevel;
 
-
 	DCDLabel[0] = new QLabel(this);
 	DCDLabel[0]->setObjectName(QString::fromUtf8("DCDLedA"));
 	DCDLabel[0]->setGeometry(QRect(280, 31, 12, 12));
@@ -720,42 +700,16 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
 	chanOffsetLabel[2] = ui.RXOffsetC;
 	chanOffsetLabel[3] = ui.RXOffsetD;
 
+	WaterfallCopy = ui.Waterfall;
 
-	//	Waterfall[0]->setColorCount(16);
-	//	Waterfall[1]->setColorCount(16);
+	initWaterfall(Firstwaterfall | Secondwaterfall);
 
-
-	//	for (i = 0; i < 16; i++)
-	//	{
-	//	Waterfall[0]->setColor(i, vbColours[i]);
-	//		Waterfall[1]->setColor(i, vbColours[i]);
-	//	}
-
-	WaterfallCopy[0] = ui.WaterfallA;
-	WaterfallCopy[1] = ui.WaterfallB;
-
-	initWaterfall(0, 1);
-	initWaterfall(1, 1);
-
-	Header[0]->fill(black);
-	Header[1]->fill(black);
-
-	HeaderCopy[0] = ui.HeaderA;
-	HeaderCopy[1] = ui.HeaderB;
 	monWindowCopy = ui.monWindow;
 
 	ui.monWindow->document()->setMaximumBlockCount(10000);
 
 //	connect(ui.monWindow, SIGNAL(selectionChanged()), this, SLOT(onTEselectionChanged()));
 
-	ui.HeaderA->setPixmap(QPixmap::fromImage(*Header[0]));
-	ui.HeaderB->setPixmap(QPixmap::fromImage(*Header[1]));
-
-	wf_pointer(soundChannel[0]);
-	wf_pointer(soundChannel[1]);
-	wf_Scale(0);
-	wf_Scale(1);
-
 	connect(ui.modeA, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int)));
 	connect(ui.modeB, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int)));
 	connect(ui.modeC, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int)));
@@ -785,7 +739,6 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
 
 	ui.DCDSlider->setValue(dcd_threshold);
 
-
 	char valChar[32];
 	sprintf(valChar, "RX Offset %d", rxOffset);
 	ui.RXOffsetLabel->setText(valChar);
@@ -811,7 +764,7 @@ QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
 	connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot()));
 	timer->start(100);
 
-	QTimer *wftimer = new QTimer(this);
+	wftimer = new QTimer(this);
 	connect(wftimer, SIGNAL(timeout()), this, SLOT(doRestartWF()));
 	wftimer->start(1000 * 300);
 
@@ -885,7 +838,7 @@ void extSetOffset(int chan)
 	sprintf(valChar, "%d", chanOffset[chan]);
 	chanOffsetLabel[chan]->setText(valChar);
 
-	wf_pointer(soundChannel[chan]);
+	NeedWaterfallHeaders = true;
 
 	pnt_change[0] = 1;
 	pnt_change[1] = 1;
@@ -928,6 +881,18 @@ void QtSoundModem::MyTimerSlot()
 		DoPSKWindows();
 	}
 
+	if (NeedWaterfallHeaders)
+	{
+		NeedWaterfallHeaders = 0;
+
+		if (Waterfall)
+		{
+			Waterfall->fill(black);
+			DrawModemFreqRange();
+			DrawFreqTicks();
+		}
+	}
+
 	show_grid();
 }
 
@@ -1101,8 +1066,7 @@ void QtSoundModem::clickedSlotI(int i)
 		sprintf(valChar, "RX Offset %d",rxOffset);
 		ui.RXOffsetLabel->setText(valChar);
 
-		wf_pointer(soundChannel[0]);
-		wf_pointer(soundChannel[1]);
+		NeedWaterfallHeaders = true;
 
 		pnt_change[0] = 1;
 		pnt_change[1] = 1;
@@ -1276,10 +1240,13 @@ void QtSoundModem::clickedSlot()
 	{
 		bool ok;
 		Font = QFontDialog::getFont(&ok, QFont(Font, this));
+
 		if (ok)
 		{
 			// the user clicked OK and font is set to the font the user selected
 			QApplication::setFont(Font);
+			sessionTable->horizontalHeader()->setFont(Font); 
+
 			saveSettings();
 		}
 		else
@@ -1287,7 +1254,7 @@ void QtSoundModem::clickedSlot()
 			// the user canceled the dialog; font is set to the initial
 			// value, in this case Helvetica [Cronyx], 10
 
-			QApplication::setFont(Font);
+//			QApplication::setFont(Font);
 
 		}
 		return;
@@ -1480,6 +1447,11 @@ void QtSoundModem::doModems()
 	Dlg->IL2PModeC->setCurrentIndex(il2p_mode[2]);
 	Dlg->IL2PModeD->setCurrentIndex(il2p_mode[3]);
 
+	Dlg->CRC_A->setChecked(il2p_crc[0]);
+	Dlg->CRC_B->setChecked(il2p_crc[1]);
+	Dlg->CRC_C->setChecked(il2p_crc[2]);
+	Dlg->CRC_D->setChecked(il2p_crc[3]);
+
 	Dlg->CWIDCall->setText(CWIDCall);
 	Dlg->CWIDInterval->setText(QString::number(CWIDInterval));
 	Dlg->CWIDMark->setText(CWIDMark);
@@ -1569,6 +1541,12 @@ extern "C" void get_exclude_list(char * line, TStringList * list);
 void QtSoundModem::modemaccept()
 {
 	modemSave();
+
+	AGW_Report_Modem_Change(0);
+	AGW_Report_Modem_Change(1);
+	AGW_Report_Modem_Change(2);
+	AGW_Report_Modem_Change(3);
+
 	delete(Dlg);
 	saveSettings();
 
@@ -1698,6 +1676,11 @@ void QtSoundModem::modemSave()
 	il2p_mode[2] = Dlg->IL2PModeC->currentIndex();
 	il2p_mode[3] = Dlg->IL2PModeD->currentIndex();
 
+	il2p_crc[0] = Dlg->CRC_A->isChecked();
+	il2p_crc[1] = Dlg->CRC_B->isChecked();
+	il2p_crc[2] = Dlg->CRC_C->isChecked();
+	il2p_crc[3] = Dlg->CRC_D->isChecked();
+
 	recovery[0] = Dlg->recoverBitA->currentIndex();
 	recovery[1] = Dlg->recoverBitB->currentIndex();
 	recovery[2] = Dlg->recoverBitC->currentIndex();
@@ -1749,7 +1732,6 @@ void QtSoundModem::modemSave()
 	for (i = 0; i < 4; i++)
 	{
 		initTStringList(&list_digi_callsigns[i]);
-
 		get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]);
 	}
 
@@ -1766,6 +1748,7 @@ void QtSoundModem::modemSave()
 	Q = Dlg->LPFWidthD->text();
 	lpf[3] = Q.toInt();
 */
+
 }
 
 void QtSoundModem::modemreject()
@@ -2139,6 +2122,7 @@ void QtSoundModem::doDevices()
 	Dev->DualPTT->setChecked(DualPTT);
 
 	Dev->multiCore->setChecked(multiCore);
+	Dev->darkTheme->setChecked(darkTheme);
 
 	Dev->WaterfallMin->setCurrentIndex(Dev->WaterfallMin->findText(QString::number(WaterfallMin), Qt::MatchFixedString));
 	Dev->WaterfallMax->setCurrentIndex(Dev->WaterfallMax->findText(QString::number(WaterfallMax), Qt::MatchFixedString));
@@ -2150,6 +2134,33 @@ void QtSoundModem::doDevices()
 
 }
 
+void QtSoundModem::mysetstyle()
+{
+	if (darkTheme)
+	{
+		qApp->setStyleSheet(
+			"QWidget {color: white; background-color: black}"
+			"QTabBar::tab {color: rgb(127, 127, 127); background-color: black}"
+			"QTabBar::tab::selected {color: white}"
+			"QPushButton {border-style: outset; border-width: 2px; border-color: rgb(127, 127, 127)}"
+			"QPushButton::default {border-style: outset; border-width: 2px; border-color: white}");
+
+		sessionTable->setStyleSheet("QHeaderView::section { background-color:rgb(40, 40, 40) }");
+
+		txText = qRgb(255, 127, 127);
+		rxText = qRgb(173, 216, 230);
+	}
+	else
+	{
+		qApp->setStyleSheet("");
+
+		sessionTable->setStyleSheet("QHeaderView::section { background-color:rgb(224, 224, 224) }");
+
+		txText = qRgb(192, 0, 0);
+		rxText = qRgb(0, 0, 192);
+	}
+}
+
 void QtSoundModem::deviceaccept()
 {
 	QVariant Q = Dev->inputDevice->currentText();
@@ -2251,7 +2262,6 @@ void QtSoundModem::deviceaccept()
 	if (UsingLeft && UsingRight)
 		UsingBothChannels = 1;
 
-
 	SCO = Dev->singleChannelOutput->isChecked();
 	raduga = Dev->colourWaterfall->isChecked();
 	AGWServ = Dev->AGWEnabled->isChecked();
@@ -2275,6 +2285,8 @@ void QtSoundModem::deviceaccept()
 	DualPTT = Dev->DualPTT->isChecked();
 	TX_rotate = Dev->txRotation->isChecked();
 	multiCore = Dev->multiCore->isChecked();
+	darkTheme = Dev->darkTheme->isChecked();
+	mysetstyle();
 
 	if (Dev->CAT->isChecked())
 		PTTMode = PTTCAT;
@@ -2360,8 +2372,7 @@ void QtSoundModem::deviceaccept()
 	ClosePTTPort();
 	OpenPTTPort();
 
-	wf_pointer(soundChannel[0]);
-	wf_pointer(soundChannel[1]);
+	NeedWaterfallHeaders = true;
 
 	delete(Dev);
 	saveSettings();
@@ -2406,33 +2417,55 @@ void QtSoundModem::handleButton(int Port, int Type)
 	doCalib(Port, Type);
 }
 
+
+
 void QtSoundModem::doRestartWF()
 {
-	if (Firstwaterfall)
+	if (inWaterfall)
 	{
-		initWaterfall(0, 0);
-		initWaterfall(0, 1);
-	}
+		// in waterfall update thread
 
-	if (Secondwaterfall)
+		wftimer->start(5000);
+		return;
+	}
+		
+	lockWaterfall = true;
+
+	if (Firstwaterfall | Secondwaterfall)
 	{
-		initWaterfall(1, 0);
-		initWaterfall(1, 1);
+		initWaterfall(0);
+		initWaterfall(1);
 	}
 
 	delete(RXLevel);
 	delete(ui.RXLevel);
 	ui.RXLevel = new QLabel(ui.centralWidget);
 	RXLevelCopy = ui.RXLevel;
-	ui.RXLevel->setGeometry(QRect(780, 17, 150, 12));
-//	ui.RXLevel->setFrameShape(QFrame::Box);
-//	ui.RXLevel->setFrameShadow(QFrame::Sunken);
+	ui.RXLevel->setGeometry(QRect(780, 14, 150, 11));
+	ui.RXLevel->setFrameShape(QFrame::Box);
+	ui.RXLevel->setFrameShadow(QFrame::Sunken);
+
+	delete(RXLevel2);
+	delete(ui.RXLevel2);
+
+	ui.RXLevel2 = new QLabel(ui.centralWidget);
+	RXLevel2Copy = ui.RXLevel2;
+
+	ui.RXLevel2->setGeometry(QRect(780, 23, 150, 11));
+	ui.RXLevel2->setFrameShape(QFrame::Box);
+	ui.RXLevel2->setFrameShadow(QFrame::Sunken);
 
 	RXLevel = new QImage(150, 10, QImage::Format_RGB32);
 	RXLevel->fill(cyan);
-//	ui.RXLevel->setPixmap(QPixmap::fromImage(*RXLevel));
+
+	RXLevel2 = new QImage(150, 10, QImage::Format_RGB32);
+	RXLevel2->fill(white);
 
 	ui.RXLevel->setVisible(1);
+	if (UsingBothChannels)
+		ui.RXLevel2->setVisible(1);
+
+	lockWaterfall = false;
 }
 
 
@@ -2489,7 +2522,7 @@ void QtSoundModem::RefreshSpectrum(unsigned char * Data)
 
 	// Last 4 bytes are level busy and Tuning lines
 
-	Waterfall[0]->fill(Black);
+	Waterfall->fill(Black);
 
 	if (Data[206] != LastLevel)
 	{
@@ -2510,13 +2543,13 @@ void QtSoundModem::RefreshSpectrum(unsigned char * Data)
 		if (val > 63)
 			val = 63;
 
-		Waterfall[0]->setPixel(i, val, Yellow);
+		Waterfall->setPixel(i, val, Yellow);
 		if (val < 62)
-			Waterfall[0]->setPixel(i, val + 1, Gold);
+			Waterfall->setPixel(i, val + 1, Gold);
 		Data++;
 	}
 
-	ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0]));
+	ui.Waterfall->setPixmap(QPixmap::fromImage(*Waterfall));
 
 }
 
@@ -2552,7 +2585,7 @@ void QtSoundModem::RefreshWaterfall(int snd_ch, unsigned char * Data)
 {
 	int j;
 	unsigned char * Line;
-	int len = Waterfall[0]->bytesPerLine();
+	int len = Waterfall->bytesPerLine();
 	int TopLine = NextWaterfallLine[snd_ch];
 
 	// Write line to cyclic buffer then draw starting with the line just written
@@ -2565,16 +2598,15 @@ void QtSoundModem::RefreshWaterfall(int snd_ch, unsigned char * Data)
 
 	for (j = 63; j > 0; j--)
 	{
-		Line = Waterfall[0]->scanLine(j);
+		Line = Waterfall->scanLine(j);
 		memcpy(Line, &WaterfallLines[snd_ch][TopLine++][0], len);
 		if (TopLine > 63)
 			TopLine = 0;
 	}
 
-	ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0]));
+	ui.Waterfall->setPixmap(QPixmap::fromImage(*Waterfall));
 }
 
-
 void QtSoundModem::sendtoTrace(char * Msg, int tx)
 {
 	const QTextCursor old_cursor = monWindowCopy->textCursor();
@@ -2587,9 +2619,9 @@ void QtSoundModem::sendtoTrace(char * Msg, int tx)
 	// Insert the text at the position of the cursor (which is the end of the document).
 
 	if (tx)
-		monWindowCopy->setTextColor(qRgb(192, 0, 0));
+		monWindowCopy->setTextColor(txText);
 	else
-		monWindowCopy->setTextColor(qRgb(0, 0, 192));
+		monWindowCopy->setTextColor(rxText);
 
 	monWindowCopy->textCursor().insertText(Msg);
 
@@ -2651,180 +2683,157 @@ extern "C" int nonGUIMode;
 
 // This draws the Frequency Scale on Waterfall
 
-extern "C" void wf_Scale(int Chan)
+extern "C" void DrawFreqTicks()
 {
 	if (nonGUIMode)
 		return;
 
+	// Draw Frequency Markers on waterfall header(s);
+
 	int x, i;
 	char Textxx[20];
-	QImage * bm = Header[Chan];
+	QImage * bm = Waterfall;
 
 	QPainter qPainter(bm);
 	qPainter.setBrush(Qt::black);
 	qPainter.setPen(Qt::white);
 
-	if (Chan == 0)
-		sprintf(Textxx, "Left");
-	else
-		sprintf(Textxx, "Right");
+	int Chan;
 
 #ifdef WIN32
-	int Top = 3;
+		int Top = 3;
 #else
-	int Top = 4;
+		int Top = 4;
 #endif
+		int Base = 0;
 
-	qPainter.drawText(2, Top, 100, 20, 0, Textxx);
-
-	// We drew markers every 100 Hz or 100 / binsize pixels
-
-
-	int Markers = ((WaterfallMax - WaterfallMin) / 100) + 5;			// Number of Markers to draw
-	int Freq = WaterfallMin;
-	float PixelsPerMarker = 100.0 / BinSize;
-
-
-
-	for (i = 0; i < Markers; i++)
-	{
-		x = round(PixelsPerMarker * i);
-		if (x < 1025)
+		for (Chan = 0; Chan < 2; Chan++)
 		{
-			if ((Freq % 500) == 0)
-				qPainter.drawLine(x, 22, x, 15);
+			if (Chan == 1 || ((UsingBothChannels == 0) && (UsingRight == 1)))
+				sprintf(Textxx, "Right");
 			else
-				qPainter.drawLine(x, 22, x, 18);
+				sprintf(Textxx, "Left");
 
-			if ((Freq % 500) == 0)
+			qPainter.drawText(2, Top, 100, 20, 0, Textxx);
+
+			// We drew markers every 100 Hz or 100 / binsize pixels
+
+			int Markers = ((WaterfallMax - WaterfallMin) / 100) + 5;			// Number of Markers to draw
+			int Freq = WaterfallMin;
+			float PixelsPerMarker = 100.0 / BinSize;
+
+			for (i = 0; i < Markers; i++)
 			{
-				sprintf(Textxx, "%d", Freq);
+				x = round(PixelsPerMarker * i);
+				if (x < 1025)
+				{
+					if ((Freq % 500) == 0)
+						qPainter.drawLine(x, Base + 22, x, Base + 15);
+					else
+						qPainter.drawLine(x, Base + 22, x, Base + 18);
 
-				if (x < 924)
-					qPainter.drawText(x - 12, Top, 100, 20, 0, Textxx);
+					if ((Freq % 500) == 0)
+					{
+						sprintf(Textxx, "%d", Freq);
+
+						if (x < 924)
+							qPainter.drawText(x - 12, Top, 100, 20, 0, Textxx);
+					}
+				}
+				Freq += 100;
 			}
+
+			if (UsingBothChannels == 0)
+				break;
+
+			Top += WaterfallTotalPixels;
+			Base = WaterfallTotalPixels;
 		}
-		Freq += 100;
-	}
-	HeaderCopy[Chan]->setPixmap(QPixmap::fromImage(*bm));
 
 }
 
-// This draws the frequency Markers on the Waterfall
+// These draws the frequency Markers on the Waterfall
 
-
-void do_pointer(int waterfall)
+void DrawModemFreqRange()
 {
 	if (nonGUIMode)
 		return;
 
+	// Draws the modem freq bars on waterfall header(s)
+
 
 	int x1, x2, k, pos1, pos2, pos3;
-	QImage * bm = Header[waterfall];
+	QImage * bm = Waterfall;
 
 	QPainter qPainter(bm);
 	qPainter.setBrush(Qt::NoBrush);
 	qPainter.setPen(Qt::white);
 
-	//	bm->fill(black);
+	int Chan;
+	int LRtoDisplay = LEFT;
+	int top = 0;
 
-	qPainter.fillRect(0, 23, 1024, 10, Qt::black);
-
-	// We drew markers every 100 Hz or 100 / binsize pixels
-
-	float PixelsPerHz = 1.0 / BinSize;
-	k = 26;
-
-	// draw all enabled ports on the ports on this soundcard
-
-	// First Modem is always on the first waterfall
-	// If second is enabled it is on the first unless different
-	//		channel from first
-
-	for (int i = 0; i < 4; i++)
+	for (Chan = 0; Chan < 2; Chan++)
 	{
+		if (Chan == 1 || ((UsingBothChannels == 0) && (UsingRight == 1)))
+			LRtoDisplay = RIGHT;
+
+		//	bm->fill(black);
+
+	//	qPainter.fillRect(top, 23, 1024, 10, Qt::black);
+
+		// We drew markers every 100 Hz or 100 / binsize pixels
+
+		float PixelsPerHz = 1.0 / BinSize;
+		k = 26 + top;
+
+		// draw all enabled ports on the ports on this soundcard
+
+		// First Modem is always on the first waterfall
+		// If second is enabled it is on the first unless different
+		//		channel from first
+
+		for (int i = 0; i < 4; i++)
+		{
+			if (soundChannel[i] != LRtoDisplay)
+					continue;
+
+			pos1 = roundf((((rxOffset + chanOffset[i] + rx_freq[i]) - 0.5*rx_shift[i]) - WaterfallMin) * PixelsPerHz) - 5;
+			pos2 = roundf((((rxOffset + chanOffset[i] + rx_freq[i]) + 0.5*rx_shift[i]) - WaterfallMin) * PixelsPerHz) - 5;
+			pos3 = roundf(((rxOffset + chanOffset[i] + rx_freq[i])) - WaterfallMin * PixelsPerHz);
+			x1 = pos1 + 5;
+			x2 = pos2 + 5;
+
+			qPainter.setPen(Qt::white);
+			qPainter.drawLine(x1, k, x2, k);
+			qPainter.drawLine(x1, k - 3, x1, k + 3);
+			qPainter.drawLine(x2, k - 3, x2, k + 3);
+			//		qPainter.drawLine(pos3, k - 3, pos3, k + 3);
+
+			if (rxOffset || chanOffset[i])
+			{
+				// Draw TX posn if rxOffset used
+
+				pos3 = roundf((rx_freq[i] - WaterfallMin) * PixelsPerHz);
+				qPainter.setPen(Qt::magenta);
+				qPainter.drawLine(pos3, k - 3, pos3, k + 3);
+				qPainter.drawLine(pos3, k - 3, pos3, k + 3);
+				qPainter.drawLine(pos3 - 2, k - 3, pos3 + 2, k - 3);
+			}
+
+			k += 3;
+		}
 		if (UsingBothChannels == 0)
-		{
-			// Only One Waterfall. If first chan is 
+			break;
 
-			if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT))
-				return;
-		}
-
-		if (soundChannel[i] == 0)
-			continue;
-
-
-		if (UsingBothChannels == 1)
-			if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT))
-				continue;
-
-		pos1 = roundf((((rxOffset + chanOffset[i] + rx_freq[i]) - 0.5*rx_shift[i]) - WaterfallMin) * PixelsPerHz) - 5;
-		pos2 = roundf((((rxOffset + chanOffset[i] + rx_freq[i]) + 0.5*rx_shift[i]) - WaterfallMin) * PixelsPerHz) - 5;
-		pos3 = roundf(((rxOffset + chanOffset[i] + rx_freq[i])) - WaterfallMin  * PixelsPerHz);
-		x1 = pos1 + 5;
-		x2 = pos2 + 5;
-
-		qPainter.setPen(Qt::white);
-		qPainter.drawLine(x1, k, x2, k);
-		qPainter.drawLine(x1, k - 3, x1, k + 3);
-		qPainter.drawLine(x2, k - 3, x2, k + 3);
-		qPainter.drawLine(pos3, k - 3, pos3, k + 3);
-
-		if (rxOffset || chanOffset[i])
-		{
-			// Draw TX posn if rxOffset used
-
-			pos3 = roundf((rx_freq[i] - WaterfallMin) * PixelsPerHz);
-			qPainter.setPen(Qt::magenta);
-			qPainter.drawLine(pos3, k - 3, pos3, k + 3);
-			qPainter.drawLine(pos3, k - 3, pos3, k + 3);
-			qPainter.drawLine(pos3 - 2, k - 3, pos3 + 2, k - 3);
-		}
-
-		k += 3;
+		LRtoDisplay = RIGHT;
+		top = WaterfallTotalPixels;
 	}
-	HeaderCopy[waterfall]->setPixmap(QPixmap::fromImage(*bm));
-}
-
-void wf_pointer(int snd_ch)
-{
-	UNUSED(snd_ch);
-
-	do_pointer(0);
-	do_pointer(1);
-//	do_pointer(2);
-//	do_pointer(3);
 }
 
 
 void doWaterfallThread(void * param);
 
-/*
-#ifdef WIN32
-
-#define pthread_t uintptr_t
-
-extern "C" uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist);
-
-#else
-
-#include 
-
-extern "C" pthread_t _beginthread(void(*start_address)(void *), unsigned stack_size, void * arglist)
-{
-	pthread_t thread;
-
-	if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*)arglist) != 0)
-		perror("New Thread");
-	else
-		pthread_detach(thread);
-
-	return thread;
-}
-
-#endif
-*/
 extern "C" void doWaterfall(int snd_ch)
 {
 	if (nonGUIMode)
@@ -2833,6 +2842,9 @@ extern "C" void doWaterfall(int snd_ch)
 	if (Closing)
 		return;
 
+	if (lockWaterfall)
+		return;
+
 //	if (multiCore)			// Run modems in separate threads
 //		_beginthread(doWaterfallThread, 0, xx);
 //	else
@@ -2840,6 +2852,20 @@ extern "C" void doWaterfall(int snd_ch)
 
 }
 
+extern "C" void displayWaterfall()
+{
+	// if we are using both channels but only want right need to extract correct half of Image
+
+	if (Waterfall == nullptr)
+		return;
+
+	if (UsingBothChannels && (Firstwaterfall == 0))
+		WaterfallCopy->setAlignment(Qt::AlignBottom | Qt::AlignLeft);
+	else
+		WaterfallCopy->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+
+	WaterfallCopy->setPixmap(QPixmap::fromImage(*Waterfall));
+}
 
 extern "C" float aFFTAmpl[1024];
 extern "C" void SMUpdateBusyDetector(int LR, float * Real, float *Imag);
@@ -2847,13 +2873,20 @@ extern "C" void SMUpdateBusyDetector(int LR, float * Real, float *Imag);
 void doWaterfallThread(void * param)
 {
 	int snd_ch = (int)(size_t)param;
-	int WaterfallNumber = snd_ch;
+
+	if (lockWaterfall)
+		return;
+
+	if (Configuring)
+		return;
+
+	inWaterfall = true;					// don't allow restart waterfall
 
 	if (snd_ch == 1 && UsingLeft == 0)	// Only using right
 		snd_ch = 0;						// Samples are in first buffer
 
-	QImage * bm = Waterfall[snd_ch];
-	
+	QImage * bm = Waterfall;
+
 	int  i;
 	single  mag;
 	UCHAR * p;
@@ -2865,9 +2898,8 @@ void doWaterfallThread(void * param)
 	float RealOut[8192] = { 0 };
 	float ImagOut[8192];
 
-	if (Configuring)
-		return;
 
+	RefreshLevel(CurrentLevel);	// Signal Level
 
 	hFFTSize = FFTSize / 2;
 
@@ -2909,7 +2941,7 @@ void doWaterfallThread(void * param)
 		}
 	}
 	else
-	{		
+	{
 		dofft(&fft_buf[snd_ch][0], RealOut, ImagOut);
 
 		//	FourierTransform(1024, &fft_buf[snd_ch][0], RealOut, ImagOut, 0);
@@ -2950,71 +2982,70 @@ void doWaterfallThread(void * param)
 
 	SMUpdateBusyDetector(snd_ch, RealOut, ImagOut);
 
-	RefreshLevel(CurrentLevel);	// Signal Level
+	// we always do fft so we can get centre freq and do busy detect. But only upodate waterfall if on display
 
 	if (bm == 0)
+	{
+		inWaterfall = false;
 		return;
-
-	try
-	{
-
-		p = Line;
-		lineLen = bm->bytesPerLine();
-
-		if (raduga == DISP_MONO)
-		{
-			for (i = Start; i < End; i++)
-			{
-				n = fft_disp[snd_ch][i];
-				*(p++) = n;					// all colours the same
-				*(p++) = n;
-				*(p++) = n;
-				p++;
-			}
-		}
-		else
-		{
-			for (i = Start; i < End; i++)
-			{
-				n = fft_disp[snd_ch][i];
-				memcpy(p, &RGBWF[n], 4);
-				p += 4;
-			}
-		}
-
-		// Scroll
-
-		int TopLine = NextWaterfallLine[snd_ch];
-
-		// Write line to cyclic buffer then draw starting with the line just written
-
-		memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Line, 4096);
-		if (NextWaterfallLine[snd_ch] > 79)
-			NextWaterfallLine[snd_ch] = 0;
-
-		for (int j = 79; j > 0; j--)
-		{
-			p = bm->scanLine(j);
-			memcpy(p, &WaterfallLines[snd_ch][TopLine][0], lineLen);
-			TopLine++;
-			if (TopLine > 79)
-				TopLine = 0;
-		}
-
-		WaterfallCopy[WaterfallNumber]->setPixmap(QPixmap::fromImage(*bm));
-		//	WaterfallCopy[snd_ch - 1]->setPixmap(*pm);
-			//	WaterfallCopy[1]->setPixmap(QPixmap::fromImage(*bm));
 	}
-	catch (const std::exception& e) // caught by reference to base
+	if ((Firstwaterfall == 0 && snd_ch == 0) || (Secondwaterfall == 0 && snd_ch == 1))
 	{
-		qDebug() << " a standard exception was caught, with message '"
-			<< e.what() << "'\n";
+		inWaterfall = false;
+		return;
 	}
 
+	p = Line;
+	lineLen = 4096;
+
+	if (raduga == DISP_MONO)
+	{
+		for (i = Start; i < End; i++)
+		{
+			n = fft_disp[snd_ch][i];
+			*(p++) = n;					// all colours the same
+			*(p++) = n;
+			*(p++) = n;
+			p++;
+		}
+	}
+	else
+	{
+		for (i = Start; i < End; i++)
+		{
+			n = fft_disp[snd_ch][i];
+			memcpy(p, &RGBWF[n], 4);
+			p += 4;
+		}
+	}
+
+	// Scroll
+
+	int TopLine = NextWaterfallLine[snd_ch];
+	int TopScanLine = WaterfallHeaderPixels;
+
+	if (snd_ch)
+		TopScanLine += WaterfallTotalPixels;
+
+	// Write line to cyclic buffer then draw starting with the line just written
+
+	memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Line, 4096);
+	if (NextWaterfallLine[snd_ch] > 79)
+		NextWaterfallLine[snd_ch] = 0;
+
+	for (int j = 79; j > 0; j--)
+	{
+		p = bm->scanLine(j + TopScanLine);
+		memcpy(p, &WaterfallLines[snd_ch][TopLine][0], lineLen);
+		TopLine++;
+		if (TopLine > 79)
+			TopLine = 0;
+	}
+
+	inWaterfall = false;
 }
 
 
-
 void QtSoundModem::changeEvent(QEvent* e)
 {
 	if (e->type() == QEvent::WindowStateChange)
diff --git a/QtSoundModem.cpp.bak b/QtSoundModem.cpp.bak
deleted file mode 100644
index 3efef28..0000000
--- a/QtSoundModem.cpp.bak
+++ /dev/null
@@ -1,2866 +0,0 @@
-/*
-Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO
-
-This file is part of QtSoundModem
-
-QtSoundModem is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-QtSoundModem 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 QtSoundModem.  If not, see http://www.gnu.org/licenses
-
-*/
-
-// UZ7HO Soundmodem Port by John Wiseman G8BPQ
-
-// UZ7HO Soundmodem Port
-
-// Not Working 4psk100 FEC 
-
-// Thoughts on Waterfall Display.
-
-// Original used a 2048 sample FFT giving 5.859375 Hz bins. We plotted 1024 points, giving a 0 to 6000 specrum
-
-// If we want say 300 to 3300 we need about half the bin size so twice the fft size. But should we also fit required range to window size?
-
-// Unless we resize the most displayed bit of the screen in around 900 pixels. So each bin should be 3300 / 900 = 3.66667 Hz or a FFT size of around 3273
-
-#include "QtSoundModem.h"
-#include 
-//#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "UZ7HOStuff.h"
-
-
-QImage *Constellation;
-QImage *Waterfall[4] = { 0,0,0,0 };
-QImage *Header[4];
-QLabel *DCDLabel[4];
-QLineEdit *chanOffsetLabel[4];
-QImage *DCDLed[4];
-
-QImage *RXLevel;
-
-QLabel *WaterfallCopy[2];
-QLabel *HeaderCopy[2];
-
-QTextEdit * monWindowCopy;
-
-extern workerThread *t;
-extern QtSoundModem * w;
-
-QList Ports = QSerialPortInfo::availablePorts();
-
-void saveSettings();
-void getSettings();
-extern "C" void CloseSound();
-extern "C" void GetSoundDevices();
-extern "C" char modes_name[modes_count][20];
-extern "C" int speed[5];
-extern "C" int KISSPort;
-extern "C" short rx_freq[5];
-
-extern "C" int CaptureCount;
-extern "C" int PlaybackCount;
-
-extern "C" int CaptureIndex;		// Card number
-extern "C" int PlayBackIndex;
-
-extern "C" char CaptureNames[16][256];
-extern "C" char PlaybackNames[16][256];
-
-extern "C" int SoundMode;
-extern "C" int multiCore;
-
-extern "C" int refreshModems;
-
-extern "C" int pnt_change[5];
-extern "C" int needRSID[4];
-
-extern "C" int needSetOffset[4];
-
-extern "C" float MagOut[4096];
-extern "C" float MaxMagOut;
-extern "C" int MaxMagIndex;
-
-extern "C"
-{ 
-	int InitSound(BOOL Report);
-	void soundMain();
-	void MainLoop();
-	void modulator(UCHAR snd_ch, int buf_size);
-	void SampleSink(int LR, short Sample);
-	void doCalib(int Port, int Act);
-	int Freq_Change(int Chan, int Freq);
-	void set_speed(int snd_ch, int Modem);
-	void init_speed(int snd_ch);
-	void wf_pointer(int snd_ch);
-	void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform);
-	void dofft(short * in, float * outr, float * outi);
-	void init_raduga();
-	void wf_Scale(int Chan);
-	void AGW_Report_Modem_Change(int port);
-	char * strlop(char * buf, char delim);
-	void sendRSID(int Chan, int dropTX);
-	void RSIDinitfft();
-	void il2p_init(int il2p_debug);
-}
-
-void make_graph_buf(float * buf, short tap, QPainter * bitmap);
-
-int ModemA = 2;
-int ModemB = 2;
-int ModemC = 2;
-int ModemD = 2;
-int FreqA = 1500;
-int FreqB = 1500;
-int FreqC = 1500;
-int FreqD = 1500;
-int DCD = 50;
-
-char CWIDCall[128] = "";
-int CWIDInterval = 0;
-int CWIDLeft = 0;
-int CWIDRight = 0;
-int CWIDType = 1;			// on/off
-
-extern "C" { int RSID_SABM[4]; }
-extern "C" { int RSID_UI[4]; }
-extern "C" { int RSID_SetModem[4]; }
-
-int Closing = FALSE;				// Set to stop background thread
-
-QRgb white = qRgb(255, 255, 255);
-QRgb black = qRgb(0, 0, 0);
-
-QRgb green = qRgb(0, 255, 0);
-QRgb red = qRgb(255, 0, 0);
-QRgb yellow = qRgb(255, 255, 0);
-QRgb cyan = qRgb(0, 255, 255);
-
-// Indexed colour list from ARDOPC
-
-#define WHITE 0
-#define Tomato 1
-#define Gold 2
-#define Lime 3
-#define Yellow 4
-#define Orange 5
-#define Khaki 6
-#define Cyan 7
-#define DeepSkyBlue 8
-#define RoyalBlue 9
-#define Navy 10
-#define Black 11
-#define Goldenrod 12
-#define Fuchsia 13
-
-QRgb vbColours[16] = { qRgb(255, 255, 255), qRgb(255, 99, 71), qRgb(255, 215, 0), qRgb(0, 255, 0),
-						qRgb(255, 255, 0), qRgb(255, 165, 0), qRgb(240, 240, 140), qRgb(0, 255, 255),
-						qRgb(0, 191, 255), qRgb(65, 105, 225), qRgb(0, 0, 128), qRgb(0, 0, 0),
-						qRgb(218, 165, 32), qRgb(255, 0, 255) };
-
-unsigned char  WaterfallLines[2][80][4096] = { 0 };
-int NextWaterfallLine[2] = { 0 };
-
-unsigned int LastLevel = 255;
-unsigned int LastBusy = 255;
-
-extern "C" int UDPClientPort;
-extern "C" int UDPServerPort;
-extern "C" int TXPort;
-extern char UDPHost[64];
-
-QTimer *cwidtimer;
-
-QSystemTrayIcon * trayIcon = nullptr;
-
-int MintoTray = 1;
-
-int RSID_WF = 0;				// Set to use RSID FFT for Waterfall. 
-
-extern "C" void WriteDebugLog(char * Mess)
-{
-	qDebug() << Mess;
-}
-
-void QtSoundModem::doupdateDCD(int Chan, int State)
-{
-	DCDLabel[Chan]->setVisible(State);
-}
-
-extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat);
-extern "C" char * ShortDateTime();
-
-extern "C" void mon_rsid(int snd_ch, char * RSID)
-{
-	int Len;
-	char * Msg = (char *)malloc(1024);		// Cant pass local variable via signal/slot
-
-	sprintf(Msg, "%d:%s [%s%c]", snd_ch + 1, RSID, ShortDateTime(), 'R');
-
-	Len = strlen(Msg);
-
-	if (Msg[Len - 1] != '\r')
-	{
-		Msg[Len++] = '\r';
-		Msg[Len] = 0;
-	}
-
-	emit t->sendtoTrace(Msg, 0);
-}
-
-extern "C" void put_frame(int snd_ch, string * frame, char * code, int  tx, int excluded)
-{
-	UNUSED(excluded);
-
-	int Len;
-	char * Msg = (char *)malloc(1024);		// Cant pass local variable via signal/slot
-
-	if (strcmp(code, "NON-AX25") == 0)
-		sprintf(Msg, "%d: Length, ShortDateTime(), 'R');
-	else
-		sprintf(Msg, "%d:%s", snd_ch + 1, frame_monitor(frame, code, tx));
-
-	Len = strlen(Msg);
-
-	if (Msg[Len - 1] != '\r')
-	{
-		Msg[Len++] = '\r';
-		Msg[Len] = 0;
-	}
-
-	emit t->sendtoTrace(Msg, tx);
-}
-
-extern "C" void updateDCD(int Chan, bool State)
-{
-	emit t->updateDCD(Chan, State);
-}
-
-bool QtSoundModem::eventFilter(QObject* obj, QEvent *evt)
-{
-	UNUSED(obj);
-
-	if (evt->type() == QEvent::Resize)
-	{
-		return QWidget::event(evt);
-	}
-
-	if (evt->type() == QEvent::WindowStateChange)
-	{
-		if (windowState().testFlag(Qt::WindowMinimized) == true)
-			w_state = WIN_MINIMIZED;
-		else
-			w_state = WIN_MAXIMIZED;
-	}
-//	if (evt->type() == QGuiApplication::applicationStateChanged) - this is a sigma;
-//	{
-//		qDebug() << "App State changed =" << evt->type() << endl;
-//	}
-
-	return QWidget::event(evt);
-}
-
-void QtSoundModem::resizeEvent(QResizeEvent* event)
-{
-	QMainWindow::resizeEvent(event);
-
-	QRect r = geometry();
-
-	int A, B, C, W;
-	int modemBoxHeight = 30;
-
-	ui.modeB->setVisible(soundChannel[1]);
-	ui.centerB->setVisible(soundChannel[1]);
-	ui.labelB->setVisible(soundChannel[1]);
-	DCDLabel[1]->setVisible(soundChannel[1]);
-	ui.RXOffsetB->setVisible(soundChannel[1]);
-
-	ui.modeC->setVisible(soundChannel[2]);
-	ui.centerC->setVisible(soundChannel[2]);
-	ui.labelC->setVisible(soundChannel[2]);
-	DCDLabel[2]->setVisible(soundChannel[2]);
-	ui.RXOffsetC->setVisible(soundChannel[2]);
-
-	ui.modeD->setVisible(soundChannel[3]);
-	ui.centerD->setVisible(soundChannel[3]);
-	ui.labelD->setVisible(soundChannel[3]);
-	DCDLabel[3]->setVisible(soundChannel[3]);
-	ui.RXOffsetD->setVisible(soundChannel[3]);
-
-	if (soundChannel[2] || soundChannel[3])
-		modemBoxHeight = 60;
-
-
-	A = r.height() - 25;   // No waterfalls
-
-	if (UsingBothChannels && Secondwaterfall)
-	{
-		// Two waterfalls
-
-		ui.WaterfallA->setVisible(1);
-		ui.HeaderA->setVisible(1);
-		ui.WaterfallB->setVisible(1);
-		ui.HeaderB->setVisible(1);
-
-		A = r.height() - 258;   // Top of Waterfall A
-		B = A + 115;			// Top of Waterfall B
-	}
-	else
-	{
-		// One waterfall
-
-		// Could be Left or Right
-
-		if (Firstwaterfall)
-		{
-			if (soundChannel[0] == RIGHT)
-			{
-				ui.WaterfallA->setVisible(0);
-				ui.HeaderA->setVisible(0);
-				ui.WaterfallB->setVisible(1);
-				ui.HeaderB->setVisible(1);
-			}
-			else
-			{
-				ui.WaterfallA->setVisible(1);
-				ui.HeaderA->setVisible(1);
-				ui.WaterfallB->setVisible(0);
-				ui.HeaderB->setVisible(0);
-			}
-
-			A = r.height() - 145;   // Top of Waterfall A
-		}
-		else
-			A = r.height() - 25;   // Top of Waterfall A
-	}
-
-	C = A - 150;			// Bottom of Monitor, Top of connection list
-	W = r.width();
-
-	// Calc Positions of Waterfalls
-
-	ui.monWindow->setGeometry(QRect(0, modemBoxHeight, W, C - (modemBoxHeight + 26)));
-	sessionTable->setGeometry(QRect(0, C, W, 175));
-
-	if (UsingBothChannels)
-	{
-		ui.HeaderA->setGeometry(QRect(0, A, W, 35));
-		ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80));
-		ui.HeaderB->setGeometry(QRect(0, B, W, 35));
-		ui.WaterfallB->setGeometry(QRect(0, B + 35, W, 80));
-	}
-	else
-	{
-		if (soundChannel[0] == RIGHT)
-		{
-			ui.HeaderB->setGeometry(QRect(0, A, W, 35));
-			ui.WaterfallB->setGeometry(QRect(0, A + 35, W, 80));
-		}
-		else
-		{
-			ui.HeaderA->setGeometry(QRect(0, A, W, 35));
-			ui.WaterfallA->setGeometry(QRect(0, A + 35, W, 80));
-		}
-	}
-}
-
-QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State)
-{
-	QAction * Act = new QAction(Label, parent);
-	Menu->addAction(Act);
-
-	Act->setCheckable(true);
-	if (State)
-		Act->setChecked(true);
-
-	parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked()));
-
-	return Act;
-}
-
-void QtSoundModem::menuChecked()
-{
-	QAction * Act = static_cast(QObject::sender());
-
-	int state = Act->isChecked();
-
-	if (Act == actWaterfall1)
-	{
-		int oldstate = Firstwaterfall;
-		Firstwaterfall = state;
-
-		if (state != oldstate)
-			initWaterfall(0, state);
-
-	}
-	else if (Act == actWaterfall2)
-	{
-		int oldstate = Secondwaterfall;
-		Secondwaterfall = state;
-
-		if (state != oldstate)
-			initWaterfall(1, state);
-
-	}
-	saveSettings();
-}
-
-void QtSoundModem::initWaterfall(int chan, int state)
-{
-	if (state == 1)
-	{
-		if (chan == 0)
-		{
-			ui.WaterfallA = new QLabel(ui.centralWidget);
-			WaterfallCopy[0] = ui.WaterfallA;
-		}
-		else
-		{
-			ui.WaterfallB = new QLabel(ui.centralWidget);
-			WaterfallCopy[1] = ui.WaterfallB;
-		}
-		Waterfall[chan] = new QImage(1024, 80, QImage::Format_RGB32);
-		Waterfall[chan]->fill(black);
-
-	}
-	else
-	{
-		delete(Waterfall[chan]);
-		Waterfall[chan] = 0;
-	}
-
-	QSize Size(800, 602);						// Not actually used, but Event constructor needs it
-	QResizeEvent *event = new QResizeEvent(Size, Size);
-	QApplication::sendEvent(this, event);
-}
-
-// Local copies
-
-QLabel *RXOffsetLabel;
-QSlider *RXOffset;
-
-QtSoundModem::QtSoundModem(QWidget *parent) : QMainWindow(parent)
-{
-	ui.setupUi(this);
-
-	QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat);
-
-	if (MintoTray)
-	{
-		char popUp[256];
-		sprintf(popUp, "QtSoundModem %d %d", AGWPort, KISSPort);
-		trayIcon = new QSystemTrayIcon(QIcon(":/QtSoundModem/soundmodem.ico"), this);
-		trayIcon->setToolTip(popUp);
-		trayIcon->show();
-
-		connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(TrayActivated(QSystemTrayIcon::ActivationReason)));
-	}
-
-
-	restoreGeometry(mysettings.value("geometry").toByteArray());
-	restoreState(mysettings.value("windowState").toByteArray());
-
-	sessionTable = new QTableWidget(this);
-
-	sessionTable->verticalHeader()->setVisible(FALSE);
-	sessionTable->verticalHeader()->setDefaultSectionSize(20);
-	sessionTable->horizontalHeader()->setDefaultSectionSize(68);
-	sessionTable->setRowCount(1);
-	sessionTable->setColumnCount(12);
-	m_TableHeader << "MyCall" << "DestCall" << "Status" << "Sent pkts" << "Sent Bytes" << "Rcvd pkts" << "Rcvd bytes" << "Rcvd FC" << "FEC corr" << "CPS TX" << "CPS RX" << "Direction";
-
-	sessionTable->setStyleSheet("QHeaderView::section { background-color:rgb(224, 224, 224) }");
-
-	sessionTable->setHorizontalHeaderLabels(m_TableHeader);
-	sessionTable->setColumnWidth(0, 80);
-	sessionTable->setColumnWidth(1, 80);
-	sessionTable->setColumnWidth(4, 76);
-	sessionTable->setColumnWidth(5, 76);
-	sessionTable->setColumnWidth(6, 80);
-	sessionTable->setColumnWidth(11, 72);
-
-	for (int i = 0; i < modes_count; i++)
-	{
-		ui.modeA->addItem(modes_name[i]);
-		ui.modeB->addItem(modes_name[i]);
-		ui.modeC->addItem(modes_name[i]);
-		ui.modeD->addItem(modes_name[i]);
-	}
-
-	// Set up Menus
-
-	setupMenu = ui.menuBar->addMenu(tr("Settings"));
-
-	actDevices = new QAction("Setup Devices", this);
-	setupMenu->addAction(actDevices);
-
-	connect(actDevices, SIGNAL(triggered()), this, SLOT(clickedSlot()));
-	actDevices->setObjectName("actDevices");
-	actModems = new QAction("Setup Modems", this);
-	actModems->setObjectName("actModems");
-	setupMenu->addAction(actModems);
-
-	connect(actModems, SIGNAL(triggered()), this, SLOT(clickedSlot()));
-
-	actMintoTray = setupMenu->addAction("Minimize to Tray", this, SLOT(MinimizetoTray()));
-	actMintoTray->setCheckable(1);
-	actMintoTray->setChecked(MintoTray);
-
-	viewMenu = ui.menuBar->addMenu(tr("&View"));
-
-	actWaterfall1 = setupMenuLine(viewMenu, (char *)"First waterfall", this, Firstwaterfall);
-	actWaterfall2 = setupMenuLine(viewMenu, (char *)"Second Waterfall", this, Secondwaterfall);
-
-	actCalib = ui.menuBar->addAction("&Calibration");
-	connect(actCalib, SIGNAL(triggered()), this, SLOT(doCalibrate()));
-
-	actRestartWF = ui.menuBar->addAction("Restart Waterfall");
-	connect(actRestartWF, SIGNAL(triggered()), this, SLOT(doRestartWF()));
-
-	actAbout = ui.menuBar->addAction("&About");
-	connect(actAbout, SIGNAL(triggered()), this, SLOT(doAbout()));
-
-	//	Constellation = new QImage(91, 91, QImage::Format_RGB32);
-
-	Header[0] = new QImage(1024, 35, QImage::Format_RGB32);
-	Header[1] = new QImage(1024, 35, QImage::Format_RGB32);
-	RXLevel = new QImage(150, 10, QImage::Format_RGB32);
-
-	DCDLabel[0] = new QLabel(this);
-	DCDLabel[0]->setObjectName(QString::fromUtf8("DCDLedA"));
-	DCDLabel[0]->setGeometry(QRect(280, 31, 12, 12));
-	DCDLabel[0]->setVisible(TRUE);
-
-	DCDLabel[1] = new QLabel(this);
-	DCDLabel[1]->setObjectName(QString::fromUtf8("DCDLedB"));
-	DCDLabel[1]->setGeometry(QRect(575, 31, 12, 12));
-	DCDLabel[1]->setVisible(TRUE);
-
-	DCDLabel[2] = new QLabel(this);
-	DCDLabel[2]->setObjectName(QString::fromUtf8("DCDLedC"));
-	DCDLabel[2]->setGeometry(QRect(280, 61, 12, 12));
-	DCDLabel[2]->setVisible(FALSE);
-
-	DCDLabel[3] = new QLabel(this);
-	DCDLabel[3]->setObjectName(QString::fromUtf8("DCDLedD"));
-	DCDLabel[3]->setGeometry(QRect(575, 61, 12, 12));
-	DCDLabel[3]->setVisible(FALSE);
-	
-	DCDLed[0] = new QImage(12, 12, QImage::Format_RGB32);
-	DCDLed[1] = new QImage(12, 12, QImage::Format_RGB32);
-	DCDLed[2] = new QImage(12, 12, QImage::Format_RGB32);
-	DCDLed[3] = new QImage(12, 12, QImage::Format_RGB32);
-
-	DCDLed[0]->fill(red);
-	DCDLed[1]->fill(red);
-	DCDLed[2]->fill(red);
-	DCDLed[3]->fill(red);
-
-	DCDLabel[0]->setPixmap(QPixmap::fromImage(*DCDLed[0]));
-	DCDLabel[1]->setPixmap(QPixmap::fromImage(*DCDLed[1]));
-	DCDLabel[2]->setPixmap(QPixmap::fromImage(*DCDLed[2]));
-	DCDLabel[3]->setPixmap(QPixmap::fromImage(*DCDLed[3]));
-
-	chanOffsetLabel[0] = ui.RXOffsetA;
-	chanOffsetLabel[1] = ui.RXOffsetB;
-	chanOffsetLabel[2] = ui.RXOffsetC;
-	chanOffsetLabel[3] = ui.RXOffsetD;
-
-
-	//	Waterfall[0]->setColorCount(16);
-	//	Waterfall[1]->setColorCount(16);
-
-
-	//	for (i = 0; i < 16; i++)
-	//	{
-	//	Waterfall[0]->setColor(i, vbColours[i]);
-	//		Waterfall[1]->setColor(i, vbColours[i]);
-	//	}
-
-	WaterfallCopy[0] = ui.WaterfallA;
-	WaterfallCopy[1] = ui.WaterfallB;
-
-	initWaterfall(0, 1);
-	initWaterfall(1, 1);
-
-	Header[0]->fill(black);
-	Header[1]->fill(black);
-
-	HeaderCopy[0] = ui.HeaderA;
-	HeaderCopy[1] = ui.HeaderB;
-	monWindowCopy = ui.monWindow;
-
-	ui.monWindow->document()->setMaximumBlockCount(10000);
-
-//	connect(ui.monWindow, SIGNAL(selectionChanged()), this, SLOT(onTEselectionChanged()));
-
-	ui.HeaderA->setPixmap(QPixmap::fromImage(*Header[0]));
-	ui.HeaderB->setPixmap(QPixmap::fromImage(*Header[1]));
-
-	wf_pointer(soundChannel[0]);
-	wf_pointer(soundChannel[1]);
-	wf_Scale(0);
-	wf_Scale(1);
-
-	//	RefreshLevel(0);
-	//	RXLevel->setPixmap(QPixmap::fromImage(*RXLevel));
-
-	connect(ui.modeA, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int)));
-	connect(ui.modeB, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int)));
-	connect(ui.modeC, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int)));
-	connect(ui.modeD, SIGNAL(currentIndexChanged(int)), this, SLOT(clickedSlotI(int)));
-
-	ui.modeA->setCurrentIndex(speed[0]);
-	ui.modeB->setCurrentIndex(speed[1]);
-	ui.modeC->setCurrentIndex(speed[2]);
-	ui.modeD->setCurrentIndex(speed[3]);
-
-	ModemA = ui.modeA->currentIndex();
-
-	ui.centerA->setValue(rx_freq[0]);
-	ui.centerB->setValue(rx_freq[1]);
-	ui.centerC->setValue(rx_freq[2]);
-	ui.centerD->setValue(rx_freq[3]);
-
-	connect(ui.centerA, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int)));
-	connect(ui.centerB, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int)));
-	connect(ui.centerC, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int)));
-	connect(ui.centerD, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int)));
-
-	ui.DCDSlider->setValue(dcd_threshold);
-
-
-	char valChar[32];
-	sprintf(valChar, "RX Offset %d", rxOffset);
-	ui.RXOffsetLabel->setText(valChar);
-	ui.RXOffset->setValue(rxOffset);
-
-	RXOffsetLabel = ui.RXOffsetLabel;
-	RXOffset = ui.RXOffset;
-
-	connect(ui.DCDSlider, SIGNAL(sliderMoved(int)), this, SLOT(clickedSlotI(int)));
-	connect(ui.RXOffset, SIGNAL(valueChanged(int)), this, SLOT(clickedSlotI(int)));
-
-
-	QObject::connect(t, SIGNAL(sendtoTrace(char *, int)), this, SLOT(sendtoTrace(char *, int)), Qt::QueuedConnection);
-	QObject::connect(t, SIGNAL(updateDCD(int, int)), this, SLOT(doupdateDCD(int, int)), Qt::QueuedConnection);
-
-	connect(ui.RXOffsetA, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
-	connect(ui.RXOffsetB, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
-	connect(ui.RXOffsetC, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
-	connect(ui.RXOffsetD, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
-
-	QTimer *timer = new QTimer(this);
-	connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot()));
-	timer->start(100);
-
-
-	cwidtimer = new QTimer(this);
-	connect(cwidtimer, SIGNAL(timeout()), this, SLOT(CWIDTimer()));
-
-	if (CWIDInterval)
-		cwidtimer->start(CWIDInterval * 60000);
-
-	if (RSID_SetModem[0])
-	{
-		RSID_WF = 1;
-		RSIDinitfft();
-	}
-	il2p_init(1);
-}
-
-void QtSoundModem::MinimizetoTray()
-{
-	MintoTray = actMintoTray->isChecked();
-	saveSettings();
-	QMessageBox::about(this, tr("QtSoundModem"),
-	tr("Program must be restarted to change Minimize mode"));
-}
-
-
-void QtSoundModem::TrayActivated(QSystemTrayIcon::ActivationReason reason)
-{
-	if (reason == 3)
-	{
-		showNormal();
-		w->setWindowState((w->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
-	} 
-}
-
-extern "C" void sendCWID(char * strID, BOOL blnPlay, int Chan);
-
-void QtSoundModem::CWIDTimer()
-{
-	sendCWID(CWIDCall, CWIDType, 0);
-	calib_mode[0] = 4;
-}
-
-void extSetOffset(int chan)
-{
-	char valChar[32];
-	sprintf(valChar, "%d", chanOffset[chan]);
-	chanOffsetLabel[chan]->setText(valChar);
-
-	wf_pointer(soundChannel[chan]);
-
-	pnt_change[0] = 1;
-	pnt_change[1] = 1;
-	pnt_change[2] = 1;
-	pnt_change[3] = 1;
-
-	return;
-}
-	
-void QtSoundModem::MyTimerSlot()
-{
-	// 100 mS Timer Event
-
-	for (int i = 0; i < 4; i++)
-	{
-
-		if (needSetOffset[i])
-		{
-			needSetOffset[i] = 0;
-			extSetOffset(i);						// Update GUI
-		}
-	}
-
-	if (refreshModems)
-	{
-		refreshModems = 0;
-
-		ui.modeA->setCurrentIndex(speed[0]);
-		ui.modeB->setCurrentIndex(speed[1]);
-		ui.modeC->setCurrentIndex(speed[2]);
-		ui.modeD->setCurrentIndex(speed[3]);
-		ui.centerA->setValue(rx_freq[0]);
-		ui.centerB->setValue(rx_freq[1]);
-		ui.centerC->setValue(rx_freq[2]);
-		ui.centerD->setValue(rx_freq[3]);
-	}
-
-	show_grid();
-}
-
-void QtSoundModem::returnPressed()
-{
-	char Name[32];
-	int Chan;
-	QString val;
-	
-	strcpy(Name, sender()->objectName().toUtf8());
-
-	Chan = Name[8] - 'A';
-
-	val = chanOffsetLabel[Chan]->text();
-
-	chanOffset[Chan] = val.toInt();
-	needSetOffset[Chan] = 1;				// Update GUI
-
-
-}
-
-
-void QtSoundModem::clickedSlotI(int i)
-{
-	char Name[32];
-
-	strcpy(Name, sender()->objectName().toUtf8());
-
-	if (strcmp(Name, "modeA") == 0)
-	{
-		ModemA = ui.modeA->currentIndex();
-		set_speed(0, ModemA);
-		saveSettings();
-		AGW_Report_Modem_Change(0);
-		return;
-	}
-
-	if (strcmp(Name, "modeB") == 0)
-	{
-		ModemB = ui.modeB->currentIndex();
-		set_speed(1, ModemB);
-		saveSettings();
-		AGW_Report_Modem_Change(1);
-		return;
-	}
-
-	if (strcmp(Name, "modeC") == 0)
-	{
-		ModemC = ui.modeC->currentIndex();
-		set_speed(2, ModemC);
-		saveSettings();
-		AGW_Report_Modem_Change(2);
-		return;
-	}
-
-	if (strcmp(Name, "modeD") == 0)
-	{
-		ModemD = ui.modeD->currentIndex();
-		set_speed(3, ModemD);
-		saveSettings();
-		AGW_Report_Modem_Change(3);
-		return;
-	}
-
-	if (strcmp(Name, "centerA") == 0)
-	{
-		if (i > 300)
-		{
-			QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat);
-			ui.centerA->setValue(Freq_Change(0, i));
-			settings->setValue("Modem/RXFreq1", ui.centerA->value());
-			AGW_Report_Modem_Change(0);
-
-		}
-		return;
-	}
-
-	if (strcmp(Name, "centerB") == 0)
-	{
-		if (i > 300)
-		{
-			QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat);
-			ui.centerB->setValue(Freq_Change(1, i));
-			settings->setValue("Modem/RXFreq2", ui.centerB->value());
-			AGW_Report_Modem_Change(1);
-		}
-		return;
-	}
-
-	if (strcmp(Name, "centerC") == 0)
-	{
-		if (i > 300)
-		{
-			QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat);
-			ui.centerC->setValue(Freq_Change(2, i));
-			settings->setValue("Modem/RXFreq3", ui.centerC->value());
-			AGW_Report_Modem_Change(2);
-		}
-		return;
-	}
-
-	if (strcmp(Name, "centerD") == 0)
-	{
-		if (i > 300)
-		{
-			QSettings * settings = new QSettings("QtSoundModem.ini", QSettings::IniFormat);
-			ui.centerD->setValue(Freq_Change(3, i));
-			settings->setValue("Modem/RXFreq4", ui.centerD->value());
-			AGW_Report_Modem_Change(3);
-		}
-		return;
-	}
-
-	if (strcmp(Name, "DCDSlider") == 0)
-	{
-		dcd_threshold = i;
-		saveSettings();
-		return;
-	}
-	
-	if (strcmp(Name, "RXOffset") == 0)
-	{
-		char valChar[32];
-		rxOffset = i;
-		sprintf(valChar, "RX Offset %d",rxOffset);
-		ui.RXOffsetLabel->setText(valChar);
-
-		wf_pointer(soundChannel[0]);
-		wf_pointer(soundChannel[1]);
-
-		pnt_change[0] = 1;
-		pnt_change[1] = 1;
-		pnt_change[2] = 1;
-		pnt_change[3] = 1;
-
-		saveSettings();
-		return;
-	}
-
-
-	QMessageBox msgBox;
-	msgBox.setWindowTitle("MessageBox Title");
-	msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName());
-	msgBox.exec();
-}
-
-
-void QtSoundModem::clickedSlot()
-{
-	char Name[32];
-
-	strcpy(Name, sender()->objectName().toUtf8());
-
-	if (strcmp(Name, "actDevices") == 0)
-	{
-		doDevices();
-		return;
-	}
-
-	if (strcmp(Name, "actModems") == 0)
-	{
-		doModems();
-		return;
-	}
-
-	if (strcmp(Name, "showBPF_A") == 0)
-	{
-		doFilter(0, 0);
-		return;
-	}
-
-	if (strcmp(Name, "showTXBPF_A") == 0)
-	{
-		doFilter(0, 1);
-		return;
-	}
-
-	if (strcmp(Name, "showLPF_A") == 0)
-	{
-		doFilter(0, 2);
-		return;
-	}
-	
-
-	if (strcmp(Name, "showBPF_B") == 0)
-	{
-		doFilter(1, 0);
-		return;
-	}
-
-	if (strcmp(Name, "showTXBPF_B") == 0)
-	{
-		doFilter(1, 1);
-		return;
-	}
-
-	if (strcmp(Name, "showLPF_B") == 0)
-	{
-		doFilter(1, 2);
-		return;
-	}
-
-	if (strcmp(Name, "Low_A") == 0)
-	{
-		handleButton(0, 1);
-		return;
-	}
-
-	if (strcmp(Name, "High_A") == 0)
-	{
-		handleButton(0, 2);
-		return;
-	}
-
-	if (strcmp(Name, "Both_A") == 0)
-	{
-		handleButton(0, 3);
-		return;
-	}
-
-	if (strcmp(Name, "Stop_A") == 0)
-	{
-		handleButton(0, 0);
-		return;
-	}
-
-
-	if (strcmp(Name, "Low_B") == 0)
-	{
-		handleButton(1, 1);
-		return;
-	}
-
-	if (strcmp(Name, "High_B") == 0)
-	{
-		handleButton(1, 2);
-		return;
-	}
-
-	if (strcmp(Name, "Both_B") == 0)
-	{
-		handleButton(1, 3);
-		return;
-	}
-
-	if (strcmp(Name, "Stop_B") == 0)
-	{
-		handleButton(1, 0);
-		return;
-	}
-
-	if (strcmp(Name, "Low_C") == 0)
-	{
-		handleButton(2, 1);
-		return;
-	}
-
-	if (strcmp(Name, "High_C") == 0)
-	{
-		handleButton(2, 2);
-		return;
-	}
-
-	if (strcmp(Name, "Both_C") == 0)
-	{
-		handleButton(2, 3);
-		return;
-	}
-
-	if (strcmp(Name, "Stop_C") == 0)
-	{
-		handleButton(2, 0);
-		return;
-	}
-
-	if (strcmp(Name, "Low_D") == 0)
-	{
-		handleButton(3, 1);
-		return;
-	}
-
-	if (strcmp(Name, "High_D") == 0)
-	{
-		handleButton(3, 2);
-		return;
-	}
-
-	if (strcmp(Name, "Both_D") == 0)
-	{
-		handleButton(3, 3);
-		return;
-	}
-
-	if (strcmp(Name, "Stop_D") == 0)
-	{
-		handleButton(3, 0);
-		return;
-	}
-
-	QMessageBox msgBox;
-	msgBox.setWindowTitle("MessageBox Title");
-	msgBox.setText("You Clicked " + ((QPushButton*)sender())->objectName());
-	msgBox.exec();
-}
-
-Ui_ModemDialog * Dlg;
-
-QDialog * modemUI;
-QDialog * deviceUI;
-
-void QtSoundModem::doModems()
-{
-	Dlg = new(Ui_ModemDialog);
-
-	QDialog UI;
-	char valChar[10];
-
-	Dlg->setupUi(&UI);
-
-	modemUI = &UI;
-	deviceUI = 0;
-
-	myResize *resize = new myResize();
-
-	UI.installEventFilter(resize);
-
-	sprintf(valChar, "%d", bpf[0]);
-	Dlg->BPFWidthA->setText(valChar);
-	sprintf(valChar, "%d", bpf[1]);
-	Dlg->BPFWidthB->setText(valChar);
-	sprintf(valChar, "%d", bpf[2]);
-	Dlg->BPFWidthC->setText(valChar);
-	sprintf(valChar, "%d", bpf[3]);
-	Dlg->BPFWidthD->setText(valChar);
-
-	sprintf(valChar, "%d", txbpf[0]);
-	Dlg->TXBPFWidthA->setText(valChar);
-	sprintf(valChar, "%d", txbpf[1]);
-	Dlg->TXBPFWidthB->setText(valChar);
-	sprintf(valChar, "%d", txbpf[2]);
-	Dlg->TXBPFWidthC->setText(valChar);
-	sprintf(valChar, "%d", txbpf[3]);
-	Dlg->TXBPFWidthD->setText(valChar);
-
-	sprintf(valChar, "%d", lpf[0]);
-	Dlg->LPFWidthA->setText(valChar);
-	sprintf(valChar, "%d", lpf[1]);
-	Dlg->LPFWidthB->setText(valChar);
-	sprintf(valChar, "%d", lpf[2]);
-	Dlg->LPFWidthC->setText(valChar);
-	sprintf(valChar, "%d", lpf[4]);
-	Dlg->LPFWidthD->setText(valChar);
-
-	sprintf(valChar, "%d", BPF_tap[0]);
-	Dlg->BPFTapsA->setText(valChar);
-	sprintf(valChar, "%d", BPF_tap[1]);
-	Dlg->BPFTapsB->setText(valChar);
-	sprintf(valChar, "%d", BPF_tap[2]);
-	Dlg->BPFTapsC->setText(valChar);
-	sprintf(valChar, "%d", BPF_tap[3]);
-	Dlg->BPFTapsD->setText(valChar);
-
-	sprintf(valChar, "%d", LPF_tap[0]);
-	Dlg->LPFTapsA->setText(valChar);
-	sprintf(valChar, "%d", LPF_tap[1]);
-	Dlg->LPFTapsB->setText(valChar);
-	sprintf(valChar, "%d", LPF_tap[2]);
-	Dlg->LPFTapsC->setText(valChar);
-	sprintf(valChar, "%d", LPF_tap[3]);
-	Dlg->LPFTapsD->setText(valChar);
-
-	Dlg->preEmphAllA->setChecked(emph_all[0]);
-
-	if (emph_all[0])
-		Dlg->preEmphA->setDisabled(TRUE);
-	else
-		Dlg->preEmphA->setCurrentIndex(emph_db[0]);
-
-	Dlg->preEmphAllB->setChecked(emph_all[1]);
-
-	if (emph_all[1])
-		Dlg->preEmphB->setDisabled(TRUE);
-	else
-		Dlg->preEmphB->setCurrentIndex(emph_db[1]);
-
-	Dlg->preEmphAllC->setChecked(emph_all[2]);
-
-	if (emph_all[2])
-		Dlg->preEmphC->setDisabled(TRUE);
-	else
-		Dlg->preEmphC->setCurrentIndex(emph_db[2]);
-
-	Dlg->preEmphAllD->setChecked(emph_all[3]);
-
-	if (emph_all[3])
-		Dlg->preEmphD->setDisabled(TRUE);
-	else
-		Dlg->preEmphD->setCurrentIndex(emph_db[3]);
-
-
-	Dlg->nonAX25A->setChecked(NonAX25[0]);
-	Dlg->nonAX25B->setChecked(NonAX25[1]);
-	Dlg->nonAX25C->setChecked(NonAX25[2]);
-	Dlg->nonAX25D->setChecked(NonAX25[3]);
-
-	Dlg->KISSOptA->setChecked(KISS_opt[0]);
-	Dlg->KISSOptB->setChecked(KISS_opt[1]);
-	Dlg->KISSOptC->setChecked(KISS_opt[2]);
-	Dlg->KISSOptD->setChecked(KISS_opt[3]);
-
-	sprintf(valChar, "%d", txdelay[0]);
-	Dlg->TXDelayA->setText(valChar);
-	sprintf(valChar, "%d", txdelay[1]);
-	Dlg->TXDelayB->setText(valChar);
-	sprintf(valChar, "%d", txdelay[2]);
-	Dlg->TXDelayC->setText(valChar);
-	sprintf(valChar, "%d", txdelay[3]);
-	Dlg->TXDelayD->setText(valChar);
-
-	sprintf(valChar, "%d", txtail[0]);
-	Dlg->TXTailA->setText(valChar);
-	sprintf(valChar, "%d", txtail[1]);
-	Dlg->TXTailB->setText(valChar);
-	sprintf(valChar, "%d", txtail[2]);
-	Dlg->TXTailC->setText(valChar);
-	sprintf(valChar, "%d", txtail[3]);
-	Dlg->TXTailD->setText(valChar);
-
-	Dlg->FrackA->setText(QString::number(frack_time[0]));
-	Dlg->FrackB->setText(QString::number(frack_time[1]));
-	Dlg->FrackC->setText(QString::number(frack_time[2]));
-	Dlg->FrackD->setText(QString::number(frack_time[3]));
-
-	Dlg->RetriesA->setText(QString::number(fracks[0]));
-	Dlg->RetriesB->setText(QString::number(fracks[1]));
-	Dlg->RetriesC->setText(QString::number(fracks[2]));
-	Dlg->RetriesD->setText(QString::number(fracks[3]));
-
-	sprintf(valChar, "%d", RCVR[0]);
-	Dlg->AddRXA->setText(valChar);
-	sprintf(valChar, "%d", RCVR[1]);
-	Dlg->AddRXB->setText(valChar);
-	sprintf(valChar, "%d", RCVR[2]);
-	Dlg->AddRXC->setText(valChar);
-	sprintf(valChar, "%d", RCVR[3]);
-	Dlg->AddRXD->setText(valChar);
-
-	sprintf(valChar, "%d", rcvr_offset[0]);
-	Dlg->RXShiftA->setText(valChar);
-
-	sprintf(valChar, "%d", rcvr_offset[1]);
-	Dlg->RXShiftB->setText(valChar);
-
-	sprintf(valChar, "%d", rcvr_offset[2]);
-	Dlg->RXShiftC->setText(valChar);
-	sprintf(valChar, "%d", rcvr_offset[3]);
-	Dlg->RXShiftD->setText(valChar);
-
-	//	speed[1]
-	//	speed[2];
-
-	Dlg->recoverBitA->setCurrentIndex(recovery[0]);
-	Dlg->recoverBitB->setCurrentIndex(recovery[1]);
-	Dlg->recoverBitC->setCurrentIndex(recovery[2]);
-	Dlg->recoverBitD->setCurrentIndex(recovery[3]);
-
-	Dlg->fx25ModeA->setCurrentIndex(fx25_mode[0]);
-	Dlg->fx25ModeB->setCurrentIndex(fx25_mode[1]);
-	Dlg->fx25ModeC->setCurrentIndex(fx25_mode[2]);
-	Dlg->fx25ModeD->setCurrentIndex(fx25_mode[3]);
-
-	Dlg->IL2PModeA->setCurrentIndex(il2p_mode[0]);
-	Dlg->IL2PModeB->setCurrentIndex(il2p_mode[1]);
-	Dlg->IL2PModeC->setCurrentIndex(il2p_mode[2]);
-	Dlg->IL2PModeD->setCurrentIndex(il2p_mode[3]);
-
-	Dlg->CWIDCall->setText(CWIDCall);
-	Dlg->CWIDInterval->setText(QString::number(CWIDInterval));
-
-	if (CWIDType)
-		Dlg->radioButton_2->setChecked(1);
-	else
-		Dlg->CWIDType->setChecked(1);
-
-	Dlg->RSIDSABM_A->setChecked(RSID_SABM[0]);
-	Dlg->RSIDSABM_B->setChecked(RSID_SABM[1]);
-	Dlg->RSIDSABM_C->setChecked(RSID_SABM[2]);
-	Dlg->RSIDSABM_D->setChecked(RSID_SABM[3]);
-
-	Dlg->RSIDUI_A->setChecked(RSID_UI[0]);
-	Dlg->RSIDUI_B->setChecked(RSID_UI[1]);
-	Dlg->RSIDUI_C->setChecked(RSID_UI[2]);
-	Dlg->RSIDUI_D->setChecked(RSID_UI[3]);
-
-	Dlg->DigiCallsA->setText(MyDigiCall[0]);
-	Dlg->DigiCallsB->setText(MyDigiCall[1]);
-	Dlg->DigiCallsC->setText(MyDigiCall[2]);
-	Dlg->DigiCallsD->setText(MyDigiCall[3]);
-
-	Dlg->RSID_1_SETMODEM->setChecked(RSID_SetModem[0]);
-	Dlg->RSID_2_SETMODEM->setChecked(RSID_SetModem[1]);
-	Dlg->RSID_3_SETMODEM->setChecked(RSID_SetModem[2]);
-	Dlg->RSID_4_SETMODEM->setChecked(RSID_SetModem[3]);
-	
-	connect(Dlg->showBPF_A, SIGNAL(released()), this, SLOT(clickedSlot()));
-	connect(Dlg->showTXBPF_A, SIGNAL(released()), this, SLOT(clickedSlot()));
-	connect(Dlg->showLPF_A, SIGNAL(released()), this, SLOT(clickedSlot()));
-
-	connect(Dlg->showBPF_B, SIGNAL(released()), this, SLOT(clickedSlot()));
-	connect(Dlg->showTXBPF_B, SIGNAL(released()), this, SLOT(clickedSlot()));
-	connect(Dlg->showLPF_B, SIGNAL(released()), this, SLOT(clickedSlot()));
-
-	connect(Dlg->showBPF_C, SIGNAL(released()), this, SLOT(clickedSlot()));
-	connect(Dlg->showTXBPF_C, SIGNAL(released()), this, SLOT(clickedSlot()));
-	connect(Dlg->showLPF_C, SIGNAL(released()), this, SLOT(clickedSlot()));
-
-	connect(Dlg->showBPF_D, SIGNAL(released()), this, SLOT(clickedSlot()));
-	connect(Dlg->showTXBPF_D, SIGNAL(released()), this, SLOT(clickedSlot()));
-	connect(Dlg->showLPF_D, SIGNAL(released()), this, SLOT(clickedSlot()));
-
-	connect(Dlg->okButton, SIGNAL(clicked()), this, SLOT(modemaccept()));
-	connect(Dlg->modemSave, SIGNAL(clicked()), this, SLOT(modemSave()));
-	connect(Dlg->cancelButton, SIGNAL(clicked()), this, SLOT(modemreject()));
-
-	connect(Dlg->SendRSID_1, SIGNAL(clicked()), this, SLOT(doRSIDA()));
-	connect(Dlg->SendRSID_2, SIGNAL(clicked()), this, SLOT(doRSIDB()));
-	connect(Dlg->SendRSID_3, SIGNAL(clicked()), this, SLOT(doRSIDC()));
-	connect(Dlg->SendRSID_4, SIGNAL(clicked()), this, SLOT(doRSIDD()));
-
-	connect(Dlg->preEmphAllA, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllAChanged(int)));
-	connect(Dlg->preEmphAllB, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllBChanged(int)));
-	connect(Dlg->preEmphAllC, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllCChanged(int)));
-	connect(Dlg->preEmphAllD, SIGNAL(stateChanged(int)), this, SLOT(preEmphAllDChanged(int)));
-
-	UI.exec();
-}
-
-void QtSoundModem::preEmphAllAChanged(int state)
-{
-	Dlg->preEmphA->setDisabled(state);
-}
-
-void QtSoundModem::preEmphAllBChanged(int state)
-{
-	Dlg->preEmphB->setDisabled(state);
-}
-
-void QtSoundModem::preEmphAllCChanged(int state)
-{
-	Dlg->preEmphC->setDisabled(state);
-}
-
-void QtSoundModem::preEmphAllDChanged(int state)
-{
-	Dlg->preEmphD->setDisabled(state);
-}
-
-extern "C" void get_exclude_list(char * line, TStringList * list);
-
-void QtSoundModem::modemaccept()
-{
-	modemSave();
-	delete(Dlg);
-	saveSettings();
-
-	modemUI->accept();
-
-}
-
-void QtSoundModem::modemSave()
-{
-	QVariant Q;
-	
-	emph_all[0] = Dlg->preEmphAllA->isChecked();
-	emph_db[0] = Dlg->preEmphA->currentIndex();
-
-	emph_all[1] = Dlg->preEmphAllB->isChecked();
-	emph_db[1] = Dlg->preEmphB->currentIndex();
-
-	emph_all[2] = Dlg->preEmphAllC->isChecked();
-	emph_db[2] = Dlg->preEmphC->currentIndex();
-
-	emph_all[3] = Dlg->preEmphAllD->isChecked();
-	emph_db[3] = Dlg->preEmphD->currentIndex();
-
-	NonAX25[0] = Dlg->nonAX25A->isChecked();
-	NonAX25[1] = Dlg->nonAX25B->isChecked();
-	NonAX25[2] = Dlg->nonAX25C->isChecked();
-	NonAX25[3] = Dlg->nonAX25D->isChecked();
-
-	KISS_opt[0] = Dlg->KISSOptA->isChecked();
-	KISS_opt[1] = Dlg->KISSOptB->isChecked();
-	KISS_opt[2] = Dlg->KISSOptC->isChecked();
-	KISS_opt[3] = Dlg->KISSOptD->isChecked();
-
-	if (emph_db[0] < 0 || emph_db[0] > nr_emph)
-		emph_db[0] = 0;
-
-	if (emph_db[1] < 0 || emph_db[1] > nr_emph)
-		emph_db[1] = 0;
-
-	if (emph_db[2] < 0 || emph_db[2] > nr_emph)
-		emph_db[2] = 0;
-
-	if (emph_db[3] < 0 || emph_db[3] > nr_emph)
-		emph_db[3] = 0;
-
-	Q = Dlg->TXDelayA->text();
-	txdelay[0] = Q.toInt();
-
-	Q = Dlg->TXDelayB->text();
-	txdelay[1] = Q.toInt();
-	
-	Q = Dlg->TXDelayC->text();
-	txdelay[2] = Q.toInt();
-
-	Q = Dlg->TXDelayD->text();
-	txdelay[3] = Q.toInt();
-
-	Q = Dlg->TXTailA->text();
-	txtail[0] = Q.toInt();
-
-	Q = Dlg->TXTailB->text();
-	txtail[1] = Q.toInt();
-
-	Q = Dlg->TXTailC->text();
-	txtail[2] = Q.toInt();
-
-	txtail[3] = Dlg->TXTailD->text().toInt();
-
-	frack_time[0] = Dlg->FrackA->text().toInt();
-	frack_time[1] = Dlg->FrackB->text().toInt();
-	frack_time[2] = Dlg->FrackC->text().toInt();
-	frack_time[3] = Dlg->FrackD->text().toInt();
-
-	fracks[0] = Dlg->RetriesA->text().toInt();
-	fracks[1] = Dlg->RetriesB->text().toInt();
-	fracks[2] = Dlg->RetriesC->text().toInt();
-	fracks[3] = Dlg->RetriesD->text().toInt();
-
-	Q = Dlg->AddRXA->text();
-	RCVR[0] = Q.toInt();
-
-	Q = Dlg->AddRXB->text();
-	RCVR[1] = Q.toInt();
-
-	Q = Dlg->AddRXC->text();
-	RCVR[2] = Q.toInt();
-
-	Q = Dlg->AddRXD->text();
-	RCVR[3] = Q.toInt();
-
-	Q = Dlg->RXShiftA->text();
-	rcvr_offset[0] = Q.toInt();
-
-	Q = Dlg->RXShiftB->text();
-	rcvr_offset[1] = Q.toInt();
-
-	Q = Dlg->RXShiftC->text();
-	rcvr_offset[2] = Q.toInt();
-
-	Q = Dlg->RXShiftD->text();
-	rcvr_offset[3] = Q.toInt();
-
-	fx25_mode[0] = Dlg->fx25ModeA->currentIndex();
-	fx25_mode[1] = Dlg->fx25ModeB->currentIndex();
-	fx25_mode[2] = Dlg->fx25ModeC->currentIndex();
-	fx25_mode[3] = Dlg->fx25ModeD->currentIndex();
-
-	il2p_mode[0] = Dlg->IL2PModeA->currentIndex();
-	il2p_mode[1] = Dlg->IL2PModeB->currentIndex();
-	il2p_mode[2] = Dlg->IL2PModeC->currentIndex();
-	il2p_mode[3] = Dlg->IL2PModeD->currentIndex();
-
-	recovery[0] = Dlg->recoverBitA->currentIndex();
-	recovery[1] = Dlg->recoverBitB->currentIndex();
-	recovery[2] = Dlg->recoverBitC->currentIndex();
-	recovery[3] = Dlg->recoverBitD->currentIndex();
-
-
-	strcpy(CWIDCall, Dlg->CWIDCall->text().toUtf8().toUpper());
-	CWIDInterval = Dlg->CWIDInterval->text().toInt();
-	CWIDType = Dlg->radioButton_2->isChecked();
-
-	if (CWIDInterval)
-		cwidtimer->start(CWIDInterval * 60000);
-	else
-		cwidtimer->stop();
-
-
-	RSID_SABM[0] = Dlg->RSIDSABM_A->isChecked();
-	RSID_SABM[1] = Dlg->RSIDSABM_B->isChecked();
-	RSID_SABM[2] = Dlg->RSIDSABM_C->isChecked();
-	RSID_SABM[3] = Dlg->RSIDSABM_D->isChecked();
-
-	RSID_UI[0] = Dlg->RSIDUI_A->isChecked();
-	RSID_UI[1] = Dlg->RSIDUI_B->isChecked();
-	RSID_UI[2] = Dlg->RSIDUI_C->isChecked();
-	RSID_UI[3] = Dlg->RSIDUI_D->isChecked();
-
-	RSID_SetModem[0] = Dlg->RSID_1_SETMODEM->isChecked();
-	RSID_SetModem[1] = Dlg->RSID_2_SETMODEM->isChecked();
-	RSID_SetModem[2] = Dlg->RSID_3_SETMODEM->isChecked();
-	RSID_SetModem[3] = Dlg->RSID_4_SETMODEM->isChecked();
-
-	Q = Dlg->DigiCallsA->text();
-	strcpy(MyDigiCall[0], Q.toString().toUtf8().toUpper());
-
-	Q = Dlg->DigiCallsB->text();
-	strcpy(MyDigiCall[1], Q.toString().toUtf8().toUpper());
-
-	Q = Dlg->DigiCallsC->text();
-	strcpy(MyDigiCall[2], Q.toString().toUtf8().toUpper());
-
-	Q = Dlg->DigiCallsD->text();
-	strcpy(MyDigiCall[3], Q.toString().toUtf8().toUpper());
-
-	int i;
-
-	for (i = 0; i < 4; i++)
-	{
-		initTStringList(&list_digi_callsigns[i]);
-
-		get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]);
-	}
-
-}
-
-void QtSoundModem::modemreject()
-{
-	delete(Dlg);
-	modemUI->reject();
-}
-
-void QtSoundModem::doRSIDA()
-{
-	needRSID[0] = 1;
-}
-
-void QtSoundModem::doRSIDB()
-{
-	needRSID[1] = 1;
-}
-
-void QtSoundModem::doRSIDC()
-{
-	needRSID[2] = 1;
-}
-
-void QtSoundModem::doRSIDD()
-{
-	needRSID[3] = 1;
-}
-
-
-
-
-void QtSoundModem::doFilter(int Chan, int Filter)
-{
-	Ui_Dialog Dev;
-	QImage * bitmap;
-
-	QDialog UI;
-
-	Dev.setupUi(&UI);
-
-	bitmap = new QImage(642, 312, QImage::Format_RGB32);
-
-	bitmap->fill(qRgb(255, 255, 255));
-
-	QPainter qPainter(bitmap);
-	qPainter.setBrush(Qt::NoBrush);
-	qPainter.setPen(Qt::black);
-
-	if (Filter == 0)
-		make_graph_buf(DET[0][0].BPF_core[Chan], BPF_tap[Chan], &qPainter);
-	else if (Filter == 1)
-		make_graph_buf(tx_BPF_core[Chan], tx_BPF_tap[Chan], &qPainter);
-	else
-		make_graph_buf(LPF_core[Chan], LPF_tap[Chan], &qPainter);
-
-	qPainter.end();
-	Dev.label->setPixmap(QPixmap::fromImage(*bitmap));
-
-	UI.exec();
-
-}
-
-Ui_devicesDialog * Dev;
-
-char NewPTTPort[80];
-
-int newSoundMode = 0;
-int oldSoundMode = 0;
-
-void QtSoundModem::SoundModeChanged(bool State)
-{
-	UNUSED(State);
-
-	// Mustn't change SoundMode until dialog is accepted
-
-	if (Dev->UDP->isChecked())
-		newSoundMode = 3;
-	else if (Dev->PULSE->isChecked())
-		newSoundMode = 2;
-	else
-		newSoundMode = Dev->OSS->isChecked();
-
-}
-
-void QtSoundModem::DualPTTChanged(bool State)
-{
-	UNUSED(State);
-
-	// Forse Evaluation of Cat Port setting
-
-	PTTPortChanged(0);
-}
-
-void QtSoundModem::CATChanged(bool State)
-{
-	UNUSED(State);
-	PTTPortChanged(0);
-}
-
-void QtSoundModem::PTTPortChanged(int Selected)
-{
-	UNUSED(Selected);
-
-	QVariant Q = Dev->PTTPort->currentText();
-	strcpy(NewPTTPort, Q.toString().toUtf8());
-
-	Dev->RTSDTR->setVisible(false);
-	Dev->CAT->setVisible(false);
-
-	Dev->PTTOnLab->setVisible(false);
-	Dev->PTTOn->setVisible(false);
-	Dev->PTTOff->setVisible(false);
-	Dev->PTTOffLab->setVisible(false);
-	Dev->CATLabel->setVisible(false);
-	Dev->CATSpeed->setVisible(false);
-
-	Dev->GPIOLab->setVisible(false);
-	Dev->GPIOLeft->setVisible(false);
-	Dev->GPIORight->setVisible(false);
-	Dev->GPIOLab2->setVisible(false);
-
-	Dev->CM108Label->setVisible(false);
-	Dev->VIDPID->setVisible(false);
-
-	if (strcmp(NewPTTPort, "None") == 0)
-	{
-	}
-	else if (strcmp(NewPTTPort, "GPIO") == 0)
-	{
-		Dev->GPIOLab->setVisible(true);
-		Dev->GPIOLeft->setVisible(true);
-		if (Dev->DualPTT->isChecked())
-		{
-			Dev->GPIORight->setVisible(true);
-			Dev->GPIOLab2->setVisible(true);
-		}
-	}
-
-	else if (strcmp(NewPTTPort, "CM108") == 0)
-	{
-		Dev->CM108Label->setVisible(true);
-//#ifdef __ARM_ARCHX
-		Dev->CM108Label->setText("CM108 Device");
-//#else
-//		Dev->CM108Label->setText("CM108 VID/PID");
-//#endif
-		Dev->VIDPID->setText(CM108Addr);
-		Dev->VIDPID->setVisible(true);
-	}
-	else if (strcmp(NewPTTPort, "HAMLIB") == 0)
-	{
-		Dev->CM108Label->setVisible(true);
-		Dev->CM108Label->setText("rigctrld Port");
-		Dev->VIDPID->setText(QString::number(HamLibPort));
-		Dev->VIDPID->setVisible(true);
-		Dev->PTTOnLab->setText("rigctrld Host");
-		Dev->PTTOnLab->setVisible(true);
-		Dev->PTTOn->setText(HamLibHost);
-		Dev->PTTOn->setVisible(true);
-	}
-	else
-	{
-		Dev->RTSDTR->setVisible(true);
-		Dev->CAT->setVisible(true);
-
-		if (Dev->CAT->isChecked())
-		{
-			Dev->PTTOnLab->setVisible(true);
-			Dev->PTTOnLab->setText("PTT On String");
-			Dev->PTTOn->setText(PTTOnString);
-			Dev->PTTOn->setVisible(true);
-			Dev->PTTOff->setVisible(true);
-			Dev->PTTOff->setText(PTTOffString);
-			Dev->PTTOffLab->setVisible(true);
-			Dev->CATLabel->setVisible(true);
-			Dev->CATSpeed->setVisible(true);
-		}
-	}
-}
-
-bool myResize::eventFilter(QObject *obj, QEvent *event)
-{
-	if (event->type() == QEvent::Resize)
-	{
-		QResizeEvent *resizeEvent = static_cast(event);
-		QSize size = resizeEvent->size();
-		int h = size.height();
-		int w = size.width();
-
-		if (obj == deviceUI)
-			Dev->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10));
-		else
-			Dlg->scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10));
-
-		return true;
-	}
-	return QObject::eventFilter(obj, event);
-}
-
-void QtSoundModem::doDevices()
-{
-	char valChar[10];
-
-	Dev = new(Ui_devicesDialog);
-
-	QDialog UI;
-
-	int i;
-
-	Dev->setupUi(&UI);
-
-	deviceUI = &UI;
-	modemUI = 0;
-
-	myResize *resize = new myResize();
-
-	UI.installEventFilter(resize);
-
-	newSoundMode = SoundMode;
-	oldSoundMode = SoundMode;
-
-#ifdef WIN32
-	Dev->ALSA->setText("WaveOut");
-	Dev->OSS->setVisible(0);
-	Dev->PULSE->setVisible(0);
-#endif
-
-	if (SoundMode == 0)
-		Dev->ALSA->setChecked(1);
-	else if (SoundMode == 1)
-		Dev->OSS->setChecked(1);
-	else if (SoundMode == 2)
-		Dev->PULSE->setChecked(1);
-	else if (SoundMode == 2)
-		Dev->UDP->setChecked(1);
-
-	connect(Dev->ALSA, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool)));
-	connect(Dev->OSS, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool)));
-	connect(Dev->PULSE, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool)));
-	connect(Dev->UDP, SIGNAL(toggled(bool)), this, SLOT(SoundModeChanged(bool)));
-
-	for (i = 0; i < PlaybackCount; i++)
-		Dev->outputDevice->addItem(&PlaybackNames[i][0]);
-
-	i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains);
-
-
-	if (i == -1)
-	{
-		// Add device to list
-
-		Dev->outputDevice->addItem(PlaybackDevice);
-		i = Dev->outputDevice->findText(PlaybackDevice, Qt::MatchContains);
-	}
-
-	Dev->outputDevice->setCurrentIndex(i);
-
-	for (i = 0; i < CaptureCount; i++)
-		Dev->inputDevice->addItem(&CaptureNames[i][0]);
-
-	i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains);
-
-	if (i == -1)
-	{
-		// Add device to list
-
-		Dev->inputDevice->addItem(CaptureDevice);
-		i = Dev->inputDevice->findText(CaptureDevice, Qt::MatchContains);
-	}
-	Dev->inputDevice->setCurrentIndex(i);
-
-	Dev->Modem_1_Chan->setCurrentIndex(soundChannel[0]);
-	Dev->Modem_2_Chan->setCurrentIndex(soundChannel[1]);
-	Dev->Modem_3_Chan->setCurrentIndex(soundChannel[2]);
-	Dev->Modem_4_Chan->setCurrentIndex(soundChannel[3]);
-
-	// Disable "None" option in first modem
-
-	QStandardItemModel *model = dynamic_cast(Dev->Modem_1_Chan->model());
-	QStandardItem * item = model->item(0, 0);
-	item->setEnabled(false);
-
-	Dev->singleChannelOutput->setChecked(SCO);
-	Dev->colourWaterfall->setChecked(raduga);
-
-	sprintf(valChar, "%d", KISSPort);
-	Dev->KISSPort->setText(valChar);
-	Dev->KISSEnabled->setChecked(KISSServ);
-
-	sprintf(valChar, "%d", AGWPort);
-	Dev->AGWPort->setText(valChar);
-	Dev->AGWEnabled->setChecked(AGWServ);
-
-	Dev->PTTOn->setText(PTTOnString);
-	Dev->PTTOff->setText(PTTOffString);
-
-	sprintf(valChar, "%d", PTTBAUD);
-	Dev->CATSpeed->setText(valChar);
-
-	sprintf(valChar, "%d", UDPClientPort);
-	Dev->UDPPort->setText(valChar);
-	Dev->UDPTXHost->setText(UDPHost);
-
-	if (UDPServerPort != TXPort)
-		sprintf(valChar, "%d/%d", UDPServerPort, TXPort);
-	else
-		sprintf(valChar, "%d", UDPServerPort);
-
-	Dev->UDPTXPort->setText(valChar);
-
-	Dev->UDPEnabled->setChecked(UDPServ);
-
-	sprintf(valChar, "%d", pttGPIOPin);
-	Dev->GPIOLeft->setText(valChar);
-	sprintf(valChar, "%d", pttGPIOPinR);
-	Dev->GPIORight->setText(valChar);
-
-	Dev->VIDPID->setText(CM108Addr);
-
-	QStringList items;
-
-	connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool)));
-	connect(Dev->DualPTT, SIGNAL(toggled(bool)), this, SLOT(DualPTTChanged(bool)));
-	connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int)));
-
-
-
-	if (PTTMode == PTTCAT)
-		Dev->CAT->setChecked(true);
-	else
-		Dev->RTSDTR->setChecked(true);
-
-	for (const QSerialPortInfo &info : Ports)
-	{
-		items.append(info.portName());
-	}
-
-	items.sort();
-
-	Dev->PTTPort->addItem("None");
-	Dev->PTTPort->addItem("CM108");
-
-	//#ifdef __ARM_ARCH
-
-	Dev->PTTPort->addItem("GPIO");
-
-	//#endif
-
-	Dev->PTTPort->addItem("HAMLIB");
-
-	for (const QString &info : items)
-	{
-		Dev->PTTPort->addItem(info);
-	}
-
-	Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString));
-
-	PTTPortChanged(0);				// Force reevaluation
-
-	Dev->txRotation->setChecked(TX_rotate);
-	Dev->DualPTT->setChecked(DualPTT);
-
-	Dev->multiCore->setChecked(multiCore);
-
-	QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept()));
-	QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject()));
-
-	UI.exec();
-
-}
-
-void QtSoundModem::deviceaccept()
-{
-	QVariant Q = Dev->inputDevice->currentText();
-	int cardChanged = 0;
-	char portString[32];
-
-	if (Dev->UDP->isChecked())
-	{
-		// cant have server and slave
-
-		if (Dev->UDPEnabled->isChecked())
-		{
-			QMessageBox::about(this, tr("QtSoundModem"),
-				tr("Can't have UDP sound source and UDP server at same time"));
-			return;
-		}
-	}
-
-	if (oldSoundMode != newSoundMode)
-	{
-		QMessageBox msgBox;
-
-		msgBox.setText("QtSoundModem must restart to change Sound Mode.\n"
-			"Program will close if you hit Ok\n"
-			"You will need to reselect audio devices after restarting");
-
-		msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
-
-		int i = msgBox.exec();
-
-		if (i == QMessageBox::Ok)
-		{
-			SoundMode = newSoundMode;
-
-			saveSettings();
-
-			Closing = 1;
-			return;
-		}
-
-		if (oldSoundMode == 0)
-			Dev->ALSA->setChecked(1);
-		else if (oldSoundMode == 1)
-			Dev->OSS->setChecked(1);
-		else if (oldSoundMode == 2)
-			Dev->PULSE->setChecked(1);
-		else if (oldSoundMode == 3)
-			Dev->UDP->setChecked(1);
-
-		QMessageBox::about(this, tr("Info"),
-			tr("Changes not saved "));
-
-		return;
-
-	}
-
-	if (strcmp(CaptureDevice, Q.toString().toUtf8()) != 0)
-	{
-		strcpy(CaptureDevice, Q.toString().toUtf8());
-		cardChanged = 1;
-	}
-
-	CaptureIndex = Dev->inputDevice->currentIndex();
-
-	Q = Dev->outputDevice->currentText();
-
-	if (strcmp(PlaybackDevice, Q.toString().toUtf8()) != 0)
-	{
-		strcpy(PlaybackDevice, Q.toString().toUtf8());
-		cardChanged = 1;
-	}
-
-	PlayBackIndex = Dev->outputDevice->currentIndex();
-
-	soundChannel[0] = Dev->Modem_1_Chan->currentIndex();
-	soundChannel[1] = Dev->Modem_2_Chan->currentIndex();
-	soundChannel[2] = Dev->Modem_3_Chan->currentIndex();
-	soundChannel[3] = Dev->Modem_4_Chan->currentIndex();
-
-	UsingLeft = 0;
-	UsingRight = 0;
-	UsingBothChannels = 0;
-
-	for (int i = 0; i < 4; i++)
-	{
-		if (soundChannel[i] == LEFT)
-		{
-			UsingLeft = 1;
-			modemtoSoundLR[i] = 0;
-		}
-		else if (soundChannel[i] == RIGHT)
-		{
-			UsingRight = 1;
-			modemtoSoundLR[i] = 1;
-		}
-	}
-
-	if (UsingLeft && UsingRight)
-		UsingBothChannels = 1;
-
-
-	SCO = Dev->singleChannelOutput->isChecked();
-	raduga = Dev->colourWaterfall->isChecked();
-	AGWServ = Dev->AGWEnabled->isChecked();
-	KISSServ = Dev->KISSEnabled->isChecked();
-
-	Q = Dev->KISSPort->text();
-	KISSPort = Q.toInt();
-
-	Q = Dev->AGWPort->text();
-	AGWPort = Q.toInt();
-
-	Q = Dev->PTTPort->currentText();
-	strcpy(PTTPort, Q.toString().toUtf8());
-
-	DualPTT = Dev->DualPTT->isChecked();
-	TX_rotate = Dev->txRotation->isChecked();
-	multiCore = Dev->multiCore->isChecked();
-
-	if (Dev->CAT->isChecked())
-		PTTMode = PTTCAT;
-	else
-		PTTMode = PTTRTS;
-
-	Q = Dev->PTTOn->text();
-	strcpy(PTTOnString, Q.toString().toUtf8());
-	Q = Dev->PTTOff->text();
-	strcpy(PTTOffString, Q.toString().toUtf8());
-
-	Q = Dev->CATSpeed->text();
-	PTTBAUD = Q.toInt();
-
-	Q = Dev->UDPPort->text();
-	UDPClientPort = Q.toInt();
-
-
-	Q = Dev->UDPTXPort->text();
-	strcpy(portString, Q.toString().toUtf8());
-	UDPServerPort = atoi(portString);
-
-	if (strchr(portString, '/'))
-	{
-		char * ptr = strlop(portString, '/');
-		TXPort = atoi(ptr);
-	}
-	else
-		TXPort = UDPServerPort;
-
-	Q = Dev->UDPTXHost->text();
-	strcpy(UDPHost, Q.toString().toUtf8());
-
-	UDPServ = Dev->UDPEnabled->isChecked();
-
-	Q = Dev->GPIOLeft->text();
-	pttGPIOPin = Q.toInt();
-
-	Q = Dev->GPIORight->text();
-	pttGPIOPinR = Q.toInt();
-
-	Q = Dev->VIDPID->text();
-
-	if (strcmp(PTTPort, "CM108") == 0)
-		strcpy(CM108Addr, Q.toString().toUtf8());
-	else if (strcmp(PTTPort, "HAMLIB") == 0)
-	{
-		HamLibPort = Q.toInt();
-		Q = Dev->PTTOn->text();
-		strcpy(HamLibHost, Q.toString().toUtf8());
-	}
-
-	ClosePTTPort();
-	OpenPTTPort();
-
-	wf_pointer(soundChannel[0]);
-	wf_pointer(soundChannel[1]);
-
-	delete(Dev);
-	saveSettings();
-	deviceUI->accept();
-
-	if (cardChanged)
-	{
-		InitSound(1);
-	}
-
-	// Reset title and tooltip in case ports changed
-
-	char Title[128];
-	sprintf(Title, "QtSoundModem Version %s Ports %d/%d", VersionString, AGWPort, KISSPort);
-	w->setWindowTitle(Title);
-
-	sprintf(Title, "QtSoundModem %d %d", AGWPort, KISSPort);
-	if (trayIcon)
-		trayIcon->setToolTip(Title);
-
-	QSize newSize(this->size());
-	QSize oldSize(this->size());
-
-	QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize);
-
-	QCoreApplication::postEvent(this, myResizeEvent);  
-}
-
-void QtSoundModem::devicereject()
-{	
-	delete(Dev);
-	deviceUI->reject();
-}
-
-void QtSoundModem::handleButton(int Port, int Type)
-{
-	// interlock calib with CWID
-
-	if (calib_mode[0] == 4)		// CWID
-		return;
-	
-	doCalib(Port, Type);
-}
-
-void QtSoundModem::doRestartWF()
-{
-	if (Firstwaterfall)
-	{
-		initWaterfall(0, 0);
-		initWaterfall(0, 1);
-	}
-
-	if (Secondwaterfall)
-	{
-		initWaterfall(1, 0);
-		initWaterfall(1, 1);
-	}
-}
-
-
-void QtSoundModem::doAbout()
-{
-	QMessageBox::about(this, tr("About"),
-		tr("G8BPQ's port of UZ7HO's Soundmodem\n\nCopyright (C) 2019-2020 Andrei Kopanchuk UZ7HO"));
-}
-
-void QtSoundModem::doCalibrate()
-{
-	Ui_calDialog Calibrate;
-	{
-		QDialog UI;
-		Calibrate.setupUi(&UI);
-
-		connect(Calibrate.Low_A, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Both_A, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Stop_A, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Low_B, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.High_B, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Both_B, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Stop_B, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Low_C, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.High_C, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Both_C, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Stop_C, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Low_D, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.High_D, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Both_D, SIGNAL(released()), this, SLOT(clickedSlot()));
-		connect(Calibrate.Stop_D, SIGNAL(released()), this, SLOT(clickedSlot()));
-
-		/*
-		
-		connect(Calibrate.Low_A, &QPushButton::released, this, [=] { handleButton(0, 1); });
-		connect(Calibrate.High_A, &QPushButton::released, this, [=] { handleButton(0, 2); });
-		connect(Calibrate.Both_A, &QPushButton::released, this, [=] { handleButton(0, 3); });
-		connect(Calibrate.Stop_A, &QPushButton::released, this, [=] { handleButton(0, 0); });
-		connect(Calibrate.Low_B, &QPushButton::released, this, [=] { handleButton(1, 1); });
-		connect(Calibrate.High_B, &QPushButton::released, this, [=] { handleButton(1, 2); });
-		connect(Calibrate.Both_B, &QPushButton::released, this, [=] { handleButton(1, 3); });
-		connect(Calibrate.Stop_B, &QPushButton::released, this, [=] { handleButton(1, 0); });
-
-//		connect(Calibrate.High_A, SIGNAL(released()), this, SLOT(handleButton(1, 2)));
-*/
-		UI.exec();
-	}
-}
-
-void QtSoundModem::RefreshSpectrum(unsigned char * Data)
-{
-	int i;
-
-	// Last 4 bytes are level busy and Tuning lines
-
-	Waterfall[0]->fill(Black);
-
-	if (Data[206] != LastLevel)
-	{
-		LastLevel = Data[206];
-//		RefreshLevel(LastLevel);
-	}
-
-	if (Data[207] != LastBusy)
-	{
-		LastBusy = Data[207];
-//		Busy->setVisible(LastBusy);
-	}
-
-	for (i = 0; i < 205; i++)
-	{
-		int val = Data[0];
-
-		if (val > 63)
-			val = 63;
-
-		Waterfall[0]->setPixel(i, val, Yellow);
-		if (val < 62)
-			Waterfall[0]->setPixel(i, val + 1, Gold);
-		Data++;
-	}
-
-	ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0]));
-
-}
-
-void QtSoundModem::RefreshWaterfall(int snd_ch, unsigned char * Data)
-{
-	int j;
-	unsigned char * Line;
-	int len = Waterfall[0]->bytesPerLine();
-	int TopLine = NextWaterfallLine[snd_ch];
-
-	// Write line to cyclic buffer then draw starting with the line just written
-
-	// Length is 208 bytes, including Level and Busy flags
-
-	memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Data, 206);
-	if (NextWaterfallLine[snd_ch] > 63)
-		NextWaterfallLine[snd_ch] = 0;
-
-	for (j = 63; j > 0; j--)
-	{
-		Line = Waterfall[0]->scanLine(j);
-		memcpy(Line, &WaterfallLines[snd_ch][TopLine++][0], len);
-		if (TopLine > 63)
-			TopLine = 0;
-	}
-
-	ui.WaterfallA->setPixmap(QPixmap::fromImage(*Waterfall[0]));
-}
-
-
-void QtSoundModem::sendtoTrace(char * Msg, int tx)
-{
-	const QTextCursor old_cursor = monWindowCopy->textCursor();
-	const int old_scrollbar_value = monWindowCopy->verticalScrollBar()->value();
-	const bool is_scrolled_down = old_scrollbar_value == monWindowCopy->verticalScrollBar()->maximum();
-
-	// Move the cursor to the end of the document.
-	monWindowCopy->moveCursor(QTextCursor::End);
-
-	// Insert the text at the position of the cursor (which is the end of the document).
-
-	if (tx)
-		monWindowCopy->setTextColor(qRgb(192, 0, 0));
-	else
-		monWindowCopy->setTextColor(qRgb(0, 0, 192));
-
-	monWindowCopy->textCursor().insertText(Msg);
-
-	if (old_cursor.hasSelection() || !is_scrolled_down)
-	{
-		// The user has selected text or scrolled away from the bottom: maintain position.
-		monWindowCopy->setTextCursor(old_cursor);
-		monWindowCopy->verticalScrollBar()->setValue(old_scrollbar_value);
-	}
-	else
-	{
-		// The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom.
-		monWindowCopy->moveCursor(QTextCursor::End);
-		monWindowCopy->verticalScrollBar()->setValue(monWindowCopy->verticalScrollBar()->maximum());
-	}
-
-	free(Msg);
-}
-
-
-// I think this does the waterfall
-
-typedef struct TRGBQ_t
-{
-	Byte b, g, r, re;
-
-} TRGBWQ;
-
-typedef struct tagRECT
-{
-	int    left;
-	int    top;
-	int    right;
-	int    bottom;
-} RECT;
-
-unsigned int RGBWF[256] ;
-
-
-extern "C" void init_raduga()
-{
-	Byte offset[6] = {0, 51, 102, 153, 204};
-	Byte i, n;
-
-	for (n = 0; n < 52; n++)
-	{
-		i = n * 5;
-
-		RGBWF[n + offset[0]] = qRgb(0, 0, i);
-		RGBWF[n + offset[1]] = qRgb(0, i, 255);
-		RGBWF[n + offset[2]] = qRgb(0, 255, 255 - i);
-		RGBWF[n + offset[3]] = qRgb(1, 255, 0);
-		RGBWF[n + offset[4]] = qRgb(255, 255 - 1, 0);
-	}
-}
-
-extern "C" int nonGUIMode;
-
-
-// This draws the Frequency Scale on Waterfall
-
-extern "C" void wf_Scale(int Chan)
-{
-	if (nonGUIMode)
-		return;
-
-	float k;
-	int maxfreq, x, i;
-	char Textxx[20];
-	QImage * bm = Header[Chan];
-
-	QPainter qPainter(bm);
-	qPainter.setBrush(Qt::black);
-	qPainter.setPen(Qt::white);
-
-	maxfreq = roundf(RX_Samplerate*0.005);
-	k = 100 * fft_size / RX_Samplerate;
-
-	if (Chan == 0)
-		sprintf(Textxx, "Left");
-	else
-		sprintf(Textxx, "Right");
-
-	qPainter.drawText(2, 1,
-		100, 20, 0, Textxx);
-
-	for (i = 0; i < maxfreq; i++)
-	{
-		x = round(k*i);
-		if (x < 1025)
-		{
-			if ((i % 5) == 0)
-				qPainter.drawLine(x, 20, x, 13);
-			else
-				qPainter.drawLine(x, 20, x, 16);
-
-			if ((i % 10) == 0)
-			{
-				sprintf(Textxx, "%d", i * 100);
-
-				qPainter.drawText(x - 12, 1,
-					100, 20, 0, Textxx);
-			}
-		}
-	}
-	HeaderCopy[Chan]->setPixmap(QPixmap::fromImage(*bm));
-
-}
-
-// This draws the frequency Markers on the Waterfall
-
-
-void do_pointer(int waterfall)
-{
-	if (nonGUIMode)
-		return;
-
-	float x;
-
-	int x1, x2, k, pos1, pos2, pos3;
-	QImage * bm = Header[waterfall];
-
-	QPainter qPainter(bm);
-	qPainter.setBrush(Qt::NoBrush);
-	qPainter.setPen(Qt::white);
-
-	//	bm->fill(black);
-
-	qPainter.fillRect(0, 26, 1024, 9, Qt::black);
-
-	k = 29;
-	x = fft_size / RX_Samplerate;
-
-	// draw all enabled ports on the ports on this soundcard
-
-	// First Modem is always on the first waterfall
-	// If second is enabled it is on the first unless different
-	//		channel from first
-
-	for (int i = 0; i < 4; i++)
-	{
-		if (UsingBothChannels == 0)
-		{
-			// Only One Waterfall. If first chan is 
-
-			if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT))
-				return;
-		}
-
-		if (soundChannel[i] == 0)
-			continue;
-
-
-		if (UsingBothChannels == 1)
-			if ((waterfall == 0 && soundChannel[i] == RIGHT) || (waterfall == 1 && soundChannel[i] == LEFT))
-				continue;
-
-		pos1 = roundf(((rxOffset + chanOffset[i] + rx_freq[i]) - 0.5*rx_shift[i])*x) - 5;
-		pos2 = roundf(((rxOffset + chanOffset[i] + rx_freq[i]) + 0.5*rx_shift[i])*x) - 5;
-		pos3 = roundf((rxOffset + chanOffset[i] + rx_freq[i]) * x);
-		x1 = pos1 + 5;
-		x2 = pos2 + 5;
-
-		qPainter.setPen(Qt::white);
-		qPainter.drawLine(x1, k, x2, k);
-		qPainter.drawLine(x1, k - 3, x1, k + 3);
-		qPainter.drawLine(x2, k - 3, x2, k + 3);
-		qPainter.drawLine(pos3, k - 3, pos3, k + 3);
-
-		if (rxOffset || chanOffset[i])
-		{
-			// Draw TX posn if rxOffset used
-
-			pos3 = roundf(rx_freq[i] * x);
-			qPainter.setPen(Qt::magenta);
-			qPainter.drawLine(pos3, k - 3, pos3, k + 3);
-			qPainter.drawLine(pos3, k - 3, pos3, k + 3);
-			qPainter.drawLine(pos3 - 2, k - 3, pos3 + 2, k - 3);
-
-		}
-	}
-	HeaderCopy[waterfall]->setPixmap(QPixmap::fromImage(*bm));
-}
-
-void wf_pointer(int snd_ch)
-{
-	UNUSED(snd_ch);
-
-	do_pointer(0);
-	do_pointer(1);
-//	do_pointer(2);
-//	do_pointer(3);
-}
-
-
-void doWaterfallThread(void * param);
-
-/*
-#ifdef WIN32
-
-#define pthread_t uintptr_t
-
-extern "C" uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist);
-
-#else
-
-#include 
-
-extern "C" pthread_t _beginthread(void(*start_address)(void *), unsigned stack_size, void * arglist)
-{
-	pthread_t thread;
-
-	if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*)arglist) != 0)
-		perror("New Thread");
-	else
-		pthread_detach(thread);
-
-	return thread;
-}
-
-#endif
-*/
-extern "C" void doWaterfall(int snd_ch)
-{
-	if (nonGUIMode)
-		return;
-
-	if (Closing)
-		return;
-
-//	if (multiCore)			// Run modems in separate threads
-//		_beginthread(doWaterfallThread, 0, xx);
-//	else
-		doWaterfallThread((void *)(size_t)snd_ch);
-
-}
-
-
-extern "C" float aFFTAmpl[1024];
-
-void doWaterfallThread(void * param)
-{
-	int snd_ch = (int)(size_t)param;
-
-	QImage * bm = Waterfall[snd_ch];
-	
-	word  i, wid;
-	single  mag;
-	UCHAR * p;
-	UCHAR Line[4096];
-
-	int lineLen;
-	word  hfft_size;
-	Byte  n;
-	float RealOut[4096] = { 0 };
-	float ImagOut[4096];
-
-	QRegion exposed;
-
-	hfft_size = fft_size / 2;
-
-	// I think an FFT should produce n/2 bins, each of Samp/n Hz
-	// Looks like my code only works with n a power of 2
-
-	// So can use 1024 or 4096. 1024 gives 512 bins of 11.71875 and a 512 pixel 
-	// display (is this enough?)
-
-	// This does 2048
-
-	if (0)	//RSID_WF
-	{
-		// Use the Magnitudes in float aFFTAmpl[RSID_FFT_SIZE];
-
-		for (i = 0; i < hfft_size; i++)
-		{
-			mag = aFFTAmpl[i];
-
-			mag *= 0.00000042f;
-
-			if (mag < 0.00001f)
-				mag = 0.00001f;
-
-			if (mag > 1.0f)
-				mag = 1.0f;
-
-			mag = 22 * log2f(mag) + 255;
-
-			if (mag < 0)
-				mag = 0;
-
-			fft_disp[snd_ch][i] = round(mag);
-		}
-	}
-	else
-	{
-		dofft(&fft_buf[snd_ch][0], RealOut, ImagOut);
-
-		//	FourierTransform(1024, &fft_buf[snd_ch][0], RealOut, ImagOut, 0);
-
-		for (i = 0; i < hfft_size; i++)
-		{
-			//mag: = ComplexMag(fft_d[i])*0.00000042;
-
-	//		mag = sqrtf(powf(RealOut[i], 2) + powf(ImagOut[i], 2)) * 0.00000042f;
-
-			mag = powf(RealOut[i], 2);
-			mag += powf(ImagOut[i], 2);
-			mag = sqrtf(mag);
-			mag *= 0.00000042f;
-
-
-			if (mag > MaxMagOut)
-			{
-				MaxMagOut = mag;
-				MaxMagIndex = i;
-			}
-
-			if (mag < 0.00001f)
-				mag = 0.00001f;
-
-			if (mag > 1.0f)
-				mag = 1.0f;
-
-			mag = 22 * log2f(mag) + 255;
-
-			if (mag < 0)
-				mag = 0;
-
-			MagOut[i] = mag;
-			fft_disp[snd_ch][i] = round(mag);
-		}
-	}
-
-
-
-	/*
-		for (i = 0; i < hfft_size; i++)
-			fft[i] = (powf(RealOut[i], 2) + powf(ImagOut[i], 2));
-
-		for (i = 0; i < hfft_size; i++)
-		{
-			if (fft[i] > max)
-			{
-				max = fft[i];
-				imax = i;
-			}
-		}
-
-		if (max > 0)
-		{
-			for (i = 0; i < hfft_size; i++)
-				fft[i] = fft[i] / max;
-		}
-
-
-		for (i = 0; i < hfft_size; i++)
-		{
-			mag = fft[i];
-
-			if (mag < 0.00001f)
-				mag = 0.00001f;
-
-			if (mag > 1.0f)
-				mag = 1.0f;
-
-			mag = 22 * log2f(mag) + 255;
-
-			if (mag < 0)
-				mag = 0;
-
-			fft_disp[snd_ch][i] = round(mag);
-		}
-
-		*/
-
-	//	bm[snd_ch].Canvas.CopyRect(d, bm[snd_ch].canvas, s)
-
-	//pm->scroll(0, 1, 0, 0, 1024, 80, &exposed);
-
-	// Each bin is 12000 /2048 = 5.859375
-	// I think we plot at 6 Hz per pixel.
-
-	wid = bm->width();
-	if (wid > hfft_size)
-		wid = hfft_size;
-
-	wid = wid - 1;
-
-	p = Line;
-	lineLen = bm->bytesPerLine();
-
-	if (wid > lineLen / 4)
-		wid = lineLen / 4;
-
-	if (raduga == DISP_MONO)
-	{
-		for (i = 0; i < wid; i++)
-		{
-			n = fft_disp[snd_ch][i];
-			*(p++) = n;					// all colours the same
-			*(p++) = n;
-			*(p++) = n;
-			p++;
-		}
-	}
-	else
-	{
-		for (i = 0; i < wid; i++)
-		{
-			n = fft_disp[snd_ch][i];
-
-		memcpy(p, &RGBWF[n], 4);
-			p += 4;
-		}
-	}
-
-	// Scroll
-
-	int TopLine = NextWaterfallLine[snd_ch];
-
-	// Write line to cyclic buffer then draw starting with the line just written
-
-	memcpy(&WaterfallLines[snd_ch][NextWaterfallLine[snd_ch]++][0], Line, 4096);
-	if (NextWaterfallLine[snd_ch] > 79)
-		NextWaterfallLine[snd_ch] = 0;
-
-	for (int j = 79; j > 0; j--)
-	{
-		p = bm->scanLine(j);
-		memcpy(p, &WaterfallLines[snd_ch][TopLine][0], lineLen);
-		TopLine++;
-		if (TopLine > 79)
-			TopLine = 0;
-	}
-
-	WaterfallCopy[snd_ch]->setPixmap(QPixmap::fromImage(*bm));
-	//	WaterfallCopy[snd_ch - 1]->setPixmap(*pm);
-		//	WaterfallCopy[1]->setPixmap(QPixmap::fromImage(*bm));
-
-}
-
-
-
-void QtSoundModem::changeEvent(QEvent* e)
-{
-	if (e->type() == QEvent::WindowStateChange)
-	{
-		QWindowStateChangeEvent* ev = static_cast(e);
-
-		qDebug() << windowState();
-
-		if (!(ev->oldState() & Qt::WindowMinimized) && windowState() & Qt::WindowMinimized)
-		{
-			if (trayIcon)
-				setVisible(false);
-		}
-//		if (!(ev->oldState() != Qt::WindowNoState) && windowState() == Qt::WindowNoState)
-//		{
-//			QMessageBox::information(this, "", "Window has been restored");
-//		}
-
-	}
-	QWidget::changeEvent(e);
-}
-
-#include 
-
-void QtSoundModem::closeEvent(QCloseEvent *event)
-{
-	UNUSED(event);
-
-	QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat);
-	mysettings.setValue("geometry", QWidget::saveGeometry());
-	mysettings.setValue("windowState", saveState());
-
-	Closing = TRUE;
-	qDebug() << "Closing";
-
-	QThread::msleep(100);
-}
-
-	
-QtSoundModem::~QtSoundModem()
-{
-	qDebug() << "Saving Settings";
-		
-	QSettings mysettings("QtSoundModem.ini", QSettings::IniFormat);
-	mysettings.setValue("geometry", saveGeometry());
-	mysettings.setValue("windowState", saveState());
-	
-	saveSettings();	
-	Closing = TRUE;
-	qDebug() << "Closing";
-
-	QThread::msleep(100);
-}
-
-extern "C" void QSleep(int ms)
-{
-	QThread::msleep(ms);
-}
-
-int upd_time = 30;
-
-void QtSoundModem::show_grid()
-{
-	// This refeshes the session list
-
-	int  snd_ch, i, num_rows, row_idx;
-	QTableWidgetItem *item;
-	const char * msg;
-
-	int  speed_tx, speed_rx;
-
-	if (grid_time < 10)
-	{
-		grid_time++;
-		return;
-	}
-
-	grid_time = 0;
-
-	//label7.Caption = inttostr(stat_r_mem); mem_arq
-
-	num_rows = 0;
-	row_idx = 0;
-
-	for (snd_ch = 0; snd_ch < 4; snd_ch++)
-	{
-		for (i = 0; i < port_num; i++)
-		{
-			if (AX25Port[snd_ch][i].status != STAT_NO_LINK)
-				num_rows++;
-		}
-	}
-
-	if (num_rows == 0)
-	{
-		sessionTable->clearContents();
-		sessionTable->setRowCount(0);
-		sessionTable->setRowCount(1);
-	}
-	else
-		sessionTable->setRowCount(num_rows);
-
-
-	for (snd_ch = 0; snd_ch < 4; snd_ch++)
-	{
-		for (i = 0; i < port_num; i++)
-		{
-			if (AX25Port[snd_ch][i].status != STAT_NO_LINK)
-			{
-				switch (AX25Port[snd_ch][i].status)
-				{
-				case STAT_NO_LINK:
-
-					msg = "No link";
-					break;
-
-				case STAT_LINK:
-
-					msg = "Link";
-					break;
-
-				case STAT_CHK_LINK:
-
-					msg = "Chk link";
-					break;
-
-				case STAT_WAIT_ANS:
-
-					msg = "Wait ack";
-					break;
-
-				case STAT_TRY_LINK:
-
-					msg = "Try link";
-					break;
-
-				case STAT_TRY_UNLINK:
-
-					msg = "Try unlink";
-				}
-
-
-				item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].mycall);
-				sessionTable->setItem(row_idx, 0, item);
-
-				item = new QTableWidgetItem(AX25Port[snd_ch][i].kind);
-				sessionTable->setItem(row_idx, 11, item);
-
-				item = new QTableWidgetItem((char *)AX25Port[snd_ch][i].corrcall);
-				sessionTable->setItem(row_idx, 1, item);
-
-				item = new QTableWidgetItem(msg);
-				sessionTable->setItem(row_idx, 2, item);
-
-				item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_pkt));
-				sessionTable->setItem(row_idx, 3, item);
-
-				item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_s_byte));
-				sessionTable->setItem(row_idx, 4, item);
-
-				item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_pkt));
-				sessionTable->setItem(row_idx, 5, item);
-
-				item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_byte));
-				sessionTable->setItem(row_idx, 6, item);
-
-				item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_r_fc));
-				sessionTable->setItem(row_idx, 7, item);
-
-				item = new QTableWidgetItem(QString::number(AX25Port[snd_ch][i].info.stat_fec_count));
-				sessionTable->setItem(row_idx, 8, item);
-
-				if (grid_timer != upd_time)
-					grid_timer++;
-				else
-				{
-					grid_timer = 0;
-					speed_tx = round(abs(AX25Port[snd_ch][i].info.stat_s_byte - AX25Port[snd_ch][i].info.stat_l_s_byte) / upd_time);
-					speed_rx = round(abs(AX25Port[snd_ch][i].info.stat_r_byte - AX25Port[snd_ch][i].info.stat_l_r_byte) / upd_time);
-
-					item = new QTableWidgetItem(QString::number(speed_tx));
-					sessionTable->setItem(row_idx, 9, item);
-
-					item = new QTableWidgetItem(QString::number(speed_rx));
-					sessionTable->setItem(row_idx, 10, item);
-
-					AX25Port[snd_ch][i].info.stat_l_r_byte = AX25Port[snd_ch][i].info.stat_r_byte;
-					AX25Port[snd_ch][i].info.stat_l_s_byte = AX25Port[snd_ch][i].info.stat_s_byte;	
-				}
-
-				row_idx++;
-			}
-		}
-	}
-}
-
-// "Copy on Select" Code
-
-void QtSoundModem::onTEselectionChanged()
-{
-	QTextEdit * x = static_cast(QObject::sender());
-	x->copy();
-}
-
diff --git a/QtSoundModem.h b/QtSoundModem.h
index fc21d79..626ddd9 100644
--- a/QtSoundModem.h
+++ b/QtSoundModem.h
@@ -29,7 +29,7 @@ public:
 	~QtSoundModem();
 
 	void RefreshWaterfall(int snd_ch, unsigned char * Data);
-	void initWaterfall(int chan, int state);
+	void initWaterfall(int state);
 	void show_grid();
 	void checkforCWID();
 
@@ -39,6 +39,7 @@ private slots:
 
 	void CWIDTimer();
 	void doDevices();
+	void mysetstyle();
 	void updateFont();
 	void MinimizetoTray();
 	void TrayActivated(QSystemTrayIcon::ActivationReason reason);
@@ -111,3 +112,9 @@ protected:
 	bool eventFilter(QObject *obj, QEvent *event) override;
 };
 
+
+#define WaterfallDisplayPixels 80
+#define WaterfallHeaderPixels 38
+#define WaterfallTotalPixels WaterfallDisplayPixels + WaterfallHeaderPixels
+#define WaterfallImageHeight (WaterfallTotalPixels + WaterfallTotalPixels)
+
diff --git a/QtSoundModem.ui b/QtSoundModem.ui
index e264b7d..1d7b110 100644
--- a/QtSoundModem.ui
+++ b/QtSoundModem.ui
@@ -6,8 +6,8 @@
    
     0
     0
-    962
-    721
+    993
+    900
    
   
   
@@ -50,48 +50,6 @@
      
     
    
-   
-    
-     
-      0
-      586
-      959
-      80
-     
-    
-    
-     
-      0
-      0
-     
-    
-    
-     
-      600
-      80
-     
-    
-    
-     
-      5000
-      100
-     
-    
-    
-     
-      8
-     
-    
-    
-     QFrame::Box
-    
-    
-     QFrame::Plain
-    
-    
-     Waterfall
-    
-   
    
     
      
@@ -121,25 +79,25 @@
      1500
     
    
-   
+   
     
      
       80
       488
       881
-      80
+      100
      
     
     
      
       600
-      80
+      100
      
     
     
      
       5000
-      100
+      250
      
     
     
@@ -171,9 +129,9 @@
     
      
       690
-      0
+      2
       73
-      16
+      13
      
     
     
@@ -215,78 +173,6 @@
      10
     
    
-   
-    
-     
-      25
-      460
-      1076
-      38
-     
-    
-    
-     
-      600
-      10
-     
-    
-    
-     
-      5000
-      100
-     
-    
-    
-     
-      8
-     
-    
-    
-     QFrame::Box
-    
-    
-     QFrame::Plain
-    
-    
-     Waterfall
-    
-   
-   
-    
-     
-      10
-      560
-      1076
-      38
-     
-    
-    
-     
-      600
-      10
-     
-    
-    
-     
-      5000
-      100
-     
-    
-    
-     
-      8
-     
-    
-    
-     QFrame::Box
-    
-    
-     QFrame::Plain
-    
-    
-     Waterfall
-    
-   
    
     
      
@@ -412,7 +298,7 @@
       600
       2
       87
-      16
+      13
      
     
     
@@ -487,9 +373,9 @@
     
      
       780
-      17
+      14
       150
-      12
+      11
      
     
     
@@ -508,7 +394,7 @@
       780
       0
       91
-      16
+      13
      
     
     
@@ -526,13 +412,32 @@
      true
     
    
+   
+    
+     
+      780
+      23
+      150
+      11
+     
+    
+    
+     QFrame::Box
+    
+    
+     QFrame::Sunken
+    
+    
+     
+    
+   
   
   
+     
+      
+       
+        260
+        304
+        161
+        17
+       
+      
+      
+       Dark Theme
+      
+     
     
     
      
diff --git a/digipeater.h b/digipeater.h
deleted file mode 100644
index 5c84976..0000000
--- a/digipeater.h
+++ /dev/null
@@ -1,78 +0,0 @@
-
-#ifndef DIGIPEATER_H
-#define DIGIPEATER_H 1
-
-#include "regex.h"
-
-#include "direwolf.h"		/* for MAX_CHANS */
-#include "ax25_pad.h"		/* for packet_t */
-#include "audio.h"		/* for radio channel properties */
-
-
-/*
- * Information required for digipeating.
- *
- * The configuration file reader fills in this information
- * and it is passed to digipeater_init at application start up time.
- */
-
-
-struct digi_config_s {
-
-
-	int	dedupe_time;	/* Don't digipeat duplicate packets */
-				/* within this number of seconds. */
-
-#define DEFAULT_DEDUPE 30
-
-/*
- * Rules for each of the [from_chan][to_chan] combinations.
- */
-
-	regex_t	alias[MAX_CHANS][MAX_CHANS];
-
-	regex_t	wide[MAX_CHANS][MAX_CHANS];
-
-	int	enabled[MAX_CHANS][MAX_CHANS];
-
-	enum preempt_e { PREEMPT_OFF, PREEMPT_DROP, PREEMPT_MARK, PREEMPT_TRACE } preempt[MAX_CHANS][MAX_CHANS];
-
-	// ATGP is an ugly hack for the specific need of ATGP which needs more that 8 digipeaters.
-	// DO NOT put this in the User Guide.  On a need to know basis.
-
-	char atgp[MAX_CHANS][MAX_CHANS][AX25_MAX_ADDR_LEN];
-
-	char *filter_str[MAX_CHANS+1][MAX_CHANS+1];
-						// NULL or optional Packet Filter strings such as "t/m".
-						// Notice the size of arrays is one larger than normal.
-						// That extra position is for the IGate.
-
-	int regen[MAX_CHANS][MAX_CHANS];	// Regenerate packet.  
-						// Sort of like digipeating but passed along unchanged.
-};
-
-/*
- * Call once at application start up time.
- */
-
-extern void digipeater_init (struct audio_s *p_audio_config, struct digi_config_s *p_digi_config);
-
-/*
- * Call this for each packet received.
- * Suitable packets will be queued for transmission.
- */
-
-extern void digipeater (int from_chan, packet_t pp);
-
-void digi_regen (int from_chan, packet_t pp);
-
-
-/* Make statistics available. */
-
-int digipeater_get_count (int from_chan, int to_chan);
-
-
-#endif 
-
-/* end digipeater.h */
-
diff --git a/dlq.h b/dlq.h
deleted file mode 100644
index 8771636..0000000
--- a/dlq.h
+++ /dev/null
@@ -1,148 +0,0 @@
-
-/*------------------------------------------------------------------
- *
- * Module:      dlq.h
- *
- *---------------------------------------------------------------*/
-
-#ifndef DLQ_H
-#define DLQ_H 1
-
-#include "ax25_pad.h"
-#include "audio.h"
-
-
-/* A transmit or receive data block for connected mode. */
-
-typedef struct cdata_s {
-	int magic;			/* For integrity checking. */
-
-#define TXDATA_MAGIC 0x09110911
-
-	struct cdata_s *next;		/* Pointer to next when part of a list. */
-
-	int pid;			/* Protocol id. */
-
-	int size;			/* Number of bytes allocated. */
-
-	int len;			/* Number of bytes actually used. */
-
-	char data[];			/* Variable length data. */
-
-} cdata_t;
-
-
-
-/* Types of things that can be in queue. */
-
-typedef enum dlq_type_e {DLQ_REC_FRAME, DLQ_CONNECT_REQUEST, DLQ_DISCONNECT_REQUEST, DLQ_XMIT_DATA_REQUEST, DLQ_REGISTER_CALLSIGN, DLQ_UNREGISTER_CALLSIGN, DLQ_OUTSTANDING_FRAMES_REQUEST, DLQ_CHANNEL_BUSY, DLQ_SEIZE_CONFIRM, DLQ_CLIENT_CLEANUP} dlq_type_t;
-
-
-/* A queue item. */
-
-// TODO: call this event rather than item.
-// TODO: should add fences.
-
-typedef struct dlq_item_s {
-
-	struct dlq_item_s *nextp;	/* Next item in queue. */
-
-	dlq_type_t type;		/* Type of item. */
-					/* See enum definition above. */
-
-	int chan;			/* Radio channel of origin. */
-
-// I'm not worried about amount of memory used but this might be a
-// little clearer if a union was used for the different event types.
-
-// Used for received frame.
-
-	int subchan;			/* Winning "subchannel" when using multiple */
-					/* decoders on one channel.  */
-					/* Special case, -1 means DTMF decoder. */
-					/* Maybe we should have a different type in this case? */
-
-	int slice;			/* Winning slicer. */
-
-	packet_t pp;			/* Pointer to frame structure. */
-
-	alevel_t alevel;		/* Audio level. */
-
-	int is_fx25;			/* Was it from FX.25? */
-
-	retry_t retries;		/* Effort expended to get a valid CRC. */
-					/* Bits changed for regular AX.25. */
-					/* Number of bytes fixed for FX.25. */
-
-	char spectrum[MAX_SUBCHANS*MAX_SLICERS+1];	/* "Spectrum" display for multi-decoders. */
-
-// Used by requests from a client application, connect, etc.
-
-	char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
-
-	int num_addr;			/* Range 2 .. 10. */
-
-	int client;
-
-
-// Used only by client request to transmit connected data.
-
-	cdata_t *txdata;
-
-// Used for channel activity change.
-// It is useful to know when the channel is busy either for carrier detect
-// or when we are transmitting.
-
-	int activity;			/* OCTYPE_PTT for my transmission start/end. */
-					/* OCTYPE_DCD if we hear someone else. */
-
-	int status;			/* 1 for active or 0 for quiet. */
-
-} dlq_item_t;
-
-
-
-void dlq_init (void);
-
-
-
-void dlq_rec_frame (int chan, int subchan, int slice, packet_t pp, alevel_t alevel, int is_fx25, retry_t retries, char *spectrum);
-
-void dlq_connect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client, int pid);
-
-void dlq_disconnect_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client);
-
-void dlq_outstanding_frames_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client);
-
-void dlq_xmit_data_request (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, int chan, int client, int pid, char *xdata_ptr, int xdata_len);
-
-void dlq_register_callsign (char addr[AX25_MAX_ADDR_LEN], int chan, int client);
-
-void dlq_unregister_callsign (char addr[AX25_MAX_ADDR_LEN], int chan, int client);
-
-void dlq_channel_busy (int chan, int activity, int status);
-
-void dlq_seize_confirm (int chan);
-
-void dlq_client_cleanup (int client);
-
-
-
-int dlq_wait_while_empty (double timeout_val);
-
-struct dlq_item_s *dlq_remove (void);
-
-void dlq_delete (struct dlq_item_s *pitem);
-
-
-
-cdata_t *cdata_new (int pid, char *data, int len);
-
-void cdata_delete (cdata_t *txdata);
-
-void cdata_check_leak (void);
-
-
-#endif
-
-/* end dlq.h */
diff --git a/dns_sd_common.h b/dns_sd_common.h
deleted file mode 100644
index f104bf8..0000000
--- a/dns_sd_common.h
+++ /dev/null
@@ -1,7 +0,0 @@
-
-#if (USE_AVAHI_CLIENT|USE_MACOS_DNSSD)
-
-char *dns_sd_default_service_name(void);
-
-#endif
-
diff --git a/dns_sd_dw.h b/dns_sd_dw.h
deleted file mode 100644
index 79f4b86..0000000
--- a/dns_sd_dw.h
+++ /dev/null
@@ -1,10 +0,0 @@
-
-#if (USE_AVAHI_CLIENT|USE_MACOS_DNSSD)
-
-#include "config.h"
-
-#define DNS_SD_SERVICE "_kiss-tnc._tcp"
-
-void dns_sd_announce (struct misc_config_s *mc);
-
-#endif // USE_AVAHI_CLIENT
diff --git a/dtime_now.h b/dtime_now.h
deleted file mode 100644
index 411534b..0000000
--- a/dtime_now.h
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-extern double dtime_realtime (void);
-
-extern double dtime_monotonic (void);
-
-
-void timestamp_now (char *result, int result_size, int show_ms);
-
-void timestamp_user_format (char *result, int result_size, char *user_format);
-
-void timestamp_filename (char *result, int result_size);
-
-
-// FIXME:  remove temp workaround.
-// Needs many scattered updates.
-
-#define dtime_now dtime_realtime
diff --git a/dtmf.h b/dtmf.h
deleted file mode 100644
index c1b52b9..0000000
--- a/dtmf.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* dtmf.h */
-
-
-#include "audio.h"
-
-void dtmf_init (struct audio_s *p_audio_config, int amp);
-
-char dtmf_sample (int c, float input);
-
-int dtmf_send (int chan, char *str, int speed, int txdelay, int txtail);
-
-
-/* end dtmf.h */
-
diff --git a/dw9600.c b/dw9600.c
index 8307342..407feb1 100644
--- a/dw9600.c
+++ b/dw9600.c
@@ -25,6 +25,7 @@ typedef struct TStringList_T
 
 extern int fx25_mode[4];
 extern int il2p_mode[4];
+extern int il2p_crc[4];
 extern short rx_baudrate[5];
 
 #define FX25_MODE_NONE  0
diff --git a/dwgps.h b/dwgps.h
deleted file mode 100644
index 78f821f..0000000
--- a/dwgps.h
+++ /dev/null
@@ -1,61 +0,0 @@
-
-/* dwgps.h */
-
-#ifndef DWGPS_H
-#define DWGPS_H 1
-
-
-#include 
-#include "config.h"	/* for struct misc_config_s */
-
-
-/*
- * Values for fix, equivalent to values from libgps.
- *	-2 = not initialized.
- *	-1 = error communicating with GPS receiver.
- *	0 = nothing heard yet.
- *	1 = had signal but lost it.
- *	2 = 2D.
- *	3 = 3D.
- *
- * Undefined float & double values are set to G_UNKNOWN.
- *
- */
-
-enum dwfix_e { DWFIX_NOT_INIT= -2, DWFIX_ERROR= -1, DWFIX_NOT_SEEN=0, DWFIX_NO_FIX=1, DWFIX_2D=2, DWFIX_3D=3 };
-
-typedef enum dwfix_e dwfix_t;
-
-typedef struct dwgps_info_s {
-	time_t timestamp;	/* When last updated.  System time. */
-	dwfix_t fix;		/* Quality of position fix. */
-	double dlat;		/* Latitude.  Valid if fix >= 2. */
-	double dlon;		/* Longitude. Valid if fix >= 2. */
-	float speed_knots;	/* libgps uses meters/sec but we use GPS usual knots. */
-	float track;		/* What is difference between track and course? */
-	float altitude;		/* meters above mean sea level. Valid if fix == 3. */
-} dwgps_info_t;
-
-
-
-
-
-void dwgps_init (struct misc_config_s *pconfig, int debug);
-
-void dwgps_clear (dwgps_info_t *gpsinfo);
-
-dwfix_t dwgps_read (dwgps_info_t *gpsinfo);
-
-void dwgps_print (char *msg, dwgps_info_t *gpsinfo);
-
-void dwgps_term (void);
-
-void dwgps_set_data (dwgps_info_t *gpsinfo);
-
-
-#endif /* DWGPS_H 1 */
-
-/* end dwgps.h */
-
-
-
diff --git a/dwgpsd.h b/dwgpsd.h
deleted file mode 100644
index 4c0e0fd..0000000
--- a/dwgpsd.h
+++ /dev/null
@@ -1,22 +0,0 @@
-
-/* dwgpsd.h   -   For communicating with daemon */
-
-
-
-#ifndef DWGPSD_H
-#define DWGPSD_H 1
-
-#include "config.h"
-
-
-int dwgpsd_init (struct misc_config_s *pconfig, int debug);
-
-void dwgpsd_term (void);
-
-#endif
-
-
-/* end dwgpsd.h */
-
-
-
diff --git a/dwgpsnmea.h b/dwgpsnmea.h
deleted file mode 100644
index ffe5a12..0000000
--- a/dwgpsnmea.h
+++ /dev/null
@@ -1,32 +0,0 @@
-
-/* dwgpsnmea.h   -   For reading NMEA sentences over serial port */
-
-
-
-#ifndef DWGPSNMEA_H
-#define DWGPSNMEA_H 1
-
-#include "dwgps.h"		/* for dwfix_t */
-#include "config.h"
-#include "serial_port.h"	/* for MYFDTYPE */
-
-
-int dwgpsnmea_init (struct misc_config_s *pconfig, int debug);
-
-MYFDTYPE dwgpsnmea_get_fd(char *wp_port_name, int speed);
-
-void dwgpsnmea_term (void);
-
-
-dwfix_t dwgpsnmea_gprmc (char *sentence, int quiet, double *odlat, double *odlon, float *oknots, float *ocourse);
-
-dwfix_t dwgpsnmea_gpgga (char *sentence, int quiet, double *odlat, double *odlon, float *oalt, int *onsat);
-
-
-#endif
-
-
-/* end dwgpsnmea.h */
-
-
-
diff --git a/dwsock.h b/dwsock.h
deleted file mode 100644
index 986f6a2..0000000
--- a/dwsock.h
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/* dwsock.h - Socket helper functions. */
-
-#ifndef DWSOCK_H
-#define DWSOCK_H 1
-
-#define DWSOCK_IPADDR_LEN 48		// Size of string to hold IPv4 or IPv6 address.
-					// I think 40 would be adequate but we'll make
-					// it a little larger just to be safe.
-					// Use INET6_ADDRSTRLEN (from netinet/in.h) instead?
-
-int dwsock_init (void);
-
-int dwsock_connect (char *hostname, char *port, char *description, int allow_ipv6, int debug, char ipaddr_str[DWSOCK_IPADDR_LEN]);
-								/* ipaddr_str needs to be at least SOCK_IPADDR_LEN bytes */
-
-char *dwsock_ia_to_text (int  Family, void * pAddr, char * pStringBuf, size_t StringBufSize);
-
-void dwsock_close (int fd);
-
-#endif
\ No newline at end of file
diff --git a/encode_aprs.h b/encode_aprs.h
deleted file mode 100644
index dc7b8bd..0000000
--- a/encode_aprs.h
+++ /dev/null
@@ -1,17 +0,0 @@
-
-int encode_position (int messaging, int compressed, double lat, double lon, int ambiguity, int alt_ft,
-		char symtab, char symbol, 
-		int power, int height, int gain, char *dir,
-		int course, int speed_knots,
-		float freq, float tone, float offset,
-		char *comment,
-		char *presult, size_t result_size);
-
-int encode_object (char *name, int compressed, time_t thyme, double lat, double lon, int ambiguity,
-		char symtab, char symbol, 
-		int power, int height, int gain, char *dir,
-		int course, int speed_knots,
-		float freq, float tone, float offset, char *comment,
-		char *presult, size_t result_size);
-
-int encode_message (char *addressee, char *text, char *id, char *presult, size_t result_size);
diff --git a/fcs_calc.h b/fcs_calc.h
deleted file mode 100644
index 2e2b0ef..0000000
--- a/fcs_calc.h
+++ /dev/null
@@ -1,11 +0,0 @@
-
-/* fcs_calc.h */
-
-
-unsigned short fcs_calc (unsigned char *data, int len);
-
-unsigned short crc16 (unsigned char *data, int len, unsigned short seed);
-
-/* end fcs_calc.h */
-
-
diff --git a/fsk_filters.h b/fsk_filters.h
deleted file mode 100644
index 81c4e9a..0000000
--- a/fsk_filters.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* 1200 bits/sec with Audio sample rate = 11025 */
-/* Mark freq = 1200, Space freq = 2200 */
-
-static const signed short m_sin_table[9] = { 0 , 7347 , 11257 , 9899 , 3909 , -3909 , -9899 , -11257 , -7347  };
-static const signed short m_cos_table[9] = { 11431 , 8756 , 1984 , -5715 , -10741 , -10741 , -5715 , 1984 , 8756  };
-static const signed short s_sin_table[9] = { 0 , 10950 , 6281 , -7347 , -10496 , 1327 , 11257 , 5130 , -8314  };
-static const signed short s_cos_table[9] = { 11431 , 3278 , -9550 , -8756 , 4527 , 11353 , 1984 , -10215 , -7844  };
diff --git a/fsk_gen_filter.h b/fsk_gen_filter.h
deleted file mode 100644
index e7e8fa6..0000000
--- a/fsk_gen_filter.h
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-#ifndef FSK_GEN_FILTER_H
-#define FSK_GEN_FILTER_H 1
-
-#include "audio.h"
-#include "fsk_demod_state.h"
-
-void fsk_gen_filter (int samples_per_sec, 
-			int baud, 
-			int mark_freq, int space_freq, 
-			char profile,
-			struct demodulator_state_s *D);
-
-#endif
\ No newline at end of file
diff --git a/gen_tone.h b/gen_tone.h
deleted file mode 100644
index bbe23b5..0000000
--- a/gen_tone.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * gen_tone.h
- */
-
-
-int gen_tone_init (struct audio_s *pp, int amp, int gen_packets);
-
-
-//int gen_tone_open (int nchan, int sample_rate, int bit_rate, int f1, int f2, int amp, char *fname);
-
-//int gen_tone_open_fd (int nchan, int sample_rate, int bit_rate, int f1, int f2, int amp, int fd)  ;
-
-//int gen_tone_close (void);
-
-void tone_gen_put_bit (int chan, int dat);
-
-void gen_tone_put_sample (int chan, int a, int sam);
\ No newline at end of file
diff --git a/grm_sym.h b/grm_sym.h
deleted file mode 100644
index 7a15041..0000000
--- a/grm_sym.h
+++ /dev/null
@@ -1,501 +0,0 @@
-
-/*
- * grm_sym.h
- *
- * Symbol codes for use in $PGRMWPL sentence. 
- *
- * Copied from 
- *	Garmin Device Interface Specification
- *	May 19, 2006
- *	Drawing Number: 001-00063-00 Rev. C
- */
-
-
-typedef unsigned short symbol_type_t;
-
-enum symbol_type_e
-{
-/*---------------------------------------------------------------
-Marine symbols
----------------------------------------------------------------*/
-sym_anchor = 0, /* white anchor symbol */
-sym_bell = 1, /* white bell symbol */
-sym_diamond_grn = 2, /* green diamond symbol */
-sym_diamond_red = 3, /* red diamond symbol */
-sym_dive1 = 4, /* diver down flag 1 */
-sym_dive2 = 5, /* diver down flag 2 */
-sym_dollar = 6, /* white dollar symbol */
-sym_fish = 7, /* white fish symbol */
-sym_fuel = 8, /* white fuel symbol */
-sym_horn = 9, /* white horn symbol */
-sym_house = 10, /* white house symbol */
-sym_knife = 11, /* white knife & fork symbol */
-sym_light = 12, /* white light symbol */
-sym_mug = 13, /* white mug symbol */
-sym_skull = 14, /* white skull and crossbones symbol*/
-sym_square_grn = 15, /* green square symbol */
-sym_square_red = 16, /* red square symbol */
-sym_wbuoy = 17, /* white buoy waypoint symbol */
-sym_wpt_dot = 18, /* waypoint dot */
-sym_wreck = 19, /* white wreck symbol */
-sym_null = 20, /* null symbol (transparent) */
-sym_mob = 21, /* man overboard symbol */
-sym_buoy_ambr = 22, /* amber map buoy symbol */
-sym_buoy_blck = 23, /* black map buoy symbol */
-sym_buoy_blue = 24, /* blue map buoy symbol */
-sym_buoy_grn = 25, /* green map buoy symbol */
-sym_buoy_grn_red = 26, /* green/red map buoy symbol */
-sym_buoy_grn_wht = 27, /* green/white map buoy symbol */
-sym_buoy_orng = 28, /* orange map buoy symbol */
-sym_buoy_red = 29, /* red map buoy symbol */
-sym_buoy_red_grn = 30, /* red/green map buoy symbol */
-sym_buoy_red_wht = 31, /* red/white map buoy symbol */
-sym_buoy_violet = 32, /* violet map buoy symbol */
-sym_buoy_wht = 33, /* white map buoy symbol */
-sym_buoy_wht_grn = 34, /* white/green map buoy symbol */
-sym_buoy_wht_red = 35, /* white/red map buoy symbol */
-sym_dot = 36, /* white dot symbol */
-sym_rbcn = 37, /* radio beacon symbol */
-sym_boat_ramp = 150, /* boat ramp symbol */
-sym_camp = 151, /* campground symbol */
-sym_restrooms = 152, /* restrooms symbol */
-sym_showers = 153, /* shower symbol */
-sym_drinking_wtr = 154, /* drinking water symbol */
-sym_phone = 155, /* telephone symbol */
-sym_1st_aid = 156, /* first aid symbol */
-sym_info = 157, /* information symbol */
-sym_parking = 158, /* parking symbol */
-sym_park = 159, /* park symbol */
-sym_picnic = 160, /* picnic symbol */
-sym_scenic = 161, /* scenic area symbol */
-sym_skiing = 162, /* skiing symbol */
-sym_swimming = 163, /* swimming symbol */
-sym_dam = 164, /* dam symbol */
-sym_controlled = 165, /* controlled area symbol */
-sym_danger = 166, /* danger symbol */
-sym_restricted = 167, /* restricted area symbol */
-sym_null_2 = 168, /* null symbol */
-sym_ball = 169, /* ball symbol */
-sym_car = 170, /* car symbol */
-sym_deer = 171, /* deer symbol */
-sym_shpng_cart = 172, /* shopping cart symbol */
-sym_lodging = 173, /* lodging symbol */
-sym_mine = 174, /* mine symbol */
-sym_trail_head = 175, /* trail head symbol */
-sym_truck_stop = 176, /* truck stop symbol */
-sym_user_exit = 177, /* user exit symbol */
-sym_flag = 178, /* flag symbol */
-sym_circle_x = 179, /* circle with x in the center */
-sym_open_24hr = 180, /* open 24 hours symbol */
-sym_fhs_facility = 181, /* U Fishing Hot Spots(tm) Facility */
-sym_bot_cond = 182, /* Bottom Conditions */
-sym_tide_pred_stn = 183, /* Tide/Current Prediction Station */
-sym_anchor_prohib = 184, /* U anchor prohibited symbol */
-sym_beacon = 185, /* U beacon symbol */
-sym_coast_guard = 186, /* U coast guard symbol */
-sym_reef = 187, /* U reef symbol */
-sym_weedbed = 188, /* U weedbed symbol */
-sym_dropoff = 189, /* U dropoff symbol */
-sym_dock = 190, /* U dock symbol */
-sym_marina = 191, /* U marina symbol */
-sym_bait_tackle = 192, /* U bait and tackle symbol */
-sym_stump = 193, /* U stump symbol */
-/*---------------------------------------------------------------
-User customizable symbols
-The values from sym_begin_custom to sym_end_custom inclusive are
-reserved for the identification of user customizable symbols.
----------------------------------------------------------------*/
-sym_begin_custom = 7680, /* first user customizable symbol */
-sym_end_custom = 8191, /* last user customizable symbol */
-/*---------------------------------------------------------------
-Land symbols
----------------------------------------------------------------*/
-sym_is_hwy = 8192, /* interstate hwy symbol */
-sym_us_hwy = 8193, /* us hwy symbol */
-sym_st_hwy = 8194, /* state hwy symbol */
-sym_mi_mrkr = 8195, /* mile marker symbol */
-sym_trcbck = 8196, /* TracBack (feet) symbol */
-sym_golf = 8197, /* golf symbol */
-sym_sml_cty = 8198, /* small city symbol */
-sym_med_cty = 8199, /* medium city symbol */
-sym_lrg_cty = 8200, /* large city symbol */
-sym_freeway = 8201, /* intl freeway hwy symbol */
-sym_ntl_hwy = 8202, /* intl national hwy symbol */
-sym_cap_cty = 8203, /* capitol city symbol (star) */
-sym_amuse_pk = 8204, /* amusement park symbol */
-sym_bowling = 8205, /* bowling symbol */
-sym_car_rental = 8206, /* car rental symbol */
-sym_car_repair = 8207, /* car repair symbol */
-sym_fastfood = 8208, /* fast food symbol */
-sym_fitness = 8209, /* fitness symbol */
-sym_movie = 8210, /* movie symbol */
-sym_museum = 8211, /* museum symbol */
-sym_pharmacy = 8212, /* pharmacy symbol */
-sym_pizza = 8213, /* pizza symbol */
-sym_post_ofc = 8214, /* post office symbol */
-sym_rv_park = 8215, /* RV park symbol */
-sym_school = 8216, /* school symbol */
-sym_stadium = 8217, /* stadium symbol */
-sym_store = 8218, /* dept. store symbol */
-sym_zoo = 8219, /* zoo symbol */
-sym_gas_plus = 8220, /* convenience store symbol */
-sym_faces = 8221, /* live theater symbol */
-sym_ramp_int = 8222, /* ramp intersection symbol */
-sym_st_int = 8223, /* street intersection symbol */
-sym_weigh_sttn = 8226, /* inspection/weigh station symbol */
-sym_toll_booth = 8227, /* toll booth symbol */
-sym_elev_pt = 8228, /* elevation point symbol */
-sym_ex_no_srvc = 8229, /* exit without services symbol */
-sym_geo_place_mm = 8230, /* Geographic place name, man-made */
-sym_geo_place_wtr = 8231, /* Geographic place name, water */
-sym_geo_place_lnd = 8232, /* Geographic place name, land */
-sym_bridge = 8233, /* bridge symbol */
-sym_building = 8234, /* building symbol */
-sym_cemetery = 8235, /* cemetery symbol */
-sym_church = 8236, /* church symbol */
-sym_civil = 8237, /* civil location symbol */
-sym_crossing = 8238, /* crossing symbol */
-sym_hist_town = 8239, /* historical town symbol */
-sym_levee = 8240, /* levee symbol */
-sym_military = 8241, /* military location symbol */
-sym_oil_field = 8242, /* oil field symbol */
-sym_tunnel = 8243, /* tunnel symbol */
-sym_beach = 8244, /* beach symbol */
-sym_forest = 8245, /* forest symbol */
-sym_summit = 8246, /* summit symbol */
-sym_lrg_ramp_int = 8247, /* large ramp intersection symbol */
-sym_lrg_ex_no_srvc = 8248, /* large exit without services smbl */
-sym_badge = 8249, /* police/official badge symbol */
-sym_cards = 8250, /* gambling/casino symbol */
-sym_snowski = 8251, /* snow skiing symbol */
-sym_iceskate = 8252, /* ice skating symbol */
-sym_wrecker = 8253, /* tow truck (wrecker) symbol */
-sym_border = 8254, /* border crossing (port of entry) */
-sym_geocache = 8255, /* geocache location */
-sym_geocache_fnd = 8256, /* found geocache */
-sym_cntct_smiley = 8257, /* Rino contact symbol, "smiley" */
-sym_cntct_ball_cap = 8258, /* Rino contact symbol, "ball cap" */
-sym_cntct_big_ears = 8259, /* Rino contact symbol, "big ear" */
-sym_cntct_spike = 8260, /* Rino contact symbol, "spike" */
-sym_cntct_goatee = 8261, /* Rino contact symbol, "goatee" */
-sym_cntct_afro = 8262, /* Rino contact symbol, "afro" */
-sym_cntct_dreads = 8263, /* Rino contact symbol, "dreads" */
-sym_cntct_female1 = 8264, /* Rino contact symbol, "female 1" */
-sym_cntct_female2 = 8265, /* Rino contact symbol, "female 2" */
-sym_cntct_female3 = 8266, /* Rino contact symbol, "female 3" */
-sym_cntct_ranger = 8267, /* Rino contact symbol, "ranger" */
-sym_cntct_kung_fu = 8268, /* Rino contact symbol, "kung fu" */
-sym_cntct_sumo = 8269, /* Rino contact symbol, "sumo" */
-sym_cntct_pirate = 8270, /* Rino contact symbol, "pirate" */
-sym_cntct_biker = 8271, /* Rino contact symbol, "biker" */
-sym_cntct_alien = 8272, /* Rino contact symbol, "alien" */
-sym_cntct_bug = 8273, /* Rino contact symbol, "bug" */
-sym_cntct_cat = 8274, /* Rino contact symbol, "cat" */
-sym_cntct_dog = 8275, /* Rino contact symbol, "dog" */
-sym_cntct_pig = 8276, /* Rino contact symbol, "pig" */
-sym_hydrant = 8282, /* water hydrant symbol */
-sym_flag_blue = 8284, /* blue flag symbol */
-sym_flag_green = 8285, /* green flag symbol */
-sym_flag_red = 8286, /* red flag symbol */
-sym_pin_blue = 8287, /* blue pin symbol */
-sym_pin_green = 8288, /* green pin symbol */
-sym_pin_red = 8289, /* red pin symbol */
-sym_block_blue = 8290, /* blue block symbol */
-sym_block_green = 8291, /* green block symbol */
-sym_block_red = 8292, /* red block symbol */
-sym_bike_trail = 8293, /* bike trail symbol */
-sym_circle_red = 8294, /* red circle symbol */
-sym_circle_green = 8295, /* green circle symbol */
-sym_circle_blue = 8296, /* blue circle symbol */
-sym_diamond_blue = 8299, /* blue diamond symbol */
-sym_oval_red = 8300, /* red oval symbol */
-sym_oval_green = 8301, /* green oval symbol */
-sym_oval_blue = 8302, /* blue oval symbol */
-sym_rect_red = 8303, /* red rectangle symbol */
-sym_rect_green = 8304, /* green rectangle symbol */
-sym_rect_blue = 8305, /* blue rectangle symbol */
-sym_square_blue = 8308, /* blue square symbol */
-sym_letter_a_red = 8309, /* red letter 'A' symbol */
-sym_letter_b_red = 8310, /* red letter 'B' symbol */
-sym_letter_c_red = 8311, /* red letter 'C' symbol */
-sym_letter_d_red = 8312, /* red letter 'D' symbol */
-sym_letter_a_green = 8313, /* green letter 'A' symbol */
-sym_letter_c_green = 8314, /* green letter 'C' symbol */
-sym_letter_b_green = 8315, /* green letter 'B' symbol */
-sym_letter_d_green = 8316, /* green letter 'D' symbol */
-sym_letter_a_blue = 8317, /* blue letter 'A' symbol */
-sym_letter_b_blue = 8318, /* blue letter 'B' symbol */
-sym_letter_c_blue = 8319, /* blue letter 'C' symbol */
-sym_letter_d_blue = 8320, /* blue letter 'D' symbol */
-sym_number_0_red = 8321, /* red number '0' symbol */
-sym_number_1_red = 8322, /* red number '1' symbol */
-sym_number_2_red = 8323, /* red number '2' symbol */
-sym_number_3_red = 8324, /* red number '3' symbol */
-sym_number_4_red = 8325, /* red number '4' symbol */
-sym_number_5_red = 8326, /* red number '5' symbol */
-sym_number_6_red = 8327, /* red number '6' symbol */
-sym_number_7_red = 8328, /* red number '7' symbol */
-sym_number_8_red = 8329, /* red number '8' symbol */
-sym_number_9_red = 8330, /* red number '9' symbol */
-sym_number_0_green = 8331, /* green number '0' symbol */
-sym_number_1_green = 8332, /* green number '1' symbol */
-sym_number_2_green = 8333, /* green number '2' symbol */
-sym_number_3_green = 8334, /* green number '3' symbol */
-sym_number_4_green = 8335, /* green number '4' symbol */
-sym_number_5_green = 8336, /* green number '5' symbol */
-sym_number_6_green = 8337, /* green number '6' symbol */
-sym_number_7_green = 8338, /* green number '7' symbol */
-sym_number_8_green = 8339, /* green number '8' symbol */
-sym_number_9_green = 8340, /* green number '9' symbol */
-sym_number_0_blue = 8341, /* blue number '0' symbol */
-sym_number_1_blue = 8342, /* blue number '1' symbol */
-sym_number_2_blue = 8343, /* blue number '2' symbol */
-sym_number_3_blue = 8344, /* blue number '3' symbol */
-sym_number_4_blue = 8345, /* blue number '4' symbol */
-sym_number_5_blue = 8346, /* blue number '5' symbol */
-sym_number_6_blue = 8347, /* blue number '6' symbol */
-sym_number_7_blue = 8348, /* blue number '7' symbol */
-sym_number_8_blue = 8349, /* blue number '8' symbol */
-sym_number_9_blue = 8350, /* blue number '9' symbol */
-sym_triangle_blue = 8351, /* blue triangle symbol */
-sym_triangle_green = 8352, /* green triangle symbol */
-sym_triangle_red = 8353, /* red triangle symbol */
-sym_food_asian = 8359, /* asian food symbol */
-sym_food_deli = 8360, /* deli symbol */
-sym_food_italian = 8361, /* italian food symbol */
-sym_food_seafood = 8362, /* seafood symbol */
-sym_food_steak = 8363, /* steak symbol */
-/*---------------------------------------------------------------
-Aviation symbols
----------------------------------------------------------------*/
-sym_airport = 16384, /* airport symbol */
-sym_int = 16385, /* intersection symbol */
-sym_ndb = 16386, /* non-directional beacon symbol */
-sym_vor = 16387, /* VHF omni-range symbol */
-sym_heliport = 16388, /* heliport symbol */
-sym_private = 16389, /* private field symbol */
-sym_soft_fld = 16390, /* soft field symbol */
-sym_tall_tower = 16391, /* tall tower symbol */
-sym_short_tower = 16392, /* short tower symbol */
-sym_glider = 16393, /* glider symbol */
-sym_ultralight = 16394, /* ultralight symbol */
-sym_parachute = 16395, /* parachute symbol */
-sym_vortac = 16396, /* VOR/TACAN symbol */
-sym_vordme = 16397, /* VOR-DME symbol */
-sym_faf = 16398, /* first approach fix */
-sym_lom = 16399, /* localizer outer marker */
-sym_map = 16400, /* missed approach point */
-sym_tacan = 16401, /* TACAN symbol */
-sym_seaplane = 16402, /* Seaplane Base */
-};
-
-
-
-/*
- * Mapping from APRS symbols to Garmin.
- */
-
-// TODO:  NEEDS MORE WORK!!!
-
-
-#define SYMTAB_SIZE 95
-
-#define sym_default sym_diamond_grn
-
-
-static const symbol_type_t grm_primary_symtab[SYMTAB_SIZE] =  {
-
-	sym_default,		//     00  	 --no-symbol--
-	sym_cntct_ranger,	//  !  01  	 Police, Sheriff
-	sym_default,		//  "  02  	 reserved  (was rain)
-	sym_rbcn,		//  #  03  	 DIGI (white center)
-	sym_phone,		//  $  04  	 PHONE
-	sym_rbcn,		//  %  05  	 DX CLUSTER
-	sym_rbcn,		//  &  06  	 HF GATEway
-	sym_glider,		//  '  07  	 Small AIRCRAFT
-	sym_rbcn,		//  (  08  	 Mobile Satellite Station
-	sym_default,		//  )  09  	 Wheelchair (handicapped)
-	sym_car,		//  *  10  	 SnowMobile
-	sym_1st_aid,		//  +  11  	 Red Cross
-	sym_cntct_ball_cap,	//  ,  12  	 Boy Scouts
-	sym_house,		//  -  13  	 House QTH (VHF)
-	sym_default,		//  .  14  	 X
-	sym_default,		//  /  15  	 Red Dot
-	sym_default,		//  0  16  	 # circle (obsolete)
-	sym_default,		//  1  17  	 TBD
-	sym_default,		//  2  18  	 TBD
-	sym_default,		//  3  19  	 TBD
-	sym_default,		//  4  20  	 TBD
-	sym_default,		//  5  21  	 TBD
-	sym_default,		//  6  22  	 TBD
-	sym_default,		//  7  23  	 TBD
-	sym_default,		//  8  24  	 TBD
-	sym_default,		//  9  25  	 TBD
-	sym_default,		//  :  26  	 FIRE
-	sym_camp,		//  ;  27  	 Campground (Portable ops)
-	sym_cntct_biker,	//  <  28  	 Motorcycle
-	sym_default,		//  =  29  	 RAILROAD ENGINE
-	sym_car,		//  >  30  	 CAR
-	sym_default,		//  ?  31  	 SERVER for Files
-	sym_default,		//  @  32  	 HC FUTURE predict (dot)
-	sym_1st_aid,		//  A  33  	 Aid Station
-	sym_rbcn,		//  B  34  	 BBS or PBBS
-	sym_boat_ramp,		//  C  35  	 Canoe
-	sym_default,		//  D  36  	 
-	sym_default,		//  E  37  	 EYEBALL (Eye catcher!)
-	sym_default,		//  F  38  	 Farm Vehicle (tractor)
-	sym_default,		//  G  39  	 Grid Square (6 digit)
-	sym_lodging,		//  H  40  	 HOTEL (blue bed symbol)
-	sym_rbcn,		//  I  41  	 TcpIp on air network stn
-	sym_default,		//  J  42  	 
-	sym_school,		//  K  43  	 School
-	sym_default,		//  L  44  	 PC user
-	sym_default,		//  M  45  	 MacAPRS
-	sym_default,		//  N  46  	 NTS Station
-	sym_parachute,		//  O  47  	 BALLOON
-	sym_cntct_ranger,	//  P  48  	 Police
-	sym_default,		//  Q  49  	 TBD
-	sym_rv_park,		//  R  50  	 REC. VEHICLE
-	sym_glider,		//  S  51  	 SHUTTLE
-	sym_default,		//  T  52  	 SSTV
-	sym_car,		//  U  53  	 BUS
-	sym_cntct_biker,	//  V  54  	 ATV
-	sym_default,		//  W  55  	 National WX Service Site
-	sym_default,		//  X  56  	 HELO
-	sym_default,		//  Y  57  	 YACHT (sail)
-	sym_default,		//  Z  58  	 WinAPRS
-	sym_cntct_smiley,	//  [  59  	 Human/Person (HT)
-	sym_triangle_green,	//  \  60  	 TRIANGLE(DF station)
-	sym_default,		//  ]  61  	 MAIL/PostOffice(was PBBS)
-	sym_glider,		//  ^  62  	 LARGE AIRCRAFT
-	sym_default,		//  _  63  	 WEATHER Station (blue)
-	sym_rbcn,		//  `  64  	 Dish Antenna
-	sym_1st_aid,		//  a  65  	 AMBULANCE
-	sym_cntct_biker,	//  b  66  	 BIKE
-	sym_default,		//  c  67  	 Incident Command Post
-	sym_hydrant,		//  d  68  	 Fire dept
-	sym_deer,		//  e  69  	 HORSE (equestrian)
-	sym_hydrant,		//  f  70  	 FIRE TRUCK
-	sym_glider,		//  g  71  	 Glider
-	sym_1st_aid,		//  h  72  	 HOSPITAL
-	sym_default,		//  i  73  	 IOTA (islands on the air)
-	sym_car,		//  j  74  	 JEEP
-	sym_car,		//  k  75  	 TRUCK
-	sym_default,		//  l  76  	 Laptop
-	sym_rbcn,		//  m  77  	 Mic-E Repeater
-	sym_default,		//  n  78  	 Node (black bulls-eye)
-	sym_default,		//  o  79  	 EOC
-	sym_cntct_dog,		//  p  80  	 ROVER (puppy, or dog)
-	sym_default,		//  q  81  	 GRID SQ shown above 128 m
-	sym_rbcn,		//  r  82  	 Repeater
-	sym_default,		//  s  83  	 SHIP (pwr boat)
-	sym_truck_stop,		//  t  84  	 TRUCK STOP
-	sym_truck_stop,		//  u  85  	 TRUCK (18 wheeler)
-	sym_car,		//  v  86  	 VAN
-	sym_drinking_wtr,	//  w  87  	 WATER station
-	sym_default,		//  x  88  	 xAPRS (Unix)
-	sym_tall_tower,		//  y  89  	 YAGI @ QTH
-	sym_default,		//  z  90  	 TBD
-	sym_default,		//  {  91  	 
-	sym_default,		//  |  92  	 TNC Stream Switch
-	sym_default,		//  }  93  	 
-	sym_default };		//  ~  94  	 TNC Stream Switch
-
-static const symbol_type_t grm_alternate_symtab[SYMTAB_SIZE] =  {
-
-	sym_default,		//     00  	 --no-symbol--
-	sym_default,		//  !  01  	 EMERGENCY (!)
-	sym_default,		//  "  02  	 reserved
-	sym_default,		//  #  03  	 OVERLAY DIGI (green star)
-	sym_default,		//  $  04  	 Bank or ATM  (green box)
-	sym_default,		//  %  05  	 Power Plant with overlay
-	sym_rbcn,		//  &  06  	 I=Igte IGate R=RX T=1hopTX 2=2hopTX
-	sym_default,		//  '  07  	 Crash (& now Incident sites)
-	sym_default,		//  (  08  	 CLOUDY (other clouds w ovrly)
-	sym_hydrant,		//  )  09  	 Firenet MEO, MODIS Earth Obs.
-	sym_default,		//  *  10  	 SNOW (& future ovrly codes)
-	sym_default,		//  +  11  	 Church
-	sym_cntct_female1,	//  ,  12  	 Girl Scouts
-	sym_house,		//  -  13  	 House (H=HF) (O = Op Present)
-	sym_default,		//  .  14  	 Ambiguous (Big Question mark)
-	sym_default,		//  /  15  	 Waypoint Destination
-	sym_default,		//  0  16  	 CIRCLE (E/I/W=IRLP/Echolink/WIRES)
-	sym_default,		//  1  17  	 
-	sym_default,		//  2  18  	 
-	sym_default,		//  3  19  	
-	sym_default,		//  4  20  
-	sym_default,		//  5  21 
-	sym_default,		//  6  22
-	sym_default,		//  7  23
-	sym_default,		//  8  24  	 802.11 or other network node
-	sym_default,		//  9  25  	 Gas Station (blue pump)
-	sym_default,		//  :  26  	 Hail (& future ovrly codes)
-	sym_park,		//  ;  27  	 Park/Picnic area
-	sym_default,		//  <  28  	 ADVISORY (one WX flag)
-	sym_rbcn,		//  =  29  	 APRStt Touchtone (DTMF users)
-	sym_car,		//  >  30  	 OVERLAID CAR
-	sym_default,		//  ?  31  	 INFO Kiosk  (Blue box with ?)
-	sym_default,		//  @  32  	 HURRICANE/Trop-Storm
-	sym_default,		//  A  33  	 overlayBOX DTMF & RFID & XO
-	sym_default,		//  B  34  	 Blwng Snow (& future codes)
-	sym_coast_guard,	//  C  35  	 Coast Guard
-	sym_default,		//  D  36  	 Drizzle (proposed APRStt)
-	sym_default,		//  E  37  	 Smoke (& other vis codes)
-	sym_default,		//  F  38  	 Freezng rain (&future codes)
-	sym_default,		//  G  39  	 Snow Shwr (& future ovrlys)
-	sym_default,		//  H  40  	 Haze (& Overlay Hazards)
-	sym_default,		//  I  41  	 Rain Shower
-	sym_default,		//  J  42  	 Lightning (& future ovrlys)
-	sym_rbcn,		//  K  43  	 Kenwood HT (W)
-	sym_light,		//  L  44  	 Lighthouse
-	sym_default,		//  M  45  	 MARS (A=Army,N=Navy,F=AF)
-	sym_default,		//  N  46  	 Navigation Buoy
-	sym_default,		//  O  47  	 Rocket
-	sym_default,		//  P  48  	 Parking
-	sym_default,		//  Q  49  	 QUAKE
-	sym_default,		//  R  50  	 Restaurant
-	sym_rbcn,		//  S  51  	 Satellite/Pacsat
-	sym_default,		//  T  52  	 Thunderstorm
-	sym_default,		//  U  53  	 SUNNY
-	sym_default,		//  V  54  	 VORTAC Nav Aid
-	sym_default,		//  W  55  	 # NWS site (NWS options)
-	sym_pharmacy,		//  X  56  	 Pharmacy Rx (Apothicary)
-	sym_rbcn,		//  Y  57  	 Radios and devices
-	sym_default,		//  Z  58  	 
-	sym_default,		//  [  59  	 W.Cloud (& humans w Ovrly)
-	sym_default,		//  \  60  	 New overlayable GPS symbol
-	sym_default,		//  ]  61  	 
-	sym_glider,		//  ^  62  	 # Aircraft (shows heading)
-	sym_default,		//  _  63  	 # WX site (green digi)
-	sym_default,		//  `  64  	 Rain (all types w ovrly)
-	sym_default,		//  a  65  	 ARRL, ARES, WinLINK
-	sym_default,		//  b  66  	 Blwng Dst/Snd (& others)
-	sym_default,		//  c  67  	 CD triangle RACES/SATERN/etc
-	sym_default,		//  d  68  	 DX spot by callsign
-	sym_default,		//  e  69  	 Sleet (& future ovrly codes)
-	sym_default,		//  f  70  	 Funnel Cloud
-	sym_default,		//  g  71  	 Gale Flags
-	sym_default,		//  h  72  	 Store. or HAMFST Hh=HAM store
-	sym_default,		//  i  73  	 BOX or points of Interest
-	sym_default,		//  j  74  	 WorkZone (Steam Shovel)
-	sym_car,		//  k  75  	 Special Vehicle SUV,ATV,4x4
-	sym_default,		//  l  76  	 Areas      (box,circles,etc)
-	sym_default,		//  m  77  	 Value Sign (3 digit display)
-	sym_default,		//  n  78  	 OVERLAY TRIANGLE
-	sym_default,		//  o  79  	 small circle
-	sym_default,		//  p  80  	 Prtly Cldy (& future ovrlys)
-	sym_default,		//  q  81  	 
-	sym_restrooms,		//  r  82  	 Restrooms
-	sym_default,		//  s  83  	 OVERLAY SHIP/boat (top view)
-	sym_default,		//  t  84  	 Tornado
-	sym_car,		//  u  85  	 OVERLAID TRUCK
-	sym_car,		//  v  86  	 OVERLAID Van
-	sym_default,		//  w  87  	 Flooding
-	sym_wreck,		//  x  88  	 Wreck or Obstruction ->X<-
-	sym_default,		//  y  89  	 Skywarn
-	sym_default,		//  z  90  	 OVERLAID Shelter
-	sym_default,		//  {  91  	 Fog (& future ovrly codes)
-	sym_default,		//  |  92  	 TNC Stream Switch
-	sym_default,		//  }  93  	 
-	sym_default };		//  ~  94  	 TNC Stream Switch
-
diff --git a/hdlc_send.h b/hdlc_send.h
deleted file mode 100644
index 4f8a105..0000000
--- a/hdlc_send.h
+++ /dev/null
@@ -1,17 +0,0 @@
-
-/* hdlc_send.h */
-
-// In version 1.7 an extra layer of abstraction was added here.
-// Rather than calling hdlc_send_frame, we now use another function
-// which sends AX.25, FX.25, or IL2P depending on
-
-#include "ax25_pad.h"
-#include "audio.h"
-
-int layer2_send_frame (int chan, packet_t pp, int bad_fcs, struct audio_s *audio_config_p);
-
-int layer2_preamble_postamble (int chan, int flags, int finish, struct audio_s *audio_config_p);
-
-/* end hdlc_send.h */
-
-
diff --git a/igate.h b/igate.h
deleted file mode 100644
index 8203ac7..0000000
--- a/igate.h
+++ /dev/null
@@ -1,128 +0,0 @@
-
-/*----------------------------------------------------------------------------
- * 
- * Name:	igate.h
- *
- * Purpose:	Interface to the Internet Gateway functions.
- *
- *-----------------------------------------------------------------------------*/
-
-
-#ifndef IGATE_H
-#define IGATE_H 1
-
-
-#include "ax25_pad.h"
-#include "digipeater.h"
-#include "audio.h"
-
-
-#define DEFAULT_IGATE_PORT 14580
-
-
-
-struct igate_config_s {
-
-/*
- * For logging into the IGate server.
- */
-	char t2_server_name[40];	/* Tier 2 IGate server name. */
-
-	int t2_server_port;		/* Typically 14580. */
-
-	char t2_login[AX25_MAX_ADDR_LEN];/* e.g. WA9XYZ-15 */
-					/* Note that the ssid could be any two alphanumeric */
-					/* characters not just 1 thru 15. */
-					/* Could be same or different than the radio call(s). */
-					/* Not sure what the consequences would be. */
-
-	char t2_passcode[8];		/* Max. 5 digits. Could be "-1". */
-
-	char *t2_filter;		/* Optional filter for IS -> RF direction. */
-					/* This is the "server side" filter. */
-					/* A better name would be subscription or something */
-					/* like that because we can only ask for more. */
-
-/*
- * For transmitting.
- */
-	int tx_chan;			/* Radio channel for transmitting. */
-					/* 0=first, etc.  -1 for none. */
-					/* Presently IGate can transmit on only a single channel. */
-					/* A future version might generalize this.  */
-					/* Each transmit channel would have its own client side filtering. */
-
-	char tx_via[80];		/* VIA path for transmitting third party packets. */
-					/* Usual text representation.  */
-					/* Must start with "," if not empty so it can */
-					/* simply be inserted after the destination address. */
-
-	int max_digi_hops;		/* Maximum number of digipeater hops possible for via path. */
-					/* Derived from the SSID when last character of address is a digit. */
-					/* e.g.  "WIDE1-1,WIDE5-2" would be 3. */
-					/* This is useful to know so we can determine how many */
-					/* stations we might be able to reach. */
-
-	int tx_limit_1;			/* Max. packets to transmit in 1 minute. */
-
-	int tx_limit_5;			/* Max. packets to transmit in 5 minutes. */
-
-	int igmsp;			/* Number of message sender position reports to allow. */
-					/* Common practice is to default to 1.  */
-					/* We allow additional flexibility of 0 to disable feature */
-					/* or a small number to allow more. */
-
-/*
- * Receiver to IS data options.
- */
-	int rx2ig_dedupe_time;		/* seconds.  0 to disable. */
-
-/*
- * Special SATgate mode to delay packets heard directly.
- */
-	int satgate_delay;		/* seconds.  0 to disable. */
-};
-
-
-#define IGATE_TX_LIMIT_1_DEFAULT 6
-#define IGATE_TX_LIMIT_1_MAX     20
-
-#define IGATE_TX_LIMIT_5_DEFAULT 20
-#define IGATE_TX_LIMIT_5_MAX     80
-
-#define IGATE_RX2IG_DEDUPE_TIME 0		/* Issue 85.  0 means disable dupe checking in RF>IS direction. */
-						/* See comments in rx_to_ig_remember & rx_to_ig_allow. */
-						/* Currently there is no configuration setting to change this. */
-
-#define DEFAULT_SATGATE_DELAY 10
-#define MIN_SATGATE_DELAY 5
-#define MAX_SATGATE_DELAY 30
-
-
-/* Call this once at startup */
-
-void igate_init (struct audio_s *p_audio_config, struct igate_config_s *p_igate_config, struct digi_config_s *p_digi_config, int debug_level);
-
-/* Call this with each packet received from the radio. */
-
-void igate_send_rec_packet (int chan, packet_t recv_pp);
-
-/* This when digipeater transmits.  Set bydigi to 1 . */
-
-void ig_to_tx_remember (packet_t pp, int chan, int bydigi);
-
-
-
-/* Get statistics for IGATE status beacon. */
-
-int igate_get_msg_cnt (void);
-
-int igate_get_pkt_cnt (void);
-
-int igate_get_upl_cnt (void);
-
-int igate_get_dnl_cnt (void);
-
-
-
-#endif
diff --git a/il2p.c b/il2p.c
index e51264c..6a284f2 100644
--- a/il2p.c
+++ b/il2p.c
@@ -42,11 +42,44 @@ along with QtSoundModem.  If not, see http://www.gnu.org/licenses
 
 // IP2P receive code (il2p_rec_bit) is called from the bit receiving code in ax25_demod.c, so includes parallel decoders
 
-
-
-
 #include "UZ7HOStuff.h"
 
+#include 	// for uint64_t
+
+ // Oct 2023 Nino has added an optional crc
+
+// Hamming(7,4) Encoding Table
+// Enter this table with the 4-bit value to be encoded.
+// Returns 7-bit encoded value, with high bit zero'd.
+
+uint8_t Hamming74EncodeTable[16] = { 0x0, 0x71, 0x62, 0x13, 0x54, 0x25, 0x36, 0x47, 0x38, 0x49, 0x5a, 0x2b, 0x6c, 0x1d, 0xe, 0x7f };
+
+// Hamming(7,4) Decoding Table
+// Enter this table with 7-bit encoded value, high bit masked.
+// Returns 4-bit decoded value.
+
+uint16_t Hamming74DecodeTable[128] = { \
+	  0x0, 0x0, 0x0, 0x3, 0x0, 0x5, 0xe, 0x7, \
+	  0x0, 0x9, 0xe, 0xb, 0xe, 0xd, 0xe, 0xe, \
+	  0x0, 0x3, 0x3, 0x3, 0x4, 0xd, 0x6, 0x3, \
+	  0x8, 0xd, 0xa, 0x3, 0xd, 0xd, 0xe, 0xd, \
+	  0x0, 0x5, 0x2, 0xb, 0x5, 0x5, 0x6, 0x5, \
+	  0x8, 0xb, 0xb, 0xb, 0xc, 0x5, 0xe, 0xb, \
+	  0x8, 0x1, 0x6, 0x3, 0x6, 0x5, 0x6, 0x6, \
+	  0x8, 0x8, 0x8, 0xb, 0x8, 0xd, 0x6, 0xf, \
+	  0x0, 0x9, 0x2, 0x7, 0x4, 0x7, 0x7, 0x7, \
+	  0x9, 0x9, 0xa, 0x9, 0xc, 0x9, 0xe, 0x7, \
+	  0x4, 0x1, 0xa, 0x3, 0x4, 0x4, 0x4, 0x7, \
+	  0xa, 0x9, 0xa, 0xa, 0x4, 0xd, 0xa, 0xf, \
+	  0x2, 0x1, 0x2, 0x2, 0xc, 0x5, 0x2, 0x7, \
+	  0xc, 0x9, 0x2, 0xb, 0xc, 0xc, 0xc, 0xf, \
+	  0x1, 0x1, 0x2, 0x1, 0x4, 0x1, 0x6, 0xf, \
+	  0x8, 0x1, 0xa, 0xf, 0xc, 0xf, 0xf, 0xf };
+
+
+
+
+
 void Debugprintf(const char * format, ...);
 int SMUpdatePhaseConstellation(int chan, float * Phases, float * Mags, int intPSKPhase, int Count);
 
@@ -109,7 +142,6 @@ int MaxMagIndex = 0;
 #ifndef FX25_H
 #define FX25_H
 
-#include 	// for uint64_t
 
 extern unsigned int pskStates[4];
 
@@ -343,6 +375,7 @@ struct packet_s {
 	unsigned char frame_data[AX25_MAX_PACKET_LEN + 1];
 	/* Raw frame contents, without the CRC. */
 
+	unsigned char crc[4];		// received crc
 
 	int magic2;		/* Will get stomped on if above overflows. */
 };
@@ -1015,6 +1048,39 @@ void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t
 
 	sprintf(Mode, "IL2P %d", centreFreq);
 
+	// check crc if enabled
+
+	if (il2p_crc[snd_ch])
+	{
+		unsigned short CRCMSG;
+		unsigned short CRCCALC;
+		uint8_t crc[4];
+
+		// check crc if enabled
+
+			// The four encoded CRC bytes are arranged :
+			// | CRC3 | CRC2 | CRC1 | CRC0 | but we store as received, so F->crc[0] is CRC3
+			// CRC3 encoded from high nibble of 16 - bit CRC value (from crc2)
+			// CRC0 encoded from low nibble of 16 - bit CRC value (from crc1)
+
+		crc[0] = Hamming74DecodeTable[(pp->crc[0] & 0x7f)];
+		crc[1] = Hamming74DecodeTable[(pp->crc[1] & 0x7f)];
+		crc[2] = Hamming74DecodeTable[(pp->crc[2] & 0x7f)];
+		crc[3] = Hamming74DecodeTable[(pp->crc[3] & 0x7f)];
+
+		CRCMSG = crc[0] << 12 | crc[1] << 8 | crc[2] << 4 | crc[3];
+
+		CRCCALC = get_fcs(pp->frame_data, pp->frame_len);
+
+		if (CRCCALC != CRCMSG)
+		{
+			Debugprintf("CRC Error Decoder %d  Received %x Sent %x", subchan, CRCCALC, CRCMSG);
+	//		freeString(data);
+	//		ax25_delete(pp);
+	//		return;
+		}
+	}
+
 	stringAdd(data, pp->frame_data, pp->frame_len + 2);  // QTSM assumes a CRC
 
 	ax25_delete(pp);
@@ -3151,6 +3217,13 @@ int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr)
 	ax25_get_addr_no_ssid(pp, AX25_SOURCE, src_addr);
 	int src_ssid = ax25_get_ssid(pp, AX25_SOURCE);
 
+	if ((pp->frame_data[6] & 0x80) == (pp->frame_data[13] & 0x80))
+	{
+		// Both C bits are the same (ax.25 v1) so can't be sent as type 1 as will be changed
+
+		return -1;
+	}
+
 	unsigned char *a = (unsigned char *)dst_addr;
 	for (int i = 0; *a != '\0'; i++, a++) {
 		if (*a < ' ' || *a > '_') {
@@ -3919,7 +3992,7 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
 		//assert(slice >= 0 && slice < MAX_SLICERS);
 		F = il2p_context[chan][subchan][slice] = (struct il2p_context_s *)malloc(sizeof(struct il2p_context_s));
 		//assert(F != NULL);
-		memset(F, 0, sizeof(struct il2p_context_s));
+memset(F, 0, sizeof(struct il2p_context_s));
 	}
 
 	// Accumulate most recent 24 bits received.  Most recent is LSB.
@@ -3942,7 +4015,7 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
 			nPhases[chan][subchan][slice] = 0;
 
 			// Determine Centre Freq
-			
+
 			centreFreq[chan] = GuessCentreFreq(chan);
 		}
 		else if (__builtin_popcount((~F->acc & 0x00ffffff) ^ IL2P_SYNC_WORD) <= 1) {
@@ -3956,7 +4029,7 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
 			centreFreq[chan] = GuessCentreFreq(chan);
 			nPhases[chan][subchan][slice] = 0;
 		}
-			
+
 		break;
 
 	case IL2P_HEADER:		// Gathering the header.
@@ -3990,7 +4063,7 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
 					F->eplen = il2p_payload_compute(&plprop, len, max_fec);
 
 					if (il2p_get_debug() >= 1)
-					{	
+					{
 						Debugprintf("Header type %d, max fec = %d", hdr_type, max_fec);
 						Debugprintf("Need to collect %d encoded bytes for %d byte payload.", F->eplen, len);
 						Debugprintf("%d small blocks of %d and %d large blocks of %d.  %d parity symbols per block",
@@ -4008,9 +4081,21 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
 						F->pc = 0;
 						F->state = IL2P_PAYLOAD;
 					}
-					else if (F->eplen == 0) {	// No payload.
+					else if (F->eplen == 0)
+					{
+						// No payload.
+
 						F->pc = 0;
-						F->state = IL2P_DECODE;
+
+						if (il2p_crc[chan])
+						{
+							// enter collect crc state
+
+							F->crccount = 0;
+							F->state = IL2P_CRC;
+						}
+						else
+							F->state = IL2P_DECODE;
 					}
 					else {			// Error.
 
@@ -4039,16 +4124,47 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
 			else {
 				F->spayload[F->pc++] = (~F->acc) & 0xff;
 			}
-			if (F->pc == F->eplen) {
+			if (F->pc == F->eplen)
+			{
+				// got frame. See if need crc
 
-				// TODO?: for symmetry it seems like we should clarify the payload before combining.
+				if (il2p_crc[chan])
+				{
+					// enter collect crc state
 
-				F->state = IL2P_DECODE;
+					F->crccount = 0;
+					F->state = IL2P_CRC;
+				}
+				else
+					F->state = IL2P_DECODE;
 			}
 		}
 		break;
 
+	case IL2P_CRC:
+
+		F->bc++;
+		if (F->bc == 8)
+		{
+			// full byte has been collected.
+			F->bc = 0;
+			if (!F->polarity)
+				F->crc[F->crccount++] = F->acc & 0xff;
+			else
+				F->crc[F->crccount++] = (~F->acc) & 0xff;
+
+			if (F->crccount == 4)
+			{
+				// have all crc bytes. enter DECODE
+
+				F->state = IL2P_DECODE;
+			}
+		}
+
+			break;
+
 	case IL2P_DECODE:
+
 		// We get here after a good header and any payload has been collected.
 		// Processing is delayed by one bit but I think it makes the logic cleaner.
 		// During unit testing be sure to send an extra bit to flush it out at the end.
@@ -4077,6 +4193,18 @@ void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
 
 			// TODO: Could we put last 3 arguments in packet object rather than passing around separately?
 
+			// if using crc pass received crc to packet object
+
+			if (il2p_crc[chan])
+			{
+				//copy crc bytes to packet object
+
+				pp->crc[0] = F->crc[0];
+				pp->crc[1] = F->crc[1];
+				pp->crc[2] = F->crc[2];
+				pp->crc[3] = F->crc[3];
+			}
+
 			multi_modem_process_rec_packet(chan, subchan, slice, pp, alevel, retries, is_fx25, slice, centreFreq[chan]);
 		}
 	}   // end block for local variables.
@@ -4269,13 +4397,19 @@ static void send_bit(int chan, int b, int polarity);
  *
  *--------------------------------------------------------------*/
 
+
 string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity)
 {
-	unsigned char encoded[IL2P_MAX_PACKET_SIZE];
+	unsigned char encoded[IL2P_MAX_PACKET_SIZE] = "";
 	string * packet = newString();
 	int preamblecount;
 	unsigned char preamble[1024];
 
+	// The data includes the 2 byte crc but length doesn't
+
+	uint8_t crc1 = pp->frame_data[pp->frame_len];			// Low 8 bits
+	uint8_t crc2 = pp->frame_data[pp->frame_len + 1];		// High 8 bits
+
 	encoded[0] = (IL2P_SYNC_WORD >> 16) & 0xff;
 	encoded[1] = (IL2P_SYNC_WORD >> 8) & 0xff;
 	encoded[2] = (IL2P_SYNC_WORD) & 0xff;
@@ -4289,6 +4423,24 @@ string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity)
 
 	elen += IL2P_SYNC_WORD_SIZE;
 
+	// if we are using crc add it now. elen should point to end of data
+	// crc should be at pp->frame_data[pp->frame_len]
+
+	if (il2p_crc[chan])
+	{
+		// The four encoded CRC bytes are arranged :
+		// | CRC3 | CRC2 | CRC1 | CRC0 |
+
+		// CRC3 encoded from high nibble of 16 - bit CRC value (from crc2)
+		// CRC0 encoded from low nibble of 16 - bit CRC value (from crc1)
+
+		encoded[elen++] = Hamming74EncodeTable[crc2 >> 4];
+		encoded[elen++] = Hamming74EncodeTable[crc2 & 0xf];
+		encoded[elen++] = Hamming74EncodeTable[crc1 >> 4];
+		encoded[elen++] = Hamming74EncodeTable[crc1 &0xf];
+	}
+
+
 	number_of_bits_sent[chan] = 0;
 
 	if (il2p_get_debug() >= 1) {
@@ -4366,7 +4518,7 @@ string * fill_il2p_data(int snd_ch, string * data)
 	// Call il2p_send_frame to build the bit stream
 
 	pp->frame_len = data->Length - 2;					// Included CRC
-	memcpy(pp->frame_data, data->Data, data->Length);
+	memcpy(pp->frame_data, data->Data, data->Length);	// Copy the crc in case we are going to send it
 
 	result = il2p_send_frame(snd_ch, pp, 1, 0);
 
diff --git a/il2p.c.bak b/il2p.c.bak
deleted file mode 100644
index 2c81201..0000000
--- a/il2p.c.bak
+++ /dev/null
@@ -1,4502 +0,0 @@
-/*
-Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO
-
-This file is part of QtSoundModem
-
-QtSoundModem is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-QtSoundModem 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 QtSoundModem.  If not, see http://www.gnu.org/licenses
-
-*/
-
-// UZ7HO Soundmodem Port by John Wiseman G8BPQ
-
-// IL2P code. Based on Direwolf code, under the following copyright
-
-//
-//    Copyright (C) 2021  John Langner, WB2OSZ
-//
-//    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, see .
-//
-
-
-// IP2P receive code (il2p_rec_bit) is called from the bit receiving code in ax25_demod.c, so includes parallel decoders
-
-
-
-
-#include "UZ7HOStuff.h"
-
-void Debugprintf(const char * format, ...);
-
-#define MAX_ADEVS 3			
-
-#define MAX_RADIO_CHANS ((MAX_ADEVS) * 2)
-
-#define MAX_CHANS MAX_RADIO_CHANS	// TODO: Replace all former  with latter to avoid confusion with following.
-
-#define MAX_TOTAL_CHANS 16		// v1.7 allows additional virtual channels which are connected
- // to something other than radio modems.
- // Total maximum channels is based on the 4 bit KISS field.
- // Someone with very unusual requirements could increase this and
- // use only the AGW network protocol.
-
-
-#define MAX_SUBCHANS 9
-
-#define MAX_SLICERS 9
-
-#define max(x, y) ((x) > (y) ? (x) : (y))
-#define min(x, y) ((x) < (y) ? (x) : (y))
-
-/* For option to try fixing frames with bad CRC. */
-
-typedef enum retry_e {
-	RETRY_NONE = 0,
-	RETRY_INVERT_SINGLE = 1,
-	RETRY_INVERT_DOUBLE = 2,
-	RETRY_INVERT_TRIPLE = 3,
-	RETRY_INVERT_TWO_SEP = 4,
-	RETRY_MAX = 5
-}  retry_t;
-
-typedef struct alevel_s {
-	int rec;
-	int mark;
-	int space;
-	//float ms_ratio;	// TODO: take out after temporary investigation.
-} alevel_t;
-
-
-alevel_t demod_get_audio_level(int chan, int subchan);
-void tone_gen_put_bit(int chan, int dat);
-
-int ax25memdebug = 1;
-
-// Code to try to determine centre freq
-
-float MagOut[4096];
-float MaxMagOut = 0;
-int MaxMagIndex = 0;
-
-// FFT Bin Size is 12000 / FFTSize
-
-#ifndef FX25_H
-#define FX25_H
-
-#include 	// for uint64_t
-
-
-/* Reed-Solomon codec control block */
-struct rs {
-	unsigned int mm;              /* Bits per symbol */
-	unsigned int nn;              /* Symbols per block (= (1<mm)
-#define NN (rs->nn)
-#define ALPHA_TO (rs->alpha_to) 
-#define INDEX_OF (rs->index_of)
-#define GENPOLY (rs->genpoly)
-#define NROOTS (rs->nroots)
-#define FCR (rs->fcr)
-#define PRIM (rs->prim)
-#define IPRIM (rs->iprim)
-#define A0 (NN)
-
-int __builtin_popcountll(unsigned long long int i)
-{
-	return 0;
-}
-
-int __builtin_popcount(unsigned int n)
-{
-	unsigned int count = 0;
-	while (n)
-	{
-		count += n & 1;
-		n >>= 1;
-	}
-	return count;
-}
-
-static inline int modnn(struct rs *rs, int x) {
-	while (x >= rs->nn) {
-		x -= rs->nn;
-		x = (x >> rs->mm) + (x & rs->nn);
-	}
-	return x;
-}
-
-#define MODNN(x) modnn(rs,x)
-
-
-#define ENCODE_RS encode_rs_char
-#define DECODE_RS decode_rs_char
-#define INIT_RS init_rs_char
-#define FREE_RS free_rs_char
-
-#define DTYPE unsigned char
-
-void ENCODE_RS(struct rs *rs, DTYPE *data, DTYPE *bb);
-
-int DECODE_RS(struct rs *rs, DTYPE *data, int *eras_pos, int no_eras);
-
-struct rs *INIT_RS(unsigned int symsize, unsigned int gfpoly,
-	unsigned int fcr, unsigned int prim, unsigned int nroots);
-
-void FREE_RS(struct rs *rs);
-
-
-
-// These 3 are the external interface.
-// Maybe these should be in a different file, separated from the internal stuff.
-
-void fx25_init(int debug_level);
-int fx25_send_frame(int chan, unsigned char *fbuf, int flen, int fx_mode);
-void fx25_rec_bit(int chan, int subchan, int slice, int dbit);
-int fx25_rec_busy(int chan);
-
-
-// Other functions in fx25_init.c.
-
-struct rs *fx25_get_rs(int ctag_num);
-uint64_t fx25_get_ctag_value(int ctag_num);
-int fx25_get_k_data_radio(int ctag_num);
-int fx25_get_k_data_rs(int ctag_num);
-int fx25_get_nroots(int ctag_num);
-int fx25_get_debug(void);
-int fx25_tag_find_match(uint64_t t);
-int fx25_pick_mode(int fx_mode, int dlen);
-
-void fx_hex_dump(unsigned char *x, int len);
-
-/*-------------------------------------------------------------------
- *
- * Name:	ax25_pad.h
- *
- * Purpose:	Header file for using ax25_pad.c
- *
- *------------------------------------------------------------------*/
-
-#ifndef AX25_PAD_H
-#define AX25_PAD_H 1
-
-
-#define AX25_MAX_REPEATERS 8
-#define AX25_MIN_ADDRS 2	/* Destination & Source. */
-#define AX25_MAX_ADDRS 10	/* Destination, Source, 8 digipeaters. */	
-
-#define AX25_DESTINATION  0	/* Address positions in frame. */
-#define AX25_SOURCE       1	
-#define AX25_REPEATER_1   2
-#define AX25_REPEATER_2   3
-#define AX25_REPEATER_3   4
-#define AX25_REPEATER_4   5
-#define AX25_REPEATER_5   6
-#define AX25_REPEATER_6   7
-#define AX25_REPEATER_7   8
-#define AX25_REPEATER_8   9
-
-#define AX25_MAX_ADDR_LEN 12	/* In theory, you would expect the maximum length */
- /* to be 6 letters, dash, 2 digits, and nul for a */
- /* total of 10.  However, object labels can be 10 */
- /* characters so throw in a couple extra bytes */
- /* to be safe. */
-
-#define AX25_MIN_INFO_LEN 0	/* Previously 1 when considering only APRS. */
-
-#define AX25_MAX_INFO_LEN 2048	/* Maximum size for APRS. */
-				/* AX.25 starts out with 256 as the default max */
-				/* length but the end stations can negotiate */
-				/* something different. */
-				/* version 0.8:  Change from 256 to 2028 to */
-				/* handle the larger paclen for Linux AX25. */
-
-				/* These don't include the 2 bytes for the */
-				/* HDLC frame FCS. */
-
-/*
- * Previously, for APRS only.
- * #define AX25_MIN_PACKET_LEN ( 2 * 7 + 2 + AX25_MIN_INFO_LEN)
- * #define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + AX25_MAX_INFO_LEN)
- */
-
- /* The more general case. */
- /* An AX.25 frame can have a control byte and no protocol. */
-
-#define AX25_MIN_PACKET_LEN ( 2 * 7 + 1 )
-
-#define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + 3 + AX25_MAX_INFO_LEN)
-
-
-/*
- * packet_t is a pointer to a packet object.
- *
- * The actual implementation is not visible outside ax25_pad.c.
- */
-
-#define AX25_UI_FRAME 3		/* Control field value. */
-
-#define AX25_PID_NO_LAYER_3 0xf0		/* protocol ID used for APRS */
-#define AX25_PID_SEGMENTATION_FRAGMENT 0x08
-#define AX25_PID_ESCAPE_CHARACTER 0xff
-
-struct packet_s {
-
-	int magic1;		/* for error checking. */
-
-	int seq;		/* unique sequence number for debugging. */
-
-	double release_time;	/* Time stamp in format returned by dtime_now(). */
-				/* When to release from the SATgate mode delay queue. */
-
-#define MAGIC 0x41583235
-
-	struct packet_s *nextp;	/* Pointer to next in queue. */
-
-	int num_addr;		/* Number of addresses in frame. */
-				/* Range of AX25_MIN_ADDRS .. AX25_MAX_ADDRS for AX.25. */
-				/* It will be 0 if it doesn't look like AX.25. */
-				/* -1 is used temporarily at allocation to mean */
-				/* not determined yet. */
-
-
-
-				/*
-				 * The 7th octet of each address contains:
-					 *
-				 * Bits:   H  R  R  SSID  0
-				 *
-				 *   H 		for digipeaters set to 0 initially.
-				 *		Changed to 1 when position has been used.
-				 *
-				 *		for source & destination it is called
-				 *		command/response.  Normally both 1 for APRS.
-				 *		They should be opposites for connected mode.
-				 *
-				 *   R	R	Reserved.  Normally set to 1 1.
-				 *
-				 *   SSID	Substation ID.  Range of 0 - 15.
-				 *
-				 *   0		Usually 0 but 1 for last address.
-				 */
-
-
-#define SSID_H_MASK	0x80
-#define SSID_H_SHIFT	7
-
-#define SSID_RR_MASK	0x60
-#define SSID_RR_SHIFT	5
-
-#define SSID_SSID_MASK	0x1e
-#define SSID_SSID_SHIFT	1
-
-#define SSID_LAST_MASK	0x01
-
-
-	int frame_len;		/* Frame length without CRC. */
-
-	int modulo;		/* I & S frames have sequence numbers of either 3 bits (modulo 8) */
-				/* or 7 bits (modulo 128).  This is conveyed by either 1 or 2 */
-				/* control bytes.  Unfortunately, we can't determine this by looking */
-				/* at an isolated frame.  We need to know about the context.  If we */
-				/* are part of the conversation, we would know.  But if we are */
-				/* just listening to others, this would be more difficult to determine. */
-
-				/* For U frames:   	set to 0 - not applicable */
-				/* For I & S frames:	8 or 128 if known.  0 if unknown. */
-
-	unsigned char frame_data[AX25_MAX_PACKET_LEN + 1];
-	/* Raw frame contents, without the CRC. */
-
-
-	int magic2;		/* Will get stomped on if above overflows. */
-};
-
-
-
-typedef struct packet_s *packet_t;
-
-typedef enum cmdres_e { cr_00 = 2, cr_cmd = 1, cr_res = 0, cr_11 = 3 } cmdres_t;
-
-
-extern packet_t ax25_new(void);
-
-
-#ifdef AX25_PAD_C	/* Keep this hidden - implementation could change. */
-
-
-/*
- * APRS always has one control octet of 0x03 but the more
- * general AX.25 case is one or two control bytes depending on
- * whether "modulo 128 operation" is in effect.
- */
-
- //#define DEBUGX 1
-
-static inline int ax25_get_control_offset(packet_t this_p)
-{
-	return (this_p->num_addr * 7);
-}
-
-static inline int ax25_get_num_control(packet_t this_p)
-{
-	int c;
-
-	c = this_p->frame_data[ax25_get_control_offset(this_p)];
-
-	if ((c & 0x01) == 0) {			/* I   xxxx xxx0 */
-#if DEBUGX
-		Debugprintf("ax25_get_num_control, %02x is I frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1);
-#endif
-		return ((this_p->modulo == 128) ? 2 : 1);
-	}
-
-	if ((c & 0x03) == 1) {			/* S   xxxx xx01 */
-#if DEBUGX
-		Debugprintf("ax25_get_num_control, %02x is S frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1);
-#endif
-		return ((this_p->modulo == 128) ? 2 : 1);
-	}
-
-#if DEBUGX
-	Debugprintf("ax25_get_num_control, %02x is U frame, always returns 1.\n", c);
-#endif
-
-	return (1);					/* U   xxxx xx11 */
-}
-
-
-
-/*
- * APRS always has one protocol octet of 0xF0 meaning no level 3
- * protocol but the more general case is 0, 1 or 2 protocol ID octets.
- */
-
-static inline int ax25_get_pid_offset(packet_t this_p)
-{
-	return (ax25_get_control_offset(this_p) + ax25_get_num_control(this_p));
-}
-
-static int ax25_get_num_pid(packet_t this_p)
-{
-	int c;
-	int pid;
-
-	c = this_p->frame_data[ax25_get_control_offset(this_p)];
-
-	if ((c & 0x01) == 0 ||				/* I   xxxx xxx0 */
-		c == 0x03 || c == 0x13) {			/* UI  000x 0011 */
-
-		pid = this_p->frame_data[ax25_get_pid_offset(this_p)];
-#if DEBUGX
-		Debugprintf("ax25_get_num_pid, %02x is I or UI frame, pid = %02x, returns %d\n", c, pid, (pid == AX25_PID_ESCAPE_CHARACTER) ? 2 : 1);
-#endif
-		if (pid == AX25_PID_ESCAPE_CHARACTER) {
-			return (2);			/* pid 1111 1111 means another follows. */
-		}
-		return (1);
-	}
-#if DEBUGX
-	Debugprintf("ax25_get_num_pid, %02x is neither I nor UI frame, returns 0\n", c);
-#endif
-	return (0);
-}
-
-
-/*
- * AX.25 has info field for 5 frame types depending on the control field.
- *
- *	xxxx xxx0	I
- *	000x 0011	UI		(which includes APRS)
- *	101x 1111	XID
- *	111x 0011	TEST
- *	100x 0111	FRMR
- *
- * APRS always has an Information field with at least one octet for the Data Type Indicator.
- */
-
-static inline int ax25_get_info_offset(packet_t this_p)
-{
-	int offset = ax25_get_control_offset(this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p);
-#if DEBUGX
-	Debugprintf("ax25_get_info_offset, returns %d\n", offset);
-#endif
-	return (offset);
-}
-
-static inline int ax25_get_num_info(packet_t this_p)
-{
-	int len;
-
-	/* assuming AX.25 frame. */
-
-	len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p);
-	if (len < 0) {
-		len = 0;		/* print error? */
-	}
-
-	return (len);
-}
-
-#endif
-
-
-typedef enum ax25_modulo_e { modulo_unknown = 0, modulo_8 = 8, modulo_128 = 128 } ax25_modulo_t;
-
-typedef enum ax25_frame_type_e {
-
-	frame_type_I = 0,	// Information
-
-	frame_type_S_RR,	// Receive Ready - System Ready To Receive
-	frame_type_S_RNR,	// Receive Not Ready - TNC Buffer Full
-	frame_type_S_REJ,	// Reject Frame - Out of Sequence or Duplicate
-	frame_type_S_SREJ,	// Selective Reject - Request single frame repeat
-
-	frame_type_U_SABME,	// Set Async Balanced Mode, Extended
-	frame_type_U_SABM,	// Set Async Balanced Mode
-	frame_type_U_DISC,	// Disconnect
-	frame_type_U_DM,	// Disconnect Mode
-	frame_type_U_UA,	// Unnumbered Acknowledge
-	frame_type_U_FRMR,	// Frame Reject
-	frame_type_U_UI,	// Unnumbered Information
-	frame_type_U_XID,	// Exchange Identification
-	frame_type_U_TEST,	// Test
-	frame_type_U,		// other Unnumbered, not used by AX.25.
-
-	frame_not_AX25		// Could not get control byte from frame.
-				// This must be last because value plus 1 is
-				// for the size of an array.
-
-} ax25_frame_type_t;
-
-
-/*
- * Originally this was a single number.
- * Let's try something new in version 1.2.
- * Also collect AGC values from the mark and space filters.
- */
-
-#ifndef AXTEST
-// TODO: remove this?
-#define AX25MEMDEBUG 1
-#endif
-
-
-
-extern packet_t ax25_from_text(char *monitor, int strict);
-
-extern packet_t ax25_from_frame(unsigned char *data, int len, alevel_t alevel);
-
-extern packet_t ax25_dup(packet_t copy_from);
-
-extern void ax25_delete(packet_t pp);
-
-
-
-extern int ax25_parse_addr(int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard);
-extern int ax25_check_addresses(packet_t pp);
-
-extern packet_t ax25_unwrap_third_party(packet_t from_pp);
-
-extern void ax25_set_addr(packet_t pp, int, char *);
-extern void ax25_insert_addr(packet_t this_p, int n, char *ad);
-extern void ax25_remove_addr(packet_t this_p, int n);
-
-extern int ax25_get_num_addr(packet_t pp);
-extern int ax25_get_num_repeaters(packet_t this_p);
-
-extern void ax25_get_addr_with_ssid(packet_t pp, int n, char *station);
-extern void ax25_get_addr_no_ssid(packet_t pp, int n, char *station);
-
-extern int ax25_get_ssid(packet_t pp, int n);
-extern void ax25_set_ssid(packet_t this_p, int n, int ssid);
-
-extern int ax25_get_h(packet_t pp, int n);
-
-extern void ax25_set_h(packet_t pp, int n);
-
-extern int ax25_get_heard(packet_t this_p);
-
-extern int ax25_get_first_not_repeated(packet_t pp);
-
-extern int ax25_get_rr(packet_t this_p, int n);
-
-extern int ax25_get_info(packet_t pp, unsigned char **paddr);
-extern void ax25_set_info(packet_t pp, unsigned char *info_ptr, int info_len);
-extern int ax25_cut_at_crlf(packet_t this_p);
-
-extern void ax25_set_nextp(packet_t this_p, packet_t next_p);
-
-extern int ax25_get_dti(packet_t this_p);
-
-extern packet_t ax25_get_nextp(packet_t this_p);
-
-extern void ax25_set_release_time(packet_t this_p, double release_time);
-extern double ax25_get_release_time(packet_t this_p);
-
-extern void ax25_set_modulo(packet_t this_p, int modulo);
-extern int ax25_get_modulo(packet_t this_p);
-
-extern void ax25_format_addrs(packet_t pp, char *);
-extern void ax25_format_via_path(packet_t this_p, char *result, size_t result_size);
-
-extern int ax25_pack(packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]);
-
-extern ax25_frame_type_t ax25_frame_type(packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns);
-
-extern void ax25_hex_dump(packet_t this_p);
-
-extern int ax25_is_aprs(packet_t pp);
-extern int ax25_is_null_frame(packet_t this_p);
-
-extern int ax25_get_control(packet_t this_p);
-extern int ax25_get_c2(packet_t this_p);
-
-extern int ax25_get_pid(packet_t this_p);
-
-extern int ax25_get_frame_len(packet_t this_p);
-extern unsigned char *ax25_get_frame_data_ptr(packet_t this_p);
-
-extern unsigned short ax25_dedupe_crc(packet_t pp);
-
-extern unsigned short ax25_m_m_crc(packet_t pp);
-
-extern void ax25_safe_print(char *, int, int ascii_only);
-
-#define AX25_ALEVEL_TO_TEXT_SIZE 40	// overkill but safe.
-extern int ax25_alevel_to_text(alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE]);
-
-
-#endif /* AX25_PAD_H */
-
-/* end ax25_pad.h */
-
-
-
-
-#define CTAG_MIN 0x01
-#define CTAG_MAX 0x0B
-
-// Maximum sizes of "data" and "check" parts.
-
-#define FX25_MAX_DATA 239	// i.e. RS(255,239)
-#define FX25_MAX_CHECK 64	// e.g. RS(255, 191)
-#define FX25_BLOCK_SIZE 255	// Block size always 255 for 8 bit symbols.
-
-#endif // FX25_H
-
-#ifndef IL2P_H
-#define IL2P_H 1
-
-
-#define IL2P_PREAMBLE 0x55
-
-#define IL2P_SYNC_WORD 0xF15E48
-
-#define IL2P_SYNC_WORD_SIZE 3
-#define IL2P_HEADER_SIZE 13	// Does not include 2 parity.
-#define IL2P_HEADER_PARITY 2
-
-#define IL2P_MAX_PAYLOAD_SIZE 1023
-#define IL2P_MAX_PAYLOAD_BLOCKS 5
-#define IL2P_MAX_PARITY_SYMBOLS 16		// For payload only.
-#define IL2P_MAX_ENCODED_PAYLOAD_SIZE (IL2P_MAX_PAYLOAD_SIZE + IL2P_MAX_PAYLOAD_BLOCKS * IL2P_MAX_PARITY_SYMBOLS)
-
-#define IL2P_MAX_PACKET_SIZE (IL2P_SYNC_WORD_SIZE + IL2P_HEADER_SIZE + IL2P_HEADER_PARITY + IL2P_MAX_ENCODED_PAYLOAD_SIZE)
-
-
-float GuessCentreFreq(int i)
-{
-	float Freq = 0;
-	float Start;
-	float End;
-	int n;
-	float Max = 0;
-	int Index = 0;
-
-	Start = (rx_freq[i] - RCVR[i] * rcvr_offset[i]) / BinSize;
-	End = (rx_freq[i] + RCVR[i] * rcvr_offset[i]) / BinSize;
-
-	for (n = Start; n <= End; n++)
-	{
-		if (MagOut[n] > Max)
-		{
-			Max = MagOut[n];
-			Index = n;
-		}
-	}
-
-	Freq = Index * BinSize;
-
-	return Freq;
-}
-
-/*------------------------------------------------------------------------------
- *
- * Name:	ax25_new
- *
- * Purpose:	Allocate memory for a new packet object.
- *
- * Returns:	Identifier for a new packet object.
- *		In the current implementation this happens to be a pointer.
- *
- *------------------------------------------------------------------------------*/
-
-int last_seq_num = 0;
-int new_count = 0;
-int delete_count = 0;
-
-packet_t ax25_new(void)
-{
-	struct packet_s *this_p;
-
-
-#if DEBUG 
-	text_color_set(DW_COLOR_DEBUG);
-	Debugprintf("ax25_new(): before alloc, new=%d, delete=%d\n", new_count, delete_count);
-#endif
-
-	last_seq_num++;
-	new_count++;
-
-	/*
-	 * check for memory leak.
-	 */
-
-	 // version 1.4 push up the threshold.   We could have considerably more with connected mode.
-
-		 //if (new_count > delete_count + 100) {
-	if (new_count > delete_count + 256) {
-
-		Debugprintf("Report to WB2OSZ - Memory leak for packet objects.  new=%d, delete=%d\n", new_count, delete_count);
-#if AX25MEMDEBUG
-#endif
-	}
-
-	this_p = calloc(sizeof(struct packet_s), (size_t)1);
-
-	if (this_p == NULL) {
-		Debugprintf("ERROR - can't allocate memory in ax25_new.\n");
-	}
-
-//	assert(this_p != NULL);
-
-	this_p->magic1 = MAGIC;
-	this_p->seq = last_seq_num;
-	this_p->magic2 = MAGIC;
-	this_p->num_addr = (-1);
-
-	return (this_p);
-}
-
-/*------------------------------------------------------------------------------
- *
- * Name:	ax25_delete
- *
- * Purpose:	Destroy a packet object, freeing up memory it was using.
- *
- *------------------------------------------------------------------------------*/
-
-void ax25_delete(packet_t this_p)
-{
-	if (this_p == NULL) {
-		Debugprintf("ERROR - NULL pointer passed to ax25_delete.\n");
-		return;
-	}
-
-	delete_count++;
-
-//	assert(this_p->magic1 == MAGIC);
-//	assert(this_p->magic2 == MAGIC);
-
-	this_p->magic1 = 0;
-	this_p->magic1 = 0;
-
-	free(this_p);
-}
-
-
-
-
-
-/*------------------------------------------------------------------------------
- *
- * Name:	ax25_s_frame
- *
- * Purpose:	Construct an S frame.
- *
- * Input:	addrs		- Array of addresses.
- *
- *		num_addr	- Number of addresses, range 2 .. 10.
- *
- *		cr		- cr_cmd command frame, cr_res for a response frame.
- *
- *		ftype		- One of:
- *				        frame_type_S_RR,        // Receive Ready - System Ready To Receive
- *				        frame_type_S_RNR,       // Receive Not Ready - TNC Buffer Full
- *				        frame_type_S_REJ,       // Reject Frame - Out of Sequence or Duplicate
- *				        frame_type_S_SREJ,      // Selective Reject - Request single frame repeat
- *
- *		modulo		- 8 or 128.  Determines if we have 1 or 2 control bytes.
- *
- *		nr		- N(R) field --- describe.
- *
- *		pf		- Poll/Final flag.
- *
- *		pinfo		- Pointer to data for Info field.  Allowed only for SREJ.
- *
- *		info_len	- Length for Info field.
- *
- *
- * Returns:	Pointer to new packet object.
- *
- *------------------------------------------------------------------------------*/
-
-
-packet_t ax25_s_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, unsigned char *pinfo, int info_len)
-{
-	packet_t this_p;
-	unsigned char *p;
-	int ctrl = 0;
-
-	this_p = ax25_new();
-
-	if (this_p == NULL) return (NULL);
-
-	if (!set_addrs(this_p, addrs, num_addr, cr)) {
-		Debugprintf("Internal error in %s: Could not set addresses for S frame.\n", __func__);
-		ax25_delete(this_p);
-		return (NULL);
-	}
-
-	if (modulo != 8 && modulo != 128) {
-		Debugprintf("Internal error in %s: Invalid modulo %d for S frame.\n", __func__, modulo);
-		modulo = 8;
-	}
-	this_p->modulo = modulo;
-
-	if (nr < 0 || nr >= modulo) {
-		Debugprintf("Internal error in %s: Invalid N(R) %d for S frame.\n", __func__, nr);
-		nr &= (modulo - 1);
-	}
-
-	// Erratum: The AX.25 spec is not clear about whether SREJ should be command, response, or both.
-	// The underlying X.25 spec clearly says it is response only.  Let's go with that.
-
-	if (ftype == frame_type_S_SREJ && cr != cr_res) {
-		Debugprintf("Internal error in %s: SREJ must be response.\n", __func__);
-	}
-
-	switch (ftype) {
-
-	case frame_type_S_RR:		ctrl = 0x01;	break;
-	case frame_type_S_RNR:	ctrl = 0x05;	break;
-	case frame_type_S_REJ:	ctrl = 0x09;	break;
-	case frame_type_S_SREJ:	ctrl = 0x0d;	break;
-
-	default:
-		Debugprintf("Internal error in %s: Invalid ftype %d for S frame.\n", __func__, ftype);
-		ax25_delete(this_p);
-		return (NULL);
-		break;
-	}
-
-	p = this_p->frame_data + this_p->frame_len;
-
-	if (modulo == 8) {
-		if (pf) ctrl |= 0x10;
-		ctrl |= nr << 5;
-		*p++ = ctrl;
-		this_p->frame_len++;
-	}
-	else {
-		*p++ = ctrl;
-		this_p->frame_len++;
-
-		ctrl = pf & 1;
-		ctrl |= nr << 1;
-		*p++ = ctrl;
-		this_p->frame_len++;
-	}
-
-	if (ftype == frame_type_S_SREJ) {
-		if (pinfo != NULL && info_len > 0) {
-			if (info_len > AX25_MAX_INFO_LEN) {
-				Debugprintf("Internal error in %s: SREJ frame, Invalid information field length %d.\n", __func__, info_len);
-				info_len = AX25_MAX_INFO_LEN;
-			}
-			memcpy(p, pinfo, info_len);
-			p += info_len;
-			this_p->frame_len += info_len;
-		}
-	}
-	else {
-		if (pinfo != NULL || info_len != 0) {
-			Debugprintf("Internal error in %s: Info part not allowed for RR, RNR, REJ frame.\n", __func__);
-		}
-	}
-	*p = '\0';
-
-
-	return (this_p);
-
-} /* end ax25_s_frame */
-
-
-
-
-
-/*------------------------------------------------------------------------------
- *
- * Name:	ax25_i_frame
- *
- * Purpose:	Construct an I frame.
- *
- * Input:	addrs		- Array of addresses.
- *
- *		num_addr	- Number of addresses, range 2 .. 10.
- *
- *		cr		- cr_cmd command frame, cr_res for a response frame.
- *
- *		modulo		- 8 or 128.
- *
- *		nr		- N(R) field --- describe.
- *
- *		ns		- N(S) field --- describe.
- *
- *		pf		- Poll/Final flag.
- *
- *		pid		- Protocol ID.
- *				  Normally 0xf0 meaning no level 3.
- *				  Could be other values for NET/ROM, etc.
- *
- *		pinfo		- Pointer to data for Info field.
- *
- *		info_len	- Length for Info field.
- *
- *
- * Returns:	Pointer to new packet object.
- *
- *------------------------------------------------------------------------------*/
-
-packet_t ax25_i_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, int modulo, int nr, int ns, int pf, int pid, unsigned char *pinfo, int info_len)
-{
-	packet_t this_p;
-	unsigned char *p;
-	int ctrl = 0;
-
-	this_p = ax25_new();
-
-	if (this_p == NULL) return (NULL);
-
-	if (!set_addrs(this_p, addrs, num_addr, cr)) {
-		Debugprintf("Internal error in %s: Could not set addresses for I frame.\n", __func__);
-		ax25_delete(this_p);
-		return (NULL);
-	}
-
-	if (modulo != 8 && modulo != 128) {
-		Debugprintf("Internal error in %s: Invalid modulo %d for I frame.\n", __func__, modulo);
-		modulo = 8;
-	}
-	this_p->modulo = modulo;
-
-	if (nr < 0 || nr >= modulo) {
-		Debugprintf("Internal error in %s: Invalid N(R) %d for I frame.\n", __func__, nr);
-		nr &= (modulo - 1);
-	}
-
-	if (ns < 0 || ns >= modulo) {
-		Debugprintf("Internal error in %s: Invalid N(S) %d for I frame.\n", __func__, ns);
-		ns &= (modulo - 1);
-	}
-
-	p = this_p->frame_data + this_p->frame_len;
-
-	if (modulo == 8) {
-		ctrl = (nr << 5) | (ns << 1);
-		if (pf) ctrl |= 0x10;
-		*p++ = ctrl;
-		this_p->frame_len++;
-	}
-	else {
-		ctrl = ns << 1;
-		*p++ = ctrl;
-		this_p->frame_len++;
-
-		ctrl = nr << 1;
-		if (pf) ctrl |= 0x01;
-		*p++ = ctrl;
-		this_p->frame_len++;
-	}
-
-	// Definitely don't want pid value of 0 (not in valid list)
-	// or 0xff (which means more bytes follow).
-
-	if (pid < 0 || pid == 0 || pid == 0xff) {
-		Debugprintf("Warning: Client application provided invalid PID value, 0x%02x, for I frame.\n", pid);
-		pid = AX25_PID_NO_LAYER_3;
-	}
-	*p++ = pid;
-	this_p->frame_len++;
-
-	if (pinfo != NULL && info_len > 0) {
-		if (info_len > AX25_MAX_INFO_LEN) {
-			Debugprintf("Internal error in %s: I frame, Invalid information field length %d.\n", __func__, info_len);
-			info_len = AX25_MAX_INFO_LEN;
-		}
-		memcpy(p, pinfo, info_len);
-		p += info_len;
-		this_p->frame_len += info_len;
-	}
-
-	*p = '\0';
-
-
-	return (this_p);
-
-} /* end ax25_i_frame */
-
-
-
-
-
-extern TStringList detect_list[5];
-extern TStringList detect_list_c[5];
-
-void multi_modem_process_rec_packet(int snd_ch, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, int is_fx25, int emph, int centreFreq)
-{
-	// Convert to QtSM internal format
-
-	struct TDetector_t * pDET = &DET[emph][subchan];
-	string *  data = newString();
-	char Mode[16] = "IL2P";
-
-	sprintf(Mode, "IL2P %d", centreFreq);
-
-	stringAdd(data, pp->frame_data, pp->frame_len + 2);  // QTSM assumes a CRC
-
-	ax25_delete(pp);
-
-	if (retries)
-	{
-		pDET->rx_decoded = decodedFEC;
-		pDET->emph_decoded = decodedFEC;
-		pDET->errors = retries;
-	}
-	else
-	{
-		pDET->rx_decoded = decodedNormal;
-		pDET->emph_decoded = decodedNormal;
-		pDET->errors = 0;
-	}
-
-	if (detect_list[snd_ch].Count > 0 &&
-		my_indexof(&detect_list[snd_ch], data) >= 0)
-	{
-		// Already have a copy of this frame
-
-		freeString(data);
-		Debugprintf("Discarding copy rcvr %d emph %d", subchan, 0);
-		return;
-	}
-
-	string * xx = newString();
-	memset(xx->Data, 0, 16);
-
-	Add(&detect_list_c[snd_ch], xx);
-	Add(&detect_list[snd_ch], data);
-
-//	if (retries)
-//		sprintf(Mode, "IP2P-%d", retries);
-
-	stringAdd(xx, Mode, strlen(Mode));
-	return;
-
-}
-
-
-
-
-alevel_t demod_get_audio_level(int chan, int subchan)
-{
-	alevel_t alevel;
-	alevel.rec = 0;
-	alevel.mark = 0;
-	alevel.space = 0;
-	return (alevel);
-}
-
-void ax25_hex_dump(packet_t this_p)
-{}
-
-
-/*------------------------------------------------------------------------------
- *
- * Name:	ax25_from_frame
- *
- * Purpose:	Split apart an HDLC frame to components.
- *
- * Inputs:	fbuf	- Pointer to beginning of frame.
- *
- *		flen	- Length excluding the two FCS bytes.
- *
- *		alevel	- Audio level of received signal.
- *			  Maximum range 0 - 100.
- *			  -1 might be used when not applicable.
- *
- * Returns:	Pointer to new packet object or NULL if error.
- *
- * Outputs:	Use the "get" functions to retrieve information in different ways.
- *
- *------------------------------------------------------------------------------*/
-
-
-packet_t ax25_from_frame(unsigned char *fbuf, int flen, alevel_t alevel)
-{
-	packet_t this_p;
-
-
-	/*
-	 * First make sure we have an acceptable length:
-	 *
-	 *	We are not concerned with the FCS (CRC) because someone else checked it.
-	 *
-	 * Is is possible to have zero length for info?
-	 *
-	 * In the original version, assuming APRS, the answer was no.
-	 * We always had at least 3 octets after the address part:
-	 * control, protocol, and first byte of info part for data type.
-	 *
-	 * In later versions, this restriction was relaxed so other
-	 * variations of AX.25 could be used.  Now the minimum length
-	 * is 7+7 for addresses plus 1 for control.
-	 *
-	 */
-
-
-	if (flen < AX25_MIN_PACKET_LEN || flen > AX25_MAX_PACKET_LEN)
-	{
-		Debugprintf("Frame length %d not in allowable range of %d to %d.", flen, AX25_MIN_PACKET_LEN, AX25_MAX_PACKET_LEN);
-		return (NULL);
-	}
-
-	this_p = ax25_new();
-
-	/* Copy the whole thing intact. */
-
-	memcpy(this_p->frame_data, fbuf, flen);
-	this_p->frame_data[flen] = 0;
-	this_p->frame_len = flen;
-
-	/* Find number of addresses. */
-
-	this_p->num_addr = (-1);
-	(void)ax25_get_num_addr(this_p);
-
-	return (this_p);
-}
-
-
-
-/*------------------------------------------------------------------------------
- *
- * Name:	ax25_get_num_addr
- *
- * Purpose:	Return number of addresses in current packet.
- *
- * Assumption:	ax25_from_text or ax25_from_frame was called first.
- *
- * Returns:	Number of addresses in the current packet.
- *		Should be in the range of 2 .. AX25_MAX_ADDRS.
- *
- * Version 0.9:	Could be zero for a non AX.25 frame in KISS mode.
- *
- *------------------------------------------------------------------------------*/
-
-int ax25_get_num_addr(packet_t this_p)
-{
-	//unsigned char *pf;
-	int a;
-	int addr_bytes;
-
-
-//	assert(this_p->magic1 == MAGIC);
-//	assert(this_p->magic2 == MAGIC);
-
-	/* Use cached value if already set. */
-
-	if (this_p->num_addr >= 0) {
-		return (this_p->num_addr);
-	}
-
-	/* Otherwise, determine the number ofaddresses. */
-
-	this_p->num_addr = 0;		/* Number of addresses extracted. */
-
-	addr_bytes = 0;
-	for (a = 0; a < this_p->frame_len && addr_bytes == 0; a++) {
-		if (this_p->frame_data[a] & SSID_LAST_MASK) {
-			addr_bytes = a + 1;
-		}
-	}
-
-	if (addr_bytes % 7 == 0) {
-		int addrs = addr_bytes / 7;
-		if (addrs >= AX25_MIN_ADDRS && addrs <= AX25_MAX_ADDRS) {
-			this_p->num_addr = addrs;
-		}
-	}
-
-	return (this_p->num_addr);
-}
-
-
-
-void ax25_get_addr_with_ssid(packet_t pp, int n, char *station)
-{}
-
-/*------------------------------------------------------------------------------
- *
- * Name:	ax25_get_addr_no_ssid
- *
- * Purpose:	Return specified address WITHOUT any SSID.
- *
- * Inputs:	n	- Index of address.   Use the symbols
- *			  AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
- *
- * Outputs:	station - String representation of the station, WITHOUT the SSID.
- *			e.g.  "WB2OSZ"
- *			  Usually variables will be AX25_MAX_ADDR_LEN bytes
- *			  but 7 would be adequate.
- *
- * Bugs:	No bounds checking is performed.  Be careful.
- *
- * Assumption:	ax25_from_text or ax25_from_frame was called first.
- *
- * Returns:	Character string in usual human readable format,
- *
- *
- *------------------------------------------------------------------------------*/
-
-void ax25_get_addr_no_ssid(packet_t this_p, int n, char *station)
-{
-	int i;
-
-	//assert(this_p->magic1 == MAGIC);
-	//assert(this_p->magic2 == MAGIC);
-
-
-	if (n < 0) {
-		Debugprintf("Internal error detected in ax25_get_addr_no_ssid, %s, line %d.\n", __FILE__, __LINE__);
-		Debugprintf("Address index, %d, is less than zero.\n", n);
-		strcpy(station, "??????");
-		return;
-	}
-
-	if (n >= this_p->num_addr) {
-		Debugprintf("Internal error detected in ax25_get_no_with_ssid, %s, line %d.\n", __FILE__, __LINE__);
-		Debugprintf("Address index, %d, is too large for number of addresses, %d.\n", n, this_p->num_addr);
-		strcpy(station, "??????");
-		return;
-	}
-
-	// At one time this would stop at the first space, on the assumption we would have only trailing spaces.
-	// Then there was a forum discussion where someone encountered the address " WIDE2" with a leading space.
-	// In that case, we would have returned a zero length string here.
-	// Now we return exactly what is in the address field and trim trailing spaces.
-	// This will provide better information for troubleshooting.
-
-	for (i = 0; i < 6; i++) {
-		station[i] = (this_p->frame_data[n * 7 + i] >> 1) & 0x7f;
-	}
-	station[6] = '\0';
-
-	for (i = 5; i >= 0; i--) {
-		if (station[i] == ' ')
-			station[i] = '\0';
-		else
-			break;
-	}
-
-	if (strlen(station) == 0) {
-		Debugprintf("Station address, in position %d, is empty!  This is not a valid AX.25 frame.\n", n);
-	}
-
-} /* end ax25_get_addr_no_ssid */
-
-
-/*------------------------------------------------------------------------------
- *
- * Name:	ax25_get_ssid
- *
- * Purpose:	Return SSID of specified address in current packet.
- *
- * Inputs:	n	- Index of address.   Use the symbols
- *			  AX25_DESTINATION, AX25_SOURCE, AX25_REPEATER1, etc.
- *
- * Assumption:	ax25_from_text or ax25_from_frame was called first.
- *
- * Returns:	Substation id, as integer 0 .. 15.
- *
- *------------------------------------------------------------------------------*/
-
-int ax25_get_ssid(packet_t this_p, int n)
-{
-
-//	assert(this_p->magic1 == MAGIC);
-//	assert(this_p->magic2 == MAGIC);
-
-	if (n >= 0 && n < this_p->num_addr) {
-		return ((this_p->frame_data[n * 7 + 6] & SSID_SSID_MASK) >> SSID_SSID_SHIFT);
-	}
-	else {
-		Debugprintf("Internal error: ax25_get_ssid(%d), num_addr=%d\n", n, this_p->num_addr);
-		return (0);
-	}
-}
-
-
-
-static inline int ax25_get_pid_offset(packet_t this_p)
-{
-	return (ax25_get_control_offset(this_p) + ax25_get_num_control(this_p));
-}
-
-static int ax25_get_num_pid(packet_t this_p)
-{
-	int c;
-	int pid;
-
-	c = this_p->frame_data[ax25_get_control_offset(this_p)];
-
-	if ((c & 0x01) == 0 ||				/* I   xxxx xxx0 */
-		c == 0x03 || c == 0x13) {			/* UI  000x 0011 */
-
-		pid = this_p->frame_data[ax25_get_pid_offset(this_p)];
-		if (pid == AX25_PID_ESCAPE_CHARACTER) {
-			return (2);			/* pid 1111 1111 means another follows. */
-		}
-		return (1);
-	}
-	return (0);
-}
-
-
-inline int ax25_get_control_offset(packet_t this_p)
-{
-	return (this_p->num_addr * 7);
-}
-
-inline int ax25_get_num_control(packet_t this_p)
-{
-	int c;
-
-	c = this_p->frame_data[ax25_get_control_offset(this_p)];
-
-	if ((c & 0x01) == 0) {			/* I   xxxx xxx0 */
-		return ((this_p->modulo == 128) ? 2 : 1);
-	}
-
-	if ((c & 0x03) == 1) {			/* S   xxxx xx01 */
-		return ((this_p->modulo == 128) ? 2 : 1);
-	}
-
-	return (1);					/* U   xxxx xx11 */
-}
-
-
-
-
-int ax25_get_info_offset(packet_t this_p)
-{
-	int offset = ax25_get_control_offset(this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p);
-	return (offset);
-}
-
-int ax25_get_num_info(packet_t this_p)
-{
-	int len;
-
-	/* assuming AX.25 frame. */
-
-	len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p);
-	if (len < 0) {
-		len = 0;		/* print error? */
-	}
-
-	return (len);
-}
-
-
-
-
-
-	/*------------------------------------------------------------------------------
-	 *
-	 * Name:	ax25_get_info
-	 *
-	 * Purpose:	Obtain Information part of current packet.
-	 *
-	 * Inputs:	this_p	- Packet object pointer.
-	 *
-	 * Outputs:	paddr	- Starting address of information part is returned here.
-	 *
-	 * Assumption:	ax25_from_text or ax25_from_frame was called first.
-	 *
-	 * Returns:	Number of octets in the Information part.
-	 *		Should be in the range of AX25_MIN_INFO_LEN .. AX25_MAX_INFO_LEN.
-	 *
-	 *------------------------------------------------------------------------------*/
-
-int ax25_get_info(packet_t this_p, unsigned char **paddr)
-{
-	unsigned char *info_ptr;
-	int info_len;
-
-
-	//assert(this_p->magic1 == MAGIC);
-	//assert(this_p->magic2 == MAGIC);
-
-	if (this_p->num_addr >= 2) {
-
-		/* AX.25 */
-
-		info_ptr = this_p->frame_data + ax25_get_info_offset(this_p);
-		info_len = ax25_get_num_info(this_p);
-	}
-	else {
-
-		/* Not AX.25.  Treat Whole packet as info. */
-
-		info_ptr = this_p->frame_data;
-		info_len = this_p->frame_len;
-	}
-
-	/* Add nul character in case caller treats as printable string. */
-
-//		assert(info_len >= 0);
-
-	info_ptr[info_len] = '\0';
-
-	*paddr = info_ptr;
-	return (info_len);
-
-} /* end ax25_get_info */
-
-
-
-
-void ax25_set_info(packet_t this_p, unsigned char *new_info_ptr, int new_info_len)
-{
-	unsigned char *old_info_ptr;
-	int old_info_len = ax25_get_info(this_p, &old_info_ptr);
-	this_p->frame_len -= old_info_len;
-
-	if (new_info_len < 0) new_info_len = 0;
-	if (new_info_len > AX25_MAX_INFO_LEN) new_info_len = AX25_MAX_INFO_LEN;
-	memcpy(old_info_ptr, new_info_ptr, new_info_len);
-	this_p->frame_len += new_info_len;
-}
-
-int ax25_get_pid(packet_t this_p)
-{
-//	assert(this_p->magic1 == MAGIC);
-//	assert(this_p->magic2 == MAGIC);
-
-	// TODO: handle 2 control byte case.
-	// TODO: sanity check: is it I or UI frame?
-
-	if (this_p->frame_len == 0) return(-1);
-
-	if (this_p->num_addr >= 2) {
-		return (this_p->frame_data[ax25_get_pid_offset(this_p)]);
-	}
-	return (-1);
-}
-
-
-int ax25_get_frame_len(packet_t this_p)
-{
-//	assert(this_p->magic1 == MAGIC);
-//	assert(this_p->magic2 == MAGIC);
-
-//	assert(this_p->frame_len >= 0 && this_p->frame_len <= AX25_MAX_PACKET_LEN);
-
-	return (this_p->frame_len);
-
-} /* end ax25_get_frame_len */
-
-
-unsigned char *ax25_get_frame_data_ptr(packet_t this_p)
-{
-//	assert(this_p->magic1 == MAGIC);
-//	assert(this_p->magic2 == MAGIC);
-
-	return (this_p->frame_data);
-
-} /* end ax25_get_frame_data_ptr */
-
-
-int ax25_get_modulo(packet_t this_p)
-{
-	return 7;
-}
-
-
-/*------------------------------------------------------------------
- *
- * Function:	ax25_get_control
-		ax25_get_c2
- *
- * Purpose:	Get Control field from packet.
- *
- * Inputs:	this_p	- pointer to packet object.
- *
- * Returns:	APRS uses AX25_UI_FRAME.
- *		This could also be used in other situations.
- *
- *------------------------------------------------------------------*/
-
-
-int ax25_get_control(packet_t this_p)
-{
-//	assert(this_p->magic1 == MAGIC);
-//	assert(this_p->magic2 == MAGIC);
-
-	if (this_p->frame_len == 0) return(-1);
-
-	if (this_p->num_addr >= 2) {
-		return (this_p->frame_data[ax25_get_control_offset(this_p)]);
-	}
-	return (-1);
-}
-
-
-/*------------------------------------------------------------------
-*
-* Function:	ax25_frame_type
-*
-* Purpose : Extract the type of frame.
-*		This is derived from the control byte(s) but
-*		is an enumerated type for easier handling.
-*
-* Inputs : this_p - pointer to packet object.
-*
-* Outputs : desc - Text description such as "I frame" or
-*"U frame SABME".
-*			  Supply 56 bytes to be safe.
-*
-*		cr - Command or response ?
-*
-*		pf - P / F - Poll / Final or -1 if not applicable
-*
-*		nr - N(R) - receive sequence or -1 if not applicable.
-*
-*		ns - N(S) - send sequence or -1 if not applicable.
-*
-* Returns:	Frame type from  enum ax25_frame_type_e.
-*
-*------------------------------------------------------------------*/
-
-// TODO: need someway to ensure caller allocated enough space.
-// Should pass in as parameter.
-
-#define DESC_SIZ 56
-
-
-ax25_frame_type_t ax25_frame_type(packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns)
-{
-	int c;		// U frames are always one control byte.
-	int c2 = 0;	// I & S frames can have second Control byte.
-
-//	assert(this_p->magic1 == MAGIC);
-//	assert(this_p->magic2 == MAGIC);
-
-
-	strcpy(desc, "????");
-	*cr = cr_11;
-	*pf = -1;
-	*nr = -1;
-	*ns = -1;
-
-	c = ax25_get_control(this_p);
-	if (c < 0) {
-		strcpy(desc, "Not AX.25");
-		return (frame_not_AX25);
-	}
-
-	/*
-	 * TERRIBLE HACK :-(  for display purposes.
-	 *
-	 * I and S frames can have 1 or 2 control bytes but there is
-	 * no good way to determine this without dipping into the data
-	 * link state machine.  Can we guess?
-	 *
-	 * S frames have no protocol id or information so if there is one
-	 * more byte beyond the control field, we could assume there are
-	 * two control bytes.
-	 *
-	 * For I frames, the protocol id will usually be 0xf0.  If we find
-	 * that as the first byte of the information field, it is probably
-	 * the pid and not part of the information.  Ditto for segments 0x08.
-	 * Not fool proof but good enough for troubleshooting text out.
-	 *
-	 * If we have a link to the peer station, this will be set properly
-	 * before it needs to be used for other reasons.
-	 *
-	 * Setting one of the RR bits (find reference!) is sounding better and better.
-	 * It's in common usage so I should lobby to get that in the official protocol spec.
-	 */
-
-	// Dont support mod 128
-/*
-	if (this_p->modulo == 0 && (c & 3) == 1 && ax25_get_c2(this_p) != -1) {
-		this_p->modulo = modulo_128;
-	}
-	else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0xF0) {
-		this_p->modulo = modulo_128;
-	}
-	else if (this_p->modulo == 0 && (c & 1) == 0 && this_p->frame_data[ax25_get_info_offset(this_p)] == 0x08) {	// same for segments
-		this_p->modulo = modulo_128;
-	}
-
-
-	if (this_p->modulo == modulo_128) {
-		c2 = ax25_get_c2(this_p);
-	}
-*/
-
-		int dst_c = this_p->frame_data[AX25_DESTINATION * 7 + 6] & SSID_H_MASK;
-		int src_c = this_p->frame_data[AX25_SOURCE * 7 + 6] & SSID_H_MASK;
-
-		char cr_text[8];
-		char pf_text[8];
-
-		if (dst_c) {
-			if (src_c) { *cr = cr_11;  strcpy(cr_text, "cc=11"); strcpy(pf_text, "p/f"); }
-			else { *cr = cr_cmd; strcpy(cr_text, "cmd");   strcpy(pf_text, "p"); }
-		}
-		else {
-			if (src_c) { *cr = cr_res; strcpy(cr_text, "res");   strcpy(pf_text, "f"); }
-			else { *cr = cr_00;  strcpy(cr_text, "cc=00"); strcpy(pf_text, "p/f"); }
-		}
-
-		if ((c & 1) == 0) {
-
-			// Information 			rrr p sss 0		or	sssssss 0  rrrrrrr p
-
-			if (this_p->modulo == modulo_128) {
-				*ns = (c >> 1) & 0x7f;
-				*pf = c2 & 1;
-				*nr = (c2 >> 1) & 0x7f;
-			}
-			else {
-				*ns = (c >> 1) & 7;
-				*pf = (c >> 4) & 1;
-				*nr = (c >> 5) & 7;
-			}
-
-			//snprintf (desc, DESC_SIZ, "I %s, n(s)=%d, n(r)=%d, %s=%d", cr_text, *ns, *nr, pf_text, *pf);
-			sprintf(desc, "I %s, n(s)=%d, n(r)=%d, %s=%d, pid=0x%02x", cr_text, *ns, *nr, pf_text, *pf, ax25_get_pid(this_p));
-			return (frame_type_I);
-		}
-		else if ((c & 2) == 0) {
-
-			// Supervisory			rrr p/f ss 0 1		or	0000 ss 0 1  rrrrrrr p/f
-
-			if (this_p->modulo == modulo_128) {
-				*pf = c2 & 1;
-				*nr = (c2 >> 1) & 0x7f;
-			}
-			else {
-				*pf = (c >> 4) & 1;
-				*nr = (c >> 5) & 7;
-			}
-
-
-			switch ((c >> 2) & 3) {
-			case 0: sprintf(desc, "RR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf);   return (frame_type_S_RR);   break;
-			case 1: sprintf(desc, "RNR %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf);  return (frame_type_S_RNR);  break;
-			case 2: sprintf(desc, "REJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf);  return (frame_type_S_REJ);  break;
-			case 3: sprintf(desc, "SREJ %s, n(r)=%d, %s=%d", cr_text, *nr, pf_text, *pf); return (frame_type_S_SREJ); break;
-			}
-		}
-		else {
-
-			// Unnumbered			mmm p/f mm 1 1
-
-			*pf = (c >> 4) & 1;
-
-			switch (c & 0xef) {
-
-			case 0x6f: sprintf(desc, "SABME %s, %s=%d", cr_text, pf_text, *pf);  return (frame_type_U_SABME); break;
-			case 0x2f: sprintf(desc, "SABM %s, %s=%d", cr_text, pf_text, *pf);  return (frame_type_U_SABM);  break;
-			case 0x43: sprintf(desc, "DISC %s, %s=%d", cr_text, pf_text, *pf);  return (frame_type_U_DISC);  break;
-			case 0x0f: sprintf(desc, "DM %s, %s=%d", cr_text, pf_text, *pf);  return (frame_type_U_DM);    break;
-			case 0x63: sprintf(desc, "UA %s, %s=%d", cr_text, pf_text, *pf);  return (frame_type_U_UA);    break;
-			case 0x87: sprintf(desc, "FRMR %s, %s=%d", cr_text, pf_text, *pf);  return (frame_type_U_FRMR);  break;
-			case 0x03: sprintf(desc, "UI %s, %s=%d", cr_text, pf_text, *pf);  return (frame_type_U_UI);    break;
-			case 0xaf: sprintf(desc, "XID %s, %s=%d", cr_text, pf_text, *pf);  return (frame_type_U_XID);   break;
-			case 0xe3: sprintf(desc, "TEST %s, %s=%d", cr_text, pf_text, *pf);  return (frame_type_U_TEST);  break;
-			default:   sprintf(desc, "U other???");        				 return (frame_type_U);       break;
-			}
-		}
-
-		// Should be unreachable but compiler doesn't realize that.
-		// Here only to suppress "warning: control reaches end of non-void function"
-
-	return (frame_not_AX25);
-
-} /* end ax25_frame_type */
-
-
-
-packet_t ax25_u_frame(char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int pf, int pid, unsigned char *pinfo, int info_len)
-{
-	packet_t this_p;
-	unsigned char *p;
-	int ctrl = 0;
-	unsigned int t = 999;	// 1 = must be cmd, 0 = must be response, 2 = can be either.
-	int i = 0;		// Is Info part allowed?
-
-	this_p = ax25_new();
-
-	if (this_p == NULL) return (NULL);
-
-	this_p->modulo = 0;
-
-	if (!set_addrs(this_p, addrs, num_addr, cr)) {
-		Debugprintf("Internal error in %s: Could not set addresses for U frame.\n", __func__);
-		ax25_delete(this_p);
-		return (NULL);
-	}
-
-	switch (ftype) {
-		// 1 = cmd only, 0 = res only, 2 = either
-	case frame_type_U_SABME:	ctrl = 0x6f;	t = 1;		break;
-	case frame_type_U_SABM:	ctrl = 0x2f;	t = 1;		break;
-	case frame_type_U_DISC:	ctrl = 0x43;	t = 1;		break;
-	case frame_type_U_DM:		ctrl = 0x0f;	t = 0;		break;
-	case frame_type_U_UA:		ctrl = 0x63;	t = 0;		break;
-	case frame_type_U_FRMR:	ctrl = 0x87;	t = 0;	i = 1;	break;
-	case frame_type_U_UI:		ctrl = 0x03;	t = 2;	i = 1;	break;
-	case frame_type_U_XID:	ctrl = 0xaf;	t = 2;	i = 1;	break;
-	case frame_type_U_TEST:	ctrl = 0xe3;	t = 2;	i = 1;	break;
-
-	default:
-		Debugprintf("Internal error in %s: Invalid ftype %d for U frame.\n", __func__, ftype);
-		ax25_delete(this_p);
-		return (NULL);
-		break;
-	}
-	if (pf) ctrl |= 0x10;
-
-	if (t != 2) {
-		if (cr != t) {
-			Debugprintf("Internal error in %s: U frame, cr is %d but must be %d. ftype=%d\n", __func__, cr, t, ftype);
-		}
-	}
-
-	p = this_p->frame_data + this_p->frame_len;
-	*p++ = ctrl;
-	this_p->frame_len++;
-
-	if (ftype == frame_type_U_UI) {
-
-		// Definitely don't want pid value of 0 (not in valid list)
-		// or 0xff (which means more bytes follow).
-
-		if (pid < 0 || pid == 0 || pid == 0xff) {
-			Debugprintf("Internal error in %s: U frame, Invalid pid value 0x%02x.\n", __func__, pid);
-			pid = AX25_PID_NO_LAYER_3;
-		}
-		*p++ = pid;
-		this_p->frame_len++;
-	}
-
-	if (i) {
-		if (pinfo != NULL && info_len > 0) {
-			if (info_len > AX25_MAX_INFO_LEN) {
-
-				Debugprintf("Internal error in %s: U frame, Invalid information field length %d.\n", __func__, info_len);
-				info_len = AX25_MAX_INFO_LEN;
-			}
-			memcpy(p, pinfo, info_len);
-			p += info_len;
-			this_p->frame_len += info_len;
-		}
-	}
-	else {
-		if (pinfo != NULL && info_len > 0) {
-			Debugprintf("Internal error in %s: Info part not allowed for U frame type.\n", __func__);
-		}
-	}
-	*p = '\0';
-
-	//assert(p == this_p->frame_data + this_p->frame_len);
-	//assert(this_p->magic1 == MAGIC);
-	//assert(this_p->magic2 == MAGIC);
-
-#if PAD2TEST
-	ax25_frame_type_t check_ftype;
-	cmdres_t check_cr;
-	char check_desc[80];
-	int check_pf;
-	int check_nr;
-	int check_ns;
-
-	check_ftype = ax25_frame_type(this_p, &check_cr, check_desc, &check_pf, &check_nr, &check_ns);
-
-	text_color_set(DW_COLOR_DEBUG);
-	Debugprintf("check: ftype=%d, desc=\"%s\", pf=%d\n", check_ftype, check_desc, check_pf);
-
-	assert(check_cr == cr);
-	assert(check_ftype == ftype);
-	assert(check_pf == pf);
-	assert(check_nr == -1);
-	assert(check_ns == -1);
-
-#endif
-
-	return (this_p);
-
-} /* end ax25_u_frame */
-
-
-
-
-
-
-static const char *position_name[1 + AX25_MAX_ADDRS] = {
-	"", "Destination ", "Source ",
-	"Digi1 ", "Digi2 ", "Digi3 ", "Digi4 ",
-	"Digi5 ", "Digi6 ", "Digi7 ", "Digi8 " };
-
-int ax25_parse_addr(int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard)
-{
-	char *p;
-	char sstr[8];		/* Should be 1 or 2 digits for SSID. */
-	int i, j, k;
-	int maxlen;
-
-	*out_addr = '\0';
-	*out_ssid = 0;
-	*out_heard = 0;
-
-	// Debugprintf ("ax25_parse_addr in: position=%d, '%s', strict=%d\n", position, in_addr, strict);
-
-	if (position < -1) position = -1;
-	if (position > AX25_REPEATER_8) position = AX25_REPEATER_8;
-	position++;	/* Adjust for position_name above. */
-
-	if (strlen(in_addr) == 0) {
-		Debugprintf("%sAddress \"%s\" is empty.\n", position_name[position], in_addr);
-		return 0;
-	}
-
-	if (strict && strlen(in_addr) >= 2 && strncmp(in_addr, "qA", 2) == 0) {
-
-		Debugprintf("%sAddress \"%s\" is a \"q-construct\" used for communicating with\n", position_name[position], in_addr);
-		Debugprintf("APRS Internet Servers.  It should never appear when going over the radio.\n");
-	}
-
-	// Debugprintf ("ax25_parse_addr in: %s\n", in_addr);
-
-	maxlen = strict ? 6 : (AX25_MAX_ADDR_LEN - 1);
-	p = in_addr;
-	i = 0;
-	for (p = in_addr; *p != '\0' && *p != '-' && *p != '*'; p++) {
-		if (i >= maxlen) {
-			Debugprintf("%sAddress is too long. \"%s\" has more than %d characters.\n", position_name[position], in_addr, maxlen);
-			return 0;
-		}
-		if (!isalnum(*p)) {
-			Debugprintf("%sAddress, \"%s\" contains character other than letter or digit in character position %d.\n", position_name[position], in_addr, (int)(long)(p - in_addr) + 1);
-			return 0;
-		}
-
-		out_addr[i++] = *p;
-		out_addr[i] = '\0';
-
-#if DECAMAIN	// Hack when running in decode_aprs utility.
-		// Exempt the "qA..." case because it was already mentioned.
-
-		if (strict && islower(*p) && strncmp(in_addr, "qA", 2) != 0) {
-			text_color_set(DW_COLOR_ERROR);
-			Debugprintf("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr);
-		}
-#else
-		if (strict && islower(*p)) {
-			Debugprintf("%sAddress has lower case letters. \"%s\" must be all upper case.\n", position_name[position], in_addr);
-			return 0;
-		}
-#endif
-	}
-
-	j = 0;
-	sstr[j] = '\0';
-	if (*p == '-') {
-		for (p++; isalnum(*p); p++) {
-			if (j >= 2) {
-				Debugprintf("%sSSID is too long. SSID part of \"%s\" has more than 2 characters.\n", position_name[position], in_addr);
-				return 0;
-			}
-			sstr[j++] = *p;
-			sstr[j] = '\0';
-			if (strict && !isdigit(*p)) {
-				Debugprintf("%sSSID must be digits. \"%s\" has letters in SSID.\n", position_name[position], in_addr);
-				return 0;
-			}
-		}
-		k = atoi(sstr);
-		if (k < 0 || k > 15) {
-			Debugprintf("%sSSID out of range. SSID of \"%s\" not in range of 0 to 15.\n", position_name[position], in_addr);
-			return 0;
-		}
-		*out_ssid = k;
-	}
-
-	if (*p == '*') {
-		*out_heard = 1;
-		p++;
-		if (strict == 2) {
-			Debugprintf("\"*\" is not allowed at end of address \"%s\" here.\n", in_addr);
-			return 0;
-		}
-	}
-
-	if (*p != '\0') {
-		Debugprintf("Invalid character \"%c\" found in %saddress \"%s\".\n", *p, position_name[position], in_addr);
-		return 0;
-	}
-
-	// Debugprintf ("ax25_parse_addr out: '%s' %d %d\n", out_addr, *out_ssid, *out_heard);
-
-	return (1);
-
-} /* end ax25_parse_addr */
-
-
-
-int set_addrs(packet_t pp, char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr)
-{
-	int n;
-
-	//assert(pp->frame_len == 0);
-	//assert(cr == cr_cmd || cr == cr_res);
-
-	if (num_addr < AX25_MIN_ADDRS || num_addr > AX25_MAX_ADDRS) {
-		Debugprintf("INTERNAL ERROR: %s %s %d, num_addr = %d\n", __FILE__, __func__, __LINE__, num_addr);
-		return (0);
-	}
-
-	for (n = 0; n < num_addr; n++) {
-
-		unsigned char *pa = pp->frame_data + n * 7;
-		int ok;
-		int strict = 1;
-		char oaddr[AX25_MAX_ADDR_LEN];
-		int ssid;
-		int heard;
-		int j;
-
-		ok = ax25_parse_addr(n, addrs[n], strict, oaddr, &ssid, &heard);
-
-		if (!ok) return (0);
-
-		// Fill in address.
-
-		memset(pa, ' ' << 1, 6);
-		for (j = 0; oaddr[j]; j++) {
-			pa[j] = oaddr[j] << 1;
-		}
-		pa += 6;
-
-		// Fill in SSID.
-
-		*pa = 0x60 | ((ssid & 0xf) << 1);
-
-		// Command / response flag.
-
-		switch (n) {
-		case AX25_DESTINATION:
-			if (cr == cr_cmd) *pa |= 0x80;
-			break;
-		case AX25_SOURCE:
-			if (cr == cr_res) *pa |= 0x80;
-			break;
-		default:
-			break;
-		}
-
-		// Is this the end of address field?
-
-		if (n == num_addr - 1) {
-			*pa |= 1;
-		}
-
-		pp->frame_len += 7;
-	}
-
-	pp->num_addr = num_addr;
-	return (1);
-
-} /* end set_addrs */
-
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// 	il2p_init.c
-//
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Init must be called at start of application.
-
-extern void il2p_init(int debug);
-
-extern struct rs *il2p_find_rs(int nparity);	// Internal later?
-
-extern void il2p_encode_rs(unsigned char *tx_data, int data_size, int num_parity, unsigned char *parity_out);
-
-extern int il2p_decode_rs(unsigned char *rec_block, int data_size, int num_parity, unsigned char *out);
-
-extern int il2p_get_debug(void);
-extern void il2p_set_debug(int debug);
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// 	il2p_rec.c
-//
-///////////////////////////////////////////////////////////////////////////////
-
-// Receives a bit stream from demodulator.
-
-extern void il2p_rec_bit(int chan, int subchan, int slice, int dbit);
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// 	il2p_send.c
-//
-///////////////////////////////////////////////////////////////////////////////
-
-
-// Send bit stream to modulator.
-
-string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity);
-
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// 	il2p_codec.c
-//
-///////////////////////////////////////////////////////////////////////////////
-
-
-extern int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout);
-
-packet_t il2p_decode_frame(unsigned char *irec);
-
-packet_t il2p_decode_header_payload(unsigned char* uhdr, unsigned char *epayload, int *symbols_corrected);
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// 	il2p_header.c
-//
-///////////////////////////////////////////////////////////////////////////////
-
-
-extern int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr);
-
-extern packet_t il2p_decode_header_type_1(unsigned char *hdr, int num_sym_changed);
-
-
-extern int il2p_type_0_header(packet_t pp, int max_fec, unsigned char *hdr);
-
-extern int il2p_clarify_header(unsigned char *rec_hdr, unsigned char *corrected_descrambled_hdr);
-
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// 	il2p_scramble.c
-//
-///////////////////////////////////////////////////////////////////////////////
-
-extern void il2p_scramble_block(unsigned char *in, unsigned char *out, int len);
-
-extern void il2p_descramble_block(unsigned char *in, unsigned char *out, int len);
-
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// 	il2p_payload.c
-//
-///////////////////////////////////////////////////////////////////////////////
-
-
-typedef struct {
-	int payload_byte_count;		// Total size, 0 thru 1023
-	int payload_block_count;
-	int small_block_size;
-	int large_block_size;
-	int large_block_count;
-	int small_block_count;
-	int parity_symbols_per_block;	// 2, 4, 6, 8, 16
-} il2p_payload_properties_t;
-
-extern int il2p_payload_compute(il2p_payload_properties_t *p, int payload_size, int max_fec);
-
-extern int il2p_encode_payload(unsigned char *payload, int payload_size, int max_fec, unsigned char *enc);
-
-extern int il2p_decode_payload(unsigned char *received, int payload_size, int max_fec, unsigned char *payload_out, int *symbols_corrected);
-
-extern int il2p_get_header_attributes(unsigned char *hdr, int *hdr_type, int *max_fec);
-
-#endif
-
-
-
-// Interesting related stuff:
-// https://www.kernel.org/doc/html/v4.15/core-api/librs.html
-// https://berthub.eu/articles/posts/reed-solomon-for-programmers/ 
-
-
-#define MAX_NROOTS 16
-
-#define NTAB 5
-
-static struct {
-	int symsize;          // Symbol size, bits (1-8).  Always 8 for this application.
-	int genpoly;          // Field generator polynomial coefficients.
-	int fcs;              // First root of RS code generator polynomial, index form.
-			  // FX.25 uses 1 but IL2P uses 0.
-	int prim;             // Primitive element to generate polynomial roots.
-	int nroots;           // RS code generator polynomial degree (number of roots).
-						  // Same as number of check bytes added.
-	struct rs *rs;        // Pointer to RS codec control block.  Filled in at init time.
-} Tab[NTAB] = {
-  {8, 0x11d,   0,   1, 2, NULL },  // 2 parity
-  {8, 0x11d,   0,   1, 4, NULL },  // 4 parity
-  {8, 0x11d,   0,   1, 6, NULL },  // 6 parity
-  {8, 0x11d,   0,   1, 8, NULL },  // 8 parity
-  {8, 0x11d,   0,   1, 16, NULL },  // 16 parity
-};
-
-
-
-static int g_il2p_debug = 0;
-
-
-/*-------------------------------------------------------------
- *
- * Name:	il2p_init
- *
- * Purpose:	This must be called at application start up time.
- *		It sets up tables for the Reed-Solomon functions.
- *
- * Inputs:	debug	- Enable debug output.
- *
- *--------------------------------------------------------------*/
-
-void il2p_init(int il2p_debug)
-{
-	g_il2p_debug = il2p_debug;
-
-	for (int i = 0; i < NTAB; i++) {
-		//assert(Tab[i].nroots <= MAX_NROOTS);
-		Tab[i].rs = INIT_RS(Tab[i].symsize, Tab[i].genpoly, Tab[i].fcs, Tab[i].prim, Tab[i].nroots);
-		if (Tab[i].rs == NULL) {
-			Debugprintf("IL2P internal error: init_rs_char failed!\n");
-			exit(0);
-		}
-	}
-
-} // end il2p_init
-
-
-int il2p_get_debug(void)
-{
-	return (g_il2p_debug);
-}
-void il2p_set_debug(int debug)
-{
-	g_il2p_debug = debug;
-}
-
-
-// Find RS codec control block for specified number of parity symbols.
-
-struct rs *il2p_find_rs(int nparity)
-{
-	for (int n = 0; n < NTAB; n++) {
-		if (Tab[n].nroots == nparity) {
-			return (Tab[n].rs);
-		}
-	}
-	Debugprintf("IL2P INTERNAL ERROR: il2p_find_rs: control block not found for nparity = %d.\n", nparity);
-	return (Tab[0].rs);
-}
-
-
-/*-------------------------------------------------------------
- *
- * Name:	void il2p_encode_rs
- *
- * Purpose:	Add parity symbols to a block of data.
- *
- * Inputs:	tx_data		Header or other data to transmit.
- *		data_size	Number of data bytes in above.
- *		num_parity	Number of parity symbols to add.
- *				Maximum of IL2P_MAX_PARITY_SYMBOLS.
- *
- * Outputs:	parity_out	Specified number of parity symbols
- *
- * Restriction:	data_size + num_parity <= 255 which is the RS block size.
- *		The caller must ensure this.
- *
- *--------------------------------------------------------------*/
-
-void il2p_encode_rs(unsigned char *tx_data, int data_size, int num_parity, unsigned char *parity_out)
-{
-	//assert(data_size >= 1);
-	//assert(num_parity == 2 || num_parity == 4 || num_parity == 6 || num_parity == 8 || num_parity == 16);
-	//assert(data_size + num_parity <= 255);
-
-	unsigned char rs_block[FX25_BLOCK_SIZE];
-	memset(rs_block, 0, sizeof(rs_block));
-	memcpy(rs_block + sizeof(rs_block) - data_size - num_parity, tx_data, data_size);
-	ENCODE_RS(il2p_find_rs(num_parity), rs_block, parity_out);
-}
-
-/*-------------------------------------------------------------
- *
- * Name:	void il2p_decode_rs
- *
- * Purpose:	Check and attempt to fix block with FEC.
- *
- * Inputs:	rec_block	Received block composed of data and parity.
- *				Total size is sum of following two parameters.
- *		data_size	Number of data bytes in above.
- *		num_parity	Number of parity symbols (bytes) in above.
- *
- * Outputs:	out		Original with possible corrections applied.
- *				data_size bytes.
- *
- * Returns:	-1 for unrecoverable.
- *		>= 0 for success.  Number of symbols corrected.
- *
- *--------------------------------------------------------------*/
-
-int il2p_decode_rs(unsigned char *rec_block, int data_size, int num_parity, unsigned char *out)
-{
-
-	//  Use zero padding in front if data size is too small.
-
-	int n = data_size + num_parity;		// total size in.
-
-	unsigned char rs_block[FX25_BLOCK_SIZE];
-
-	// We could probably do this more efficiently by skipping the
-	// processing of the bytes known to be zero.  Good enough for now.
-
-	memset(rs_block, 0, sizeof(rs_block) - n);
-	memcpy(rs_block + sizeof(rs_block) - n, rec_block, n);
-
-	if (il2p_get_debug() >= 3) {
-		Debugprintf("==============================  il2p_decode_rs  ==============================\n");
-		Debugprintf("%d filler zeros, %d data, %d parity\n", (int)(sizeof(rs_block) - n), data_size, num_parity);
-		fx_hex_dump(rs_block, sizeof(rs_block));
-	}
-
-	int derrlocs[FX25_MAX_CHECK];	// Half would probably be OK.
-
-	int derrors = DECODE_RS(il2p_find_rs(num_parity), rs_block, derrlocs, 0);
-	memcpy(out, rs_block + sizeof(rs_block) - n, data_size);
-
-	if (il2p_get_debug() >= 3) {
-		if (derrors == 0) {
-			Debugprintf("No errors reported for RS block.\n");
-		}
-		else if (derrors > 0) {
-			Debugprintf("%d errors fixed in positions:\n", derrors);
-			for (int j = 0; j < derrors; j++) {
-				Debugprintf("        %3d  (0x%02x)\n", derrlocs[j], derrlocs[j]);
-			}
-			fx_hex_dump(rs_block, sizeof(rs_block));
-		}
-	}
-
-	// It is possible to have a situation where too many errors are
-	// present but the algorithm could get a good code block by "fixing"
-	// one of the padding bytes that should be 0.
-
-	for (int i = 0; i < derrors; i++) {
-		if (derrlocs[i] < sizeof(rs_block) - n) {
-			if (il2p_get_debug() >= 3) {
-				Debugprintf("RS DECODE ERROR!  Padding position %d should be 0 but it was set to %02x.\n", derrlocs[i], rs_block[derrlocs[i]]);
-			}
-			derrors = -1;
-			break;
-		}
-	}
-
-	if (il2p_get_debug() >= 3) {
-		Debugprintf("==============================  il2p_decode_rs  returns %d  ==============================\n", derrors);
-	}
-	return (derrors);
-}
-
-// end il2p_init.c
-
-
-
-
-
-
-
-
-
-
-
-
-
-void ENCODE_RS(struct rs * rs, DTYPE * data, DTYPE * bb)
-{
-
-	int i, j;
-	DTYPE feedback;
-
-	memset(bb, 0, NROOTS * sizeof(DTYPE)); // clear out the FEC data area
-
-	for (i = 0; i < NN - NROOTS; i++) {
-		feedback = INDEX_OF[data[i] ^ bb[0]];
-		if (feedback != A0) {      /* feedback term is non-zero */
-			for (j = 1; j < NROOTS; j++)
-				bb[j] ^= ALPHA_TO[MODNN(feedback + GENPOLY[NROOTS - j])];
-		}
-		/* Shift */
-		memmove(&bb[0], &bb[1], sizeof(DTYPE)*(NROOTS - 1));
-		if (feedback != A0)
-			bb[NROOTS - 1] = ALPHA_TO[MODNN(feedback + GENPOLY[0])];
-		else
-			bb[NROOTS - 1] = 0;
-	}
-}
-
-
-
-
-int DECODE_RS(struct rs * rs, DTYPE * data, int *eras_pos, int no_eras) {
-
-	int deg_lambda, el, deg_omega;
-	int i, j, r, k;
-	DTYPE u, q, tmp, num1, num2, den, discr_r;
-	//  DTYPE lambda[NROOTS+1], s[NROOTS];	/* Err+Eras Locator poly and syndrome poly */
-	//  DTYPE b[NROOTS+1], t[NROOTS+1], omega[NROOTS+1];
-	//  DTYPE root[NROOTS], reg[NROOTS+1], loc[NROOTS];
-	DTYPE lambda[FX25_MAX_CHECK + 1], s[FX25_MAX_CHECK];	/* Err+Eras Locator poly and syndrome poly */
-	DTYPE b[FX25_MAX_CHECK + 1], t[FX25_MAX_CHECK + 1], omega[FX25_MAX_CHECK + 1];
-	DTYPE root[FX25_MAX_CHECK], reg[FX25_MAX_CHECK + 1], loc[FX25_MAX_CHECK];
-	int syn_error, count;
-
-	/* form the syndromes; i.e., evaluate data(x) at roots of g(x) */
-	for (i = 0; i < NROOTS; i++)
-		s[i] = data[0];
-
-	for (j = 1; j < NN; j++) {
-		for (i = 0; i < NROOTS; i++) {
-			if (s[i] == 0) {
-				s[i] = data[j];
-			}
-			else {
-				s[i] = data[j] ^ ALPHA_TO[MODNN(INDEX_OF[s[i]] + (FCR + i)*PRIM)];
-			}
-		}
-	}
-
-	/* Convert syndromes to index form, checking for nonzero condition */
-	syn_error = 0;
-	for (i = 0; i < NROOTS; i++) {
-		syn_error |= s[i];
-		s[i] = INDEX_OF[s[i]];
-	}
-
-	// fprintf(stderr,"syn_error = %4x\n",syn_error);
-	if (!syn_error) {
-		/* if syndrome is zero, data[] is a codeword and there are no
-		 * errors to correct. So return data[] unmodified
-		 */
-		count = 0;
-		goto finish;
-	}
-	memset(&lambda[1], 0, NROOTS * sizeof(lambda[0]));
-	lambda[0] = 1;
-
-	if (no_eras > 0) {
-		/* Init lambda to be the erasure locator polynomial */
-		lambda[1] = ALPHA_TO[MODNN(PRIM*(NN - 1 - eras_pos[0]))];
-		for (i = 1; i < no_eras; i++) {
-			u = MODNN(PRIM*(NN - 1 - eras_pos[i]));
-			for (j = i + 1; j > 0; j--) {
-				tmp = INDEX_OF[lambda[j - 1]];
-				if (tmp != A0)
-					lambda[j] ^= ALPHA_TO[MODNN(u + tmp)];
-			}
-		}
-
-#if DEBUG >= 1
-		/* Test code that verifies the erasure locator polynomial just constructed
-		   Needed only for decoder debugging. */
-
-		   /* find roots of the erasure location polynomial */
-		for (i = 1; i <= no_eras; i++)
-			reg[i] = INDEX_OF[lambda[i]];
-
-		count = 0;
-		for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM)) {
-			q = 1;
-			for (j = 1; j <= no_eras; j++)
-				if (reg[j] != A0) {
-					reg[j] = MODNN(reg[j] + j);
-					q ^= ALPHA_TO[reg[j]];
-				}
-			if (q != 0)
-				continue;
-			/* store root and error location number indices */
-			root[count] = i;
-			loc[count] = k;
-			count++;
-		}
-		if (count != no_eras) {
-			fprintf(stderr, "count = %d no_eras = %d\n lambda(x) is WRONG\n", count, no_eras);
-			count = -1;
-			goto finish;
-		}
-#if DEBUG >= 2
-		fprintf(stderr, "\n Erasure positions as determined by roots of Eras Loc Poly:\n");
-		for (i = 0; i < count; i++)
-			fprintf(stderr, "%d ", loc[i]);
-		fprintf(stderr, "\n");
-#endif
-#endif
-	}
-	for (i = 0; i < NROOTS + 1; i++)
-		b[i] = INDEX_OF[lambda[i]];
-
-	/*
-	 * Begin Berlekamp-Massey algorithm to determine error+erasure
-	 * locator polynomial
-	 */
-	r = no_eras;
-	el = no_eras;
-	while (++r <= NROOTS) {	/* r is the step number */
-	  /* Compute discrepancy at the r-th step in poly-form */
-		discr_r = 0;
-		for (i = 0; i < r; i++) {
-			if ((lambda[i] != 0) && (s[r - i - 1] != A0)) {
-				discr_r ^= ALPHA_TO[MODNN(INDEX_OF[lambda[i]] + s[r - i - 1])];
-			}
-		}
-		discr_r = INDEX_OF[discr_r];	/* Index form */
-		if (discr_r == A0) {
-			/* 2 lines below: B(x) <-- x*B(x) */
-			memmove(&b[1], b, NROOTS * sizeof(b[0]));
-			b[0] = A0;
-		}
-		else {
-			/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
-			t[0] = lambda[0];
-			for (i = 0; i < NROOTS; i++) {
-				if (b[i] != A0)
-					t[i + 1] = lambda[i + 1] ^ ALPHA_TO[MODNN(discr_r + b[i])];
-				else
-					t[i + 1] = lambda[i + 1];
-			}
-			if (2 * el <= r + no_eras - 1) {
-				el = r + no_eras - el;
-				/*
-				 * 2 lines below: B(x) <-- inv(discr_r) *
-				 * lambda(x)
-				 */
-				for (i = 0; i <= NROOTS; i++)
-					b[i] = (lambda[i] == 0) ? A0 : MODNN(INDEX_OF[lambda[i]] - discr_r + NN);
-			}
-			else {
-				/* 2 lines below: B(x) <-- x*B(x) */
-				memmove(&b[1], b, NROOTS * sizeof(b[0]));
-				b[0] = A0;
-			}
-			memcpy(lambda, t, (NROOTS + 1) * sizeof(t[0]));
-		}
-	}
-
-	/* Convert lambda to index form and compute deg(lambda(x)) */
-	deg_lambda = 0;
-	for (i = 0; i < NROOTS + 1; i++) {
-		lambda[i] = INDEX_OF[lambda[i]];
-		if (lambda[i] != A0)
-			deg_lambda = i;
-	}
-	/* Find roots of the error+erasure locator polynomial by Chien search */
-	memcpy(®[1], &lambda[1], NROOTS * sizeof(reg[0]));
-	count = 0;		/* Number of roots of lambda(x) */
-	for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN(k + IPRIM)) {
-		q = 1; /* lambda[0] is always 0 */
-		for (j = deg_lambda; j > 0; j--) {
-			if (reg[j] != A0) {
-				reg[j] = MODNN(reg[j] + j);
-				q ^= ALPHA_TO[reg[j]];
-			}
-		}
-		if (q != 0)
-			continue; /* Not a root */
-		  /* store root (index-form) and error location number */
-#if DEBUG>=2
-		fprintf(stderr, "count %d root %d loc %d\n", count, i, k);
-#endif
-		root[count] = i;
-		loc[count] = k;
-		/* If we've already found max possible roots,
-		 * abort the search to save time
-		 */
-		if (++count == deg_lambda)
-			break;
-	}
-	if (deg_lambda != count) {
-		/*
-		 * deg(lambda) unequal to number of roots => uncorrectable
-		 * error detected
-		 */
-		count = -1;
-		goto finish;
-	}
-	/*
-	 * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
-	 * x**NROOTS). in index form. Also find deg(omega).
-	 */
-	deg_omega = 0;
-	for (i = 0; i < NROOTS; i++) {
-		tmp = 0;
-		j = (deg_lambda < i) ? deg_lambda : i;
-		for (; j >= 0; j--) {
-			if ((s[i - j] != A0) && (lambda[j] != A0))
-				tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])];
-		}
-		if (tmp != 0)
-			deg_omega = i;
-		omega[i] = INDEX_OF[tmp];
-	}
-	omega[NROOTS] = A0;
-
-	/*
-	 * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
-	 * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form
-	 */
-	for (j = count - 1; j >= 0; j--) {
-		num1 = 0;
-		for (i = deg_omega; i >= 0; i--) {
-			if (omega[i] != A0)
-				num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])];
-		}
-		num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)];
-		den = 0;
-
-		/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
-		for (i = min(deg_lambda, NROOTS - 1) & ~1; i >= 0; i -= 2) {
-			if (lambda[i + 1] != A0)
-				den ^= ALPHA_TO[MODNN(lambda[i + 1] + i * root[j])];
-		}
-		if (den == 0) {
-#if DEBUG >= 1
-			fprintf(stderr, "\n ERROR: denominator = 0\n");
-#endif
-			count = -1;
-			goto finish;
-		}
-		/* Apply error to data */
-		if (num1 != 0) {
-			data[loc[j]] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])];
-		}
-	}
-finish:
-	if (eras_pos != NULL) {
-		for (i = 0; i < count; i++)
-			eras_pos[i] = loc[i];
-	}
-	return count;
-}
-
-
-
-
-struct rs *INIT_RS(unsigned int symsize, unsigned int gfpoly, unsigned fcr, unsigned prim,
-	unsigned int nroots) {
-	struct rs *rs;
-	int i, j, sr, root, iprim;
-
-	if (symsize > 8 * sizeof(DTYPE))
-		return NULL; /* Need version with ints rather than chars */
-
-	if (fcr >= (1 << symsize))
-		return NULL;
-	if (prim == 0 || prim >= (1 << symsize))
-		return NULL;
-	if (nroots >= (1 << symsize))
-		return NULL; /* Can't have more roots than symbol values! */
-
-	rs = (struct rs *)calloc(1, sizeof(struct rs));
-	if (rs == NULL) {
-		Debugprintf("FATAL ERROR: Out of memory.\n");
-		exit(0);
-	}
-	rs->mm = symsize;
-	rs->nn = (1 << symsize) - 1;
-
-	rs->alpha_to = (DTYPE *)calloc((rs->nn + 1), sizeof(DTYPE));
-	if (rs->alpha_to == NULL) {
-		Debugprintf("FATAL ERROR: Out of memory.\n");
-		exit(0);
-	}
-	rs->index_of = (DTYPE *)calloc((rs->nn + 1), sizeof(DTYPE));
-	if (rs->index_of == NULL) {
-		Debugprintf("FATAL ERROR: Out of memory.\n");
-		exit(0);
-	}
-
-	/* Generate Galois field lookup tables */
-	rs->index_of[0] = A0; /* log(zero) = -inf */
-	rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */
-	sr = 1;
-	for (i = 0; i < rs->nn; i++) {
-		rs->index_of[sr] = i;
-		rs->alpha_to[i] = sr;
-		sr <<= 1;
-		if (sr & (1 << symsize))
-			sr ^= gfpoly;
-		sr &= rs->nn;
-	}
-	if (sr != 1) {
-		/* field generator polynomial is not primitive! */
-		free(rs->alpha_to);
-		free(rs->index_of);
-		free(rs);
-		return NULL;
-	}
-
-	/* Form RS code generator polynomial from its roots */
-	rs->genpoly = (DTYPE *)calloc((nroots + 1), sizeof(DTYPE));
-	if (rs->genpoly == NULL) {
-		Debugprintf("FATAL ERROR: Out of memory.\n");
-		exit(0);
-	}
-	rs->fcr = fcr;
-	rs->prim = prim;
-	rs->nroots = nroots;
-
-	/* Find prim-th root of 1, used in decoding */
-	for (iprim = 1; (iprim % prim) != 0; iprim += rs->nn)
-		;
-	rs->iprim = iprim / prim;
-
-	rs->genpoly[0] = 1;
-	for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) {
-		rs->genpoly[i + 1] = 1;
-
-		/* Multiply rs->genpoly[] by  @**(root + x) */
-		for (j = i; j > 0; j--) {
-			if (rs->genpoly[j] != 0)
-				rs->genpoly[j] = rs->genpoly[j - 1] ^ rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[j]] + root)];
-			else
-				rs->genpoly[j] = rs->genpoly[j - 1];
-		}
-		/* rs->genpoly[0] can never be zero */
-		rs->genpoly[0] = rs->alpha_to[modnn(rs, rs->index_of[rs->genpoly[0]] + root)];
-	}
-	/* convert rs->genpoly[] to index form for quicker encoding */
-	for (i = 0; i <= nroots; i++) {
-		rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
-	}
-
-	// diagnostic prints
-#if 0
-	printf("Alpha To:\n\r");
-	for (i = 0; i < sizeof(DTYPE)*(rs->nn + 1); i++)
-		printf("0x%2x,", rs->alpha_to[i]);
-	printf("\n\r");
-
-	printf("Index Of:\n\r");
-	for (i = 0; i < sizeof(DTYPE)*(rs->nn + 1); i++)
-		printf("0x%2x,", rs->index_of[i]);
-	printf("\n\r");
-
-	printf("GenPoly:\n\r");
-	for (i = 0; i <= nroots; i++)
-		printf("0x%2x,", rs->genpoly[i]);
-	printf("\n\r");
-#endif
-	return rs;
-}
-
-
-// TEMPORARY!!!
-// FIXME: We already have multiple copies of this.
-// Consolidate them into one somewhere.
-
-void fx_hex_dump(unsigned char *p, int len)
-{
-	int n, i, offset;
-
-	offset = 0;
-	while (len > 0) {
-		n = len < 16 ? len : 16;
-		Debugprintf("  %03x: ", offset);
-		for (i = 0; i < n; i++) {
-			Debugprintf(" %02x", p[i]);
-		}
-		for (i = n; i < 16; i++) {
-			Debugprintf("   ");
-		}
-		Debugprintf("  ");
-		for (i = 0; i < n; i++) {
-			Debugprintf("%c", isprint(p[i]) ? p[i] : '.');
-		}
-		Debugprintf("\n");
-		p += 16;
-		offset += 16;
-		len -= 16;
-	}
-}
-
-
-/*-------------------------------------------------------------
- *
- * File:	il2p_codec.c
- *
- * Purpose:	Convert IL2P encoded format from and to direwolf internal packet format.
- *
- *--------------------------------------------------------------*/
-
-
- /*-------------------------------------------------------------
-  *
-  * Name:	il2p_encode_frame
-  *
-  * Purpose:	Convert AX.25 frame to IL2P encoding.
-  *
-  * Inputs:	chan	- Audio channel number, 0 = first.
-  *
-  *		pp	- Packet object pointer.
-  *
-  *		max_fec	- 1 to send maximum FEC size rather than automatic.
-  *
-  * Outputs:	iout	- Encoded result, excluding the 3 byte sync word.
-  *			  Caller should provide  IL2P_MAX_PACKET_SIZE  bytes.
-  *
-  * Returns:	Number of bytes for transmission.
-  *		-1 is returned for failure.
-  *
-  * Description:	Encode into IL2P format.
-  *
-  * Errors:	If something goes wrong, return -1.
-  *
-  *		Most likely reason is that the frame is too large.
-  *		IL2P has a max payload size of 1023 bytes.
-  *		For a type 1 header, this is the maximum AX.25 Information part size.
-  *		For a type 0 header, this is the entire AX.25 frame.
-  *
-  *--------------------------------------------------------------*/
-
-int il2p_encode_frame(packet_t pp, int max_fec, unsigned char *iout)
-{
-
-	// Can a type 1 header be used?
-
-	unsigned char hdr[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY];
-	int e;
-	int out_len = 0;
-
-	e = il2p_type_1_header(pp, max_fec, hdr);
-	if (e >= 0) {
-		il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE);
-		il2p_encode_rs(iout, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, iout + IL2P_HEADER_SIZE);
-		out_len = IL2P_HEADER_SIZE + IL2P_HEADER_PARITY;
-
-		if (e == 0) {
-			// Success. No info part.
-			return (out_len);
-		}
-
-		// Payload is AX.25 info part.
-		unsigned char *pinfo;
-		int info_len;
-		info_len = ax25_get_info(pp, &pinfo);
-
-		int k = il2p_encode_payload(pinfo, info_len, max_fec, iout + out_len);
-		if (k > 0) {
-			out_len += k;
-			// Success. Info part was <= 1023 bytes.
-			return (out_len);
-		}
-
-		// Something went wrong with the payload encoding.
-		return (-1);
-	}
-	else if (e == -1) {
-
-		// Could not use type 1 header for some reason.
-		// e.g. More than 2 addresses, extended (mod 128) sequence numbers, etc.
-
-		e = il2p_type_0_header(pp, max_fec, hdr);
-		if (e > 0) {
-
-			il2p_scramble_block(hdr, iout, IL2P_HEADER_SIZE);
-			il2p_encode_rs(iout, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, iout + IL2P_HEADER_SIZE);
-			out_len = IL2P_HEADER_SIZE + IL2P_HEADER_PARITY;
-
-			// Payload is entire AX.25 frame.
-
-			unsigned char *frame_data_ptr = ax25_get_frame_data_ptr(pp);
-			int frame_len = ax25_get_frame_len(pp);
-			int k = il2p_encode_payload(frame_data_ptr, frame_len, max_fec, iout + out_len);
-			if (k > 0) {
-				out_len += k;
-				// Success. Entire AX.25 frame <= 1023 bytes.
-				return (out_len);
-			}
-			// Something went wrong with the payload encoding.
-			return (-1);
-		}
-		else if (e == 0) {
-			// Impossible condition.  Type 0 header must have payload.
-			return (-1);
-		}
-		else {
-			// AX.25 frame is too large.
-			return (-1);
-		}
-	}
-
-	// AX.25 Information part is too large.
-	return (-1);
-}
-
-
-
-/*-------------------------------------------------------------
- *
- * Name:	il2p_decode_frame
- *
- * Purpose:	Convert IL2P encoding to AX.25 frame.
- *		This is only used during testing, with a whole encoded frame.
- *		During reception, the header would have FEC and descrambling
- *		applied first so we would know how much to collect for the payload.
- *
- * Inputs:	irec	- Received IL2P frame excluding the 3 byte sync word.
- *
- * Future Out:	Number of symbols corrected.
- *
- * Returns:	Packet pointer or NULL for error.
- *
- *--------------------------------------------------------------*/
-
-packet_t il2p_decode_frame(unsigned char *irec)
-{
-	unsigned char uhdr[IL2P_HEADER_SIZE];		// After FEC and descrambling.
-	int e = il2p_clarify_header(irec, uhdr);
-
-	// TODO?: for symmetry we might want to clarify the payload before combining.
-
-	return (il2p_decode_header_payload(uhdr, irec + IL2P_HEADER_SIZE + IL2P_HEADER_PARITY, &e));
-}
-
-
-/*-------------------------------------------------------------
- *
- * Name:	il2p_decode_header_payload
- *
- * Purpose:	Convert IL2P encoding to AX.25 frame
- *
- * Inputs:	uhdr 		- Received header after FEC and descrambling.
- *		epayload	- Encoded payload.
- *
- * In/Out:	symbols_corrected - Symbols (bytes) corrected in the header.
- *				  Should be 0 or 1 because it has 2 parity symbols.
- *				  Here we add number of corrections for the payload.
- *
- * Returns:	Packet pointer or NULL for error.
- *
- *--------------------------------------------------------------*/
-
-packet_t il2p_decode_header_payload(unsigned char* uhdr, unsigned char *epayload, int *symbols_corrected)
-{
-	int hdr_type;
-	int max_fec;
-	int payload_len = il2p_get_header_attributes(uhdr, &hdr_type, &max_fec);
-
-	packet_t pp = NULL;
-
-	if (hdr_type == 1) {
-
-		// Header type 1.  Any payload is the AX.25 Information part.
-
-		pp = il2p_decode_header_type_1(uhdr, *symbols_corrected);
-		if (pp == NULL) {
-			// Failed for some reason.
-			return (NULL);
-		}
-
-		if (payload_len > 0) {
-			// This is the AX.25 Information part.
-
-			unsigned char extracted[IL2P_MAX_PAYLOAD_SIZE];
-			int e = il2p_decode_payload(epayload, payload_len, max_fec, extracted, symbols_corrected);
-
-			// It would be possible to have a good header but too many errors in the payload.
-
-			if (e <= 0) {
-				ax25_delete(pp);
-				pp = NULL;
-				return (pp);
-			}
-
-			if (e != payload_len) {
-				Debugprintf("IL2P Internal Error: %s(): hdr_type=%d, max_fec=%d, payload_len=%d, e=%d.\n", __func__, hdr_type, max_fec, payload_len, e);
-			}
-
-			ax25_set_info(pp, extracted, payload_len);
-		}
-		return (pp);
-	}
-	else {
-
-		// Header type 0.  The payload is the entire AX.25 frame.
-
-		unsigned char extracted[IL2P_MAX_PAYLOAD_SIZE];
-		int e = il2p_decode_payload(epayload, payload_len, max_fec, extracted, symbols_corrected);
-
-		if (e <= 0) {	// Payload was not received correctly.
-			return (NULL);
-		}
-
-		if (e != payload_len) {
-			Debugprintf("IL2P Internal Error: %s(): hdr_type=%d, e=%d, payload_len=%d\n", __func__, hdr_type, e, payload_len);
-			return (NULL);
-		}
-
-		alevel_t alevel;
-		memset(&alevel, 0, sizeof(alevel));
-		//alevel = demod_get_audio_level (chan, subchan); 	// What TODO? We don't know channel here.
-						// I think alevel gets filled in somewhere later making
-						// this redundant.
-
-		pp = ax25_from_frame(extracted, payload_len, alevel);
-		return (pp);
-	}
-
-} // end il2p_decode_header_payload
-
-// end il2p_codec.c
-
-
-
-/*--------------------------------------------------------------------------------
- *
- * File:	il2p_header.c
- *
- * Purpose:	Functions to deal with the IL2P header.
- *
- * Reference:	http://tarpn.net/t/il2p/il2p-specification0-4.pdf
- *
- *--------------------------------------------------------------------------------*/
-
-
-
- // Convert ASCII to/from DEC SIXBIT as defined here:
- // https://en.wikipedia.org/wiki/Six-bit_character_code#DEC_six-bit_code
-
-static inline int ascii_to_sixbit(int a)
-{
-	if (a >= ' ' && a <= '_') return (a - ' ');
-	return (31);	// '?' for any invalid.
-}
-
-static inline int sixbit_to_ascii(int s)
-{
-	return (s + ' ');
-}
-
-// Functions for setting the various header fields.
-// It is assumed that it was zeroed first so only the '1' bits are set.
-
-static void set_field(unsigned char *hdr, int bit_num, int lsb_index, int width, int value)
-{
-	while (width > 0 && value != 0) {
-		//assert(lsb_index >= 0 && lsb_index <= 11);
-		if (value & 1) {
-			hdr[lsb_index] |= 1 << bit_num;
-		}
-		value >>= 1;
-		lsb_index--;
-		width--;
-	}
-	//assert(value == 0);
-}
-
-#define SET_UI(hdr,val) set_field(hdr, 6, 0, 1, val)
-
-#define SET_PID(hdr,val) set_field(hdr, 6, 4, 4, val)
-
-#define SET_CONTROL(hdr,val) set_field(hdr, 6, 11, 7, val)
-
-
-#define SET_FEC_LEVEL(hdr,val) set_field(hdr, 7, 0, 1, val)
-
-#define SET_HDR_TYPE(hdr,val) set_field(hdr, 7, 1, 1, val)
-
-#define SET_PAYLOAD_BYTE_COUNT(hdr,val) set_field(hdr, 7, 11, 10, val)
-
-
-// Extracting the fields.
-
-static int get_field(unsigned char *hdr, int bit_num, int lsb_index, int width)
-{
-	int result = 0;
-	lsb_index -= width - 1;
-	while (width > 0) {
-		result <<= 1;
-		//assert(lsb_index >= 0 && lsb_index <= 11);
-		if (hdr[lsb_index] & (1 << bit_num)) {
-			result |= 1;
-		}
-		lsb_index++;
-		width--;
-	}
-	return (result);
-}
-
-#define GET_UI(hdr) get_field(hdr, 6, 0, 1)
-
-#define GET_PID(hdr) get_field(hdr, 6, 4, 4)
-
-#define GET_CONTROL(hdr) get_field(hdr, 6, 11, 7)
-
-
-#define GET_FEC_LEVEL(hdr) get_field(hdr, 7, 0, 1)
-
-#define GET_HDR_TYPE(hdr) get_field(hdr, 7, 1, 1)
-
-#define GET_PAYLOAD_BYTE_COUNT(hdr) get_field(hdr, 7, 11, 10)
-
-
-
-// AX.25 'I' and 'UI' frames have a protocol ID which determines how the
-// information part should be interpreted.
-// Here we squeeze the most common cases down to 4 bits.
-// Return -1 if translation is not possible.  Fall back to type 0 header in this case.
-
-static int encode_pid(packet_t pp)
-{
-	int pid = ax25_get_pid(pp);
-
-	if ((pid & 0x30) == 0x20) return (0x2);		// AX.25 Layer 3
-	if ((pid & 0x30) == 0x10) return (0x2);		// AX.25 Layer 3
-	if (pid == 0x01) return (0x3);			// ISO 8208 / CCIT X.25 PLP
-	if (pid == 0x06) return (0x4);			// Compressed TCP/IP
-	if (pid == 0x07) return (0x5);			// Uncompressed TCP/IP
-	if (pid == 0x08) return (0x6);			// Segmentation fragmen
-	if (pid == 0xcc) return (0xb);			// ARPA Internet Protocol
-	if (pid == 0xcd) return (0xc);			// ARPA Address Resolution
-	if (pid == 0xce) return (0xd);			// FlexNet
-	if (pid == 0xcf) return (0xe);			// TheNET
-	if (pid == 0xf0) return (0xf);			// No L3
-	return (-1);
-}
-
-// Convert IL2P 4 bit PID to AX.25 8 bit PID.
-
-
-static int decode_pid(int pid)
-{
-	static const unsigned char axpid[16] = {
-	0xf0,			// Should not happen. 0 is for 'S' frames.
-	0xf0,			// Should not happen. 1 is for 'U' frames (but not UI).
-	0x20,			// AX.25 Layer 3
-	0x01,			// ISO 8208 / CCIT X.25 PLP
-	0x06,			// Compressed TCP/IP
-	0x07,			// Uncompressed TCP/IP
-	0x08,			// Segmentation fragment
-	0xf0,			// Future
-	0xf0,			// Future
-	0xf0,			// Future
-	0xf0,			// Future
-	0xcc,			// ARPA Internet Protocol
-	0xcd,			// ARPA Address Resolution
-	0xce,			// FlexNet
-	0xcf,			// TheNET
-	0xf0 };			// No L3
-
-	//assert(pid >= 0 && pid <= 15);
-	return (axpid[pid]);
-}
-
-
-
-/*--------------------------------------------------------------------------------
- *
- * Function:	il2p_type_1_header
- *
- * Purpose:	Attempt to create type 1 header from packet object.
- *
- * Inputs:	pp	- Packet object.
- *
- *		max_fec	- 1 to use maximum FEC symbols , 0 for automatic.
- *
- * Outputs:	hdr	- IL2P header with no scrambling or parity symbols.
- *			  Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes.
- *
- * Returns:	Number of bytes for information part or -1 for failure.
- *		In case of failure, fall back to type 0 transparent encapsulation.
- *
- * Description:	Type 1 Headers do not support AX.25 repeater callsign addressing,
- *		Modulo-128 extended mode window sequence numbers, nor any callsign
- *		characters that cannot translate to DEC SIXBIT.
- *		If these cases are encountered during IL2P packet encoding,
- *		the encoder switches to Type 0 Transparent Encapsulation.
- *		SABME can't be handled by type 1.
- *
- *--------------------------------------------------------------------------------*/
-
-int il2p_type_1_header(packet_t pp, int max_fec, unsigned char *hdr)
-{
-	memset(hdr, 0, IL2P_HEADER_SIZE);
-
-	if (ax25_get_num_addr(pp) != 2) {
-		// Only two addresses are allowed for type 1 header.
-		return (-1);
-	}
-
-	// Check does not apply for 'U' frames but put in one place rather than two.
-
-	if (ax25_get_modulo(pp) == 128) return(-1);
-
-	// Destination and source addresses go into low bits 0-5 for bytes 0-11.
-
-	char dst_addr[AX25_MAX_ADDR_LEN];
-	char src_addr[AX25_MAX_ADDR_LEN];
-
-	ax25_get_addr_no_ssid(pp, AX25_DESTINATION, dst_addr);
-	int dst_ssid = ax25_get_ssid(pp, AX25_DESTINATION);
-
-	ax25_get_addr_no_ssid(pp, AX25_SOURCE, src_addr);
-	int src_ssid = ax25_get_ssid(pp, AX25_SOURCE);
-
-	unsigned char *a = (unsigned char *)dst_addr;
-	for (int i = 0; *a != '\0'; i++, a++) {
-		if (*a < ' ' || *a > '_') {
-			// Shouldn't happen but follow the rule.
-			return (-1);
-		}
-		hdr[i] = ascii_to_sixbit(*a);
-	}
-
-	a = (unsigned char *)src_addr;
-	for (int i = 6; *a != '\0'; i++, a++) {
-		if (*a < ' ' || *a > '_') {
-			// Shouldn't happen but follow the rule.
-			return (-1);
-		}
-		hdr[i] = ascii_to_sixbit(*a);
-	}
-
-	// Byte 12 has DEST SSID in upper nybble and SRC SSID in lower nybble and 
-	hdr[12] = (dst_ssid << 4) | src_ssid;
-
-	ax25_frame_type_t frame_type;
-	cmdres_t cr;			// command or response.
-	char description[64];
-	int pf;				// Poll/Final.
-	int nr, ns;			// Sequence numbers.
-
-	frame_type = ax25_frame_type(pp, &cr, description, &pf, &nr, &ns);
-
-	//Debugprintf ("%s(): %s-%d>%s-%d: %s\n", __func__, src_addr, src_ssid, dst_addr, dst_ssid, description);
-
-	switch (frame_type) {
-
-	case frame_type_S_RR:		// Receive Ready - System Ready To Receive
-	case frame_type_S_RNR:		// Receive Not Ready - TNC Buffer Full
-	case frame_type_S_REJ:		// Reject Frame - Out of Sequence or Duplicate
-	case frame_type_S_SREJ:		// Selective Reject - Request single frame repeat
-
-		// S frames (RR, RNR, REJ, SREJ), mod 8, have control N(R) P/F S S 0 1
-		// These are mapped into    P/F N(R) C S S
-		// Bit 6 is not mentioned in documentation but it is used for P/F for the other frame types.
-		// C is copied from the C bit in the destination addr.
-		// C from source is not used here.  Reception assumes it is the opposite.
-		// PID is set to 0, meaning none, for S frames.
-
-		SET_UI(hdr, 0);
-		SET_PID(hdr, 0);
-		SET_CONTROL(hdr, (pf << 6) | (nr << 3) | (((cr == cr_cmd) | (cr == cr_11)) << 2));
-
-		// This gets OR'ed into the above.
-		switch (frame_type) {
-		case frame_type_S_RR:	SET_CONTROL(hdr, 0);	break;
-		case frame_type_S_RNR:	SET_CONTROL(hdr, 1);	break;
-		case frame_type_S_REJ:	SET_CONTROL(hdr, 2);	break;
-		case frame_type_S_SREJ:	SET_CONTROL(hdr, 3);	break;
-		default:	break;
-		}
-
-		break;
-
-	case frame_type_U_SABM:		// Set Async Balanced Mode
-	case frame_type_U_DISC:		// Disconnect
-	case frame_type_U_DM:		// Disconnect Mode
-	case frame_type_U_UA:		// Unnumbered Acknowledge
-	case frame_type_U_FRMR:		// Frame Reject
-	case frame_type_U_UI:		// Unnumbered Information
-	case frame_type_U_XID:		// Exchange Identification
-	case frame_type_U_TEST:		// Test
-
-		// The encoding allows only 3 bits for frame type and SABME got left out.
-		// Control format:  P/F opcode[3] C n/a n/a
-		// The grayed out n/a bits are observed as 00 in the example.
-		// The header UI field must also be set for UI frames.
-		// PID is set to 1 for all U frames other than UI.
-
-		if (frame_type == frame_type_U_UI) {
-			SET_UI(hdr, 1);	// I guess this is how we distinguish 'I' and 'UI'
-				// on the receiving end.
-			int pid = encode_pid(pp);
-			if (pid < 0) return (-1);
-			SET_PID(hdr, pid);
-		}
-		else {
-			SET_PID(hdr, 1);	// 1 for 'U' other than 'UI'.
-		}
-
-		// Each of the destination and source addresses has a "C" bit.
-		// They should normally have the opposite setting.
-		// IL2P has only a single bit to represent 4 possbilities.
-		//
-		//	dst	src	il2p	meaning
-		//	---	---	----	-------
-		//	0	0	0	Not valid (earlier protocol version)
-		//	1	0	1	Command (v2)
-		//	0	1	0	Response (v2)
-		//	1	1	1	Not valid (earlier protocol version)
-		//
-		// APRS does not mention how to set these bits and all 4 combinations
-		// are seen in the wild.  Apparently these are ignored on receive and no
-		// one cares.  Here we copy from the C bit in the destination address.
-		// It should be noted that the case of both C bits being the same can't
-		// be represented so the il2p encode/decode bit not produce exactly the
-		// same bits.  We see this in the second example in the protocol spec.
-		// The original UI frame has both C bits of 0 so it is received as a response.
-
-		SET_CONTROL(hdr, (pf << 6) | (((cr == cr_cmd) | (cr == cr_11)) << 2));
-
-		// This gets OR'ed into the above.
-		switch (frame_type) {
-		case frame_type_U_SABM:	SET_CONTROL(hdr, 0 << 3);	break;
-		case frame_type_U_DISC:	SET_CONTROL(hdr, 1 << 3);	break;
-		case frame_type_U_DM:	SET_CONTROL(hdr, 2 << 3);	break;
-		case frame_type_U_UA:	SET_CONTROL(hdr, 3 << 3);	break;
-		case frame_type_U_FRMR:	SET_CONTROL(hdr, 4 << 3);	break;
-		case frame_type_U_UI:	SET_CONTROL(hdr, 5 << 3);	break;
-		case frame_type_U_XID:	SET_CONTROL(hdr, 6 << 3);	break;
-		case frame_type_U_TEST:	SET_CONTROL(hdr, 7 << 3);	break;
-		default:	break;
-		}
-		break;
-
-	case frame_type_I:		// Information
-
-		// I frames (mod 8 only)
-		// encoded control: P/F N(R) N(S)
-
-		SET_UI(hdr, 0);
-
-		int pid2 = encode_pid(pp);
-		if (pid2 < 0) return (-1);
-		SET_PID(hdr, pid2);
-
-		SET_CONTROL(hdr, (pf << 6) | (nr << 3) | ns);
-		break;
-
-	case frame_type_U_SABME:		// Set Async Balanced Mode, Extended
-	case frame_type_U:			// other Unnumbered, not used by AX.25.
-	case frame_not_AX25:		// Could not get control byte from frame.
-	default:
-
-		// Fall back to the header type 0 for these.
-		return (-1);
-	}
-
-	// Common for all header type 1.
-
-		// Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10]
-
-	SET_FEC_LEVEL(hdr, max_fec);
-	SET_HDR_TYPE(hdr, 1);
-
-	unsigned char *pinfo;
-	int info_len;
-
-	info_len = ax25_get_info(pp, &pinfo);
-	if (info_len < 0 || info_len > IL2P_MAX_PAYLOAD_SIZE) {
-		return (-2);
-	}
-
-	SET_PAYLOAD_BYTE_COUNT(hdr, info_len);
-	return (info_len);
-}
-
-
-// This should create a packet from the IL2P header.
-// The information part will not be filled in.
-
-static void trim(char *stuff)
-{
-	char *p = stuff + strlen(stuff) - 1;
-	while (strlen(stuff) > 0 && (*p == ' ')) {
-		*p = '\0';
-		p--;
-	}
-}
-
-
-
-/*--------------------------------------------------------------------------------
- *
- * Function:	il2p_decode_header_type_1
- *
- * Purpose:	Attempt to convert type 1 header to a packet object.
- *
- * Inputs:	hdr - IL2P header with no scrambling or parity symbols.
- *
- *		num_sym_changed - Number of symbols changed by FEC in the header.
- *				Should be 0 or 1.
- *
- * Returns:	Packet Object or NULL for failure.
- *
- * Description:	A later step will process the payload for the information part.
- *
- *--------------------------------------------------------------------------------*/
-
-packet_t il2p_decode_header_type_1(unsigned char *hdr, int num_sym_changed)
-{
-
-	if (GET_HDR_TYPE(hdr) != 1) {
-		Debugprintf("IL2P Internal error.  Should not be here: %s, when header type is 0.\n", __func__);
-		return (NULL);
-	}
-
-	// First get the addresses including SSID.
-
-	char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
-	int num_addr = 2;
-	memset(addrs, 0, 2 * AX25_MAX_ADDR_LEN);
-
-	// The IL2P header uses 2 parity symbols which means a single corrupted symbol (byte)
-	// can always be corrected.
-	// However, I have seen cases, where the error rate is very high, where the RS decoder
-	// thinks it found a valid code block by changing one symbol but it was the wrong one.
-	// The result is trash.  This shows up as address fields like 'R&G4"A' and 'TEW\ !'.
-	// I added a sanity check here to catch characters other than upper case letters and digits.
-	// The frame should be rejected in this case.  The question is whether to discard it
-	// silently or print a message so the user can see that something strange is happening?
-	// My current thinking is that it should be silently ignored if the header has been
-	// modified (correctee or more likely, made worse in this cases).
-	// If no changes were made, something weird is happening.  We should mention it for
-	// troubleshooting rather than sweeping it under the rug.
-
-	// The same thing has been observed with the payload, under very high error conditions,
-	// and max_fec==0.  Here I don't see a good solution.  AX.25 information can contain
-	// "binary" data so I'm not sure what sort of sanity check could be added.
-	// This was not observed with max_fec==1.  If we make that the default, same as Nino TNC,
-	// it would be extremely extremely unlikely unless someone explicitly selects weaker FEC.
-
-	// TODO: We could do something similar for header type 0.
-	// The address fields should be all binary zero values.
-	// Someone overly ambitious might check the addresses found in the first payload block.
-
-	for (int i = 0; i <= 5; i++) {
-		addrs[AX25_DESTINATION][i] = sixbit_to_ascii(hdr[i] & 0x3f);
-	}
-	trim(addrs[AX25_DESTINATION]);
-	for (int i = 0; i < strlen(addrs[AX25_DESTINATION]); i++) {
-		if (!isupper(addrs[AX25_DESTINATION][i]) && !isdigit(addrs[AX25_DESTINATION][i])) {
-			if (num_sym_changed == 0) {
-				// This can pop up sporadically when receiving random noise.
-				// Would be better to show only when debug is enabled but variable not available here.
-				// TODO: For now we will just suppress it.
-					//text_color_set(DW_COLOR_ERROR);
-					//Debugprintf ("IL2P: Invalid character '%c' in destination address '%s'\n", addrs[AX25_DESTINATION][i], addrs[AX25_DESTINATION]);
-			}
-			return (NULL);
-		}
-	}
-	sprintf(addrs[AX25_DESTINATION] + strlen(addrs[AX25_DESTINATION]), "-%d", (hdr[12] >> 4) & 0xf);
-
-	for (int i = 0; i <= 5; i++) {
-		addrs[AX25_SOURCE][i] = sixbit_to_ascii(hdr[i + 6] & 0x3f);
-	}
-	trim(addrs[AX25_SOURCE]);
-	for (int i = 0; i < strlen(addrs[AX25_SOURCE]); i++) {
-		if (!isupper(addrs[AX25_SOURCE][i]) && !isdigit(addrs[AX25_SOURCE][i])) {
-			if (num_sym_changed == 0) {
-				// This can pop up sporadically when receiving random noise.
-				// Would be better to show only when debug is enabled but variable not available here.
-				// TODO: For now we will just suppress it.
-					//text_color_set(DW_COLOR_ERROR);
-					//Debugprintf ("IL2P: Invalid character '%c' in source address '%s'\n", addrs[AX25_SOURCE][i], addrs[AX25_SOURCE]);
-			}
-			return (NULL);
-		}
-	}
-	sprintf(addrs[AX25_SOURCE] + strlen(addrs[AX25_SOURCE]), "-%d", hdr[12] & 0xf);
-
-	// The PID field gives us the general type.
-	// 0 = 'S' frame.
-	// 1 = 'U' frame other than UI.
-	// others are either 'UI' or 'I' depending on the UI field.
-
-	int pid = GET_PID(hdr);
-	int ui = GET_UI(hdr);
-
-	if (pid == 0) {
-
-		// 'S' frame.
-		// The control field contains: P/F N(R) C S S
-
-		int control = GET_CONTROL(hdr);
-		cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res;
-		ax25_frame_type_t ftype;
-		switch (control & 0x03) {
-		case 0: ftype = frame_type_S_RR; break;
-		case 1: ftype = frame_type_S_RNR; break;
-		case 2: ftype = frame_type_S_REJ; break;
-		default: ftype = frame_type_S_SREJ; break;
-		}
-		int modulo = 8;
-		int nr = (control >> 3) & 0x07;
-		int pf = (control >> 6) & 0x01;
-		unsigned char *pinfo = NULL;	// Any info for SREJ will be added later.
-		int info_len = 0;
-		return (ax25_s_frame(addrs, num_addr, cr, ftype, modulo, nr, pf, pinfo, info_len));
-	}
-	else if (pid == 1) {
-
-		// 'U' frame other than 'UI'.
-		// The control field contains: P/F OPCODE{3) C x x
-
-		int control = GET_CONTROL(hdr);
-		cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res;
-		int axpid = 0;	// unused for U other than UI.
-		ax25_frame_type_t ftype;
-		switch ((control >> 3) & 0x7) {
-		case 0: ftype = frame_type_U_SABM; break;
-		case 1: ftype = frame_type_U_DISC; break;
-		case 2: ftype = frame_type_U_DM; break;
-		case 3: ftype = frame_type_U_UA; break;
-		case 4: ftype = frame_type_U_FRMR; break;
-		case 5: ftype = frame_type_U_UI; axpid = 0xf0; break;		// Should not happen with IL2P pid == 1.
-		case 6: ftype = frame_type_U_XID; break;
-		default: ftype = frame_type_U_TEST; break;
-		}
-		int pf = (control >> 6) & 0x01;
-		unsigned char *pinfo = NULL;	// Any info for UI, XID, TEST will be added later.
-		int info_len = 0;
-		return (ax25_u_frame(addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len));
-	}
-	else if (ui) {
-
-		// 'UI' frame.
-		// The control field contains: P/F OPCODE{3) C x x
-
-		int control = GET_CONTROL(hdr);
-		cmdres_t cr = (control & 0x04) ? cr_cmd : cr_res;
-		ax25_frame_type_t ftype = frame_type_U_UI;
-		int pf = (control >> 6) & 0x01;
-		int axpid = decode_pid(GET_PID(hdr));
-		unsigned char *pinfo = NULL;	// Any info for UI, XID, TEST will be added later.
-		int info_len = 0;
-		return (ax25_u_frame(addrs, num_addr, cr, ftype, pf, axpid, pinfo, info_len));
-	}
-	else {
-
-		// 'I' frame.
-		// The control field contains: P/F N(R) N(S)
-
-		int control = GET_CONTROL(hdr);
-		cmdres_t cr = cr_cmd;		// Always command.
-		int pf = (control >> 6) & 0x01;
-		int nr = (control >> 3) & 0x7;
-		int ns = control & 0x7;
-		int modulo = 8;
-		int axpid = decode_pid(GET_PID(hdr));
-		unsigned char *pinfo = NULL;	// Any info for UI, XID, TEST will be added later.
-		int info_len = 0;
-		return (ax25_i_frame(addrs, num_addr, cr, modulo, nr, ns, pf, axpid, pinfo, info_len));
-	}
-	return (NULL);	// unreachable but avoid warning.
-
-} // end
-
-
-/*--------------------------------------------------------------------------------
- *
- * Function:	il2p_type_0_header
- *
- * Purpose:	Attempt to create type 0 header from packet object.
- *
- * Inputs:	pp	- Packet object.
- *
- *		max_fec	- 1 to use maximum FEC symbols, 0 for automatic.
- *
- * Outputs:	hdr	- IL2P header with no scrambling or parity symbols.
- *			  Must be large enough to hold IL2P_HEADER_SIZE unsigned bytes.
- *
- * Returns:	Number of bytes for information part or -1 for failure.
- *		In case of failure, fall back to type 0 transparent encapsulation.
- *
- * Description:	The type 0 header is used when it is not one of the restricted cases
- *		covered by the type 1 header.
- *		The AX.25 frame is put in the payload.
- *		This will cover: more than one address, mod 128 sequences, etc.
- *
- *--------------------------------------------------------------------------------*/
-
-int il2p_type_0_header(packet_t pp, int max_fec, unsigned char *hdr)
-{
-	memset(hdr, 0, IL2P_HEADER_SIZE);
-
-	// Bit 7 has [FEC Level:1], [HDR Type:1], [Payload byte Count:10]
-
-	SET_FEC_LEVEL(hdr, max_fec);
-	SET_HDR_TYPE(hdr, 0);
-
-	int frame_len = ax25_get_frame_len(pp);
-
-	if (frame_len < 14 || frame_len > IL2P_MAX_PAYLOAD_SIZE) {
-		return (-2);
-	}
-
-	SET_PAYLOAD_BYTE_COUNT(hdr, frame_len);
-	return (frame_len);
-}
-
-
-/***********************************************************************************
- *
- * Name:        il2p_get_header_attributes
- *
- * Purpose:     Extract a few attributes from an IL2p header.
- *
- * Inputs:      hdr	- IL2P header structure.
- *
- * Outputs:     hdr_type - 0 or 1.
- *
- *		max_fec	- 0 for automatic or 1 for fixed maximum size.
- *
- * Returns:	Payload byte count.   (actual payload size, not the larger encoded format)
- *
- ***********************************************************************************/
-
-
-int il2p_get_header_attributes(unsigned char *hdr, int *hdr_type, int *max_fec)
-{
-	*hdr_type = GET_HDR_TYPE(hdr);
-	*max_fec = GET_FEC_LEVEL(hdr);
-	return(GET_PAYLOAD_BYTE_COUNT(hdr));
-}
-
-
-/***********************************************************************************
- *
- * Name:        il2p_clarify_header
- *
- * Purpose:     Convert received header to usable form.
- *		This involves RS FEC then descrambling.
- *
- * Inputs:      rec_hdr	- Header as received over the radio.
- *
- * Outputs:     corrected_descrambled_hdr - After RS FEC and unscrambling.
- *
- * Returns:	Number of symbols that were corrected:
- *		 0 = No errors
- *		 1 = Single symbol corrected.
- *		 <0 = Unable to obtain good header.
- *
- ***********************************************************************************/
-
-int il2p_clarify_header(unsigned char *rec_hdr, unsigned char *corrected_descrambled_hdr)
-{
-	unsigned char corrected[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY];
-
-	int e = il2p_decode_rs(rec_hdr, IL2P_HEADER_SIZE, IL2P_HEADER_PARITY, corrected);
-
-	il2p_descramble_block(corrected, corrected_descrambled_hdr, IL2P_HEADER_SIZE);
-
-	return (e);
-}
-
-// end il2p_header.c 
-
-
-/*--------------------------------------------------------------------------------
- *
- * File:	il2p_payload.c
- *
- * Purpose:	Functions dealing with the payload.
- *
- *--------------------------------------------------------------------------------*/
-
-
- /*--------------------------------------------------------------------------------
-  *
-  * Function:	il2p_payload_compute
-  *
-  * Purpose:	Compute number and sizes of data blocks based on total size.
-  *
-  * Inputs:	payload_size	0 to 1023.  (IL2P_MAX_PAYLOAD_SIZE)
-  *		max_fec		true for 16 parity symbols, false for automatic.
-  *
-  * Outputs:	*p		Payload block sizes and counts.
-  *				Number of parity symbols per block.
-  *
-  * Returns:	Number of bytes in the encoded format.
-  *		Could be 0 for no payload blocks.
-  *		-1 for error (i.e. invalid unencoded size: <0 or >1023)
-  *
-  *--------------------------------------------------------------------------------*/
-
-int il2p_payload_compute(il2p_payload_properties_t *p, int payload_size, int max_fec)
-{
-	memset(p, 0, sizeof(il2p_payload_properties_t));
-
-	if (payload_size < 0 || payload_size > IL2P_MAX_PAYLOAD_SIZE) {
-		return (-1);
-	}
-	if (payload_size == 0) {
-		return (0);
-	}
-
-	if (max_fec) {
-		p->payload_byte_count = payload_size;
-		p->payload_block_count = (p->payload_byte_count + 238) / 239;
-		p->small_block_size = p->payload_byte_count / p->payload_block_count;
-		p->large_block_size = p->small_block_size + 1;
-		p->large_block_count = p->payload_byte_count - (p->payload_block_count * p->small_block_size);
-		p->small_block_count = p->payload_block_count - p->large_block_count;
-		p->parity_symbols_per_block = 16;
-	}
-	else {
-		p->payload_byte_count = payload_size;
-		p->payload_block_count = (p->payload_byte_count + 246) / 247;
-		p->small_block_size = p->payload_byte_count / p->payload_block_count;
-		p->large_block_size = p->small_block_size + 1;
-		p->large_block_count = p->payload_byte_count - (p->payload_block_count * p->small_block_size);
-		p->small_block_count = p->payload_block_count - p->large_block_count;
-		//p->parity_symbols_per_block = (p->small_block_size / 32) + 2;  // Looks like error in documentation
-
-		// It would work if the number of parity symbols was based on large block size.
-
-		if (p->small_block_size <= 61) p->parity_symbols_per_block = 2;
-		else if (p->small_block_size <= 123) p->parity_symbols_per_block = 4;
-		else if (p->small_block_size <= 185) p->parity_symbols_per_block = 6;
-		else if (p->small_block_size <= 247) p->parity_symbols_per_block = 8;
-		else {
-			// Should not happen.  But just in case...
-			Debugprintf("IL2P parity symbol per payload block error.  small_block_size = %d\n", p->small_block_size);
-			return (-1);
-		}
-	}
-
-	// Return the total size for the encoded format.
-
-	return (p->small_block_count * (p->small_block_size + p->parity_symbols_per_block) +
-		p->large_block_count * (p->large_block_size + p->parity_symbols_per_block));
-
-} // end il2p_payload_compute
-
-
-
-/*--------------------------------------------------------------------------------
- *
- * Function:	il2p_encode_payload
- *
- * Purpose:	Split payload into multiple blocks such that each set
- *		of data and parity symbols fit into a 255 byte RS block.
- *
- * Inputs:	*payload	Array of bytes.
- *		payload_size	0 to 1023.  (IL2P_MAX_PAYLOAD_SIZE)
- *		max_fec		true for 16 parity symbols, false for automatic.
- *
- * Outputs:	*enc		Encoded payload for transmission.
- *				Up to IL2P_MAX_ENCODED_SIZE bytes.
- *
- * Returns:	-1 for error (i.e. invalid size)
- *		0 for no blocks.  (i.e. size zero)
- *		Number of bytes generated.  Maximum IL2P_MAX_ENCODED_SIZE.
- *
- * Note:	I interpreted the protocol spec as saying the LFSR state is retained
- *		between data blocks.  During interoperability testing, I found that
- *		was not the case.  It is reset for each data block.
- *
- *--------------------------------------------------------------------------------*/
-
-
-int il2p_encode_payload(unsigned char *payload, int payload_size, int max_fec, unsigned char *enc)
-{
-	if (payload_size > IL2P_MAX_PAYLOAD_SIZE) return (-1);
-	if (payload_size == 0) return (0);
-
-	// Determine number of blocks and sizes.
-
-	il2p_payload_properties_t ipp;
-	int e;
-	e = il2p_payload_compute(&ipp, payload_size, max_fec);
-	if (e <= 0) {
-		return (e);
-	}
-
-	unsigned char *pin = payload;
-	unsigned char *pout = enc;
-	int encoded_length = 0;
-	unsigned char scram[256];
-	unsigned char parity[IL2P_MAX_PARITY_SYMBOLS];
-
-	// First the large blocks.
-
-	for (int b = 0; b < ipp.large_block_count; b++) {
-
-		il2p_scramble_block(pin, scram, ipp.large_block_size);
-		memcpy(pout, scram, ipp.large_block_size);
-		pin += ipp.large_block_size;
-		pout += ipp.large_block_size;
-		encoded_length += ipp.large_block_size;
-		il2p_encode_rs(scram, ipp.large_block_size, ipp.parity_symbols_per_block, parity);
-		memcpy(pout, parity, ipp.parity_symbols_per_block);
-		pout += ipp.parity_symbols_per_block;
-		encoded_length += ipp.parity_symbols_per_block;
-	}
-
-	// Then the small blocks.
-
-	for (int b = 0; b < ipp.small_block_count; b++) {
-
-		il2p_scramble_block(pin, scram, ipp.small_block_size);
-		memcpy(pout, scram, ipp.small_block_size);
-		pin += ipp.small_block_size;
-		pout += ipp.small_block_size;
-		encoded_length += ipp.small_block_size;
-		il2p_encode_rs(scram, ipp.small_block_size, ipp.parity_symbols_per_block, parity);
-		memcpy(pout, parity, ipp.parity_symbols_per_block);
-		pout += ipp.parity_symbols_per_block;
-		encoded_length += ipp.parity_symbols_per_block;
-	}
-
-	return (encoded_length);
-
-} // end il2p_encode_payload
-
-
-/*--------------------------------------------------------------------------------
- *
- * Function:	il2p_decode_payload
- *
- * Purpose:	Extract original data from encoded payload.
- *
- * Inputs:	received	Array of bytes.  Size is unknown but in practice it
- *				must not exceed IL2P_MAX_ENCODED_SIZE.
- *		payload_size	0 to 1023.  (IL2P_MAX_PAYLOAD_SIZE)
- *				Expected result size based on header.
- *		max_fec		true for 16 parity symbols, false for automatic.
- *
- * Outputs:	payload_out	Recovered payload.
- *
- * In/Out:	symbols_corrected	Number of symbols corrected.
- *
- *
- * Returns:	Number of bytes extracted.  Should be same as payload_size going in.
- *		-3 for unexpected internal inconsistency.
- *		-2 for unable to recover from signal corruption.
- *		-1 for invalid size.
- *		0 for no blocks.  (i.e. size zero)
- *
- * Description:	Each block is scrambled separately but the LSFR state is carried
- *		from the first payload block to the next.
- *
- *--------------------------------------------------------------------------------*/
-
-int il2p_decode_payload(unsigned char *received, int payload_size, int max_fec, unsigned char *payload_out, int *symbols_corrected)
-{
-	// Determine number of blocks and sizes.
-
-	il2p_payload_properties_t ipp;
-	int e;
-	e = il2p_payload_compute(&ipp, payload_size, max_fec);
-	if (e <= 0) {
-		return (e);
-	}
-
-	unsigned char *pin = received;
-	unsigned char *pout = payload_out;
-	int decoded_length = 0;
-	int failed = 0;
-
-	// First the large blocks.
-
-	for (int b = 0; b < ipp.large_block_count; b++) {
-		unsigned char corrected_block[255];
-		int e = il2p_decode_rs(pin, ipp.large_block_size, ipp.parity_symbols_per_block, corrected_block);
-
-		// Debugprintf ("%s:%d: large block decode_rs returned status = %d\n", __FILE__, __LINE__, e);
-
-		if (e < 0) failed = 1;
-		*symbols_corrected += e;
-
-		il2p_descramble_block(corrected_block, pout, ipp.large_block_size);
-
-		if (il2p_get_debug() >= 2) {
-	
-			Debugprintf("Descrambled large payload block, %d bytes:\n", ipp.large_block_size);
-			fx_hex_dump(pout, ipp.large_block_size);
-		}
-
-		pin += ipp.large_block_size + ipp.parity_symbols_per_block;
-		pout += ipp.large_block_size;
-		decoded_length += ipp.large_block_size;
-	}
-
-	// Then the small blocks.
-
-	for (int b = 0; b < ipp.small_block_count; b++) {
-		unsigned char corrected_block[255];
-		int e = il2p_decode_rs(pin, ipp.small_block_size, ipp.parity_symbols_per_block, corrected_block);
-
-		// Debugprintf ("%s:%d: small block decode_rs returned status = %d\n", __FILE__, __LINE__, e);
-
-		if (e < 0) failed = 1;
-		*symbols_corrected += e;
-
-		il2p_descramble_block(corrected_block, pout, ipp.small_block_size);
-
-		if (il2p_get_debug() >= 2) {
-	
-			Debugprintf("Descrambled small payload block, %d bytes:\n", ipp.small_block_size);
-			fx_hex_dump(pout, ipp.small_block_size);
-		}
-
-		pin += ipp.small_block_size + ipp.parity_symbols_per_block;
-		pout += ipp.small_block_size;
-		decoded_length += ipp.small_block_size;
-	}
-
-	if (failed) {
-		//Debugprintf ("%s:%d: failed = %0x\n", __FILE__, __LINE__, failed);
-		return (-2);
-	}
-
-	if (decoded_length != payload_size) {
-		Debugprintf("IL2P Internal error: decoded_length = %d, payload_size = %d\n", decoded_length, payload_size);
-		return (-3);
-	}
-
-	return (decoded_length);
-
-} // end il2p_decode_payload
-
-// end il2p_payload.c
-
-
-
-struct il2p_context_s {
-
-	enum { IL2P_SEARCHING = 0, IL2P_HEADER, IL2P_PAYLOAD, IL2P_DECODE } state;
-
-	unsigned int acc;	// Accumulate most recent 24 bits for sync word matching.
-				// Lower 8 bits are also used for accumulating bytes for
-				// the header and payload.
-
-	int bc;			// Bit counter so we know when a complete byte has been accumulated.
-
-	int polarity;		// 1 if opposite of expected polarity.
-
-	unsigned char shdr[IL2P_HEADER_SIZE + IL2P_HEADER_PARITY];
-	// Scrambled header as received over the radio.  Includes parity.
-	int hc;			// Number if bytes placed in above.
-
-	unsigned char uhdr[IL2P_HEADER_SIZE];  // Header after FEC and unscrambling.
-
-	int eplen;		// Encoded payload length.  This is not the nuumber from
-				// from the header but rather the number of encoded bytes to gather.
-
-	unsigned char spayload[IL2P_MAX_ENCODED_PAYLOAD_SIZE];
-	// Scrambled and encoded payload as received over the radio.
-	int pc;			// Number of bytes placed in above.
-
-	int corrected;		// Number of symbols corrected by RS FEC.
-};
-
-static struct il2p_context_s *il2p_context[MAX_CHANS][MAX_SUBCHANS][MAX_SLICERS];
-
-
-
-/***********************************************************************************
- *
- * Name:        il2p_rec_bit
- *
- * Purpose:     Extract FX.25 packets from a stream of bits.
- *
- * Inputs:      chan    - Channel number.
- *
- *              subchan - This allows multiple demodulators per channel.
- *
- *              slice   - Allows multiple slicers per demodulator (subchannel).
- *
- *              dbit	- One bit from the received data stream.
- *
- * Description: This is called once for each received bit.
- *              For each valid packet, process_rec_frame() is called for further processing.
- *		It can gather multiple candidates from different parallel demodulators
- *		("subchannels") and slicers, then decide which one is the best.
- *
- ***********************************************************************************/
-
-int centreFreq[4] = { 0, 0, 0, 0 };
-
-void il2p_rec_bit(int chan, int subchan, int slice, int dbit)
-{
-	// Allocate context blocks only as needed.
-
-	if (dbit)
-		dbit = 1;
-
-	struct il2p_context_s *F = il2p_context[chan][subchan][slice];
-	if (F == NULL) {
-		//assert(chan >= 0 && chan < MAX_CHANS);
-		//assert(subchan >= 0 && subchan < MAX_SUBCHANS);
-		//assert(slice >= 0 && slice < MAX_SLICERS);
-		F = il2p_context[chan][subchan][slice] = (struct il2p_context_s *)malloc(sizeof(struct il2p_context_s));
-		//assert(F != NULL);
-		memset(F, 0, sizeof(struct il2p_context_s));
-	}
-
-	// Accumulate most recent 24 bits received.  Most recent is LSB.
-
-	F->acc = ((F->acc << 1) | (dbit & 1)) & 0x00ffffff;
-
-	// State machine to look for sync word then gather appropriate number of header and payload bytes.
-
-	switch (F->state) {
-
-	case IL2P_SEARCHING:		// Searching for the sync word.
-
-		if (__builtin_popcount(F->acc ^ IL2P_SYNC_WORD) <= 1) {	// allow single bit mismatch
-		  //text_color_set (DW_COLOR_INFO);
-		  //Debugprintf ("IL2P header has normal polarity\n");
-			F->polarity = 0;
-			F->state = IL2P_HEADER;
-			F->bc = 0;
-			F->hc = 0;
-		
-			// Determine Centre Freq
-			
-			centreFreq[chan] = GuessCentreFreq(chan);
-		}
-		else if (__builtin_popcount((~F->acc & 0x00ffffff) ^ IL2P_SYNC_WORD) <= 1) {
-			// FIXME - this pops up occasionally with random noise.  Find better way to convey information.
-			// This also happens for each slicer - to noisy.
-			//Debugprintf ("IL2P header has reverse polarity\n");
-			F->polarity = 1;
-			F->state = IL2P_HEADER;
-			F->bc = 0;
-			F->hc = 0;
-			centreFreq[chan] = GuessCentreFreq(chan);
-		}
-			
-		break;
-
-	case IL2P_HEADER:		// Gathering the header.
-
-		F->bc++;
-		if (F->bc == 8) {	// full byte has been collected.
-			F->bc = 0;
-			if (!F->polarity) {
-				F->shdr[F->hc++] = F->acc & 0xff;
-			}
-			else {
-				F->shdr[F->hc++] = (~F->acc) & 0xff;
-			}
-			if (F->hc == IL2P_HEADER_SIZE + IL2P_HEADER_PARITY) {		// Have all of header
-
-				//if (il2p_get_debug() >= 1)
-				//{
-				//	Debugprintf("IL2P header as received [%d.%d.%d]:\n", chan, subchan, slice);
-				//	fx_hex_dump(F->shdr, IL2P_HEADER_SIZE + IL2P_HEADER_PARITY);
-				//}
-
-				// Fix any errors and descramble.
-				F->corrected = il2p_clarify_header(F->shdr, F->uhdr);
-
-				if (F->corrected >= 0) {	// Good header.
-							// How much payload is expected?
-					il2p_payload_properties_t plprop;
-					int hdr_type, max_fec;
-					int len = il2p_get_header_attributes(F->uhdr, &hdr_type, &max_fec);
-
-					F->eplen = il2p_payload_compute(&plprop, len, max_fec);
-
-					if (il2p_get_debug() >= 1)
-					{	
-						Debugprintf("Header type %d, max fec = %d", hdr_type, max_fec);
-						Debugprintf("Need to collect %d encoded bytes for %d byte payload.", F->eplen, len);
-						Debugprintf("%d small blocks of %d and %d large blocks of %d.  %d parity symbols per block",
-							plprop.small_block_count, plprop.small_block_size,
-							plprop.large_block_count, plprop.large_block_size, plprop.parity_symbols_per_block);
-					}
-
-					if (F->eplen >= 1) {		// Need to gather payload.
-						F->pc = 0;
-						F->state = IL2P_PAYLOAD;
-					}
-					else if (F->eplen == 0) {	// No payload.
-						F->pc = 0;
-						F->state = IL2P_DECODE;
-					}
-					else {			// Error.
-
-						if (il2p_get_debug() >= 1) {
-							Debugprintf("IL2P header INVALID.\n");
-						}
-
-						F->state = IL2P_SEARCHING;
-					}
-				}  // good header after FEC.
-				else {
-					F->state = IL2P_SEARCHING;	// Header failed FEC check.
-				}
-			}  // entire header has been collected.    
-		}  // full byte collected.
-		break;
-
-	case IL2P_PAYLOAD:		// Gathering the payload, if any.
-
-		F->bc++;
-		if (F->bc == 8) {	// full byte has been collected.
-			F->bc = 0;
-			if (!F->polarity) {
-				F->spayload[F->pc++] = F->acc & 0xff;
-			}
-			else {
-				F->spayload[F->pc++] = (~F->acc) & 0xff;
-			}
-			if (F->pc == F->eplen) {
-
-				// TODO?: for symmetry it seems like we should clarify the payload before combining.
-
-				F->state = IL2P_DECODE;
-			}
-		}
-		break;
-
-	case IL2P_DECODE:
-		// We get here after a good header and any payload has been collected.
-		// Processing is delayed by one bit but I think it makes the logic cleaner.
-		// During unit testing be sure to send an extra bit to flush it out at the end.
-
-		// in uhdr[IL2P_HEADER_SIZE];  // Header after FEC and descrambling.
-
-		// TODO?:  for symmetry, we might decode the payload here and later build the frame.
-
-	{
-		packet_t pp = il2p_decode_header_payload(F->uhdr, F->spayload, &(F->corrected));
-
-		if (il2p_get_debug() >= 1)
-		{
-			if (pp == NULL)
-			{
-				// Most likely too many FEC errors.
-				Debugprintf("FAILED to construct frame in %s.\n", __func__);
-			}
-		}
-
-		if (pp != NULL) {
-			alevel_t alevel = demod_get_audio_level(chan, subchan);
-			retry_t retries = F->corrected;
-			int is_fx25 = 1;		// FIXME: distinguish fx.25 and IL2P.
-					  // Currently this just means that a FEC mode was used.
-
-			// TODO: Could we put last 3 arguments in packet object rather than passing around separately?
-
-			multi_modem_process_rec_packet(chan, subchan, slice, pp, alevel, retries, is_fx25, slice, centreFreq[chan]);
-		}
-	}   // end block for local variables.
-
-	if (il2p_get_debug() >= 1) {
-
-		Debugprintf("-----");
-	}
-
-	F->state = IL2P_SEARCHING;
-	break;
-
-	} // end of switch
-
-} // end il2p_rec_bit
-
-
-
-
-
-
-
-// Scramble bits for il2p transmit.
-
-// Note that there is a delay of 5 until the first bit comes out.
-// So we need to need to ignore the first 5 out and stick in
-// an extra 5 filler bits to flush at the end.
-
-#define INIT_TX_LSFR 0x00f
-
-static inline int scramble_bit(int in, int *state)
-{
-	int out = ((*state >> 4) ^ *state) & 1;
-	*state = ((((in ^ *state) & 1) << 9) | (*state ^ ((*state & 1) << 4))) >> 1;
-	return (out);
-}
-
-
-// Undo data scrambling for il2p receive.
-
-#define INIT_RX_LSFR 0x1f0
-
-static inline int descramble_bit(int in, int *state)
-{
-	int out = (in ^ *state) & 1;
-	*state = ((*state >> 1) | ((in & 1) << 8)) ^ ((in & 1) << 3);
-	return (out);
-}
-
-
-/*--------------------------------------------------------------------------------
- *
- * Function:	il2p_scramble_block
- *
- * Purpose:	Scramble a block before adding RS parity.
- *
- * Inputs:	in		Array of bytes.
- *		len		Number of bytes both in and out.
- *
- * Outputs:	out		Array of bytes.
- *
- *--------------------------------------------------------------------------------*/
-
-void il2p_scramble_block(unsigned char *in, unsigned char *out, int len)
-{
-	int tx_lfsr_state = INIT_TX_LSFR;
-
-	memset(out, 0, len);
-
-	int skipping = 1;	// Discard the first 5 out.
-	int ob = 0;		// Index to output byte.
-	int om = 0x80;		// Output bit mask;
-	for (int ib = 0; ib < len; ib++) {
-		for (int im = 0x80; im != 0; im >>= 1) {
-			int s = scramble_bit((in[ib] & im) != 0, &tx_lfsr_state);
-			if (ib == 0 && im == 0x04) skipping = 0;
-			if (!skipping) {
-				if (s) {
-					out[ob] |= om;
-				}
-				om >>= 1;
-				if (om == 0) {
-					om = 0x80;
-					ob++;
-				}
-			}
-		}
-	}
-	// Flush it.
-
-	// This is a relic from when I thought the state would need to
-	// be passed along for the next block.
-	// Preserve the LSFR state from before flushing.
-	// This might be needed as the initial state for later payload blocks.
-	int x = tx_lfsr_state;
-	for (int n = 0; n < 5; n++) {
-		int s = scramble_bit(0, &x);
-		if (s) {
-			out[ob] |= om;
-		}
-		om >>= 1;
-		if (om == 0) {
-			om = 0x80;
-			ob++;
-		}
-	}
-
-}  // end il2p_scramble_block
-
-
-
-/*--------------------------------------------------------------------------------
- *
- * Function:	il2p_descramble_block
- *
- * Purpose:	Descramble a block after removing RS parity.
- *
- * Inputs:	in		Array of bytes.
- *		len		Number of bytes both in and out.
- *
- * Outputs:	out		Array of bytes.
- *
- *--------------------------------------------------------------------------------*/
-
-void il2p_descramble_block(unsigned char *in, unsigned char *out, int len)
-{
-	int rx_lfsr_state = INIT_RX_LSFR;
-
-	memset(out, 0, len);
-
-	for (int b = 0; b < len; b++) {
-		for (int m = 0x80; m != 0; m >>= 1) {
-			int d = descramble_bit((in[b] & m) != 0, &rx_lfsr_state);
-			if (d) {
-				out[b] |= m;
-			}
-		}
-	}
-}
-
-// end il2p_scramble.c
-
-
-
-
-static int number_of_bits_sent[MAX_CHANS];		// Count number of bits sent by "il2p_send_frame"
-
-static void send_bytes(int chan, unsigned char *b, int count, int polarity);
-static void send_bit(int chan, int b, int polarity);
-
-
-
-/*-------------------------------------------------------------
- *
- * Name:	il2p_send_frame
- *
- * Purpose:	Convert frames to a stream of bits in IL2P format.
- *
- * Inputs:	chan	- Audio channel number, 0 = first.
- *
- *		pp	- Pointer to packet object.
- *
- *		max_fec	- 1 to force 16 parity symbols for each payload block.
- *			  0 for automatic depending on block size.
- *
- *		polarity - 0 for normal.  1 to invert signal.
- *			   2 special case for testing - introduce some errors to test FEC.
- *
- * Outputs:	Bits are shipped out by calling tone_gen_put_bit().
- *
- * Returns:	Number of bits sent including
- *		- Preamble   (01010101...)
- *		- 3 byte Sync Word.
- *		- 15 bytes for Header.
- *		- Optional payload.
- *		The required time can be calculated by dividing this
- *		number by the transmit rate of bits/sec.
- *		-1 is returned for failure.
- *
- * Description:	Generate an IL2P encoded frame.
- *
- * Assumptions:	It is assumed that the tone_gen module has been
- *		properly initialized so that bits sent with
- *		tone_gen_put_bit() are processed correctly.
- *
- * Errors:	Return -1 for error.  Probably frame too large.
- *
- * Note:	Inconsistency here. ax25 version has just a byte array
- *		and length going in.  Here we need the full packet object.
- *
- *--------------------------------------------------------------*/
-
-string * il2p_send_frame(int chan, packet_t pp, int max_fec, int polarity)
-{
-	unsigned char encoded[IL2P_MAX_PACKET_SIZE];
-	string * packet = newString();
-	int preamblecount;
-	unsigned char preamble[1024];
-
-
-	encoded[0] = (IL2P_SYNC_WORD >> 16) & 0xff;
-	encoded[1] = (IL2P_SYNC_WORD >> 8) & 0xff;
-	encoded[2] = (IL2P_SYNC_WORD) & 0xff;
-
-	int elen = il2p_encode_frame(pp, max_fec, encoded + IL2P_SYNC_WORD_SIZE);
-	if (elen <= 0) {
-		Debugprintf("IL2P: Unable to encode frame into IL2P.\n");
-		return (packet);
-	}
-
-	elen += IL2P_SYNC_WORD_SIZE;
-
-	number_of_bits_sent[chan] = 0;
-
-	if (il2p_get_debug() >= 1) {
-		Debugprintf("IL2P frame, max_fec = %d, %d encoded bytes total", max_fec, elen);
-//		fx_hex_dump(encoded, elen);
-	}
-
-	// Send bits to modulator.
-
-	// Try using preaamble for txdelay
-
-	preamblecount = (txdelay[chan] * tx_baudrate[chan]) / 8000;		// 8 for bits, 1000 for mS
-
-	if (preamblecount > 1024)
-		preamblecount = 1024;
-
- 	memset(preamble, IL2P_PREAMBLE, preamblecount);
-
-	stringAdd(packet, preamble, preamblecount);
-	stringAdd(packet, encoded, elen);
-
-	tx_fx25_size[chan] = packet->Length * 8;
-
-	return packet;
-}
-
-
-
-// TX Code. Builds whole packet then sends a bit at a time
-
-#define TX_SILENCE 0
-#define TX_DELAY 1
-#define TX_TAIL 2
-#define TX_NO_DATA 3
-#define TX_FRAME 4
-#define TX_WAIT_BPF 5
-
-
-#define TX_BIT0 0
-#define TX_BIT1 1
-#define FRAME_EMPTY 0
-#define FRAME_FULL 1
-#define FRAME_NO_FRAME 2
-#define FRAME_NEW_FRAME 3
-#define BYTE_EMPTY 0
-#define BYTE_FULL 1
-
-extern UCHAR tx_frame_status[5];
-extern UCHAR tx_byte_status[5];
-extern string * tx_data[5];
-extern int tx_data_len[5];
-extern UCHAR tx_bit_stream[5];
-extern UCHAR tx_bit_cnt[5];
-extern long tx_tail_cnt[5];
-extern BOOL tx_bs_bit[5];
-
-string * fill_il2p_data(int snd_ch, string * data)
-{
-	string * result;
-	packet_t pp = ax25_new();
-	
-
-	// Call il2p_send_frame to build the bit stream
-
-	pp->frame_len = data->Length - 2;					// Included CRC
-	memcpy(pp->frame_data, data->Data, data->Length);
-
-	result = il2p_send_frame(snd_ch, pp, 1, 0);
-
-	return result;
-}
-
-
-
-void il2p_get_new_frame(int snd_ch, TStringList * frame_stream)
-{
-	string * myTemp;
-
-	tx_bs_bit[snd_ch] = 0;
-	tx_bit_cnt[snd_ch] = 0;
-	tx_fx25_size_cnt[snd_ch] = 0;
-	tx_fx25_size[snd_ch] = 1;
-	tx_frame_status[snd_ch] = FRAME_NEW_FRAME;
-	tx_byte_status[snd_ch] = BYTE_EMPTY;
-
-	if (frame_stream->Count == 0)
-		tx_frame_status[snd_ch] = FRAME_NO_FRAME;
-	else
-	{
-		// We now pass control byte and ack bytes on front and pointer to socket on end if ackmode
-
-		myTemp = Strings(frame_stream, 0);			// get message
-
-		if ((myTemp->Data[0] & 0x0f) == 12)			// ACKMODE
-		{
-			// Save copy then copy data up 3 bytes
-
-			Add(&KISS_acked[snd_ch], duplicateString(myTemp));
-
-			mydelete(myTemp, 0, 3);
-			myTemp->Length -= sizeof(void *);
-		}
-		else
-		{
-			// Just remove control 
-
-			mydelete(myTemp, 0, 1);
-		}
-
-		AGW_AX25_frame_analiz(snd_ch, FALSE, myTemp);
-		put_frame(snd_ch, myTemp, "", TRUE, FALSE);
-
-		tx_data[snd_ch] = fill_il2p_data(snd_ch, myTemp);
-
-		Delete(frame_stream, 0);			// This will invalidate temp
-	}
-}
-
-
-
-// Original code
-
-/*
-static void send_bytes(int chan, unsigned char *b, int count, int polarity)
-{
-	for (int j = 0; j < count; j++) {
-		unsigned int x = b[j];
-		for (int k = 0; k < 8; k++) {
-			send_bit(chan, (x & 0x80) != 0, polarity);
-			x <<= 1;
-		}
-	}
-}
-
-// NRZI would be applied for AX.25 but IL2P does not use it.
-// However we do have an option to invert the signal.
-// The direwolf receive implementation will automatically compensate
-// for either polarity but other implementations might not.
-
-static void send_bit(int chan, int b, int polarity)
-{
-	tone_gen_put_bit(chan, (b ^ polarity) & 1);
-	number_of_bits_sent[chan]++;
-}
-*/
-
-
-
-
-int il2p_get_new_bit(int snd_ch, Byte bit)
-{
-	string *s;
-
-	if (tx_frame_status[snd_ch] == FRAME_EMPTY)
-	{
-		il2p_get_new_frame(snd_ch, &all_frame_buf[snd_ch]);
-		if (tx_frame_status[snd_ch] == FRAME_NEW_FRAME)
-			tx_frame_status[snd_ch] = FRAME_FULL;
-	}
-
-	if (tx_frame_status[snd_ch] == FRAME_FULL)
-	{
-		if (tx_byte_status[snd_ch] == BYTE_EMPTY)
-		{
-			if (tx_data[snd_ch]->Length)
-			{
-				s = tx_data[snd_ch];
-
-				tx_bit_stream[snd_ch] = s->Data[0];
-				tx_frame_status[snd_ch] = FRAME_FULL;
-				tx_byte_status[snd_ch] = BYTE_FULL;
-				tx_bit_cnt[snd_ch] = 0;
-				mydelete(tx_data[snd_ch], 0, 1);
-			}
-			else
-				tx_frame_status[snd_ch] = FRAME_EMPTY;
-		}
-		if (tx_byte_status[snd_ch] == BYTE_FULL)
-		{
-			// il2p sends high order bit first
-
-			bit = tx_bit_stream[snd_ch] >> 7;			// top bit to bottom
-
-			tx_bit_stream[snd_ch] = tx_bit_stream[snd_ch] << 1;
-			tx_bit_cnt[snd_ch]++;
-			tx_fx25_size_cnt[snd_ch]++;
-			if (tx_bit_cnt[snd_ch] >= 8)
-				tx_byte_status[snd_ch] = BYTE_EMPTY;
-			if (tx_fx25_size_cnt[snd_ch] == tx_fx25_size[snd_ch])
-				tx_frame_status[snd_ch] = FRAME_EMPTY;
-		}
-	}
-
-	if (tx_frame_status[snd_ch] == FRAME_EMPTY)
-	{
-		il2p_get_new_frame(snd_ch, &all_frame_buf[snd_ch]);
-
-		switch (tx_frame_status[snd_ch])
-		{
-		case FRAME_NEW_FRAME:
-			tx_frame_status[snd_ch] = FRAME_FULL;
-			break;
-
-		case FRAME_NO_FRAME:
-			tx_tail_cnt[snd_ch] = 0;
-			tx_frame_status[snd_ch] = FRAME_EMPTY;
-			tx_status[snd_ch] = TX_TAIL;
-			break;
-		}
-	}
-	return bit;
-}
-
-
-
diff --git a/kiss.h b/kiss.h
deleted file mode 100644
index 1dc40da..0000000
--- a/kiss.h
+++ /dev/null
@@ -1,24 +0,0 @@
-
-/* 
- * Name:	kiss.h
- *
- * This is for the pseudo terminal KISS interface.
- */
-
-
-#include "ax25_pad.h"		/* for packet_t */
-
-#include "config.h"
-
-#include "kiss_frame.h"		// for struct kissport_status_s
-
-
-void kisspt_init (struct misc_config_s *misc_config);
-
-void kisspt_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf,  int flen,
-		struct kissport_status_s *notused1, int notused2);
-
-void kisspt_set_debug (int n);
-
-
-/* end kiss.h */
diff --git a/kiss_frame.h b/kiss_frame.h
deleted file mode 100644
index 941f5c0..0000000
--- a/kiss_frame.h
+++ /dev/null
@@ -1,126 +0,0 @@
-
-/* kiss_frame.h */
-
-#ifndef KISS_FRAME_H
-#define KISS_FRAME_H
-
-
-#include "audio.h"		/* for struct audio_s */
-
-
-/*
- * The first byte of a KISS frame has:
- *	channel in upper nybble.
- *	command in lower nybble.
- */
-
-#define KISS_CMD_DATA_FRAME	0
-#define KISS_CMD_TXDELAY	1
-#define KISS_CMD_PERSISTENCE	2
-#define KISS_CMD_SLOTTIME	3
-#define KISS_CMD_TXTAIL		4
-#define KISS_CMD_FULLDUPLEX	5
-#define KISS_CMD_SET_HARDWARE	6
-#define XKISS_CMD_DATA		12	// Not supported. http://he.fi/pub/oh7lzb/bpq/multi-kiss.pdf
-#define XKISS_CMD_POLL		14	// Not supported.
-#define KISS_CMD_END_KISS	15
-
-
-
-/*
- * Special characters used by SLIP protocol.
- */
-
-#define FEND 0xC0
-#define FESC 0xDB
-#define TFEND 0xDC
-#define TFESC 0xDD
-
-
-
-enum kiss_state_e {
-	KS_SEARCHING = 0,	/* Looking for FEND to start KISS frame. */
-				/* Must be 0 so we can simply zero whole structure to initialize. */
-	KS_COLLECTING};		/* In process of collecting KISS frame. */
-
-
-#define MAX_KISS_LEN 2048	/* Spec calls for at least 1024. */
-				/* Might want to make it longer to accommodate */
-				/* maximum packet length. */
-
-#define MAX_NOISE_LEN 100
-
-typedef struct kiss_frame_s {
-	
-	enum kiss_state_e state;
-
-	unsigned char kiss_msg[MAX_KISS_LEN];
-				/* Leading FEND is optional. */
-				/* Contains escapes and ending FEND. */
-	int kiss_len;
-
-	unsigned char noise[MAX_NOISE_LEN];
-	int noise_len;
-
-} kiss_frame_t;
-
-
-// This is used only for TCPKISS but it put in kissnet.h,
-// there would be a circular dependency between the two header files.
-// Each KISS TCP port has its own status block.
-
-struct kissport_status_s {
-
-	struct kissport_status_s *pnext;	// To next in list.
-
-	volatile int arg2;			// temp for passing second arg into
-						// kissnet_listen_thread
-
-	int tcp_port;				// default 8001
-
-	int chan;				// Radio channel for this tcp port.
-						// -1 for all.
-
-	// The default is a limit of 3 client applications at the same time.
-	// You can increase the limit by changing the line below.
-	// A larger number consumes more resources so don't go crazy by making it larger than needed.
-	// TODO:  Should this be moved to direwolf.h so max number of audio devices
-	// client apps are in the same place?
-
-#define MAX_NET_CLIENTS 3
-
-	int client_sock[MAX_NET_CLIENTS];
-				/* File descriptor for socket for */
-				/* communication with client application. */
-				/* Set to -1 if not connected. */
-				/* (Don't use SOCKET type because it is unsigned.) */
-
-	kiss_frame_t kf[MAX_NET_CLIENTS];
-				/* Accumulated KISS frame and state of decoder. */
-};
-
-
-
-#ifndef KISSUTIL
-void kiss_frame_init (struct audio_s *pa);
-#endif
-
-int kiss_encapsulate (unsigned char *in, int ilen, unsigned char *out);
-
-int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out);
-
-void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, struct kissport_status_s *kps, int client,
-			void (*sendfun)(int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *onlykps, int onlyclient));
-
-typedef enum fromto_e { FROM_CLIENT=0, TO_CLIENT=1 } fromto_t;
-
-void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct kissport_status_s *kps, int client,
-			void (*sendfun)(int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *onlykps, int onlyclient));
-
-void kiss_debug_print (fromto_t fromto, char *special, unsigned char *pmsg, int msg_len);
-
-
-#endif  // KISS_FRAME_H
-
-
-/* end kiss_frame.h */
diff --git a/kiss_mode.c b/kiss_mode.c
index 5adba5d..72688a7 100644
--- a/kiss_mode.c
+++ b/kiss_mode.c
@@ -245,7 +245,6 @@ void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len)
 				Add(&KISS.buffer[Chan], TXMSG);
 		}
 
-		
 		return;
 
 	case KISS_DATA:
diff --git a/kissnet.h b/kissnet.h
deleted file mode 100644
index 469e4e6..0000000
--- a/kissnet.h
+++ /dev/null
@@ -1,29 +0,0 @@
-
-/* 
- * Name:	kissnet.h
- */
-
-#ifndef KISSNET_H
-#define KISSNET_H
-
-#include "ax25_pad.h"		/* for packet_t */
-
-#include "config.h"
-
-#include "kiss_frame.h"
-
-
-
-void kissnet_init (struct misc_config_s *misc_config);
-
-void kissnet_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf,  int flen,
-			struct kissport_status_s *onlykps, int onlyclient);
-
-void kiss_net_set_debug (int n);
-
-void kissnet_copy (unsigned char *kiss_msg, int kiss_len, int chan, int cmd, struct kissport_status_s *from_kps, int from_client);
-
-
-#endif  // KISSNET_H
-
-/* end kissnet.h */
diff --git a/kissserial.h b/kissserial.h
deleted file mode 100644
index 44fb3c3..0000000
--- a/kissserial.h
+++ /dev/null
@@ -1,23 +0,0 @@
-
-/* 
- * Name:	kissserial.h
- */
-
-
-#include "ax25_pad.h"		/* for packet_t */
-
-#include "config.h"
-
-#include "kiss_frame.h"
-
-
-void kissserial_init (struct misc_config_s *misc_config);
-
-void kissserial_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf,  int flen,
-		struct kissport_status_s *notused1, int notused2);
-
-
-void kissserial_set_debug (int n);
-
-
-/* end kissserial.h */
diff --git a/latlong.h b/latlong.h
deleted file mode 100644
index ae98fe6..0000000
--- a/latlong.h
+++ /dev/null
@@ -1,24 +0,0 @@
-
-/* latlong.h */
-
-
-/* Use this value for unknown latitude/longitude or other values. */
-
-#define G_UNKNOWN (-999999)
-
-
-void latitude_to_str (double dlat, int ambiguity, char *slat);
-void longitude_to_str (double dlong, int ambiguity, char *slong);
-
-void latitude_to_comp_str (double dlat, char *clat);
-void longitude_to_comp_str (double dlon, char *clon);
-
-void latitude_to_nmea (double dlat, char *slat, char *hemi);
-void longitude_to_nmea (double dlong, char *slong, char *hemi);
-
-double latitude_from_nmea (char *pstr, char *phemi);
-double longitude_from_nmea (char *pstr, char *phemi);
-
-double ll_distance_km (double lat1, double lon1, double lat2, double lon2);
-
-int ll_from_grid_square (char *maidenhead, double *dlat, double *dlon);
\ No newline at end of file
diff --git a/log.h b/log.h
deleted file mode 100644
index 3afb6b1..0000000
--- a/log.h
+++ /dev/null
@@ -1,19 +0,0 @@
-
-/* log.h */
-
-
-#include "hdlc_rec2.h"		// for retry_t
-
-#include "decode_aprs.h"	// for decode_aprs_t
-
-#include "ax25_pad.h"
-
-
-
-void log_init (int daily_names, char *path);
-
-void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_t retries);
-
-void log_rr_bits (decode_aprs_t *A, packet_t pp);
-
-void log_term (void); 	
\ No newline at end of file
diff --git a/main.cpp b/main.cpp
index 402e849..43ea7cd 100644
--- a/main.cpp
+++ b/main.cpp
@@ -53,6 +53,8 @@ int main(int argc, char *argv[])
 
 	qDebug() << Title;
 
+
+
 	if (nonGUIMode)
 		a = new QCoreApplication(argc, argv);
 	else
@@ -60,6 +62,7 @@ int main(int argc, char *argv[])
 
 	getSettings();
 
+
 	t = new workerThread;
 
 	if (nonGUIMode == 0)
@@ -85,4 +88,3 @@ int main(int argc, char *argv[])
 
 }
 
-
diff --git a/mgn_icon.h b/mgn_icon.h
deleted file mode 100644
index c870bc0..0000000
--- a/mgn_icon.h
+++ /dev/null
@@ -1,276 +0,0 @@
-
-
-/* 
- * MGN_icon.h 
- *
- * Waypoint icon codes for use in the $PMGNWPL sentence.
- *
- * Derived from Data Transmission Protocol For Magellan Products - version 2.11, March 2003
- *
- * http://www.gpsinformation.org/mag-proto-2-11.pdf
- *
- *
- * That's 13 years ago.  There should be something newer available but I can't find it.
- *
- * The is based on the newer models at the time.  Earlier models had shorter incompatible icon lists.
- */
-
-
-
-#define MGN_crossed_square "a"
-#define MGN_box "b"
-#define MGN_house "c"
-#define MGN_aerial "d"
-#define MGN_airport "e"
-#define MGN_amusement_park "f"
-#define MGN_ATM "g"
-#define MGN_auto_repair "h"
-#define MGN_boating "I"
-#define MGN_camping "j"
-#define MGN_exit_ramp "k"
-#define MGN_first_aid "l"
-#define MGN_nav_aid "m"
-#define MGN_buoy "n"
-#define MGN_fuel "o"
-#define MGN_garden "p"
-#define MGN_golf "q"
-#define MGN_hotel "r"
-#define MGN_hunting_fishing "s"
-#define MGN_large_city "t"
-#define MGN_lighthouse "u"
-#define MGN_major_city "v"
-#define MGN_marina "w"
-#define MGN_medium_city "x"
-#define MGN_museum "y"
-#define MGN_obstruction "z"
-#define MGN_park "aa"
-#define MGN_resort "ab"
-#define MGN_restaurant "ac"
-#define MGN_rock "ad"
-#define MGN_scuba "ae"
-#define MGN_RV_service "af"
-#define MGN_shooting "ag"
-#define MGN_sight_seeing "ah"
-#define MGN_small_city "ai"
-#define MGN_sounding "aj"
-#define MGN_sports_arena "ak"
-#define MGN_tourist_info "al"
-#define MGN_truck_service "am"
-#define MGN_winery "an"
-#define MGN_wreck "ao"
-#define MGN_zoo "ap"
-
-
-/*
- * Mapping from APRS symbols to Magellan.
- *
- * This is a bit of a challenge because there 
- * are no icons for moving objects.
- * We can use airport for flying things but 
- * what about wheeled transportation devices?
- */
-
-// TODO:  NEEDS MORE WORK!!!
-
-
-#define MGN_default MGN_crossed_square
-
-#define SYMTAB_SIZE 95
-
-static const char mgn_primary_symtab[SYMTAB_SIZE][3] =  {
-
-	MGN_default,		//     00  	 --no-symbol--
-	MGN_default,		//  !  01  	 Police, Sheriff
-	MGN_default,		//  "  02  	 reserved  (was rain)
-	MGN_aerial,		//  #  03  	 DIGI (white center)
-	MGN_default,		//  $  04  	 PHONE
-	MGN_aerial,		//  %  05  	 DX CLUSTER
-	MGN_aerial,		//  &  06  	 HF GATEway
-	MGN_airport,		//  '  07  	 Small AIRCRAFT
-	MGN_aerial,		//  (  08  	 Mobile Satellite Station
-	MGN_default,		//  )  09  	 Wheelchair (handicapped)
-	MGN_default,		//  *  10  	 SnowMobile
-	MGN_default,		//  +  11  	 Red Cross
-	MGN_default,		//  ,  12  	 Boy Scouts
-	MGN_house,		//  -  13  	 House QTH (VHF)
-	MGN_default,		//  .  14  	 X
-	MGN_default,		//  /  15  	 Red Dot
-	MGN_default,		//  0  16  	 # circle (obsolete)
-	MGN_default,		//  1  17  	 TBD
-	MGN_default,		//  2  18  	 TBD
-	MGN_default,		//  3  19  	 TBD
-	MGN_default,		//  4  20  	 TBD
-	MGN_default,		//  5  21  	 TBD
-	MGN_default,		//  6  22  	 TBD
-	MGN_default,		//  7  23  	 TBD
-	MGN_default,		//  8  24  	 TBD
-	MGN_default,		//  9  25  	 TBD
-	MGN_default,		//  :  26  	 FIRE
-	MGN_camping,		//  ;  27  	 Campground (Portable ops)
-	MGN_default,		//  <  28  	 Motorcycle
-	MGN_default,		//  =  29  	 RAILROAD ENGINE
-	MGN_default,		//  >  30  	 CAR
-	MGN_default,		//  ?  31  	 SERVER for Files
-	MGN_default,		//  @  32  	 HC FUTURE predict (dot)
-	MGN_first_aid,		//  A  33  	 Aid Station
-	MGN_aerial,		//  B  34  	 BBS or PBBS
-	MGN_boating,		//  C  35  	 Canoe
-	MGN_default,		//  D  36  	 
-	MGN_default,		//  E  37  	 EYEBALL (Eye catcher!)
-	MGN_default,		//  F  38  	 Farm Vehicle (tractor)
-	MGN_default,		//  G  39  	 Grid Square (6 digit)
-	MGN_hotel,		//  H  40  	 HOTEL (blue bed symbol)
-	MGN_aerial,		//  I  41  	 TcpIp on air network stn
-	MGN_default,		//  J  42  	 
-	MGN_default,		//  K  43  	 School
-	MGN_default,		//  L  44  	 PC user
-	MGN_default,		//  M  45  	 MacAPRS
-	MGN_aerial,		//  N  46  	 NTS Station
-	MGN_airport,		//  O  47  	 BALLOON
-	MGN_default,		//  P  48  	 Police
-	MGN_default,		//  Q  49  	 TBD
-	MGN_RV_service,		//  R  50  	 REC. VEHICLE
-	MGN_airport,		//  S  51  	 SHUTTLE
-	MGN_default,		//  T  52  	 SSTV
-	MGN_default,		//  U  53  	 BUS
-	MGN_default,		//  V  54  	 ATV
-	MGN_default,		//  W  55  	 National WX Service Site
-	MGN_default,		//  X  56  	 HELO
-	MGN_boating,		//  Y  57  	 YACHT (sail)
-	MGN_default,		//  Z  58  	 WinAPRS
-	MGN_default,		//  [  59  	 Human/Person (HT)
-	MGN_default,		//  \  60  	 TRIANGLE(DF station)
-	MGN_default,		//  ]  61  	 MAIL/PostOffice(was PBBS)
-	MGN_airport,		//  ^  62  	 LARGE AIRCRAFT
-	MGN_default,		//  _  63  	 WEATHER Station (blue)
-	MGN_aerial,		//  `  64  	 Dish Antenna
-	MGN_default,		//  a  65  	 AMBULANCE
-	MGN_default,		//  b  66  	 BIKE
-	MGN_default,		//  c  67  	 Incident Command Post
-	MGN_default,		//  d  68  	 Fire dept
-	MGN_zoo,		//  e  69  	 HORSE (equestrian)
-	MGN_default,		//  f  70  	 FIRE TRUCK
-	MGN_airport,		//  g  71  	 Glider
-	MGN_default,		//  h  72  	 HOSPITAL
-	MGN_default,		//  i  73  	 IOTA (islands on the air)
-	MGN_default,		//  j  74  	 JEEP
-	MGN_default,		//  k  75  	 TRUCK
-	MGN_default,		//  l  76  	 Laptop
-	MGN_aerial,		//  m  77  	 Mic-E Repeater
-	MGN_default,		//  n  78  	 Node (black bulls-eye)
-	MGN_default,		//  o  79  	 EOC
-	MGN_zoo,		//  p  80  	 ROVER (puppy, or dog)
-	MGN_default,		//  q  81  	 GRID SQ shown above 128 m
-	MGN_aerial,		//  r  82  	 Repeater
-	MGN_default,		//  s  83  	 SHIP (pwr boat)
-	MGN_default,		//  t  84  	 TRUCK STOP
-	MGN_default,		//  u  85  	 TRUCK (18 wheeler)
-	MGN_default,		//  v  86  	 VAN
-	MGN_default,		//  w  87  	 WATER station
-	MGN_aerial,		//  x  88  	 xAPRS (Unix)
-	MGN_aerial,		//  y  89  	 YAGI @ QTH
-	MGN_default,		//  z  90  	 TBD
-	MGN_default,		//  {  91  	 
-	MGN_default,		//  |  92  	 TNC Stream Switch
-	MGN_default,		//  }  93  	 
-	MGN_default };		//  ~  94  	 TNC Stream Switch
-
-
-static const char mgn_alternate_symtab[SYMTAB_SIZE][3] =  {
-
-	MGN_default,		//     00  	 --no-symbol--
-	MGN_default,		//  !  01  	 EMERGENCY (!)
-	MGN_default,		//  "  02  	 reserved
-	MGN_aerial,		//  #  03  	 OVERLAY DIGI (green star)
-	MGN_ATM,		//  $  04  	 Bank or ATM  (green box)
-	MGN_default,		//  %  05  	 Power Plant with overlay
-	MGN_aerial,		//  &  06  	 I=Igte IGate R=RX T=1hopTX 2=2hopTX
-	MGN_default,		//  '  07  	 Crash (& now Incident sites)
-	MGN_default,		//  (  08  	 CLOUDY (other clouds w ovrly)
-	MGN_aerial,		//  )  09  	 Firenet MEO, MODIS Earth Obs.
-	MGN_default,		//  *  10  	 SNOW (& future ovrly codes)
-	MGN_default,		//  +  11  	 Church
-	MGN_default,		//  ,  12  	 Girl Scouts
-	MGN_house,		//  -  13  	 House (H=HF) (O = Op Present)
-	MGN_default,		//  .  14  	 Ambiguous (Big Question mark)
-	MGN_default,		//  /  15  	 Waypoint Destination
-	MGN_default,		//  0  16  	 CIRCLE (E/I/W=IRLP/Echolink/WIRES)
-	MGN_default,		//  1  17  	 
-	MGN_default,		//  2  18  	 
-	MGN_default,		//  3  19  	
-	MGN_default,		//  4  20  
-	MGN_default,		//  5  21 
-	MGN_default,		//  6  22
-	MGN_default,		//  7  23
-	MGN_aerial,		//  8  24  	 802.11 or other network node
-	MGN_fuel,		//  9  25  	 Gas Station (blue pump)
-	MGN_default,		//  :  26  	 Hail (& future ovrly codes)
-	MGN_park,		//  ;  27  	 Park/Picnic area
-	MGN_default,		//  <  28  	 ADVISORY (one WX flag)
-	MGN_default,		//  =  29  	 APRStt Touchtone (DTMF users)
-	MGN_default,		//  >  30  	 OVERLAID CAR
-	MGN_tourist_info,	//  ?  31  	 INFO Kiosk  (Blue box with ?)
-	MGN_default,		//  @  32  	 HURRICANE/Trop-Storm
-	MGN_box,		//  A  33  	 overlayBOX DTMF & RFID & XO
-	MGN_default,		//  B  34  	 Blwng Snow (& future codes)
-	MGN_boating,		//  C  35  	 Coast Guard
-	MGN_default,		//  D  36  	 Drizzle (proposed APRStt)
-	MGN_default,		//  E  37  	 Smoke (& other vis codes)
-	MGN_default,		//  F  38  	 Freezng rain (&future codes)
-	MGN_default,		//  G  39  	 Snow Shwr (& future ovrlys)
-	MGN_default,		//  H  40  	 Haze (& Overlay Hazards)
-	MGN_default,		//  I  41  	 Rain Shower
-	MGN_default,		//  J  42  	 Lightning (& future ovrlys)
-	MGN_default,		//  K  43  	 Kenwood HT (W)
-	MGN_lighthouse,		//  L  44  	 Lighthouse
-	MGN_default,		//  M  45  	 MARS (A=Army,N=Navy,F=AF)
-	MGN_buoy,		//  N  46  	 Navigation Buoy
-	MGN_airport,		//  O  47  	 Rocket
-	MGN_default,		//  P  48  	 Parking
-	MGN_default,		//  Q  49  	 QUAKE
-	MGN_restaurant,		//  R  50  	 Restaurant
-	MGN_aerial,		//  S  51  	 Satellite/Pacsat
-	MGN_default,		//  T  52  	 Thunderstorm
-	MGN_default,		//  U  53  	 SUNNY
-	MGN_nav_aid,		//  V  54  	 VORTAC Nav Aid
-	MGN_default,		//  W  55  	 # NWS site (NWS options)
-	MGN_default,		//  X  56  	 Pharmacy Rx (Apothicary)
-	MGN_aerial,		//  Y  57  	 Radios and devices
-	MGN_default,		//  Z  58  	 
-	MGN_default,		//  [  59  	 W.Cloud (& humans w Ovrly)
-	MGN_default,		//  \  60  	 New overlayable GPS symbol
-	MGN_default,		//  ]  61  	 
-	MGN_airport,		//  ^  62  	 # Aircraft (shows heading)
-	MGN_default,		//  _  63  	 # WX site (green digi)
-	MGN_default,		//  `  64  	 Rain (all types w ovrly)
-	MGN_aerial,		//  a  65  	 ARRL, ARES, WinLINK
-	MGN_default,		//  b  66  	 Blwng Dst/Snd (& others)
-	MGN_default,		//  c  67  	 CD triangle RACES/SATERN/etc
-	MGN_default,		//  d  68  	 DX spot by callsign
-	MGN_default,		//  e  69  	 Sleet (& future ovrly codes)
-	MGN_default,		//  f  70  	 Funnel Cloud
-	MGN_default,		//  g  71  	 Gale Flags
-	MGN_default,		//  h  72  	 Store. or HAMFST Hh=HAM store
-	MGN_box,		//  i  73  	 BOX or points of Interest
-	MGN_default,		//  j  74  	 WorkZone (Steam Shovel)
-	MGN_default,		//  k  75  	 Special Vehicle SUV,ATV,4x4
-	MGN_default,		//  l  76  	 Areas      (box,circles,etc)
-	MGN_default,		//  m  77  	 Value Sign (3 digit display)
-	MGN_default,		//  n  78  	 OVERLAY TRIANGLE
-	MGN_default,		//  o  79  	 small circle
-	MGN_default,		//  p  80  	 Prtly Cldy (& future ovrlys)
-	MGN_default,		//  q  81  	 
-	MGN_default,		//  r  82  	 Restrooms
-	MGN_default,		//  s  83  	 OVERLAY SHIP/boat (top view)
-	MGN_default,		//  t  84  	 Tornado
-	MGN_default,		//  u  85  	 OVERLAID TRUCK
-	MGN_default,		//  v  86  	 OVERLAID Van
-	MGN_default,		//  w  87  	 Flooding
-	MGN_wreck,		//  x  88  	 Wreck or Obstruction ->X<-
-	MGN_default,		//  y  89  	 Skywarn
-	MGN_default,		//  z  90  	 OVERLAID Shelter
-	MGN_default,		//  {  91  	 Fog (& future ovrly codes)
-	MGN_default,		//  |  92  	 TNC Stream Switch
-	MGN_default,		//  }  93  	 
-	MGN_default };		//  ~  94  	 TNC Stream Switch
-
diff --git a/mheard.h b/mheard.h
deleted file mode 100644
index f8466ba..0000000
--- a/mheard.h
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-/* mheard.h */
-
-#include "decode_aprs.h"	// for decode_aprs_t
-
-
-void mheard_init (int debug);
-
-void mheard_save_rf (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_t retries);
-
-void mheard_save_is (char *ptext);
-
-int mheard_count (int max_hops, int time_limit);
-
-int mheard_was_recently_nearby (char *role, char *callsign, int time_limit, int max_hops, double dlat, double dlon, double km);
-
-void mheard_set_msp (char *callsign, int num);
-
-int mheard_get_msp (char *callsign);
\ No newline at end of file
diff --git a/morse.h b/morse.h
deleted file mode 100644
index e34dd7b..0000000
--- a/morse.h
+++ /dev/null
@@ -1,8 +0,0 @@
-/* morse.h */
-
-int morse_init (struct audio_s *audio_config_p, int amp) ;
-
-int morse_send (int chan, char *str, int wpm, int txdelay, int txtail);
-
-#define MORSE_DEFAULT_WPM 10
-
diff --git a/multi_modem.h b/multi_modem.h
deleted file mode 100644
index de3061e..0000000
--- a/multi_modem.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* multi_modem.h */
-
-#ifndef MULTI_MODEM_H
-#define MULTI_MODEM 1
-
-/* Needed for typedef retry_t. */
-#include "hdlc_rec2.h"
-
-/* Needed for struct audio_s */
-#include "audio.h"
-
-
-void multi_modem_init (struct audio_s *pmodem); 
-
-void multi_modem_process_sample (int c, int audio_sample);
-
-int multi_modem_get_dc_average (int chan);
-
-// Deprecated.  Replace with ...packet
-void multi_modem_process_rec_frame (int chan, int subchan, int slice, unsigned char *fbuf, int flen, alevel_t alevel, retry_t retries, int is_fx25);
-
-void multi_modem_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, int is_fx25);
-
-#endif
diff --git a/pfilter.h b/pfilter.h
deleted file mode 100644
index d54e056..0000000
--- a/pfilter.h
+++ /dev/null
@@ -1,13 +0,0 @@
-
-/* pfilter.h */
-
-
-#include "igate.h"		// for igate_config_s
-
-
-
-void pfilter_init (struct igate_config_s *p_igate_config, int debug_level);
-
-int pfilter (int from_chan, int to_chan, char *filter, packet_t pp, int is_aprs);
-
-int is_telem_metadata (char *infop);
\ No newline at end of file
diff --git a/ptt.h b/ptt.h
deleted file mode 100644
index 6e75253..0000000
--- a/ptt.h
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-#ifndef PTT_H
-#define PTT_H 1
-
-
-#include "audio.h"	/* for struct audio_s and definitions for octype values */
-
-
-void ptt_set_debug(int debug);
-
-void ptt_init (struct audio_s *p_modem);
-
-void ptt_set (int octype, int chan, int ptt); 
-
-void ptt_term (void);
-
-int get_input (int it, int chan);
-
-#endif
-
-
-/* end ptt.h */
-
-
-
diff --git a/recv.h b/recv.h
deleted file mode 100644
index 3201991..0000000
--- a/recv.h
+++ /dev/null
@@ -1,6 +0,0 @@
-
-/* recv.h */
-
-void recv_init (struct audio_s *pa);
-
-void recv_process (void);
\ No newline at end of file
diff --git a/redecode.h b/redecode.h
deleted file mode 100644
index ffd9a95..0000000
--- a/redecode.h
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-#ifndef REDECODE_H
-#define REDECODE_H 1
-
-#include "rrbb.h"	
-
-
-extern void redecode_init (struct audio_s *p_audio_config);
-
-
-#endif
-
-/* end redecode.h */
-
diff --git a/release/moc_predefs-DESKTOP-MHE5LO8.h b/release/moc_predefs.h
similarity index 95%
rename from release/moc_predefs-DESKTOP-MHE5LO8.h
rename to release/moc_predefs.h
index 4c9c0c7..54e9037 100644
--- a/release/moc_predefs-DESKTOP-MHE5LO8.h
+++ b/release/moc_predefs.h
@@ -1,11 +1,11 @@
-#define _MSC_EXTENSIONS 
-#define _INTEGRAL_MAX_BITS 64
-#define _MSC_VER 1916
-#define _MSC_FULL_VER 191627043
-#define _MSC_BUILD 0
-#define _WIN32 
-#define _M_IX86 600
-#define _M_IX86_FP 2
-#define _CPPRTTI 
-#define _MT 
-#define _DLL 
+#define _MSC_EXTENSIONS 
+#define _INTEGRAL_MAX_BITS 64
+#define _MSC_VER 1916
+#define _MSC_FULL_VER 191627043
+#define _MSC_BUILD 0
+#define _WIN32 
+#define _M_IX86 600
+#define _M_IX86_FP 2
+#define _CPPRTTI 
+#define _MT 
+#define _DLL 
diff --git a/rpack.h b/rpack.h
deleted file mode 100644
index d972a54..0000000
--- a/rpack.h
+++ /dev/null
@@ -1,94 +0,0 @@
-
-/*------------------------------------------------------------------
- *
- * File:        rpack.h
- *
- * Purpose:   	Definition of Garmin Rino message format.
- *		
- * References:	http://www.radio-active.net.au/web3/APRS/Resources/RINO
- *
- *		http://www.radio-active.net.au/web3/APRS/Resources/RINO/OnAir
- *
- *---------------------------------------------------------------*/
-
-
-#ifndef RPACK_H
-#define RPACK_H 1
-
-
-#define RPACK_FRAME_LEN 168
-
-
-#ifdef RPACK_C		/* Expose private details */
-
-
- 
-// Transmission order is LSB first. 
-
-struct __attribute__((__packed__)) rpack_s {
-
-	int lat;		// Latitude.
-				// Signed integer.  Scaled by 2**30/90.
-
-	int lon;		// Longitude.  Same encoding.
-
-	char unknown1;		// Unproven theory: altitude.	
-	char unknown2;		
-
-	unsigned name0:6;	// 10 character name.
-	unsigned name1:6;	// Bit packing is implementation dependent.
-	unsigned name2:6;	// Should rewrite to be more portable.
-	unsigned name3:6;
-	unsigned name4:6;
-	unsigned name5:6;
-	unsigned name6:6;
-	unsigned name7:6;
-	unsigned name8:6;
-	unsigned name9:6;
-
-	unsigned symbol:5;	
-
-	unsigned unknown3:7;		
-				
-	
-//	unsigned crc:16;	// Safe bet this is CRC for error checking.
-
-	unsigned char crc1;
-	unsigned char crc2;
-
-	char dummy[3];		// Total size should be 24 bytes if no gaps.
-
-};
-
-#else			/* Show only public interface.  */
-
-
-struct rpack_s {
-	char stuff[24];
-};
-
-
-#endif
-
-
-
-void rpack_set_bit (struct rpack_s *rp, int position, int value);
-
-int rpack_is_valid (struct rpack_s *rp);
-
-int rpack_get_bit (struct rpack_s *rp, int position);
-
-double rpack_get_lat (struct rpack_s *rp);
-
-double rpack_get_lon (struct rpack_s *rp);
-
-int rpack_get_symbol (struct rpack_s *rp);
-
-void rpack_get_name (struct rpack_s *rp, char *str);
-
-
-
-#endif
-
-/* end rpack.h */
-	
diff --git a/rrbb.h b/rrbb.h
deleted file mode 100644
index 4b28372..0000000
--- a/rrbb.h
+++ /dev/null
@@ -1,92 +0,0 @@
-
-#ifndef RRBB_H
-
-#define RRBB_H
-
-
-#define FASTER13 1		// Don't pack 8 samples per byte.
-
-
-//typedef short slice_t;
-
-
-/* 
- * Maximum size (in bytes) of an AX.25 frame including the 2 octet FCS. 
- */
-
-#define MAX_FRAME_LEN ((AX25_MAX_PACKET_LEN) + 2)	
-
-/*
- * Maximum number of bits in AX.25 frame excluding the flags.
- * Adequate for extreme case of bit stuffing after every 5 bits
- * which could never happen.
- */
-
-#define MAX_NUM_BITS (MAX_FRAME_LEN * 8 * 6 / 5)
-
-typedef struct rrbb_s {
-	int magic1;
-	struct rrbb_s* nextp;	/* Next pointer to maintain a queue. */
-
-	int chan;		/* Radio channel from which it was received. */
-	int subchan;		/* Which modem when more than one per channel. */
-	int slice;		/* Which slicer. */
-
-	alevel_t alevel;	/* Received audio level at time of frame capture. */
-	unsigned int len;	/* Current number of samples in array. */
-
-	int is_scrambled;	/* Is data scrambled G3RUH / K9NG style? */
-	int descram_state;	/* Descrambler state before first data bit of frame. */
-	int prev_descram;	/* Previous descrambled bit. */
-
-	unsigned char fdata[MAX_NUM_BITS];
-
-	int magic2;
-} *rrbb_t;
-
-
-
-rrbb_t rrbb_new (int chan, int subchan, int slice, int is_scrambled, int descram_state, int prev_descram);
-
-void rrbb_clear (rrbb_t b, int is_scrambled, int descram_state, int prev_descram);
-
-
-static inline /*__attribute__((always_inline))*/ void rrbb_append_bit (rrbb_t b, const unsigned char val)
-{
-	if (b->len >= MAX_NUM_BITS) {
-	  return;	/* Silently discard if full. */
-	}
-	b->fdata[b->len] = val;
-	b->len++;
-}
-
-static inline /*__attribute__((always_inline))*/ unsigned char rrbb_get_bit (const rrbb_t b, const int ind)
-{
-	return (b->fdata[ind]);
-}
-
-
-void rrbb_chop8 (rrbb_t b);
-
-int rrbb_get_len (rrbb_t b);
-
-//void rrbb_flip_bit (rrbb_t b, unsigned int ind);
-
-void rrbb_delete (rrbb_t b);
-
-void rrbb_set_nextp (rrbb_t b, rrbb_t np);
-rrbb_t rrbb_get_nextp (rrbb_t b);
-
-int rrbb_get_chan (rrbb_t b);
-int rrbb_get_subchan (rrbb_t b);
-int rrbb_get_slice (rrbb_t b);
-
-void rrbb_set_audio_level (rrbb_t b, alevel_t alevel);
-alevel_t rrbb_get_audio_level (rrbb_t b);
-
-int rrbb_get_is_scrambled (rrbb_t b);
-int rrbb_get_descram_state (rrbb_t b);
-int rrbb_get_prev_descram (rrbb_t b);
-
-
-#endif
diff --git a/serial_port.h b/serial_port.h
deleted file mode 100644
index 8a65a0b..0000000
--- a/serial_port.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* serial_port.h */
-
-
-#ifndef SERIAL_PORT_H
-#define SERIAL_PORT_H 1
-
-
-#if __WIN32__
-
-#include 
-
-typedef HANDLE MYFDTYPE;
-#define MYFDERROR INVALID_HANDLE_VALUE
-
-#else
-
-typedef int MYFDTYPE;
-#define MYFDERROR (-1)
-
-#endif
-
-
-extern MYFDTYPE serial_port_open (char *devicename, int baud);
-
-extern int serial_port_write (MYFDTYPE fd, char *str, int len);
-
-extern int serial_port_get1 (MYFDTYPE fd);
-
-extern void serial_port_close (MYFDTYPE fd);
-
-
-#endif
\ No newline at end of file
diff --git a/server.h b/server.h
deleted file mode 100644
index 4cc2ea0..0000000
--- a/server.h
+++ /dev/null
@@ -1,32 +0,0 @@
-
-/* 
- * Name:	server.h
- */
-
-
-#include "ax25_pad.h"		/* for packet_t */
-
-#include "config.h"
-
-
-void server_set_debug (int n);
-
-void server_init (struct audio_s *audio_config_p, struct misc_config_s *misc_config);
-
-void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf,  int flen);
-
-void server_send_monitored (int chan, packet_t pp, int own_xmit);
-
-int server_callsign_registered_by_client (char *callsign);
-
-
-void server_link_established (int chan, int client, char *remote_call, char *own_call, int incoming);
-
-void server_link_terminated (int chan, int client, char *remote_call, char *own_call, int timeout);
-
-void server_rec_conn_data (int chan, int client, char *remote_call, char *own_call, int pid, char *data_ptr, int data_len);
-
-void server_outstanding_frames_reply (int chan, int client, char *own_call, char *remote_call, int count);
-
-
-/* end server.h */
diff --git a/sm_main.c b/sm_main.c
index 57bf549..d2c6cfd 100644
--- a/sm_main.c
+++ b/sm_main.c
@@ -27,7 +27,6 @@ void make_core_BPF(UCHAR snd_ch, short freq, short width);
 void make_core_TXBPF(UCHAR snd_ch, float freq, float width);
 void make_core_INTR(UCHAR snd_ch);
 void make_core_LPF(UCHAR snd_ch, short width);
-void wf_pointer(int snd_ch);
 void dw9600ProcessSample(int snd_ch, short Sample);
 void init_RUH48(int snd_ch);
 void init_RUH96(int snd_ch);
@@ -65,11 +64,8 @@ int TXPort = 8884;
 
 BOOL Firstwaterfall = 1;
 BOOL Secondwaterfall = 1;
-
 int multiCore = FALSE;
 
-
-
 BOOL MinOnStart  =  0;
 //RS TReedSolomon;
 //  Form1 TForm1;
@@ -728,7 +724,7 @@ void init_speed(int snd_ch)
 	  form1.show_freq_a;
 	  form1.show_freq_b;
 	  */
-	wf_pointer(snd_ch);
+	NeedWaterfallHeaders = TRUE;
 
 	CheckPSKWindows();
 }
@@ -863,6 +859,8 @@ void runModemthread(void * param)
 
 // I think this processes a buffer of samples
 
+int Toggle = 0;
+
 void BufferFull(short * Samples, int nSamples)			// These are Stereo Samples
 {
 	word i, i1, j;
@@ -1064,6 +1062,8 @@ void BufferFull(short * Samples, int nSamples)			// These are Stereo Samples
 
 		// Collect samples for both channels if needed
 
+		Toggle++;
+
 		Needed = FFTSize - fftCount;
 
 		if (Needed <= rx_bufsize)
@@ -1076,7 +1076,8 @@ void BufferFull(short * Samples, int nSamples)			// These are Stereo Samples
 				data1 += 2;
 			}
 
-			doWaterfall(FirstWaterfallChan);
+			if ((Toggle & 1) || (UsingBothChannels == 0))
+				doWaterfall(FirstWaterfallChan);
 
 			if (data2)
 			{
@@ -1085,9 +1086,13 @@ void BufferFull(short * Samples, int nSamples)			// These are Stereo Samples
 					*ptr2++ = *data2;
 					data2 += 2;
 				}
-				doWaterfall(1);
+				if (((Toggle & 1) == 0))
+					doWaterfall(1);
 			}
 
+			if (Firstwaterfall || Secondwaterfall)
+				displayWaterfall();
+
 			remainingSamples = rx_bufsize - Needed;
 			fftCount = 0;
 
diff --git a/symbols.h b/symbols.h
deleted file mode 100644
index 5ed91ad..0000000
--- a/symbols.h
+++ /dev/null
@@ -1,19 +0,0 @@
-
-/* symbols.h */
-
-void symbols_init (void);
-
-void symbols_list (void);
-
-void symbols_from_dest_or_src (char dti, char *src, char *dest, char *symtab, char *symbol);
-
-int symbols_into_dest (char symtab, char symbol, char *dest);
-
-void symbols_get_description (char symtab, char symbol, char *description, size_t desc_size);
-
-int symbols_code_from_description (char overlay, char *description, char *symtab, char *symbol);
-
-void symbols_to_tones (char symtab, char symbol, char *tones, size_t tonessize);
-
-
-/* end symbols.h */
diff --git a/telemetry.h b/telemetry.h
deleted file mode 100644
index 4ef9b62..0000000
--- a/telemetry.h
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-/* telemetry.h */
-
-void telemetry_data_original (char *station, char *info, int quiet, char *output, size_t outputsize, char *comment, size_t commentsize);
- 
-void telemetry_data_base91 (char *station, char *cdata, char *output, size_t outputsize);
- 
-void telemetry_name_message (char *station, char *msg);
- 
-void telemetry_unit_label_message (char *station, char *msg);
-
-void telemetry_coefficents_message (char *station, char *msg, int quiet);
-
-void telemetry_bit_sense_message (char *station, char *msg, int quiet);
diff --git a/tq.h b/tq.h
deleted file mode 100644
index 37599d5..0000000
--- a/tq.h
+++ /dev/null
@@ -1,41 +0,0 @@
-
-/*------------------------------------------------------------------
- *
- * Module:      tq.h
- *
- * Purpose:   	Transmit queue - hold packets for transmission until the channel is clear.
- *		
- *---------------------------------------------------------------*/
-
-#ifndef TQ_H
-#define TQ_H 1
-
-#include "ax25_pad.h"
-#include "audio.h"
-
-#define TQ_NUM_PRIO 2				/* Number of priorities. */
-
-#define TQ_PRIO_0_HI 0
-#define TQ_PRIO_1_LO 1
-
-
-
-void tq_init (struct audio_s *audio_config_p);
-
-void tq_append (int chan, int prio, packet_t pp);
-
-void lm_data_request (int chan, int prio, packet_t pp);
-
-void lm_seize_request (int chan);
-
-void tq_wait_while_empty (int chan);
-
-packet_t tq_remove (int chan, int prio);
-
-packet_t tq_peek (int chan, int prio);
-
-int tq_count (int chan, int prio, char *source, char *dest, int bytes);
-
-#endif
-
-/* end tq.h */
diff --git a/tt_text.h b/tt_text.h
deleted file mode 100644
index 7cab3b8..0000000
--- a/tt_text.h
+++ /dev/null
@@ -1,38 +0,0 @@
-
-/* tt_text.h */
-
-
-/* Encode normal human readable to DTMF representation. */
-
-int tt_text_to_multipress (const char *text, int quiet, char *buttons);
-
-int tt_text_to_two_key (const char *text, int quiet, char *buttons);
-
-int tt_text_to_call10 (const char *text, int quiet, char *buttons);
-
-int tt_text_to_mhead (const char *text, int quiet, char *buttons, size_t buttonsiz);
-
-int tt_text_to_satsq (const char *text, int quiet, char *buttons, size_t buttonsiz);
-
-int tt_text_to_ascii2d (const char *text, int quiet, char *buttons);
-
-
-/* Decode DTMF to normal human readable form. */
-
-int tt_multipress_to_text (const char *buttons, int quiet, char *text);
-
-int tt_two_key_to_text (const char *buttons, int quiet, char *text);
-
-int tt_call10_to_text (const char *buttons, int quiet, char *text);
-
-int tt_call5_suffix_to_text (const char *buttons, int quiet, char *text);
-
-int tt_mhead_to_text (const char *buttons, int quiet, char *text, size_t textsiz);
-
-int tt_satsq_to_text (const char *buttons, int quiet, char *text);
-
-int tt_ascii2d_to_text (const char *buttons, int quiet, char *text);
-
-
-
-/* end tt_text.h */
\ No newline at end of file
diff --git a/tt_user.h b/tt_user.h
deleted file mode 100644
index 4ff2ec8..0000000
--- a/tt_user.h
+++ /dev/null
@@ -1,15 +0,0 @@
-
-/* tt_user.h */
-
-
-#include "audio.h"
-
-void tt_user_init (struct audio_s *p_audio_config, struct tt_config_s *p);
-
-int tt_user_heard (char *callsign, int ssid, char overlay, char symbol, char *loc_text, double latitude, 
-		double longitude, int ambiguity, char *freq, char *ctcss, char *comment, char mic_e, char *dao);
-
-int tt_3char_suffix_search (char *suffix, char *callsign);
-
-void tt_user_background (void);
-void tt_user_dump (void);
\ No newline at end of file
diff --git a/tune.h b/tune.h
deleted file mode 100644
index 8d1c8b6..0000000
--- a/tune.h
+++ /dev/null
@@ -1 +0,0 @@
- 
diff --git a/version.h b/version.h
deleted file mode 100644
index a09490c..0000000
--- a/version.h
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/* Dire Wolf version 1.6 */
-
-// Put in destination field to identify the equipment used.
-
-#define APP_TOCALL "APDW"		// Assigned by WB4APR in tocalls.txt
-
-// This now comes from compile command line options.
-
-//#define MAJOR_VERSION 1
-//#define MINOR_VERSION 6
-//#define EXTRA_VERSION "Beta Test"
-
-
-// For user-defined data format.
-// APRS protocol spec Chapter 18 and http://www.aprs.org/aprs11/expfmts.txt
-
-#define USER_DEF_USER_ID 'D'		// user id D for direwolf
-
-#define USER_DEF_TYPE_AIS 'A'		// data type A for AIS NMEA sentence
-#define USER_DEF_TYPE_EAS 'E'		// data type E for EAS broadcasts
diff --git a/waypoint.h b/waypoint.h
deleted file mode 100644
index 3ba6f1c..0000000
--- a/waypoint.h
+++ /dev/null
@@ -1,24 +0,0 @@
-
-/* 
- * Name:	waypoint.h
- */
-
-
-#include "ax25_pad.h"		/* for packet_t */
-
-#include "config.h"		/* for struct misc_config_s */
-
-
-void waypoint_init (struct misc_config_s *misc_config);
-
-void waypoint_set_debug (int n);
-
-void waypoint_send_sentence (char *wname_in, double dlat, double dlong, char symtab, char symbol, 
-			float alt, float course, float speed, char *comment_in);
-
-void waypoint_send_ais (char *sentence);
-
-void waypoint_term ();
-
-
-/* end waypoint.h */
diff --git a/xid.h b/xid.h
deleted file mode 100644
index a221b73..0000000
--- a/xid.h
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-/* xid.h */
-
-
-#include "ax25_pad.h"		// for enum ax25_modulo_e
-
-
-struct xid_param_s {
-
-	int full_duplex;
-	
-	// Order is important because negotiation keeps the lower value of
-	// REJ  (srej_none),  SREJ (default without negotiation), Multi-SREJ (if both agree).
-
-	enum srej_e { srej_none=0, srej_single=1, srej_multi=2, srej_not_specified=3 } srej;
-
-	enum ax25_modulo_e modulo;
-
-	int i_field_length_rx;	/* In bytes.  XID has it in bits. */
-
-	int window_size_rx;
-
-	int ack_timer;		/* "T1" in mSec. */
-
-	int retries;		/* "N1" */
-};
-
-
-int xid_parse (unsigned char *info, int info_len, struct xid_param_s *result, char *desc, int desc_size);
-
-int xid_encode (struct xid_param_s *param, unsigned char *info, cmdres_t cr);
\ No newline at end of file
diff --git a/xmit.h b/xmit.h
deleted file mode 100644
index 248037d..0000000
--- a/xmit.h
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-#ifndef XMIT_H
-#define XMIT_H 1
-
-#include "audio.h"	/* for struct audio_s */
-
-
-extern void xmit_init (struct audio_s *p_modem, int debug_xmit_packet);
-
-extern void xmit_set_txdelay (int channel, int value);
-
-extern void xmit_set_persist (int channel, int value);
-
-extern void xmit_set_slottime (int channel, int value);
-
-extern void xmit_set_txtail (int channel, int value);
-
-extern void xmit_set_fulldup (int channel, int value);
-
-
-extern int xmit_speak_it (char *script, int c, char *msg);
-
-#endif
-
-/* end xmit.h */
-