From 3362a37672ccf859ff2514ae1d085ded0c36bb62 Mon Sep 17 00:00:00 2001
From: Joe Taylor <k1jt@arrl.org>
Date: Mon, 25 Mar 2013 01:24:47 +0000
Subject: [PATCH] Implemented CW ID. Signal reports 0 dB and above now
 displayed as "+03", "+16", etc.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3089 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
---
 devsetup.cpp       |  6 ++++++
 devsetup.h         |  6 ++----
 devsetup.ui        | 22 +++++++++++++++++++++-
 lib/Makefile.linux |  2 +-
 mainwindow.cpp     | 31 ++++++++++++++++++++++++++-----
 mainwindow.h       |  3 +++
 soundout.cpp       | 45 +++++++++++++++++++++++++++++++++++++--------
 7 files changed, 96 insertions(+), 19 deletions(-)

diff --git a/devsetup.cpp b/devsetup.cpp
index c16f679b1..89674e84f 100644
--- a/devsetup.cpp
+++ b/devsetup.cpp
@@ -130,6 +130,7 @@ void DevSetup::initDlg()
   ui.saveDirEntry->setText(m_saveDir);
   ui.comboBoxSndIn->setCurrentIndex(m_nDevIn);
   ui.comboBoxSndOut->setCurrentIndex(m_nDevOut);
+  ui.cbID73->setChecked(m_After73);
   ui.cbPSKReporter->setChecked(m_pskReporter);
   m_paInDevice=m_inDevList[m_nDevIn];
   m_paOutDevice=m_outDevList[m_nDevOut];
@@ -304,3 +305,8 @@ void DevSetup::on_rigComboBox_activated(int index)
   QString t=ui.rigComboBox->itemText(index);
   m_rig=t.mid(0,7).toInt();
 }
+
+void DevSetup::on_cbID73_toggled(bool checked)
+{
+  m_After73=checked;
+}
diff --git a/devsetup.h b/devsetup.h
index 9753be44b..0c7fd2683 100644
--- a/devsetup.h
+++ b/devsetup.h
@@ -39,6 +39,7 @@ public:
   bool    m_pskReporter;
   bool    m_firstCall;
   bool    m_catEnabled;
+  bool    m_After73;
 
   QString m_myCall;
   QString m_myGrid;
@@ -66,14 +67,11 @@ private slots:
   void on_catPortComboBox_activated(int index);
   void on_cbEnableCAT_toggled(bool checked);
   void on_serialRateComboBox_activated(int index);
-
   void on_handshakeComboBox_activated(int index);
-
   void on_dataBitsComboBox_activated(int index);
-
   void on_stopBitsComboBox_activated(int index);
-
   void on_rigComboBox_activated(int index);
+  void on_cbID73_toggled(bool checked);
 
 private:
   void msgBox(QString t);
diff --git a/devsetup.ui b/devsetup.ui
index 115bb3ec2..8fc18ba10 100644
--- a/devsetup.ui
+++ b/devsetup.ui
@@ -387,7 +387,7 @@
           <item>
            <widget class="QSpinBox" name="idIntSpinBox">
             <property name="enabled">
-             <bool>false</bool>
+             <bool>true</bool>
             </property>
             <property name="maximumSize">
              <size>
@@ -403,6 +403,26 @@
             </property>
            </widget>
           </item>
+          <item>
+           <spacer name="horizontalSpacer_7">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QCheckBox" name="cbID73">
+            <property name="text">
+             <string>ID after 73</string>
+            </property>
+           </widget>
+          </item>
           <item>
            <spacer name="horizontalSpacer_3">
             <property name="orientation">
diff --git a/lib/Makefile.linux b/lib/Makefile.linux
index 3fb152fa1..fe3320e5e 100644
--- a/lib/Makefile.linux
+++ b/lib/Makefile.linux
@@ -29,7 +29,7 @@ OBJS1 = pctile.o graycode.o sort.o ssort.o \
 	fil3.o redsync.o decoder.o grid2n.o n2grid.o timer.o \
 	decode9a.o peakdt9.o getlags.o afc9.o fchisq.o \
 	twkfreq.o downsam9.o symspec2.o ipcomm.o sleep_msec.o \
-	stdmsg.o sec_midn.o cutil.o azdist.o geodist.o
+	stdmsg.o sec_midn.o cutil.o azdist.o geodist.o morse.o
 
 libjt9.a: $(OBJS1)
 	ar cr libjt9.a $(OBJS1) 
diff --git a/mainwindow.cpp b/mainwindow.cpp
index b7e57adf7..38535632e 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -11,6 +11,7 @@
 #include "logqso.h"
 
 int itone[85];                        //Tx audio tones for 85 symbols
+int icw[250];                         //Dits for CW ID
 int rc;
 wchar_t buffer[256];
 bool btxok;                           //True if OK to transmit
@@ -146,6 +147,7 @@ MainWindow::MainWindow(QWidget *parent) :
   m_dataAvailable=false;
   m_iptt=0;
   m_COMportOpen=0;
+  m_secID=0;
   decodeBusy(false);
 
   ui->xThermo->setFillBrush(Qt::green);
@@ -326,6 +328,7 @@ void MainWindow::writeSettings()
   settings.setValue("Tol",m_tol);
   settings.setValue("InGain",m_inGain);
   settings.setValue("PSKReporter",m_pskReporter);
+  settings.setValue("After73",m_After73);
   settings.setValue("Macros",m_macro);
   settings.setValue("toRTTY",m_toRTTY);
   settings.setValue("NoSuffix",m_noSuffix);
@@ -364,6 +367,7 @@ void MainWindow::readSettings()
 
   settings.beginGroup("Common");
   m_myCall=settings.value("MyCall","").toString();
+  morse_(m_myCall.toAscii().data(),icw,&m_ncw,m_myCall.length());
   m_myGrid=settings.value("MyGrid","").toString();
   m_idInt=settings.value("IDint",0).toInt();
   m_pttMethodIndex=settings.value("PTTmethod",1).toInt();
@@ -407,6 +411,7 @@ void MainWindow::readSettings()
   m_monitorStartOFF=settings.value("MonitorOFF",false).toBool();
   ui->actionMonitor_OFF_at_startup->setChecked(m_monitorStartOFF);
   m_pskReporter=settings.value("PSKReporter",false).toBool();
+  m_After73=settings.value("After73",false).toBool();
   m_macro=settings.value("Macros","").toStringList();
   m_toRTTY=settings.value("toRTTY",false).toBool();
   ui->actionConvert_JT9_x_to_RTTY->setChecked(m_toRTTY);
@@ -519,6 +524,7 @@ void MainWindow::on_actionDeviceSetup_triggered()               //Setup Dialog
   dlg.m_nDevIn=m_nDevIn;
   dlg.m_nDevOut=m_nDevOut;
   dlg.m_pskReporter=m_pskReporter;
+  dlg.m_After73=m_After73;
   dlg.m_macro=m_macro;
   dlg.m_catEnabled=m_catEnabled;
   dlg.m_rig=m_rig;
@@ -578,6 +584,7 @@ void MainWindow::on_actionDeviceSetup_triggered()               //Setup Dialog
     }
 #endif
     m_pskReporter=dlg.m_pskReporter;
+    m_After73=dlg.m_After73;
 
     if(dlg.m_restartSoundIn) {
       soundInThread.quit();
@@ -1231,8 +1238,7 @@ void MainWindow::guiUpdate()
   int khsym=0;
 
   double tx1=0.0;
-//  double tx2=m_TRperiod;
-  double tx2=1.0 + 85.0*m_nsps/12000.0;
+  double tx2=1.0 + 85.0*m_nsps/12000.0 + icw[0]*2048.0/48000.0;
 
   if(!m_txFirst) {
     tx1 += m_TRperiod;
@@ -1252,6 +1258,7 @@ void MainWindow::guiUpdate()
     }
 
     if(bTxTime and m_iptt==0 and !btxMute) {
+      icw[0]=m_ncw;
 #define NEW
 #ifdef NEW
       //Raise PTT
@@ -1307,10 +1314,21 @@ void MainWindow::guiUpdate()
       f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append);
       QTextStream out(&f);
       out << QDateTime::currentDateTimeUtc().toString("hhmm")
-          << "  Transmitted:  " << t << endl;
+          << "  Transmitting:  " << t << endl;
       f.close();
     }
     QStringList w=t.split(" ",QString::SkipEmptyParts);
+    icw[0]=0;
+    if(m_After73 and (w[2]=="73" or itext!=0)) icw[0]=m_ncw;
+
+    if(m_idInt>0) {
+      int nmin=(m_sec0-m_secID)/60;
+      if(nmin >= m_idInt) {
+        icw[0]=m_ncw;
+        m_secID=m_sec0;
+      }
+    }
+
     QString t2=QDateTime::currentDateTimeUtc().toString("hhmm");
     if(itext==0 and w[1]==m_myCall) {
       t=w[2];
@@ -1618,8 +1636,11 @@ void MainWindow::doubleClickOnCall(bool shift, bool ctrl)
   if(rpt.indexOf("  ")==0) rpt="+" + rpt.mid(2,2);
   if(rpt.indexOf(" -")==0) rpt=rpt.mid(1,2);
   if(rpt.indexOf(" ")==0) rpt="+" + rpt.mid(1,2);
-  if(rpt.toInt()<-50) rpt="-50";
-  if(rpt.toInt()>49) rpt="+49";
+  int nr=rpt.toInt();
+  if(nr<-50) rpt="-50";
+  if(nr>49) rpt="+49";
+  if(nr>=0 and nr<=9) rpt="+0" + rpt;
+  if(nr>=10) rpt="+" + rpt;
   genStdMsgs(rpt);
   if(t2.indexOf(m_myCall)>0) {
     m_ntx=2;
diff --git a/mainwindow.h b/mainwindow.h
index 2cde1eba8..57fa5bdb2 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -207,6 +207,7 @@ private:
     bool    m_toRTTY;
     bool    m_dBtoComments;
     bool    m_catEnabled;
+    bool    m_After73;
 
     char    m_decoded[80];
 
@@ -304,6 +305,8 @@ bool stdmsg_(const char* msg);
 void azdist_(char* MyGrid, char* HisGrid, double* utch, int* nAz, int* nEl,
              int* nDmiles, int* nDkm, int* nHotAz, int* nHotABetter,
              int len1, int len2);
+
+void morse_(char* msg, int* icw, int* ncw, int len);
 }
 
 #endif // MAINWINDOW_H
diff --git a/soundout.cpp b/soundout.cpp
index 2ada27eb1..5ca186c23 100644
--- a/soundout.cpp
+++ b/soundout.cpp
@@ -8,6 +8,7 @@ extern "C" {
 
 extern float gran();                  //Noise generator (for tests only)
 extern int itone[85];                 //Tx audio tones for 85 symbols
+extern int icw[250];                  //Dits for CW ID
 extern bool btxok;
 extern bool btxMute;
 extern double outputLatency;
@@ -40,7 +41,7 @@ extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
   static double freq;
   static double snr;
   static double fac;
-  static int ic=0;
+  static int ic=0,j=0;
   static short int i2;
   int isym;
 
@@ -55,16 +56,46 @@ extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
     srand(mstr);                                //Initialize random seed
   }
   isym=ic/(4*udata->nsps);                      //Actual fsample=48000
-  if(isym>=85) return 1;
-  baud=12000.0/udata->nsps;
-  freq=udata->ntxfreq + itone[isym]*baud;
-  dphi=twopi*freq/48000.0;
   if(udata->txsnrdb < 0.0) {
     snr=pow(10.0,0.05*(udata->txsnrdb-6.0));
     fac=3000.0;
     if(snr>1.0) fac=3000.0/snr;
   }
 
+  if(isym>=85 and icw[0]>0) {              //Output the CW ID
+    freq=udata->ntxfreq;
+    dphi=twopi*freq/48000.0;
+//    float wpm=20.0;
+//    int nspd=1.2*48000.0/wpm;
+    int nspd=3072;                         //18.75 wpm
+    nspd=2048;
+    int ic0=85*4*udata->nsps;
+    for(int i=0 ; i<framesToProcess; i++ )  {
+      phi += dphi;
+      if(phi>twopi) phi -= twopi;
+      i2=32767.0*sin(phi);
+      j=(ic-ic0)/nspd;
+      if(icw[j]==0) i2=0;
+      if(udata->txsnrdb < 0.0) {
+        int i4=fac*(gran() + i2*snr/32768.0);
+        if(i4>32767) i4=32767;
+        if(i4<-32767) i4=-32767;
+        i2=i4;
+      }
+      if(!btxok or btxMute)  i2=0;
+      *wptr++ = i2;                   //left
+#ifdef unix
+      *wptr++ = i2;                   //right
+#endif
+      ic++;
+    }
+    return paContinue;
+  }
+
+  if(isym>=85 and itone[0]>=0) return paComplete;
+  baud=12000.0/udata->nsps;
+  freq=udata->ntxfreq + itone[isym]*baud;
+  dphi=twopi*freq/48000.0;
   for(uint i=0 ; i<framesToProcess; i++ )  {
     phi += dphi;
     if(phi>twopi) phi -= twopi;
@@ -80,11 +111,9 @@ extern "C" int d2aCallback(const void *inputBuffer, void *outputBuffer,
 #ifdef unix
     *wptr++ = i2;                   //right
 #endif
-
     ic++;
   }
-  //qDebug() << "PA Callback";
-  return 0;
+  return paContinue;
 }
 
 void SoundOutThread::run()