From dea0ee902486c75f77098635660747fde86e8c1f Mon Sep 17 00:00:00 2001 From: Stelios Bounanos Date: Sat, 22 Nov 2008 01:32:17 +0000 Subject: [PATCH 1/2] Upstream version 3.04BD --- configure.ac | 2 +- src/Makefile.am | 4 + src/dialogs/Viewer.cxx | 4 + src/dialogs/confdialog.cxx | 226 ++++++++- src/dialogs/confdialog.fl | 197 +++++++- src/dialogs/fl_digi.cxx | 295 +++++++---- src/globals/globals.cxx | 34 +- src/include/FTextView.h | 1 + src/include/confdialog.h | 12 +- src/include/configuration.h | 9 +- src/include/debug.h | 1 + src/include/fl_digi.h | 9 +- src/include/fldigi-config.h | 2 + src/include/pixmaps.h | 1 + src/include/pskrep.h | 8 + src/include/re.h | 20 +- src/include/socket.h | 6 +- src/include/spot.h | 48 ++ src/include/status.h | 4 +- src/include/util.h | 5 + src/logger/logger.cxx | 167 +++++-- src/main.cxx | 6 + src/misc/configuration.cxx | 1 + src/misc/lookupcall.cxx | 66 ++- src/misc/network.cxx | 2 +- src/misc/pixmaps.cxx | 26 + src/misc/re.cxx | 18 +- src/misc/socket.cxx | 34 +- src/misc/status.cxx | 12 +- src/misc/util.cxx | 20 +- src/olivia/olivia.cxx | 6 +- src/psk/viewpsk.cxx | 4 +- src/rigcontrol/hamlib.cxx | 2 +- src/rigcontrol/rigsupport.cxx | 30 +- src/spot/pskrep.cxx | 906 ++++++++++++++++++++++++++++++++++ src/spot/spot.cxx | 203 ++++++++ src/trx/trx.cxx | 4 +- src/widgets/FTextView.cxx | 12 + 38 files changed, 2147 insertions(+), 260 deletions(-) create mode 100644 src/include/pskrep.h create mode 100644 src/include/spot.h create mode 100644 src/spot/pskrep.cxx create mode 100644 src/spot/spot.cxx diff --git a/configure.ac b/configure.ac index 4aeabda1..5cdcaa85 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,7 @@ dnl major and minor must be integers; patch may dnl contain other characters or be empty m4_define(FLDIGI_MAJOR, [3]) m4_define(FLDIGI_MINOR, [0]) -m4_define(FLDIGI_PATCH, [4BC]) +m4_define(FLDIGI_PATCH, [4BD]) AC_INIT([fldigi], FLDIGI_MAJOR.FLDIGI_MINOR[FLDIGI_PATCH], [w1hkj AT w1hkj DOT com]) diff --git a/src/Makefile.am b/src/Makefile.am index 50b2e9d6..aa5e3045 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -212,6 +212,7 @@ fldigi_SOURCES += \ include/pskeval.h \ include/ptt.h \ include/pixmaps.h \ + include/pskrep.h \ include/qrunner.h \ include/lookupcall.h \ include/qrzlib.h \ @@ -230,6 +231,7 @@ fldigi_SOURCES += \ include/socket.h \ include/sound.h \ include/soundconf.h \ + include/spot.h \ include/stacktrace.h \ include/status.h \ include/testmodem.h \ @@ -302,6 +304,8 @@ fldigi_SOURCES += \ soundcard/mixer.cxx \ soundcard/sound.cxx \ soundcard/soundconf.cxx \ + spot/pskrep.cxx \ + spot/spot.cxx \ throb/throb.cxx \ trx/modem.cxx \ trx/trx.cxx \ diff --git a/src/dialogs/Viewer.cxx b/src/dialogs/Viewer.cxx index 4e8ed3f7..ad16ad1c 100644 --- a/src/dialogs/Viewer.cxx +++ b/src/dialogs/Viewer.cxx @@ -10,6 +10,7 @@ #include "waterfall.h" #include "fl_digi.h" #include "re.h" +#include "spot.h" #include #include @@ -350,6 +351,9 @@ void viewer_redraw() void viewaddchr(int ch, int freq, char c) { if (!dlgViewer) return; + if (progStatus.spot_recv) + spot_recv(c, ch, freq); + if (rfc != wf->rfcarrier() || usb != wf->USB()) viewer_redraw(); static string nuline; diff --git a/src/dialogs/confdialog.cxx b/src/dialogs/confdialog.cxx index 0286d20a..c451f92d 100644 --- a/src/dialogs/confdialog.cxx +++ b/src/dialogs/confdialog.cxx @@ -12,6 +12,7 @@ #include "lookupcall.h" #include "icons.h" #include "Viewer.h" +#include "pskrep.h" extern void initViewer(); Fl_Double_Window *dlgConfig; @@ -156,6 +157,65 @@ static void cb_btnStartAtSweetSpot(Fl_Check_Button* o, void*) { progdefaults.changed = true; } +Fl_Group *tabSpot=(Fl_Group *)0; + +Fl_Check_Button *btnPSKRepAuto=(Fl_Check_Button *)0; + +static void cb_btnPSKRepAuto(Fl_Check_Button* o, void*) { + progdefaults.pskrep_auto = o->value(); +btnPSKRepInit->labelcolor(FL_RED); +btnPSKRepInit->redraw_label(); +progdefaults.changed = true; +} + +Fl_Check_Button *btnPSKRepLog=(Fl_Check_Button *)0; + +static void cb_btnPSKRepLog(Fl_Check_Button* o, void*) { + progdefaults.pskrep_log = o->value(); +btnPSKRepInit->labelcolor(FL_RED); +btnPSKRepInit->redraw_label(); +progdefaults.changed = true; +} + +Fl_Input *inpPSKRepHost=(Fl_Input *)0; + +static void cb_inpPSKRepHost(Fl_Input* o, void*) { + progdefaults.pskrep_host = o->value(); +btnPSKRepInit->labelcolor(FL_RED); +btnPSKRepInit->redraw_label(); +progdefaults.changed = true; +} + +Fl_Input *inpPSKRepPort=(Fl_Input *)0; + +static void cb_inpPSKRepPort(Fl_Input* o, void*) { + progdefaults.pskrep_port = o->value(); +btnPSKRepInit->labelcolor(FL_RED); +btnPSKRepInit->redraw_label(); +progdefaults.changed = true; +} + +Fl_Button *btnPSKRepInit=(Fl_Button *)0; + +static void cb_btnPSKRepInit(Fl_Button* o, void*) { + pskrep_stop(); +if (!pskrep_start()) + boxPSKRepMsg->copy_label(pskrep_error()); +else { + boxPSKRepMsg->label(0); + o->labelcolor(FL_FOREGROUND_COLOR); +}; +} + +Fl_Box *boxPSKRepMsg=(Fl_Box *)0; + +Fl_Check_Button *btnPSKRepQRG=(Fl_Check_Button *)0; + +static void cb_btnPSKRepQRG(Fl_Check_Button* o, void*) { + progdefaults.pskrep_qrg = o->value(); +progdefaults.changed = true; +} + Fl_Group *tabModems=(Fl_Group *)0; Fl_Tabs *tabsModems=(Fl_Tabs *)0; @@ -762,6 +822,13 @@ static void cb_nbrContestDigits(Fl_Value_Input* o, void*) { progdefaults.changed = true; } +Fl_Input *inpMyAntenna=(Fl_Input *)0; + +static void cb_inpMyAntenna(Fl_Input* o, void*) { + progdefaults.myAntenna = o->value(); +progdefaults.changed = true; +} + Fl_Group *tabQRZ=(Fl_Group *)0; Fl_Round_Button *btnQRZnotavailable=(Fl_Round_Button *)0; @@ -858,43 +925,56 @@ static void cb_btnPTT1(Fl_Round_Button* o, void*) { btnRigCatRTSptt->value(0); btnRigCatDTRptt->value(0); } +btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); progdefaults.changed = true; } Fl_Round_Button *btnRTSptt=(Fl_Round_Button *)0; static void cb_btnRTSptt(Fl_Round_Button*, void*) { - progdefaults.changed = true; + btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true; } Fl_Round_Button *btnDTRptt=(Fl_Round_Button *)0; static void cb_btnDTRptt(Fl_Round_Button*, void*) { - progdefaults.changed = true; + btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true; } Fl_Round_Button *btnRTSplusV=(Fl_Round_Button *)0; static void cb_btnRTSplusV(Fl_Round_Button*, void*) { - progdefaults.changed = true; + btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true; } Fl_Round_Button *btnDTRplusV=(Fl_Round_Button *)0; static void cb_btnDTRplusV(Fl_Round_Button*, void*) { - progdefaults.changed = true; + btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true; } Fl_Input_Choice *inpTTYdev=(Fl_Input_Choice *)0; static void cb_inpTTYdev(Fl_Input_Choice*, void*) { - progdefaults.changed = true; + btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true; } Fl_Button *btnInitHWPTT=(Fl_Button *)0; -static void cb_btnInitHWPTT(Fl_Button*, void*) { +static void cb_btnInitHWPTT(Fl_Button* o, void*) { progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true; } @@ -924,6 +1004,8 @@ static void cb_chkUSERIGCAT(Fl_Check_Button* o, void*) { progdefaults.chkUSERIGCATis = false; } for (int i = 0; i < 4; btnPTT[i++]->redraw()); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -936,6 +1018,8 @@ static void cb_btnPTT2(Fl_Round_Button* o, void*) { btnPTT[2]->value(0); btnPTT[4]->value(0); } +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -944,13 +1028,17 @@ Fl_Output *txtXmlRigFilename=(Fl_Output *)0; Fl_Button *btnSelectRigXmlFile=(Fl_Button *)0; static void cb_btnSelectRigXmlFile(Fl_Button*, void*) { - selectRigXmlFilename(); + btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); +selectRigXmlFilename(); } Fl_Input_Choice *inpXmlRigDevice=(Fl_Input_Choice *)0; static void cb_inpXmlRigDevice(Fl_Input_Choice* o, void*) { progdefaults.XmlRigDevice = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -958,6 +1046,8 @@ Fl_Choice *mnuXmlRigBaudrate=(Fl_Choice *)0; static void cb_mnuXmlRigBaudrate(Fl_Choice* o, void*) { progdefaults.XmlRigBaudrate = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -974,6 +1064,8 @@ static void cb_btnRigCatRTSptt(Fl_Round_Button* o, void*) { progdefaults.RigCatRTSptt = true; } else progdefaults.RigCatRTSptt = false; +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -990,6 +1082,8 @@ static void cb_btnRigCatDTRptt(Fl_Round_Button* o, void*) { progdefaults.RigCatDTRptt = true; } else progdefaults.RigCatDTRptt = false; +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -997,6 +1091,8 @@ Fl_Check_Button *btnRigCatRTSplus=(Fl_Check_Button *)0; static void cb_btnRigCatRTSplus(Fl_Check_Button* o, void*) { progdefaults.RigCatRTSplus = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -1004,6 +1100,8 @@ Fl_Check_Button *btnRigCatDTRplus=(Fl_Check_Button *)0; static void cb_btnRigCatDTRplus(Fl_Check_Button* o, void*) { progdefaults.RigCatDTRplus = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -1011,6 +1109,8 @@ Fl_Counter *cntRigCatRetries=(Fl_Counter *)0; static void cb_cntRigCatRetries(Fl_Counter* o, void*) { progdefaults.RigCatRetries = (int)o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -1018,18 +1118,25 @@ Fl_Counter *cntRigCatTimeout=(Fl_Counter *)0; static void cb_cntRigCatTimeout(Fl_Counter* o, void*) { progdefaults.RigCatTimeout = (int)o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); +progdefaults.changed = true; } Fl_Counter *cntRigCatWait=(Fl_Counter *)0; static void cb_cntRigCatWait(Fl_Counter* o, void*) { progdefaults.RigCatWait = (int)o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); +progdefaults.changed = true; } Fl_Button *btnInitRIGCAT=(Fl_Button *)0; -static void cb_btnInitRIGCAT(Fl_Button*, void*) { +static void cb_btnInitRIGCAT(Fl_Button* o, void*) { progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true; } @@ -1037,6 +1144,8 @@ Fl_Check_Button *chkRigCatRTSCTSflow=(Fl_Check_Button *)0; static void cb_chkRigCatRTSCTSflow(Fl_Check_Button* o, void*) { progdefaults.RigCatRTSCTSflow = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true; } @@ -1066,6 +1175,8 @@ static void cb_chkUSEHAMLIB(Fl_Check_Button* o, void*) { progdefaults.chkUSEHAMLIBis = false; } for (int i = 0; i < 4; btnPTT[i++]->redraw()); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } @@ -1078,19 +1189,25 @@ static void cb_btnPTT3(Fl_Round_Button* o, void*) { btnRigCatRTSptt->value(0); btnRigCatDTRptt->value(0); } +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } Fl_ComboBox *cboHamlibRig=(Fl_ComboBox *)0; static void cb_cboHamlibRig(Fl_ComboBox*, void*) { - progdefaults.changed = true; + btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); +progdefaults.changed = true; } Fl_Input_Choice *inpRIGdev=(Fl_Input_Choice *)0; static void cb_inpRIGdev(Fl_Input_Choice* o, void*) { progdefaults.HamRigDevice = o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } @@ -1098,13 +1215,16 @@ Fl_Choice *mnuBaudRate=(Fl_Choice *)0; static void cb_mnuBaudRate(Fl_Choice* o, void*) { progdefaults.HamRigBaudrate = o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } Fl_Button *btnInitHAMLIB=(Fl_Button *)0; -static void cb_btnInitHAMLIB(Fl_Button*, void*) { +static void cb_btnInitHAMLIB(Fl_Button* o, void*) { progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true; } @@ -1112,6 +1232,8 @@ Fl_Counter *cntHamlibtRetries=(Fl_Counter *)0; static void cb_cntHamlibtRetries(Fl_Counter* o, void*) { progdefaults.HamlibRetries = (int)o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } @@ -1119,18 +1241,26 @@ Fl_Counter *cntHamlibTimeout=(Fl_Counter *)0; static void cb_cntHamlibTimeout(Fl_Counter* o, void*) { progdefaults.HamlibTimeout = (int)o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); +progdefaults.changed = true; } Fl_Counter *cntHamlibWait=(Fl_Counter *)0; static void cb_cntHamlibWait(Fl_Counter* o, void*) { progdefaults.HamlibWait = (int)o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); +progdefaults.changed = true; } Fl_Check_Button *btnHamlibDTRplus=(Fl_Check_Button *)0; static void cb_btnHamlibDTRplus(Fl_Check_Button* o, void*) { progdefaults.HamlibDTRplus = o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } @@ -1142,6 +1272,8 @@ if (o->value() == 1) { chkHamlibRTSCTSflow->value(0); progdefaults.HamlibRTSCTSflow = false; } +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } @@ -1154,6 +1286,8 @@ if (o->value() == 1) { chkHamlibXONXOFFflow->value(0); progdefaults.HamlibXONXOFFflow = false; } +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } @@ -1165,6 +1299,8 @@ if (o->value() == 1) { chkHamlibRTSCTSflow->value(0); progdefaults.HamlibRTSCTSflow = false; } +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } @@ -1172,6 +1308,8 @@ Fl_Input *inpHamlibConfig=(Fl_Input *)0; static void cb_inpHamlibConfig(Fl_Input* o, void*) { progdefaults.HamConfig = o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true; } @@ -1199,6 +1337,8 @@ static void cb_chkUSEMEMMAP(Fl_Check_Button* o, void*) { progdefaults.chkUSEMEMMAPis = false; } for (int i = 0; i < 4; btnPTT[i++]->redraw()); +btnInitMEMMAP->labelcolor(FL_RED); +btnInitMEMMAP->redraw(); progdefaults.changed = true; } @@ -1211,13 +1351,16 @@ static void cb_btnPTT4(Fl_Round_Button* o, void*) { btnRigCatRTSptt->value(0); btnRigCatDTRptt->value(0); } +btnInitMEMMAP->labelcolor(FL_RED); +btnInitMEMMAP->redraw(); progdefaults.changed = true; } Fl_Button *btnInitMEMMAP=(Fl_Button *)0; -static void cb_btnInitMEMMAP(Fl_Button*, void*) { +static void cb_btnInitMEMMAP(Fl_Button* o, void*) { progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true; } @@ -1241,13 +1384,16 @@ static void cb_chkUSEXMLRPC(Fl_Check_Button* o, void*) { progdefaults.chkUSEXMLRPCis = false; } for (int i = 0; i < 4; btnPTT[i++]->redraw()); +btnInitXMLRPC->labelcolor(FL_RED); +btnInitXMLRPC->redraw(); progdefaults.changed = true; } Fl_Button *btnInitXMLRPC=(Fl_Button *)0; -static void cb_btnInitXMLRPC(Fl_Button*, void*) { +static void cb_btnInitXMLRPC(Fl_Button* o, void*) { progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true; } @@ -1809,7 +1955,7 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 o->selection_color((Fl_Color)51); o->labelsize(18); o->align(FL_ALIGN_CLIP|FL_ALIGN_INSIDE); - { tabsConfigure = new Fl_Tabs(0, 0, 405, 221); + { tabsConfigure = new Fl_Tabs(0, 0, 405, 225); tabsConfigure->color(FL_DARK1); tabsConfigure->selection_color((Fl_Color)9); { tabID = new Fl_Group(0, 25, 400, 195, "Id\'s"); @@ -1899,11 +2045,11 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 } // Fl_Group* o tabID->end(); } // Fl_Group* tabID - { tabMisc = new Fl_Group(0, 25, 400, 195, "Misc"); + { tabMisc = new Fl_Group(0, 25, 405, 200, "Misc"); tabMisc->color((Fl_Color)51); tabMisc->selection_color((Fl_Color)51); tabMisc->hide(); - { tabsMisc = new Fl_Tabs(0, 25, 400, 195); + { tabsMisc = new Fl_Tabs(0, 25, 405, 200); tabsMisc->selection_color((Fl_Color)10); { tabCPUspeed = new Fl_Group(0, 50, 400, 170, "CPU"); tabCPUspeed->hide(); @@ -1940,6 +2086,7 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 tabMacros->end(); } // Fl_Group* tabMacros { tabSweetSpot = new Fl_Group(0, 50, 400, 170, "Sweet Spot"); + tabSweetSpot->hide(); { Fl_Group* o = new Fl_Group(5, 60, 390, 75); o->box(FL_ENGRAVED_FRAME); o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); @@ -1977,6 +2124,46 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 } // Fl_Group* o tabSweetSpot->end(); } // Fl_Group* tabSweetSpot + { tabSpot = new Fl_Group(2, 55, 403, 170, "Spotting"); + { Fl_Group* o = new Fl_Group(2, 57, 395, 160, "PSK Reporter"); + o->box(FL_ENGRAVED_FRAME); + o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE); + { btnPSKRepAuto = new Fl_Check_Button(15, 80, 324, 20, "Automatically spot callsigns in decoded text"); + btnPSKRepAuto->down_box(FL_DOWN_BOX); + btnPSKRepAuto->callback((Fl_Callback*)cb_btnPSKRepAuto); + btnPSKRepAuto->value(progdefaults.pskrep_auto); + } // Fl_Check_Button* btnPSKRepAuto + { btnPSKRepLog = new Fl_Check_Button(15, 104, 327, 20, "Send reception report when logging a QSO"); + btnPSKRepLog->down_box(FL_DOWN_BOX); + btnPSKRepLog->callback((Fl_Callback*)cb_btnPSKRepLog); + btnPSKRepLog->value(progdefaults.pskrep_log); + } // Fl_Check_Button* btnPSKRepLog + { inpPSKRepHost = new Fl_Input(55, 155, 220, 24, "Host:"); + inpPSKRepHost->callback((Fl_Callback*)cb_inpPSKRepHost); + inpPSKRepHost->when(FL_WHEN_CHANGED); + inpPSKRepHost->value(progdefaults.pskrep_host.c_str()); + } // Fl_Input* inpPSKRepHost + { inpPSKRepPort = new Fl_Input(322, 155, 60, 24, "Port:"); + inpPSKRepPort->callback((Fl_Callback*)cb_inpPSKRepPort); + inpPSKRepPort->when(FL_WHEN_CHANGED); + inpPSKRepPort->value(progdefaults.pskrep_port.c_str()); + } // Fl_Input* inpPSKRepPort + { btnPSKRepInit = new Fl_Button(303, 186, 80, 24, "Initialize"); + btnPSKRepInit->callback((Fl_Callback*)cb_btnPSKRepInit); + } // Fl_Button* btnPSKRepInit + { boxPSKRepMsg = new Fl_Box(56, 186, 220, 24, ""); + boxPSKRepMsg->labelfont(2); + boxPSKRepMsg->label(0); + } // Fl_Box* boxPSKRepMsg + { btnPSKRepQRG = new Fl_Check_Button(15, 128, 357, 20, "Report QRG (enable only if you have rig control!)"); + btnPSKRepQRG->down_box(FL_DOWN_BOX); + btnPSKRepQRG->callback((Fl_Callback*)cb_btnPSKRepQRG); + btnPSKRepQRG->value(progdefaults.pskrep_qrg); + } // Fl_Check_Button* btnPSKRepQRG + o->end(); + } // Fl_Group* o + tabSpot->end(); + } // Fl_Group* tabSpot tabsMisc->end(); } // Fl_Tabs* tabsMisc tabMisc->end(); @@ -2659,10 +2846,10 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 { inpMyCallsign = new Fl_Input(78, 36, 85, 24, "Callsign:"); inpMyCallsign->callback((Fl_Callback*)cb_inpMyCallsign); } // Fl_Input* inpMyCallsign - { inpMyName = new Fl_Input(78, 62, 120, 24, "Name:"); + { inpMyName = new Fl_Input(271, 36, 120, 24, "Name:"); inpMyName->callback((Fl_Callback*)cb_inpMyName); } // Fl_Input* inpMyName - { inpMyQth = new Fl_Input(78, 89, 312, 24, "Qth:"); + { inpMyQth = new Fl_Input(79, 63, 312, 24, "Qth:"); inpMyQth->callback((Fl_Callback*)cb_inpMyQth); } // Fl_Input* inpMyQth { inpMyLocator = new Fl_Input(78, 116, 85, 24, "Locator:"); @@ -2694,6 +2881,9 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 } // Fl_Value_Input* nbrContestDigits o->end(); } // Fl_Group* o + { inpMyAntenna = new Fl_Input(78, 89, 312, 24, "Antenna:"); + inpMyAntenna->callback((Fl_Callback*)cb_inpMyAntenna); + } // Fl_Input* inpMyAntenna tabOperator->end(); } // Fl_Group* tabOperator { tabQRZ = new Fl_Group(0, 25, 400, 195, "Qrz"); @@ -2765,6 +2955,7 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 o->selection_color((Fl_Color)10); { Fl_Group* o = new Fl_Group(0, 50, 400, 170, "H/W ptt"); o->tooltip("Tottle DTR for ptt"); + o->hide(); { btnPTT[0] = new Fl_Round_Button(15, 70, 74, 17, "none"); btnPTT[0]->down_box(FL_DIAMOND_DOWN_BOX); btnPTT[0]->value(1); @@ -3021,7 +3212,6 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 o->end(); } // Fl_Group* o { Fl_Group* o = new Fl_Group(0, 50, 400, 170, "MemMap"); - o->hide(); { chkUSEMEMMAP = new Fl_Check_Button(255, 135, 20, 20, "use Memmap"); chkUSEMEMMAP->tooltip("Select Memory Mapping rig control (Kachina)"); chkUSEMEMMAP->down_box(FL_DOWN_BOX); diff --git a/src/dialogs/confdialog.fl b/src/dialogs/confdialog.fl index 1005fc6f..53c9edc2 100644 --- a/src/dialogs/confdialog.fl +++ b/src/dialogs/confdialog.fl @@ -33,6 +33,9 @@ decl {\#include "icons.h"} {} decl {\#include "Viewer.h"} {} +decl {\#include "pskrep.h"} {global +} + decl {extern void initViewer();} {} decl {Fl_Double_Window *dlgConfig;} {public @@ -60,10 +63,10 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600 code {} {} Fl_Window {} { label {fldigi - config} open - tooltip {Leading/Trailing Risetimes (msec)} xywh {606 597 400 255} type Double color 45 selection_color 51 labelsize 18 align 80 visible + tooltip {Leading/Trailing Risetimes (msec)} xywh {546 58 400 255} type Double color 45 selection_color 51 labelsize 18 align 80 visible } { Fl_Tabs tabsConfigure {open - xywh {0 0 405 221} color 47 selection_color 9 + xywh {0 0 405 225} color 47 selection_color 9 } { Fl_Group tabID { label {Id's} open @@ -154,10 +157,10 @@ progdefaults.changed = true;} } Fl_Group tabMisc { label Misc open - xywh {0 25 400 195} color 51 selection_color 51 hide + xywh {0 25 405 200} color 51 selection_color 51 hide } { Fl_Tabs tabsMisc {open - xywh {0 25 400 195} selection_color 10 + xywh {0 25 405 200} selection_color 10 } { Fl_Group tabCPUspeed { label CPU open @@ -201,7 +204,7 @@ progdefaults.changed = true;} } Fl_Group tabSweetSpot { label {Sweet Spot} open - xywh {0 50 400 170} + xywh {0 50 400 170} hide } { Fl_Group {} {open xywh {5 60 390 75} box ENGRAVED_FRAME align 21 @@ -236,6 +239,75 @@ progdefaults.changed = true;} } } } + Fl_Group tabSpot { + label Spotting open + xywh {2 55 403 170} + } { + Fl_Group {} { + label {PSK Reporter} open + xywh {2 57 395 160} box ENGRAVED_FRAME align 21 + } { + Fl_Check_Button btnPSKRepAuto { + label {Automatically spot callsigns in decoded text} + callback {progdefaults.pskrep_auto = o->value(); +btnPSKRepInit->labelcolor(FL_RED); +btnPSKRepInit->redraw_label(); +progdefaults.changed = true;} + xywh {15 80 324 20} down_box DOWN_BOX + code0 {btnPSKRepAuto->value(progdefaults.pskrep_auto);} + } + Fl_Check_Button btnPSKRepLog { + label {Send reception report when logging a QSO} + callback {progdefaults.pskrep_log = o->value(); +btnPSKRepInit->labelcolor(FL_RED); +btnPSKRepInit->redraw_label(); +progdefaults.changed = true;} + xywh {15 104 327 20} down_box DOWN_BOX + code0 {btnPSKRepLog->value(progdefaults.pskrep_log);} + } + Fl_Input inpPSKRepHost { + label {Host:} + callback {progdefaults.pskrep_host = o->value(); +btnPSKRepInit->labelcolor(FL_RED); +btnPSKRepInit->redraw_label(); +progdefaults.changed = true;} + xywh {55 155 220 24} when 1 + code0 {inpPSKRepHost->value(progdefaults.pskrep_host.c_str());} + } + Fl_Input inpPSKRepPort { + label {Port:} + callback {progdefaults.pskrep_port = o->value(); +btnPSKRepInit->labelcolor(FL_RED); +btnPSKRepInit->redraw_label(); +progdefaults.changed = true;} + xywh {322 155 60 24} when 1 + code0 {inpPSKRepPort->value(progdefaults.pskrep_port.c_str());} + } + Fl_Button btnPSKRepInit { + label Initialize + callback {pskrep_stop(); +if (!pskrep_start()) + boxPSKRepMsg->copy_label(pskrep_error()); +else { + boxPSKRepMsg->label(0); + o->labelcolor(FL_FOREGROUND_COLOR); +}} + xywh {303 186 80 24} + } + Fl_Box boxPSKRepMsg { + label {} + xywh {56 186 220 24} labelfont 2 + code0 {boxPSKRepMsg->label(0);} + } + Fl_Check_Button btnPSKRepQRG { + label {Report QRG (enable only if you have rig control!)} + callback {progdefaults.pskrep_qrg = o->value(); +progdefaults.changed = true;} + xywh {15 128 357 20} down_box DOWN_BOX + code0 {btnPSKRepQRG->value(progdefaults.pskrep_qrg);} + } + } + } } } Fl_Group tabModems { @@ -918,13 +990,13 @@ progdefaults.changed = true;} label {Name:} callback {progdefaults.myName = o->value(); progdefaults.changed = true;} - xywh {78 62 120 24} + xywh {271 36 120 24} } Fl_Input inpMyQth { label {Qth:} callback {progdefaults.myQth = o->value(); progdefaults.changed = true;} - xywh {78 89 312 24} + xywh {79 63 312 24} } Fl_Input inpMyLocator { label {Locator:} @@ -955,6 +1027,12 @@ progdefaults.changed = true;} xywh {298 170 45 24} align 1 minimum 1 maximum 5 step 1 value 3 } } + Fl_Input inpMyAntenna { + label {Antenna:} + callback {progdefaults.myAntenna = o->value(); +progdefaults.changed = true;} + xywh {78 89 312 24} + } } Fl_Group tabQRZ { label Qrz open @@ -1048,7 +1126,7 @@ progdefaults.changed = true;} } { Fl_Group {} { label {H/W ptt} open - tooltip {Tottle DTR for ptt} xywh {0 50 400 170} + tooltip {Tottle DTR for ptt} xywh {0 50 400 170} hide } { Fl_Round_Button {btnPTT[0]} { label none @@ -1070,37 +1148,50 @@ progdefaults.changed = true;} btnRigCatRTSptt->value(0); btnRigCatDTRptt->value(0); } +btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); progdefaults.changed = true;} tooltip {PTT controlled via serial port} xywh {245 75 20 19} down_box DIAMOND_DOWN_BOX selection_color 1 align 4 } Fl_Round_Button btnRTSptt { label RTS - callback {progdefaults.changed = true;} + callback {btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true;} tooltip {Toggle RTS for ptt} xywh {100 160 54 15} down_box DOWN_BOX } Fl_Round_Button btnDTRptt { label DTR - callback {progdefaults.changed = true;} + callback {btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true;} xywh {100 180 59 15} down_box DOWN_BOX } Fl_Round_Button btnRTSplusV { label {RTS = +V} - callback {progdefaults.changed = true;} + callback {btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true;} tooltip {initial voltage on RTS} xywh {172 160 87 15} down_box DOWN_BOX } Fl_Round_Button btnDTRplusV { label {DTR = +V} - callback {progdefaults.changed = true;} + callback {btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true;} tooltip {Initial voltage on DTR} xywh {172 180 87 15} down_box DOWN_BOX } Fl_Input_Choice inpTTYdev { label {Port:} - callback {progdefaults.changed = true;} open + callback {btnInitHWPTT->labelcolor(FL_RED); +btnInitHWPTT->redraw(); +progdefaults.changed = true;} open tooltip {Select serial port} xywh {136 113 125 22} } {} Fl_Button btnInitHWPTT { label Initialize callback {progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true;} xywh {275 186 113 24} } @@ -1134,6 +1225,8 @@ progdefaults.changed = true;} progdefaults.chkUSERIGCATis = false; } for (int i = 0; i < 4; btnPTT[i++]->redraw()); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} tooltip {Select rigCAT for rig control} xywh {110 67 20 20} down_box DOWN_BOX } @@ -1147,6 +1240,8 @@ progdefaults.changed = true;} btnPTT[2]->value(0); btnPTT[4]->value(0); } +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} tooltip {use PTT data command} xywh {242 67 128 19} down_box DIAMOND_DOWN_BOX selection_color 1 deactivate } @@ -1157,12 +1252,16 @@ progdefaults.changed = true;} } Fl_Button btnSelectRigXmlFile { label Select - callback {selectRigXmlFilename();} + callback {btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); +selectRigXmlFilename();} tooltip {Select xml file for your rig} xywh {166 93 54 24} } Fl_Input_Choice inpXmlRigDevice { label Port callback {progdefaults.XmlRigDevice = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} open tooltip {Select the serial port} xywh {77 122 144 22} code0 {o->value(progdefaults.XmlRigDevice.c_str());} @@ -1170,6 +1269,8 @@ progdefaults.changed = true;} open Fl_Choice mnuXmlRigBaudrate { label {Baud Rate} callback {progdefaults.XmlRigBaudrate = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} open tooltip {Select the baud rate} xywh {122 147 99 22} down_box BORDER_BOX code0 {o->add(szBaudRates);} @@ -1187,6 +1288,8 @@ progdefaults.changed = true;} open progdefaults.RigCatRTSptt = true; } else progdefaults.RigCatRTSptt = false; +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} tooltip {toggle RTS for ptt} xywh {242 90 70 15} down_box ROUND_DOWN_BOX code0 {o->value(progdefaults.RigCatRTSptt);} @@ -1203,6 +1306,8 @@ progdefaults.changed = true;} progdefaults.RigCatDTRptt = true; } else progdefaults.RigCatDTRptt = false; +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} tooltip {toggle DTR for ptt} xywh {320 90 70 15} down_box ROUND_DOWN_BOX code0 {o->value(progdefaults.RigCatDTRptt);} @@ -1210,6 +1315,8 @@ progdefaults.changed = true;} Fl_Check_Button btnRigCatRTSplus { label {set RTS +12 v} callback {progdefaults.RigCatRTSplus = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} tooltip {initial state of RTS} xywh {242 110 35 15} down_box DOWN_BOX code0 {o->value(progdefaults.RigCatRTSplus);} @@ -1217,6 +1324,8 @@ progdefaults.changed = true;} Fl_Check_Button btnRigCatDTRplus { label {set DTR +12 v} callback {progdefaults.RigCatDTRplus = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} tooltip {initial state of DTR} xywh {242 130 35 15} down_box DOWN_BOX code0 {o->value(progdefaults.RigCatDTRplus);} @@ -1224,31 +1333,42 @@ progdefaults.changed = true;} Fl_Counter cntRigCatRetries { label Retries callback {progdefaults.RigCatRetries = (int)o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} tooltip {\# times to resend command before FAIL} xywh {15 188 75 21} type Simple align 1 minimum 1 maximum 10 step 1 value 5 code0 {o->value(progdefaults.RigCatRetries);} } Fl_Counter cntRigCatTimeout { label Timeout - callback {progdefaults.RigCatTimeout = (int)o->value();} + callback {progdefaults.RigCatTimeout = (int)o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); +progdefaults.changed = true;} tooltip {milliseconds between retries} xywh {102 188 75 21} type Simple align 1 minimum 2 maximum 200 step 1 value 10 code0 {o->value(progdefaults.RigCatTimeout);} } Fl_Counter cntRigCatWait { label Wait - callback {progdefaults.RigCatWait = (int)o->value();} + callback {progdefaults.RigCatWait = (int)o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); +progdefaults.changed = true;} tooltip {Wait interval (msec) between commands} xywh {190 188 75 21} type Simple align 1 minimum 0 maximum 100 step 1 value 5 code0 {o->value(progdefaults.RigCatWait);} } Fl_Button btnInitRIGCAT { label Initialize callback {progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true;} tooltip {Initialize RigCAT interface} xywh {275 186 113 24} } Fl_Check_Button chkRigCatRTSCTSflow { label {RTS/CTS flow ctl.} callback {progdefaults.RigCatRTSCTSflow = o->value(); +btnInitRIGCAT->labelcolor(FL_RED); +btnInitRIGCAT->redraw(); progdefaults.changed = true;} tooltip {RTS/CTS hardware flow control} xywh {242 150 70 15} down_box DOWN_BOX code0 {o->value(progdefaults.RigCatRTSCTSflow);} @@ -1283,6 +1403,8 @@ progdefaults.changed = true;} progdefaults.chkUSEHAMLIBis = false; } for (int i = 0; i < 4; btnPTT[i++]->redraw()); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} tooltip {Select hamlib for rig control} xywh {155 65 20 20} down_box DOWN_BOX align 4 } @@ -1296,12 +1418,16 @@ progdefaults.changed = true;} btnRigCatRTSptt->value(0); btnRigCatDTRptt->value(0); } +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} tooltip {use PTT data command} xywh {210 65 135 20} down_box DIAMOND_DOWN_BOX selection_color 1 deactivate } Fl_Box cboHamlibRig { label {Rig:} - callback {progdefaults.changed = true;} + callback {btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); +progdefaults.changed = true;} tooltip {Select hamlib rig} xywh {43 90 160 22} box DOWN_BOX color 7 align 4 code0 {o->readonly();} class Fl_ComboBox @@ -1309,6 +1435,8 @@ progdefaults.changed = true;} Fl_Input_Choice inpRIGdev { label {Port:} callback {progdefaults.HamRigDevice = o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} open tooltip {Select serial port} xywh {59 117 144 22} code0 {o->value(progdefaults.HamRigDevice.c_str());} @@ -1316,6 +1444,8 @@ progdefaults.changed = true;} open Fl_Choice mnuBaudRate { label {Baud Rate:} callback {progdefaults.HamRigBaudrate = o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} open tooltip {Select baud rate} xywh {104 144 99 22} down_box BORDER_BOX code0 {o->add(szBaudRates);} @@ -1324,31 +1454,42 @@ progdefaults.changed = true;} open Fl_Button btnInitHAMLIB { label Initialize callback {progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true;} tooltip {Initialize Hamlib rig control} xywh {275 186 113 24} } Fl_Counter cntHamlibtRetries { label Retries callback {progdefaults.HamlibRetries = (int)o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} tooltip {\# times to resend command before FAIL} xywh {15 189 75 21} type Simple align 1 minimum 1 maximum 10 step 1 value 5 code0 {o->value(progdefaults.HamlibRetries);} } Fl_Counter cntHamlibTimeout { label Timeout - callback {progdefaults.HamlibTimeout = (int)o->value();} + callback {progdefaults.HamlibTimeout = (int)o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); +progdefaults.changed = true;} tooltip {milliseconds between retries} xywh {102 189 75 21} type Simple align 1 minimum 2 maximum 200 step 1 value 10 code0 {o->value(progdefaults.HamlibTimeout);} } Fl_Counter cntHamlibWait { label Wait - callback {progdefaults.HamlibWait = (int)o->value();} + callback {progdefaults.HamlibWait = (int)o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); +progdefaults.changed = true;} tooltip {Wait interval (msec) between commands} xywh {190 189 75 21} type Simple align 1 minimum 0 maximum 100 step 1 value 5 code0 {o->value(progdefaults.HamlibWait);} } Fl_Check_Button btnHamlibDTRplus { label {DTR +12} callback {progdefaults.HamlibDTRplus = o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} tooltip {initial state of DTR} xywh {210 93 35 15} down_box DOWN_BOX code0 {o->value(progdefaults.HamlibDTRplus);} @@ -1360,6 +1501,8 @@ if (o->value() == 1) { chkHamlibRTSCTSflow->value(0); progdefaults.HamlibRTSCTSflow = false; } +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} tooltip {initial state of RTS} xywh {300 93 35 15} down_box DOWN_BOX } @@ -1371,6 +1514,8 @@ if (o->value() == 1) { chkHamlibXONXOFFflow->value(0); progdefaults.HamlibXONXOFFflow = false; } +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} tooltip {RTS/CTS hardware flow control} xywh {210 120 70 15} down_box DOWN_BOX code0 {o->value(progdefaults.HamlibRTSCTSflow);} @@ -1382,12 +1527,16 @@ if (o->value() == 1) { chkHamlibRTSCTSflow->value(0); progdefaults.HamlibRTSCTSflow = false; } +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} tooltip {XON/XOFF hardware flow control} xywh {300 119 70 16} down_box DOWN_BOX code0 {o->value(progdefaults.HamlibXONXOFFflow);} } Fl_Input inpHamlibConfig { callback {progdefaults.HamConfig = o->value(); +btnInitHAMLIB->labelcolor(FL_RED); +btnInitHAMLIB->redraw(); progdefaults.changed = true;} tooltip {Additional configuration of format: param=val ...} xywh {210 144 176 22} @@ -1396,7 +1545,7 @@ of format: param=val ...} xywh {210 144 176 22} } Fl_Group {} { label MemMap open - xywh {0 50 400 170} hide + xywh {0 50 400 170} } { Fl_Check_Button chkUSEMEMMAP { label {use Memmap} @@ -1421,6 +1570,8 @@ of format: param=val ...} xywh {210 144 176 22} progdefaults.chkUSEMEMMAPis = false; } for (int i = 0; i < 4; btnPTT[i++]->redraw()); +btnInitMEMMAP->labelcolor(FL_RED); +btnInitMEMMAP->redraw(); progdefaults.changed = true;} tooltip {Select Memory Mapping rig control (Kachina)} xywh {255 135 20 20} down_box DOWN_BOX align 4 } @@ -1434,6 +1585,8 @@ progdefaults.changed = true;} btnRigCatRTSptt->value(0); btnRigCatDTRptt->value(0); } +btnInitMEMMAP->labelcolor(FL_RED); +btnInitMEMMAP->redraw(); progdefaults.changed = true;} xywh {255 155 20 20} down_box DIAMOND_DOWN_BOX selection_color 1 align 4 deactivate } @@ -1444,6 +1597,7 @@ progdefaults.changed = true;} Fl_Button btnInitMEMMAP { label Initialize callback {progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true;} xywh {275 186 113 24} } @@ -1471,6 +1625,8 @@ progdefaults.changed = true;} progdefaults.chkUSEXMLRPCis = false; } for (int i = 0; i < 4; btnPTT[i++]->redraw()); +btnInitXMLRPC->labelcolor(FL_RED); +btnInitXMLRPC->redraw(); progdefaults.changed = true;} tooltip experimental xywh {281 155 20 20} down_box DOWN_BOX align 4 } @@ -1481,6 +1637,7 @@ progdefaults.changed = true;} Fl_Button btnInitXMLRPC { label Initialize callback {progdefaults.initInterface(); +o->labelcolor(FL_FOREGROUND_COLOR); progdefaults.changed = true;} xywh {275 186 113 24} } diff --git a/src/dialogs/fl_digi.cxx b/src/dialogs/fl_digi.cxx index a505d2b4..4194de4a 100644 --- a/src/dialogs/fl_digi.cxx +++ b/src/dialogs/fl_digi.cxx @@ -49,6 +49,7 @@ #include #include #include +#include #include "waterfall.h" #include "raster.h" @@ -85,6 +86,7 @@ #include "confdialog.h" #include "configuration.h" #include "colorsfonts.h" +#include "status.h" #include "macros.h" #include "macroedit.h" @@ -111,6 +113,7 @@ #include "debug.h" #include "re.h" #include "network.h" +#include "spot.h" Fl_Double_Window *fl_digi_main=(Fl_Double_Window *)0; Fl_Help_Dialog *help_dialog = (Fl_Help_Dialog *)0; @@ -120,9 +123,14 @@ MixerBase* mixer = 0; //bool useCheckButtons; +Fl_Group *mnuFrame; +Fl_Menu_Bar *mnu; +Fl_Light_Button *btnAutoSpot = (Fl_Light_Button *)0; Fl_Light_Button *btnTune = (Fl_Light_Button *)0; Fl_Light_Button *btnRSID = (Fl_Light_Button *)0; +Fl_Button *btnMacroTimer; +Fl_Button *btnMacroDummy; Fl_Tile_check *TiledGroup = 0; FTextView *ReceiveText = 0; @@ -145,7 +153,10 @@ Fl_Input *inpRstIn; Fl_Input *inpRstOut; Fl_Input *inpQth; Fl_Input *inpLoc; -Fl_Input *inpNotes; +Fl_Input *inpCnty; +Fl_Input *inpSerNo; +Fl_Input *inpVEprov; +Fl_Multiline_Input *inpNotes; Fl_Input *inpAZ; // WA5ZNU Fl_Button *qsoTime; Fl_Button *qsoClear; @@ -161,6 +172,9 @@ Fl_Group *RigControlFrame = (Fl_Group *)0; Fl_Group *RigViewerFrame = (Fl_Group *)0; Fl_Group *QsoInfoFrame = (Fl_Group *)0; Fl_Group *QsoInfoFrame1 = (Fl_Group *)0; +Fl_Group *QsoInfoFrameLeft = (Fl_Group *)0; +Fl_Group *QsoInfoFrameCenter = (Fl_Group *)0; +Fl_Group *QsoInfoFrameRight = (Fl_Group *)0; Fl_Group *QsoInfoFrame2 = (Fl_Group *)0; Fl_Group *QsoButtonFrame = (Fl_Group *)0; @@ -170,14 +184,44 @@ Fl_Button *qso_btnSelFreq = (Fl_Button *)0; Fl_Button *qso_btnDelFreq = (Fl_Button *)0; Fl_Button *qso_btnClearList = (Fl_Button *)0; -Fl_Button *btnMacroTimer; -Fl_Button *btnMacroDummy; Fl_Button *btnQRZ; Fl_Group *MixerFrame; Fl_Value_Slider *valRcvMixer; Fl_Value_Slider *valXmtMixer; AFCind *AFCindicator; +#define FREQWIDTH 172 // FREQWIDTH should be a multiple of 9 + 10 +#define FREQHEIGHT 30 +#define BTNWIDTH 30 +int pad = 1; //wSpace; +int x_qsoframe = BTNWIDTH; + +int w_inpFreq = 80; +int w_inpTime = 38; +int w_qsoTime = 24; +int w_inpCall = 80; +int w_inpName = 60; +int w_inpRstIn = 30; +int w_inpRstOut = 30; +int w_inpSerNo = 40; +int wf1 = pad + w_inpFreq + pad + w_inpTime + w_qsoTime + pad + w_inpCall + + pad + w_inpName + pad + w_inpRstIn + pad + w_inpRstOut + + pad + w_inpSerNo; + +int w_fm1 = 25; +int w_fm2 = 20; +int w_fm3 = 20; +int w_fm4 = 25; +int w_fm5 = 20; +int w_inpCnty = 24; +int w_inpLOC = 65; +int w_inpAZ = 30; +int w_inpQth = wf1 - w_fm1 - w_fm2 - w_fm3 - w_fm4 - w_fm5 - + 2*w_inpCnty - w_inpLOC - w_inpAZ; + +int qh = Hqsoframe / 2; +int rig_control_width = FREQWIDTH + 4; + int altMacros = 0; bool bSaveFreqList = false; string strMacroName[NUMMACKEYS]; @@ -805,6 +849,11 @@ void cb_mnuPlayback(Fl_Widget *w, void *d) m->flags &= ~FL_MENU_VALUE; playval = false; } + else if (btnAutoSpot->value()) { + put_status("Spotting disabled", 3.0); + btnAutoSpot->value(0); + btnAutoSpot->do_callback(); + } } #endif // USE_SNDFILE @@ -854,6 +903,11 @@ void cb_mnuVisitURL(Fl_Widget*, void* arg) restoreFocus(); } +void cb_mnuVisitPSKRep(Fl_Widget*, void*) +{ + cb_mnuVisitURL(0, (void*)string("http://pskreporter.info/pskmap?").append(progdefaults.myCall).c_str()); +} + void html_help( const string &Html) { if (!help_dialog) @@ -1085,6 +1139,11 @@ void cbRSID(Fl_Widget *w, void *) { restoreFocus(); } +void cbAutoSpot(Fl_Widget* w, void*) +{ + progStatus.spot_recv = static_cast(w)->value(); +} + void toggleRSID() { btnRSID->value(0); @@ -1149,7 +1208,7 @@ LOG_INFO(qsotime.c_str()); void clearQSO() { Fl_Input* in[] = { inpCall, inpName, inpRstIn, inpRstOut, - inpQth, inpNotes, inpLoc, inpAZ }; + inpQth, inpNotes, inpLoc, inpAZ, inpSerNo, inpVEprov, inpCnty }; for (size_t i = 0; i < sizeof(in)/sizeof(*in); i++) in[i]->value(""); inpTime->value(zuluTime()); @@ -1160,8 +1219,19 @@ void cb_log(Fl_Widget*, void*) oktoclear = false; } +void showsizes() +{ +std::cout << fl_digi_main->w() << std::endl; +std::cout << fl_digi_main->h() << std::endl; +std::cout << wf1 << std::endl; +std::cout << QsoInfoFrame->x() << ", " << QsoInfoFrame->w() << std::endl; +std::cout << QsoInfoFrame1->x() << ", " << QsoInfoFrame1->w() << std::endl; +std::cout << QsoInfoFrame2->x() << ", " << QsoInfoFrame2->w() << std::endl; +} + void qsoClear_cb(Fl_Widget *b, void *) { +// showsizes(); if (progdefaults.NagMe) { if (oktoclear || fl_choice("Clear log fields?", "Cancel", "OK", NULL) == 1) { clearQSO(); @@ -1185,8 +1255,21 @@ void qsoSave_cb(Fl_Widget *b, void *) void cb_QRZ(Fl_Widget *b, void *) { - CALLSIGNquery(); - oktoclear = false; + if (!*inpCall->value()) + return; + + switch (Fl::event_button()) { + case FL_LEFT_MOUSE: + CALLSIGNquery(); + oktoclear = false; + break; + case FL_RIGHT_MOUSE: + if (quick_choice(string("Spot \"").append(inpCall->value()).append("\"?").c_str(), false)) + spot_manual(inpCall->value(), inpLoc->value()); + break; + default: + break; + } } void status_cb(Fl_Widget *b, void *arg) @@ -1505,7 +1588,8 @@ Fl_Menu_Item menu_[] = { #endif { make_icon_label("Beginners' Guide", start_here_icon), 0, cb_mnuBeginnersURL, 0, 0, _FL_MULTI_LABEL, 0, 14, 0}, { make_icon_label("Online documentation...", help_browser_icon), 0, cb_mnuVisitURL, (void *)PACKAGE_DOCS, 0, _FL_MULTI_LABEL, 0, 14, 0}, -{ make_icon_label("Fldigi web site...", net_icon), 0, cb_mnuVisitURL, (void *)PACKAGE_HOME, FL_MENU_DIVIDER, _FL_MULTI_LABEL, 0, 14, 0}, +{ make_icon_label("Fldigi web site...", net_icon), 0, cb_mnuVisitURL, (void *)PACKAGE_HOME, 0, _FL_MULTI_LABEL, 0, 14, 0}, +{ make_icon_label("Reception reports...", pskr_icon), 0, cb_mnuVisitPSKRep, 0, FL_MENU_DIVIDER, _FL_MULTI_LABEL, 0, 14, 0}, { make_icon_label("Command line options", utilities_terminal_icon), 0, cb_mnuCmdLineHelp, 0, 0, _FL_MULTI_LABEL, 0, 14, 0}, { make_icon_label("Audio device info", audio_card_icon), 0, cb_mnuAudioInfo, 0, 0, _FL_MULTI_LABEL, 0, 14, 0}, { make_icon_label("Build info", executable_icon), 0, cb_mnuBuildInfo, 0, 0, _FL_MULTI_LABEL, 0, 14, 0}, @@ -1519,8 +1603,6 @@ Fl_Menu_Item menu_[] = { }; -Fl_Menu_Bar *mnu; - Fl_Menu_Item *getMenuItem(const char *caption, Fl_Menu_Item* submenu) { if (submenu == 0 || !(submenu->flags & FL_SUBMENU)) @@ -1752,16 +1834,35 @@ void show_bw(const string& sWidth) REQ_SYNC(&Fl_ComboBox::put_value, opBW, sWidth.c_str()); } + +void show_spot(bool v) +{ + if (v) { + mnu->size(btnAutoSpot->x(), mnu->h()); + btnAutoSpot->value(progStatus.spot_recv); + btnAutoSpot->show(); + } + else { + btnAutoSpot->hide(); + btnAutoSpot->value(v); + btnAutoSpot->do_callback(); + mnu->size(btnRSID->x(), mnu->h()); + } + mnu->redraw(); +} + void create_fl_digi_main() { - int pad = 1; //wSpace; int Y = 0; + if (progdefaults.docked_rig_control) + x_qsoframe += rig_control_width; + IMAGE_WIDTH = progdefaults.wfwidth; Hwfall = progdefaults.wfheight; HNOM = DEFAULT_HNOM; - WNOM = DEFAULT_HNOM; + WNOM = progStatus.mainW;//DEFAULT_HNOM; if (progdefaults.docked_scope) Wwfall = WNOM - 2 * BEZEL - Hwfall + 24; else @@ -1769,7 +1870,9 @@ void create_fl_digi_main() { update_main_title(); fl_digi_main = new Fl_Double_Window(WNOM, HNOM, main_window_title.c_str()); - mnu = new Fl_Menu_Bar(0, 0, WNOM - 150 - pad, Hmenu); + + mnuFrame = new Fl_Group(0,0,WNOM, Hmenu); + mnu = new Fl_Menu_Bar(0, 0, WNOM - 150, Hmenu); // do some more work on the menu for (size_t i = 0; i < sizeof(menu_)/sizeof(menu_[0]); i++) { // FL_NORMAL_SIZE may have changed; update the menu items @@ -1790,6 +1893,11 @@ void create_fl_digi_main() { Fl_Tooltip::size(FL_NORMAL_SIZE); Fl_Tooltip::enable(progdefaults.tooltips); + btnAutoSpot = new Fl_Light_Button(WNOM - 200 - pad, 0, 50, Hmenu, "Spot"); + btnAutoSpot->selection_color(FL_GREEN); + btnAutoSpot->callback(cbAutoSpot, 0); + btnAutoSpot->hide(); + btnRSID = new Fl_Light_Button(WNOM - 150 - pad, 0, 50, Hmenu, "RSID"); btnRSID->selection_color(FL_GREEN); btnRSID->callback(cbRSID, 0); @@ -1804,17 +1912,12 @@ void create_fl_digi_main() { btnMacroTimer->callback(cbMacroTimerButton, 0); btnMacroTimer->hide(); btnMacroDummy = new Fl_Button(WNOM - 50 - pad, 0, 50, Hmenu, ""); - -#define FREQWIDTH 172 // FREQWIDTH should be a multiple of 9 + 10 -#define FREQHEIGHT 30 -#define BTNWIDTH 30 - + + mnuFrame->resizable(mnu); + mnuFrame->end(); + Fl_Group *TopFrame = new Fl_Group(0, Hmenu, WNOM, Hqsoframe + Hnotes); - int qh = Hqsoframe / 2; - int qfy = Hmenu + qh - pad; - int rig_control_width = FREQWIDTH + 4; - if (progdefaults.docked_rig_control) { RigControlFrame = new Fl_Group(0, Hmenu, @@ -1980,77 +2083,87 @@ void create_fl_digi_main() { qsoSave->tooltip("Save"); QsoButtonFrame->end(); } + + int y2 = Hmenu + qh + 1; + int y3 = Hmenu + Hqsoframe + 1; + + QsoInfoFrame = new Fl_Group(x_qsoframe, Hmenu, + WNOM - rightof(QsoButtonFrame) - pad, Hqsoframe + Hnotes); + + QsoInfoFrame1 = new Fl_Group(x_qsoframe, Hmenu, wf1, Hqsoframe + Hnotes); +// QsoInfoFrame1->box(FL_BORDER_BOX); - int w_inpFreq = 80; - int w_inpTime = 38; - int w_inpCall = 70; - int w_inpRstIn = 28; - int w_inpRstOut = 28; - - QsoInfoFrame = new Fl_Group(rightof(QsoButtonFrame), Hmenu, - WNOM - rightof(QsoButtonFrame), Hqsoframe + Hnotes); + inpFreq = new Fl_Input(x_qsoframe + pad, y2, w_inpFreq, qh - pad, "QSO Freq"); + inpFreq->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); - QsoInfoFrame1 = new Fl_Group(rightof(QsoButtonFrame), Hmenu, - WNOM - rightof(QsoButtonFrame), Hqsoframe); - - inpFreq = new Fl_Input(rightof(QsoButtonFrame) + pad, qfy, w_inpFreq, qh, "QSO Freq"); - inpFreq->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); + inpTime = new Fl_Input(rightof(inpFreq) + pad, y2, w_inpTime, qh - pad, "Time"); + inpTime->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); - inpTime = new Fl_Input(rightof(inpFreq) + pad, qfy, w_inpTime, qh, "Time"); - inpTime->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); + qsoTime = new Fl_Button(rightof(inpTime), y2, w_qsoTime, qh - pad); + qsoTime->image(new Fl_Pixmap(time_icon)); + qsoTime->callback(qsoTime_cb, 0); - qsoTime = new Fl_Button(rightof(inpTime), qfy, 24, qh); - qsoTime->image(new Fl_Pixmap(time_icon)); - qsoTime->callback(qsoTime_cb, 0); + inpCall = new Fl_Input(rightof(qsoTime) + pad, y2, w_inpCall, qh - pad, "Call"); + inpCall->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); - inpCall = new Fl_Input(rightof(qsoTime) + pad, qfy, - w_inpCall, qh, "Call"); - inpCall->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); + inpName = new Fl_Input(rightof(inpCall) + pad, y2, w_inpName, qh - pad, "Name"); + inpName->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); + + inpRstIn = new Fl_Input(rightof(inpName) + pad, y2, w_inpRstIn, qh - pad, "In"); + inpRstIn->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); - inpRstIn = new Fl_Input(rightof(inpCall) + pad, qfy, w_inpRstIn, qh, "In"); - inpRstIn->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); - - inpRstOut = new Fl_Input(rightof(inpRstIn) + pad, qfy, w_inpRstOut, qh, "Out"); - inpRstOut->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); - - inpQth = new Fl_Input(rightof(inpRstOut) + pad, qfy, - WNOM - rightof(inpRstOut) - pad, Hnotes, "Qth"); - inpQth->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); - - QsoInfoFrame1->resizable(inpQth); - QsoInfoFrame1->end(); + inpRstOut = new Fl_Input(rightof(inpRstIn) + pad, y2, w_inpRstOut, qh - pad, "Out"); + inpRstOut->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); - Y = Hmenu + Hqsoframe; - - QsoInfoFrame2 = new Fl_Group(rightof(QsoButtonFrame), Y, - WNOM - rightof(QsoButtonFrame), Hnotes); - - inpName = new Fl_Input(rightof(QsoButtonFrame) + 38, Y, 90, Hnotes, "Name"); - inpName->align(FL_ALIGN_LEFT); - - inpLoc = new Fl_Input(rightof(inpCall) - 58, Y, 58, Hnotes, "Loc"); - inpLoc->align(FL_ALIGN_LEFT); - - inpAZ = new Fl_Input(leftof(inpRstOut), Y, 28, Hnotes, "Az"); - inpAZ->align(FL_ALIGN_LEFT); + inpSerNo = new Fl_Input(rightof(inpRstOut) + pad, y2, w_inpSerNo, qh - pad, "##"); + inpSerNo->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); + + Fl_Box *fm1box = new Fl_Box(x_qsoframe, y3, w_fm1, qh - pad, "Qth"); + fm1box->align(FL_ALIGN_INSIDE); + inpQth = new Fl_Input( rightof(fm1box), y3, w_inpQth, qh - pad, ""); + inpQth->align(FL_ALIGN_INSIDE); - inpNotes = new Fl_Input(leftof(inpQth), Y, - inpQth->w(), Hnotes, ""); - inpNotes->value("Notes"); - inpNotes->align(FL_ALIGN_INSIDE); - - QsoInfoFrame2->resizable(inpNotes); + Fl_Box *fm2box = new Fl_Box(rightof(inpQth), y3, w_fm2, qh - pad, "St"); + fm2box->align(FL_ALIGN_INSIDE); + inpCnty = new Fl_Input(rightof(fm2box), y3, w_inpCnty, qh - pad, ""); + inpCnty->align(FL_ALIGN_INSIDE); - QsoInfoFrame2->end(); + Fl_Box *fm3box = new Fl_Box(rightof(inpCnty), y3, w_fm3, qh - pad, "Pv"); + fm3box->align(FL_ALIGN_INSIDE); + inpVEprov = new Fl_Input(rightof(fm3box), y3, w_inpCnty, qh - pad, ""); + inpVEprov->align(FL_ALIGN_INSIDE); + + Fl_Box *fm4box = new Fl_Box(rightof(inpVEprov), y3, w_fm4, qh - pad, "Loc"); + fm4box->align(FL_ALIGN_INSIDE); + inpLoc = new Fl_Input(rightof(fm4box), y3, w_inpLOC, qh - pad, ""); + inpLoc->align(FL_ALIGN_INSIDE); + + Fl_Box *fm5box = new Fl_Box(rightof(inpLoc), y3, w_fm5, qh - pad, "Az"); + fm5box->align(FL_ALIGN_INSIDE); + inpAZ = new Fl_Input(rightof(fm5box), y3, w_inpAZ, qh - pad, ""); + inpAZ->align(FL_ALIGN_INSIDE); - QsoInfoFrame->resizable(QsoInfoFrame2); - - QsoInfoFrame->end(); - - TopFrame->resizable(QsoInfoFrame); + QsoInfoFrame1->resizable(NULL); + QsoInfoFrame1->end(); - TopFrame->end(); + QsoInfoFrame2 = new Fl_Group(x_qsoframe + wf1 + pad, Hmenu, + WNOM - rightof(QsoInfoFrame1) - 2*pad, Hqsoframe + Hnotes); +// QsoInfoFrame2->box(FL_BORDER_BOX); + + inpNotes = new Fl_Multiline_Input(x_qsoframe + wf1 + pad, y2, + WNOM - rightof(QsoInfoFrame1) - 2*pad, qh + Hnotes - pad, "Notes"); + inpNotes->align(FL_ALIGN_TOP | FL_ALIGN_LEFT); + + Fl_Group::current()->resizable(inpNotes); + QsoInfoFrame2->end(); + Fl_Group::current()->resizable(QsoInfoFrame2); + QsoInfoFrame->end(); + + Fl_Group::current()->resizable(QsoInfoFrame); + + TopFrame->end(); + Y = Hmenu + Hqsoframe + Hnotes + pad; // Fl_Widget* logfields[] = { inpFreq, inpTime, inpCall, inpName, inpRstIn, @@ -2321,7 +2434,7 @@ void create_fl_digi_main() { #endif fl_digi_main->xclass(PACKAGE_NAME); - fl_digi_main->size_range(WNOM, (HNOM < 400 ? HNOM : 400)); + fl_digi_main->size_range(WMIN, HMIN);//WNOM, (HNOM < 400 ? HNOM : 400)); scopeview = new Fl_Double_Window(0,0,140,140, "Scope"); scopeview->xclass(PACKAGE_NAME); @@ -2438,11 +2551,11 @@ void put_rx_char(unsigned int data) { static unsigned int last = 0; const char **asc = ascii; + trx_mode mode = active_modem->get_mode(); if (mailclient || mailserver || arqmode) asc = ascii2; - if (active_modem->get_mode() == MODE_RTTY || - active_modem->get_mode() == MODE_CW) + if (mode == MODE_RTTY || mode == MODE_CW) asc = ascii; int style = FTextBase::RECV; @@ -2465,7 +2578,15 @@ void put_rx_char(unsigned int data) WriteARQ(data); - string s = iscntrl(data) ? ascii2[data & 0x7F] : string(1, data); + string s; + if (iscntrl(data)) + s = ascii2[data & 0x7F]; + else { + s += data; + bool viewer = (mode >= MODE_PSK_FIRST && mode <= MODE_PSK_LAST && dlgViewer && dlgViewer->visible()); + if (progStatus.spot_recv && !viewer) + spot_recv(data); + } if (Maillogfile) Maillogfile->log_to_file(cLogfile::LOG_RX, s); @@ -2879,3 +3000,9 @@ void qsy(long long rfc, long long fmid) else active_modem->set_freq(fmid); } + +bool quick_choice(const char* title, bool sel) +{ + Fl_Menu_Item m[] = { { "Confirm" }, { "Cancel" }, { 0 } }; + return m->popup(Fl::event_x(), Fl::event_y(), title, m + !sel) == m; +} diff --git a/src/globals/globals.cxx b/src/globals/globals.cxx index 29fb44eb..208804a9 100644 --- a/src/globals/globals.cxx +++ b/src/globals/globals.cxx @@ -129,34 +129,10 @@ std::istream& operator>>(std::istream& s, qrg_mode_t& m) std::string qrg_mode_t::str(void) { ostringstream s; -// s << setw(11) << setiosflags(ios::right) << setiosflags(ios::fixed) << setprecision(3) -// << rfcarrier/1000.0 << '\t' - s << setiosflags(ios::fixed) << setw(10) << setprecision(3) << rfcarrier/1000.0 << '\t' - << rmode << '\t' - << (mode < NUM_MODES ? mode_info[mode].sname : "NONE") << '\t' - << setw(4) << carrier; + s << setiosflags(ios::left | ios::fixed) + << setw(12) << setprecision(3) << rfcarrier/1000.0 + << setw(8) << rmode + << setw(10) << (mode < NUM_MODES ? mode_info[mode].sname : "NONE") + << carrier; return s.str(); - - - // This an example of how we would do things if we were not using - // Fl_Browser and had to format the fields manually and add the string - // to a menu - - // static unsigned max_mode_sname = 0; - - // if (max_mode_sname == 0) - // for (size_t i = 0; i < NUM_MODES; i++) - // if (max_mode_sname < strlen(mode_info[i].sname)) - // max_mode_sname = strlen(mode_info[i].sname); - - // ostringstream s; - - // s << setw(11) << setiosflags(ios::right) << setiosflags(ios::fixed) << setprecision(3) - // << rfcarrier/1000.0 << ' ' - // << setw(max_mode_sname) << resetiosflags(ios::right) << setiosflags(ios::left) - // << (mode < NUM_MODES ? mode_info[mode].sname : "NONE") << ' ' - // << setw(4) << resetiosflags(ios::left) << setiosflags(ios::right) - // << carrier << ' ' << rmode; - - // return s.str(); } diff --git a/src/include/FTextView.h b/src/include/FTextView.h index cf6773e5..4cb7e343 100644 --- a/src/include/FTextView.h +++ b/src/include/FTextView.h @@ -116,6 +116,7 @@ public: protected: enum { RX_MENU_QRZ_THIS, RX_MENU_CALL, RX_MENU_NAME, RX_MENU_QTH, + RX_MENU_STATE, RX_MENU_PROVINCE, RX_MENU_SERIAL, RX_MENU_LOC, RX_MENU_RST_IN, RX_MENU_DIV, RX_MENU_CLEAR, RX_MENU_COPY, #if 0 //#ifndef NDEBUG diff --git a/src/include/confdialog.h b/src/include/confdialog.h index 97485174..cb773853 100644 --- a/src/include/confdialog.h +++ b/src/include/confdialog.h @@ -39,6 +39,16 @@ extern Fl_Value_Input *valCWsweetspot; extern Fl_Value_Input *valRTTYsweetspot; extern Fl_Value_Input *valPSKsweetspot; extern Fl_Check_Button *btnStartAtSweetSpot; +extern Fl_Group *tabSpot; +extern Fl_Check_Button *btnPSKRepAuto; +extern Fl_Check_Button *btnPSKRepLog; +extern Fl_Input *inpPSKRepHost; +extern Fl_Input *inpPSKRepPort; +#include +extern Fl_Button *btnPSKRepInit; +#include +extern Fl_Box *boxPSKRepMsg; +extern Fl_Check_Button *btnPSKRepQRG; extern Fl_Group *tabModems; extern Fl_Tabs *tabsModems; extern Fl_Group *tabCW; @@ -130,6 +140,7 @@ extern Fl_Input *inpMyLocator; extern Fl_Check_Button *btnUseLeadingZeros; extern Fl_Value_Input *nbrContestStart; extern Fl_Value_Input *nbrContestDigits; +extern Fl_Input *inpMyAntenna; extern Fl_Group *tabQRZ; extern Fl_Round_Button *btnQRZnotavailable; extern Fl_Round_Button *btnQRZcdrom; @@ -139,7 +150,6 @@ extern Fl_Input *inpQRZusername; extern Fl_Input *inpQRZuserpassword; extern Fl_Round_Button *btnQRZsub; extern Fl_Round_Button *btnHamcall; -#include extern Fl_Button *btnQRZpasswordShow; extern Fl_Group *tabRig; extern Fl_Round_Button *btnPTT[5]; diff --git a/src/include/configuration.h b/src/include/configuration.h index 90e6f371..a535eec7 100644 --- a/src/include/configuration.h +++ b/src/include/configuration.h @@ -211,6 +211,7 @@ ELEM_(std::string, myName, "MYNAME", "") \ ELEM_(std::string, myLocator, "MYLOC", "") \ ELEM_(std::string, secText, "SECONDARYTEXT", "") \ + ELEM_(std::string, myAntenna, "MYANTENNA", "") \ /* Sound card */ \ ELEM_(int, btnAudioIOis, "AUDIOIO", SND_IDX_PORT) \ ELEM_(std::string, OSSdevice, "OSSDEVICE", "") \ @@ -300,7 +301,13 @@ ELEM_(int, rx_msgid, "", 9876) \ ELEM_(int, tx_msgid, "", 6789) \ ELEM_(std::string, arq_address, "", "127.0.0.1") \ - ELEM_(std::string, arq_port, "", "3122") + ELEM_(std::string, arq_port, "", "3122") \ +/* PSK reporter */ \ + ELEM_(bool, pskrep_auto, "PSKREPAUTO", false) \ + ELEM_(bool, pskrep_log, "PSKREPLOG", false) \ + ELEM_(bool, pskrep_qrg, "PSKREPQRG", false) \ + ELEM_(std::string, pskrep_host, "PSKREPHOST", "report.psk.gladstonefamily.net") \ + ELEM_(std::string, pskrep_port, "PSKREPPORT", "4739") // declare the struct #define ELEM_DECLARE_CONFIGURATION(type_, var_, tag_, ...) type_ var_; diff --git a/src/include/debug.h b/src/include/debug.h index 3b7e3fd2..5ac68ac2 100644 --- a/src/include/debug.h +++ b/src/include/debug.h @@ -23,6 +23,7 @@ #ifndef _DEBUG_H_ #define _DEBUG_H_ +#include "util.h" class debug { diff --git a/src/include/fl_digi.h b/src/include/fl_digi.h index d3777536..6a6c015c 100644 --- a/src/include/fl_digi.h +++ b/src/include/fl_digi.h @@ -39,6 +39,7 @@ #include #include #include +#include #include "combo.h" #include "FTextView.h" @@ -75,8 +76,11 @@ extern Fl_Input *inpName; extern Fl_Input *inpRstIn; extern Fl_Input *inpRstOut; extern Fl_Input *inpQth; +extern Fl_Input *inpCnty; +extern Fl_Input *inpSerNo; +extern Fl_Input *inpVEprov; extern Fl_Input *inpLoc; -extern Fl_Input *inpNotes; +extern Fl_Multiline_Input *inpNotes; extern Fl_Input *inpAZ; // WA5ZNU extern Fl_Button *qsoClear; extern Fl_Button *qsoSave; @@ -155,6 +159,7 @@ extern void set_AFCrange(double val); extern void show_frequency(long long); extern void show_mode(const string& mode); extern void show_bw(const string& sWidth); +extern void show_spot(bool v); extern void put_WARNstatus(double); @@ -196,4 +201,6 @@ Fl_Color adjust_color(Fl_Color fg, Fl_Color bg); void qsy(long long rfc, long long fmid = -1LL); +bool quick_choice(const char* title = 0, bool sel = true); + #endif diff --git a/src/include/fldigi-config.h b/src/include/fldigi-config.h index 19cf2205..49561e1f 100644 --- a/src/include/fldigi-config.h +++ b/src/include/fldigi-config.h @@ -75,6 +75,8 @@ //#define DEFAULT_HWFALL 144 #define DEFAULT_HWFALL 124 #define DEFAULT_HNOM 500 +#define WMIN 600 +#define HMIN 500 //#define Wwfall (DEFAULT_HNOM + 2 * BEZEL) #define DEFAULT_WNOM (Wwfall + 2* DEFAULT_SW) diff --git a/src/include/pixmaps.h b/src/include/pixmaps.h index a68df339..d3ae7da8 100644 --- a/src/include/pixmaps.h +++ b/src/include/pixmaps.h @@ -53,5 +53,6 @@ extern const char *tx_icon[]; extern const char *fldigi_icon[]; extern const char *waterfall_icon[]; extern const char *dice_icon[]; +extern const char *pskr_icon[]; #endif // PIXMAPS_H_ diff --git a/src/include/pskrep.h b/src/include/pskrep.h new file mode 100644 index 00000000..5c500f4f --- /dev/null +++ b/src/include/pskrep.h @@ -0,0 +1,8 @@ +#ifndef PSKREP_H_ +#define PSKREP_H_ + +bool pskrep_start(void); +void pskrep_stop(); +const char* pskrep_error(void); + +#endif // PSKREP_H_ diff --git a/src/include/re.h b/src/include/re.h index a85d7f13..908efb8b 100644 --- a/src/include/re.h +++ b/src/include/re.h @@ -38,10 +38,10 @@ public: operator bool(void) { return !error; } bool match(const char* str, int eflags_ = 0); - const char* submatch(size_t n); + const std::string& submatch(size_t n); void suboff(size_t n, int* start, int* end); size_t nsub(void) { return substrings.size(); } -private: +protected: void compile(void); std::string pattern; @@ -52,4 +52,18 @@ private: bool error; }; -#endif // RE_H_/ +class fre_t : private re_t +{ +public: + fre_t(const char* pattern_, int cflags_ = 0); + operator bool(void) { return !error; } + + bool match(const char* str, int eflags_ = 0); + const std::vector& suboff(void) { return suboffsets; } + +private: + fre_t(const fre_t& re); + fre_t& operator=(const fre_t& rhs); +}; + +#endif // RE_H_ diff --git a/src/include/socket.h b/src/include/socket.h index 4775a9b4..93b604c1 100644 --- a/src/include/socket.h +++ b/src/include/socket.h @@ -76,8 +76,8 @@ class Address { public: - Address(const std::string& host = "", int port = 0); - Address(const std::string& host, const std::string& port_name); + Address(const char* host = "", int port = 0, const char* proto_name = "tcp"); + Address(const char* host, const char* port_name, const char* proto_name = "tcp"); Address(const Address& addr); ~Address(); Address& operator=(const Address& rhs); @@ -86,7 +86,7 @@ public: const addr_info_t* get(size_t n = 0) const; private: - void lookup(void); + void lookup(const char* proto_name); std::string node; std::string service; diff --git a/src/include/spot.h b/src/include/spot.h new file mode 100644 index 00000000..f974241b --- /dev/null +++ b/src/include/spot.h @@ -0,0 +1,48 @@ +// ---------------------------------------------------------------------------- +// spot.h +// +// Copyright (C) 2008 +// Stelios Bounanos, M0GLD +// +// This file is part of fldigi. +// +// fldigi 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. +// +// fldigi 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 . +// ---------------------------------------------------------------------------- + +#ifndef SPOT_H_ +#define SPOT_H_ + +#include +#include +#include "globals.h" + +typedef void (*spot_recv_cb_t)(int afreq, const char* str, const regmatch_t* sub, size_t len, void* data); +typedef void (*spot_log_cb_t)(const char* call, const char* loc, long long freq, + trx_mode mode, time_t rtime, void* data); + +void spot_recv(char c, int decoder = -1, int afreq = 0); +void spot_log(const char* callsign, const char* locator = "", long long freq = 0LL, + trx_mode mode = NUM_MODES, time_t rtime = -1L); +void spot_manual(const char* callsign, const char* locator = "", + long long freq = 0LL, trx_mode mode = NUM_MODES, time_t rtime = -1L); + +void spot_register_log(spot_log_cb_t lcb, void* ldata); +void spot_register_manual(spot_log_cb_t mcb, void* mdata); +void spot_register_recv(spot_recv_cb_t rcb, void* rdata, const char* re, int reflags); + +void spot_unregister_log(spot_log_cb_t lcb, void* ldata); +void spot_unregister_manual(spot_log_cb_t mcb, void* mdata); +void spot_unregister_recv(spot_recv_cb_t rcb, void* rdata); + +#endif // SPOT_H_ diff --git a/src/include/status.h b/src/include/status.h index c6b1f65f..c3036559 100644 --- a/src/include/status.h +++ b/src/include/status.h @@ -1,8 +1,6 @@ #ifndef _status_H #define _status_H -#include -#include #include #include "globals.h" @@ -40,6 +38,8 @@ struct status { int scopeW; int scopeH; string LastMacroFile; + bool spot_recv; + bool spot_log; bool bLastStateRead; diff --git a/src/include/util.h b/src/include/util.h index ba491bf7..c7f17687 100644 --- a/src/include/util.h +++ b/src/include/util.h @@ -120,6 +120,11 @@ void restore_signals(void); } // extern "C" #endif +#ifdef __cplusplus +uint32_t simple_hash_data(const unsigned char* buf, unsigned len, uint32_t code = 0); +uint32_t simple_hash_str(const unsigned char* str, uint32_t code = 0); +#endif + #if !defined(NDEBUG) && defined(deprecated__) && defined(__GNUC__) #include #include diff --git a/src/logger/logger.cxx b/src/logger/logger.cxx index 739c344a..93a97ba2 100644 --- a/src/logger/logger.cxx +++ b/src/logger/logger.cxx @@ -37,46 +37,112 @@ #include "main.h" #include "modem.h" #include "debug.h" +#include "macros.h" #include +enum ADIF_FIELD_POS { + ADDRESS = 0, + AGE, + ARRL_SECT, + BAND, + CALL, + CNTY, + COMMENT, + CONT, + CONTEST_ID, + COUNTRY, + CQZ, + DXCC, + FREQ, + GRIDSQUARE, + MODE, + NAME, + NOTES, + QSLRDATE, + QSLSDATE, + QSL_RCVD, + QSL_SENT, + QSO_DATE, + QTH, + RST_RCVD, + RST_SENT, + STATE, + STX, + TIME_OFF, + TIME_ON, + TX_PWR, +// additional for 2.0 + IOTA, + ITUZ, + OPERATOR, + PFX, + PROP_MODE, + QSL_MSG, + QSL_VIA, + RX_PWR, + SAT_MODE, + SAT_NAME, + SRX, + TEN_TEN, + VE_PROV, + EXPORT, // internal use in fl_logbook + NUMFIELDS // counter for number of fields in enum +}; + struct FIELD { + int type; const char *name; - unsigned int size; + size_t size; }; FIELD fields[] = { -// NAME, SIZE - {"ADDRESS", 40}, // 0 - contacted stations mailing address - {"AGE", 3}, // 1 - contacted operators age in years - {"ARRL_SECT", 12}, // 2 - contacted stations ARRL section - {"BAND", 6}, // 3 - QSO band - {"CALL", 10}, // 4 - contacted stations CALLSIGN - {"CNTY", 20}, // 5 - secondary political subdivision, ie: STATE - {"COMMENT", 80}, // 6 - comment field for QSO - {"CONT", 10}, // 7 - contacted stations continent - {"CONTEST_ID", 6}, // 8 - QSO contest identifier - {"COUNTRY", 20}, // 9 - contacted stations DXCC entity name - {"CQZ", 8}, // 10 - contacted stations CQ Zone - {"DXCC", 8}, // 11 - contacted stations Country Code - {"FREQ", 10}, // 12 - QSO frequency in Mhz - {"GRIDSQUARE", 6}, // 13 - contacted stations Maidenhead Grid Square - {"MODE", 8}, // 14 - QSO mode - {"NAME", 18}, // 15 - contacted operators NAME - {"NOTES", 80}, // 16 - QSO notes - {"QSLRDATE", 8}, // 17 - QSL received date - {"QSLSDATE", 8}, // 18 - QSL sent date - {"QSL_RCVD", 1}, // 19 - QSL received status - {"QSL_SENT", 1}, // 20 - QSL sent status - {"QSO_DATE", 8}, // 21 - QSO date - {"QTH", 30}, // 22 - contacted stations city - {"RST_RCVD", 3}, // 23 - received signal report - {"RST_SENT", 3}, // 24 - sent signal report - {"STATE", 2}, // 25 - contacted stations STATE - {"STX", 8}, // 26 - QSO transmitted serial number - {"TIME_OFF", 4}, // 27 - HHMM or HHMMSS in UTC - {"TIME_ON", 4}, // 28 - HHMM or HHMMSS in UTC - {"TX_PWR", 4} // 29 - power transmitted by this station +// TYPE, NAME, SIZE + {ADDRESS, "ADDRESS", 40}, // 0 - contacted stations mailing address + {AGE, "AGE", 3}, // 1 - contacted operators age in years + {ARRL_SECT, "ARRL_SECT", 12}, // 2 - contacted stations ARRL section + {BAND, "BAND", 6}, // 3 - QSO band + {CALL, "CALL", 10}, // 4 - contacted stations CALLSIGN + {CNTY, "CNTY", 20}, // 5 - secondary political subdivision, ie: STATE + {COMMENT, "COMMENT", 80}, // 6 - comment field for QSO + {CONT, "CONT", 10}, // 7 - contacted stations continent + {CONTEST_ID, "CONTEST_ID", 6}, // 8 - QSO contest identifier + {COUNTRY, "COUNTRY", 20}, // 9 - contacted stations DXCC entity name + {CQZ, "CQZ", 8}, // 10 - contacted stations CQ Zone + {DXCC, "DXCC", 8}, // 11 - contacted stations Country Code + {FREQ, "FREQ", 10}, // 12 - QSO frequency in Mhz + {GRIDSQUARE, "GRIDSQUARE", 6}, // 13 - contacted stations Maidenhead Grid Square + {MODE, "MODE", 8}, // 14 - QSO mode + {NAME, "NAME", 18}, // 15 - contacted operators NAME + {NOTES, "NOTES", 80}, // 16 - QSO notes + {QSLRDATE, "QSLRDATE", 8}, // 21 - QSL received date + {QSLSDATE, "QSLSDATE", 8}, // 22 - QSL sent date + {QSL_RCVD, "QSL_RCVD", 1}, // 23 - QSL received status + {QSL_SENT, "QSL_SENT", 1}, // 24 - QSL sent status + {QSO_DATE, "QSO_DATE", 8}, // 25 - QSO data + {QTH, "QTH", 30}, // 27 - contacted stations city + {RST_RCVD, "RST_RCVD", 3}, // 28 - received signal report + {RST_SENT, "RST_SENT", 3}, // 29 - sent signal report + {STATE, "STATE", 2}, // 34 - contacted stations STATE + {STX, "STX", 8}, // 35 - QSO transmitted serial number + {TIME_OFF, "TIME_OFF", 4}, // 37 - HHMM or HHMMSS in UTC + {TIME_ON, "TIME_ON", 4}, // 38 - HHMM or HHMMSS in UTC + {TX_PWR, "TX_PWR", 4}, // 39 - power transmitted by this station +// new fields + {IOTA, "IOTA", 6}, // 13 + {ITUZ, "ITUZ", 6}, // 14 - ITU zone + {OPERATOR, "OPERATOR", 10}, // 17 - Callsign of person loggin the QSO + {PFX, "PFX", 5}, // 18 - WPA prefix + {PROP_MODE, "PROP_MODE", 5}, // 19 - propogation mode + {QSL_MSG, "QSL_MSG", 80}, // 20 - personal message to appear on qsl card + {QSL_VIA, "QSL_VIA", 30}, // 26 + {RX_PWR, "RX_PWR", 4}, // 30 - power of other station in watts + {SAT_MODE, "SAT_MODE", 8}, // 31 - satellite mode + {SAT_NAME, "SAT_NAME", 12}, // 32 - satellite name + {SRX, "SRX", 5}, // 33 - received serial number for a contest QSO + {TEN_TEN, "TEN_TEN", 10}, // 36 - ten ten # of other station + {VE_PROV, "VE_PROV", 2}, // 40 - 2 letter abbreviation for Canadian Province + {EXPORT, "EXPORT", 1} // 41 - used to indicate record is to be exported }; #define ADIF_VERS "2.1.9" @@ -165,35 +231,44 @@ int submit_log(void) adif.erase(); - FL_LOCK(); log_msg = ""; log_msg = log_msg + "program:" + PACKAGE_NAME + " v " + PACKAGE_VERSION + LOG_MSEPARATOR; log_msg = log_msg + "version:" + LOG_MVERSION + LOG_MSEPARATOR; log_msg = log_msg + "date:" + logdate + LOG_MSEPARATOR; - putadif(21, adifdate); + putadif(QSO_DATE, adifdate); log_msg = log_msg + "time:" + inpTime->value() + LOG_MSEPARATOR; - putadif(28, inpTime->value()); + putadif(TIME_ON, inpTime->value()); log_msg = log_msg + "endtime:" + logtime + LOG_MSEPARATOR; - putadif(27, logtime); + putadif(TIME_OFF, logtime); log_msg = log_msg + "call:" + inpCall->value() + LOG_MSEPARATOR; - putadif(4, inpCall->value()); + putadif(CALL, inpCall->value()); log_msg = log_msg + "mhz:" + strFreqMhz + LOG_MSEPARATOR; - putadif(12, strFreqMhz); + putadif(FREQ, strFreqMhz); log_msg = log_msg + "mode:" + mode + LOG_MSEPARATOR; - putadif(14, mode); + putadif(MODE, mode); log_msg = log_msg + "tx:" + inpRstOut->value() + LOG_MSEPARATOR; - putadif(24, inpRstOut->value()); + putadif(RST_SENT, inpRstOut->value()); log_msg = log_msg + "rx:" + inpRstIn->value() + LOG_MSEPARATOR; - putadif(23, inpRstIn->value()); + putadif(RST_RCVD, inpRstIn->value()); log_msg = log_msg + "name:" + inpName->value() + LOG_MSEPARATOR; - putadif(15, inpName->value()); + putadif(NAME, inpName->value()); log_msg = log_msg + "qth:" + inpQth->value() + LOG_MSEPARATOR; - putadif(22, inpQth->value()); + putadif(QTH, inpQth->value()); + log_msg = log_msg + "state:" + inpCnty->value() + LOG_MSEPARATOR; + putadif(CNTY, inpCnty->value()); + log_msg = log_msg + "province:" + inpVEprov->value() + LOG_MSEPARATOR; + putadif(VE_PROV, inpVEprov->value()); log_msg = log_msg + "locator:" + inpLoc->value() + LOG_MSEPARATOR; - putadif(13, inpLoc->value()); + putadif(GRIDSQUARE, inpLoc->value()); + char szcnt[5] = ""; + if (contest_count.count) + snprintf(szcnt, sizeof(szcnt), "%04d", contest_count.count); + log_msg = log_msg + "serialout:" + szcnt + LOG_MSEPARATOR; + putadif(STX, szcnt); + log_msg = log_msg + "serialin:" + inpSerNo->value() + LOG_MSEPARATOR; + putadif(SRX, inpSerNo->value()); log_msg = log_msg + "notes:" + inpNotes->value() + LOG_MSEPARATOR; - putadif(16, inpNotes->value()); - FL_UNLOCK(); + putadif(NOTES, inpNotes->value()); writeadif(); diff --git a/src/main.cxx b/src/main.cxx index 3c9adf28..b37fb3bd 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -64,6 +64,7 @@ #include "fileselect.h" #include "timeops.h" #include "debug.h" +#include "pskrep.h" #if USE_HAMLIB #include "rigclass.h" @@ -285,6 +286,9 @@ int main(int argc, char ** argv) XML_RPC_Server::start(progdefaults.xmlrpc_address.c_str(), progdefaults.xmlrpc_port.c_str()); #endif + if (!pskrep_start()) + LOG_ERROR("Could not start PSK reporter: %s", pskrep_error()); + int ret = Fl::run(); arq_close(); @@ -293,6 +297,8 @@ int main(int argc, char ** argv) XML_RPC_Server::stop(); #endif + pskrep_stop(); + for (int i = 0; i < NUM_QRUNNER_THREADS; i++) { cbq[i]->detach(); delete cbq[i]; diff --git a/src/misc/configuration.cxx b/src/misc/configuration.cxx index e4ea6f82..7b5186e1 100644 --- a/src/misc/configuration.cxx +++ b/src/misc/configuration.cxx @@ -349,6 +349,7 @@ int configuration::setDefaults() inpMyName->value(myName.c_str()); inpMyQth->value(myQth.c_str()); inpMyLocator->value(myLocator.c_str()); + inpMyAntenna->value(myAntenna.c_str()); UseLeadingZeros = btnUseLeadingZeros->value(); ContestStart = (int)nbrContestStart->value(); ContestDigits = (int)nbrContestDigits->value(); diff --git a/src/misc/lookupcall.cxx b/src/misc/lookupcall.cxx index cd7d0ced..b246e567 100644 --- a/src/misc/lookupcall.cxx +++ b/src/misc/lookupcall.cxx @@ -65,6 +65,7 @@ string lookup_name; string lookup_addr1; string lookup_addr2; string lookup_state; +string lookup_province; string lookup_zip; string lookup_country; string lookup_born; @@ -163,6 +164,7 @@ void clear_Lookup() lookup_addr1.clear(); lookup_addr2.clear(); lookup_state.clear(); + lookup_province.clear(); lookup_zip.clear(); lookup_country.clear(); lookup_born.clear(); @@ -419,6 +421,10 @@ void QRZ_disp_result() } inpQth->value(lookup_qth.c_str()); + + inpCnty->value(lookup_state.c_str()); + inpVEprov->value(lookup_province.c_str()); + inpLoc->value(lookup_grid.c_str()); if (!progdefaults.myLocator.empty()) { char buf[10]; @@ -452,10 +458,7 @@ void QRZ_CD_query() if (snip != string::npos) lookup_fname.erase(snip, lookup_fname.length() - snip); lookup_qth = qCall->GetCity(); - lookup_qth.append(" "); - lookup_qth.append(qCall->GetState()); - lookup_qth.append(" "); - lookup_qth.append(qCall->GetZIP()); + lookup_state = qCall->GetState(); lookup_grid.clear(); lookup_notes.clear(); } else { @@ -557,10 +560,6 @@ void QRZquery() REQ(QRZAlert); else { lookup_qth.clear(); - qthappend(lookup_qth, lookup_addr1); - qthappend(lookup_qth, lookup_addr2); - qthappend(lookup_qth, lookup_state); - qthappend(lookup_qth, lookup_country); REQ(QRZ_disp_result); } } @@ -596,12 +595,11 @@ void parse_html(const string& htmlpage) p++; while ((uchar)htmlpage[p] < 128 && p < htmlpage.length()) lookup_qth += htmlpage[p++]; - lookup_qth += ", "; } if ((p = htmlpage.find(HAMCALL_STATE)) != string::npos) { p++; while ((uchar)htmlpage[p] < 128 && p < htmlpage.length()) - lookup_qth += htmlpage[p++]; + lookup_state += htmlpage[p++]; } if ((p = htmlpage.find(HAMCALL_GRID)) != string::npos) { p++; @@ -702,17 +700,41 @@ bool parseQRZdetails(string &htmlpage) snip_end = htmlpage.find(snip_end_RECORD, snip); lookup_addr2 = htmlpage.substr(snip, snip_end - snip); lookup_qth += lookup_addr2; - } - - snip = htmlpage.find(BEGIN_COUNTRY); - if (snip != string::npos) { - while (lookup_qth[lookup_qth.length() -1] == ' ' || lookup_qth[lookup_qth.length() -1] == ',') - lookup_qth.erase(lookup_qth.length() -1, 1); - lookup_qth.append(", "); - snip += strlen(BEGIN_COUNTRY); - snip_end = htmlpage.find(snip_end_RECORD, snip); - lookup_country = htmlpage.substr(snip, snip_end - snip); - lookup_qth += lookup_country; + } + + string isUS = "aAkKnNwW"; + string isCAN = "vV"; + if (isUS.find(callsign[0]) != string::npos) { // a US callsign + size_t pos = lookup_qth.find(','); + if (pos != string::npos) { + lookup_state = lookup_qth.substr(pos); + lookup_qth = lookup_qth.substr(0, pos); + pos = lookup_state.find_first_not_of(", "); + if (pos != string::npos) + lookup_state = lookup_state.substr(pos); + pos = lookup_state.find(' '); + if (pos != string::npos) + lookup_state = lookup_state.substr(0,pos); + } + } else if (isCAN.find(callsign[0]) != string::npos) { // a Canadian callsign + size_t pos = lookup_qth.find(','); + if (pos != string::npos) { + lookup_province = lookup_qth.substr(pos); + lookup_qth = lookup_qth.substr(0, pos); + pos = lookup_province.find_first_not_of(", "); + if (pos != string::npos) + lookup_province = lookup_province.substr(pos); + pos = lookup_province.find(' '); + if (pos != string::npos) + lookup_province = lookup_province.substr(0,pos); + } + } else { + snip = htmlpage.find(BEGIN_COUNTRY); + if (snip != string::npos) { + snip += strlen(BEGIN_COUNTRY); + snip_end = htmlpage.find(snip_end_RECORD, snip); + lookup_state = htmlpage.substr(snip, snip_end - snip); + } } snip = htmlpage.find(BEGIN_GRID); @@ -722,7 +744,7 @@ bool parseQRZdetails(string &htmlpage) lookup_grid = htmlpage.substr(snip, snip_end - snip); } - lookup_notes = "*** Data Courtesy of WWW.QRZ.COM ***"; + lookup_notes = "Courtesy of WWW.QRZ.COM"; return true; } diff --git a/src/misc/network.cxx b/src/misc/network.cxx index eb8ad4c5..de600269 100644 --- a/src/misc/network.cxx +++ b/src/misc/network.cxx @@ -11,7 +11,7 @@ using namespace std; bool request_reply(const string& node, const string& service, const string& request, string& reply, double timeout) { try { - Socket s(Address(node, service)); + Socket s(Address(node.c_str(), service.c_str())); s.connect(); s.set_nonblocking(); s.set_timeout(timeout); diff --git a/src/misc/pixmaps.cxx b/src/misc/pixmaps.cxx index a28cef40..dfbcb096 100644 --- a/src/misc/pixmaps.cxx +++ b/src/misc/pixmaps.cxx @@ -4743,6 +4743,32 @@ const char *tx_icon[] = { " .. ", " "}; +// pskreporter.info "favicon" + +/* XPM */ +const char *pskr_icon[] = { +"16 16 3 1", +" c None", +". c #FF0000", +"+ c #FFFF00", +" .. ", +" ... ", +" ..... ", +" .....+.. ", +". ...++++... ", +".. ..+++++. .. ", +"....++++++..+. ", +"..+++++++++++.. ", +"..+++++++.++++. ", +"....+++++..++.. ", +".. ..+++++.... ", +". ..+++++.. ", +" ...+... ", +" .... ", +" .. ", +" . "}; + + /* XPM */ const char *fldigi_icon[] = { "48 48 215 2", diff --git a/src/misc/re.cxx b/src/misc/re.cxx index e8fe5d30..c0c30a02 100644 --- a/src/misc/re.cxx +++ b/src/misc/re.cxx @@ -103,9 +103,9 @@ bool re_t::match(const char* str, int eflags_) return found; } -const char* re_t::submatch(size_t n) +const string& re_t::submatch(size_t n) { - return n < nsub() ? substrings[n].c_str() : 0; + return substrings[n]; } void re_t::suboff(size_t n, int* start, int* end) @@ -119,3 +119,17 @@ void re_t::suboff(size_t n, int* start, int* end) if (end) *end = -1; } } + +// ------------------------------------------------------------------------ + +fre_t::fre_t(const char* pattern_, int cflags_) : re_t(pattern_, cflags_) { } + +bool fre_t::match(const char* str, int eflags_) +{ + if (error) + return false; + + bool nosub = cflags & REG_NOSUB || preg.re_nsub == 0; + return !regexec(&preg, str, (nosub ? 0 : preg.re_nsub+1), + (nosub ? NULL : &suboffsets[0]), eflags_); +} diff --git a/src/misc/socket.cxx b/src/misc/socket.cxx index 2c7197b8..f99df72e 100644 --- a/src/misc/socket.cxx +++ b/src/misc/socket.cxx @@ -40,7 +40,10 @@ #include #include -#include "debug.h" +#ifndef NDEBUG + #include "debug.h" +#endif + #include "socket.h" #if HAVE_GETADDRINFO && !defined(AI_NUMERICSERV) @@ -189,7 +192,7 @@ static void free_servent(struct servent* sp) // Address class // -Address::Address(const string& host, int port) +Address::Address(const char* host, int port, const char* proto_name) : node(host), copied(false) { #if HAVE_GETADDRINFO @@ -206,10 +209,10 @@ Address::Address(const string& host, int port) s << port; service = s.str(); - lookup(); + lookup(proto_name); } -Address::Address(const string& host, const string& port_name) +Address::Address(const char* host, const char* port_name, const char* proto_name) : node(host), service(port_name), copied(false) { #if HAVE_GETADDRINFO @@ -219,7 +222,7 @@ Address::Address(const string& host, const string& port_name) memset(&service_entry, 0, sizeof(service_entry)); #endif - lookup(); + lookup(proto_name); } Address::Address(const Address& addr) @@ -270,14 +273,25 @@ Address& Address::operator=(const Address& rhs) free_servent(&service_entry); copy_hostent(&host_entry, &rhs.host_entry); copy_servent(&service_entry, &rhs.service_entry); + + addr.ai_protocol = rhs.addr.ai_protocol; + addr.ai_socktype = rhs.addr.ai_socktype; #endif copied = true; return *this; } -void Address::lookup(void) +void Address::lookup(const char* proto_name) { + int proto; + if (!strcasecmp(proto_name, "tcp")) + proto = IPPROTO_TCP; + else if (!strcasecmp(proto_name, "udp")) + proto = IPPROTO_UDP; + else + throw SocketException("Bad protocol name"); + #if HAVE_GETADDRINFO struct addrinfo hints; memset(&hints, 0, sizeof(hints)); @@ -285,7 +299,7 @@ void Address::lookup(void) hints.ai_flags = AI_ADDRCONFIG; # endif hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; + hints.ai_socktype = (proto == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM); if (service.find_first_not_of("0123456789") == string::npos) hints.ai_flags |= AI_NUMERICSERV; @@ -319,6 +333,9 @@ void Address::lookup(void) else copy_servent(&service_entry, sp); + memset(&addr, 0, sizeof(addr)); + addr.ai_protocol = proto; + addr.ai_socktype = (proto == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM); #endif } @@ -369,10 +386,7 @@ const addr_info_t* Address::get(size_t n) const saddr.sin_addr = *(struct in_addr*)host_entry.h_addr_list[n]; saddr.sin_port = service_entry.s_port; - memset(&addr, 0, sizeof(addr)); addr.ai_family = saddr.sin_family; - addr.ai_socktype = SOCK_STREAM; - addr.ai_protocol = IPPROTO_TCP; addr.ai_addrlen = sizeof(saddr); addr.ai_addr = (struct sockaddr*)&saddr; # ifndef NDEBUG diff --git a/src/misc/status.cxx b/src/misc/status.cxx index 4552f985..ea1c8df3 100644 --- a/src/misc/status.cxx +++ b/src/misc/status.cxx @@ -38,8 +38,8 @@ status progStatus = { MODE_BPSK31, // trx_mode lastmode; 50, // int mainX; 50, // int mainY; - (WNOM > 600 ? WNOM : 600), // int mainW; - DEFAULT_HNOM, // int mainH; + WMIN, // int mainW; + HMIN, // int mainH; Hrcvtxt, // int RxTextHeight; false, // bool rigShown; 50, // int rigX; @@ -67,6 +67,8 @@ status progStatus = { 50, // int scopeW; 50, // int scopeH; "macros.mdf", // string LastMacroFile; + false, // bool spot_recv + false, // bool spot_log false // bool bLastStateRead; }; @@ -157,6 +159,9 @@ void status::saveLastState() spref.set("scope_h", scopeH); spref.set("last_macro_file", LastMacroFile.c_str()); + + spref.set("spot_recv", spot_recv); + spref.set("spot_log", spot_recv); } void status::loadLastState() @@ -221,6 +226,9 @@ void status::loadLastState() spref.get("last_macro_file", defbuffer, "macros.mdf"); LastMacroFile = defbuffer; if (defbuffer) free(defbuffer); + + spref.get("spot_recv", i, i); spot_recv = i; + spref.get("spot_log", i, i); spot_log = i; } void status::initLastState() diff --git a/src/misc/util.cxx b/src/misc/util.cxx index d8ffd635..fd22c948 100644 --- a/src/misc/util.cxx +++ b/src/misc/util.cxx @@ -39,9 +39,9 @@ long ver2int(const char* version) return 0; if (re.nsub() == 4) - v += strtol(re.submatch(3), NULL, 10); - v += strtol(re.submatch(2), NULL, 10) * 1000L; - v += strtol(re.submatch(1), NULL, 10) * 1000000L; + v += strtol(re.submatch(3).c_str(), NULL, 10); + v += strtol(re.submatch(2).c_str(), NULL, 10) * 1000L; + v += strtol(re.submatch(1).c_str(), NULL, 10) * 1000000L; return v; } @@ -109,3 +109,17 @@ void restore_signals(void) nsig = 0; pthread_mutex_unlock(&sigmutex); } + +uint32_t simple_hash_data(const unsigned char* buf, size_t len, uint32_t code) +{ + for (size_t i = 0; i < len; i++) + code = ((code << 4) | (code >> (32 - 4))) ^ (uint32_t)buf[i]; + + return code; +} +uint32_t simple_hash_str(const unsigned char* str, uint32_t code) +{ + while (*str) + code = ((code << 4) | (code >> (32 - 4))) ^ (uint32_t)*str++; + return code; +} diff --git a/src/olivia/olivia.cxx b/src/olivia/olivia.cxx index 02180b2b..a1778d24 100644 --- a/src/olivia/olivia.cxx +++ b/src/olivia/olivia.cxx @@ -361,10 +361,8 @@ olivia::olivia() rxbuffer = 0; samplerate = 8000; - FL_LOCK(); - Tx = new MFSK_Transmitter< float >; - Rx = new MFSK_Receiver< float >; - FL_UNLOCK(); + Tx = new MFSK_Transmitter< float >; + Rx = new MFSK_Receiver< float >; mode = MODE_OLIVIA; lastfreq = 0; diff --git a/src/psk/viewpsk.cxx b/src/psk/viewpsk.cxx index 0e39b076..32a2a0ec 100644 --- a/src/psk/viewpsk.cxx +++ b/src/psk/viewpsk.cxx @@ -157,8 +157,8 @@ void viewpsk::rx_bit(int ch, int bit) if ((shreg[ch] & 3) == 0) { c = psk_varicode_decode(shreg[ch] >> 2); shreg[ch] = 0; - if (c == '\n') c = ' '; - if (c >= ' ' && c <= 'z') { + if (c == '\n' || c == '\r') c = ' '; + if (isprint(c)) { REQ(&viewaddchr, ch, (int)frequency[ch], c); timeout[ch] = now + progdefaults.VIEWERtimeout; } diff --git a/src/rigcontrol/hamlib.cxx b/src/rigcontrol/hamlib.cxx index 65624f6c..d4e22a80 100644 --- a/src/rigcontrol/hamlib.cxx +++ b/src/rigcontrol/hamlib.cxx @@ -129,7 +129,7 @@ bool hamlib_init(bool bPtt) const char* conf = progdefaults.HamConfig.c_str(); int end; while (re.match(conf)) { - xcvr->setConf(re.submatch(1), re.submatch(2)); + xcvr->setConf(re.submatch(1).c_str(), re.submatch(2).c_str()); re.suboff(0, NULL, &end); conf += end; } diff --git a/src/rigcontrol/rigsupport.cxx b/src/rigcontrol/rigsupport.cxx index d1c23e56..853d6812 100644 --- a/src/rigcontrol/rigsupport.cxx +++ b/src/rigcontrol/rigsupport.cxx @@ -43,7 +43,34 @@ const unsigned char nfields = 4; int fwidths[nfields]; enum { max_rfcarrier, max_rmode, max_mode }; -#if USE_HAMLIB +#if !USE_HAMLIB + +typedef enum { + RIG_MODE_NONE = 0, /*!< '' -- None */ + RIG_MODE_AM = (1<<0), /*!< \c AM -- Amplitude Modulation */ + RIG_MODE_CW = (1<<1), /*!< \c CW -- CW "normal" sideband */ + RIG_MODE_USB = (1<<2), /*!< \c USB -- Upper Side Band */ + RIG_MODE_LSB = (1<<3), /*!< \c LSB -- Lower Side Band */ + RIG_MODE_RTTY = (1<<4), /*!< \c RTTY -- Radio Teletype */ + RIG_MODE_FM = (1<<5), /*!< \c FM -- "narrow" band FM */ + RIG_MODE_WFM = (1<<6), /*!< \c WFM -- broadcast wide FM */ + RIG_MODE_CWR = (1<<7), /*!< \c CWR -- CW "reverse" sideband */ + RIG_MODE_RTTYR = (1<<8), /*!< \c RTTYR -- RTTY "reverse" sideband */ + RIG_MODE_AMS = (1<<9), /*!< \c AMS -- Amplitude Modulation Synchronous */ + RIG_MODE_PKTLSB = (1<<10),/*!< \c PKTLSB -- Packet/Digital LSB mode (dedicated port) */ + RIG_MODE_PKTUSB = (1<<11),/*!< \c PKTUSB -- Packet/Digital USB mode (dedicated port) */ + RIG_MODE_PKTFM = (1<<12),/*!< \c PKTFM -- Packet/Digital FM mode (dedicated port) */ + RIG_MODE_ECSSUSB = (1<<13),/*!< \c ECSSUSB -- Exalted Carrier Single Sideband USB */ + RIG_MODE_ECSSLSB = (1<<14),/*!< \c ECSSLSB -- Exalted Carrier Single Sideband LSB */ + RIG_MODE_FAX = (1<<15),/*!< \c FAX -- Facsimile Mode */ + RIG_MODE_SAM = (1<<16),/*!< \c SAM -- Synchronous AM double sideband */ + RIG_MODE_SAL = (1<<17),/*!< \c SAL -- Synchronous AM lower sideband */ + RIG_MODE_SAH = (1<<18),/*!< \c SAH -- Synchronous AM upper (higher) sideband */ + RIG_MODE_DSB = (1<<19), /*!< \c DSB -- Double sideband suppressed carrier */ +} rmode_t; + +#endif + struct rmode_name_t { rmode_t mode; const char *name; @@ -98,7 +125,6 @@ void selFreq(long int f) if (FreqDisp) FreqDisp->value(f); } -#endif // USE_HAMLIB void initOptionMenus() { diff --git a/src/spot/pskrep.cxx b/src/spot/pskrep.cxx new file mode 100644 index 00000000..c89a9d32 --- /dev/null +++ b/src/spot/pskrep.cxx @@ -0,0 +1,906 @@ +// ---------------------------------------------------------------------------- +// pskrep.cxx +// +// Copyright (C) 2008 +// Stelios Bounanos, M0GLD +// +// This is a client for N1DQ's PSK Automatic Propagation Reporter +// (see http://pskreporter.info/). Philip Gladstone, N1DQ, is +// thanked for his helpful explanation of the protocol. +// +// +// This file is part of fldigi. +// +// fldigi 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. +// +// fldigi is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ---------------------------------------------------------------------------- + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "socket.h" +#include "re.h" +#include "debug.h" +#include "util.h" +#include "trx.h" +#include "waterfall.h" +#include "configuration.h" +#include "rigsupport.h" +#include "spot.h" + +#include "pskrep.h" + +// ------------------------------------------------------------------------------------------------- + +// The regular expression that matches the spotter's buffer when it calls us. +// It must define at least two capturing groups, the second of which is the +// spotted callsign. +#define CALLSIGN_RE "[[:alnum:]]?[[:alpha:]/]+[[:digit:]]+[[:alnum:]/]+" +#define PSKREP_RE "(de|cq|qrz)[^[:alnum:]/\n]+" "(" CALLSIGN_RE ")" " +(.* +)?\\2[^[:alnum:]]+$" + +// Try to flush the report queue every SEND_INTERVAL seconds. +#define SEND_INTERVAL 300 + +// Ignore reports that are less than DUP_INTERVAL seconds older than +// a previously sent report for the same callsign and frequency band. +// Sent reports are also garbage-collected after DUP_INTERVAL seconds. +#define DUP_INTERVAL 3600 + +// The first TEMPLATE_THRESHOLD packets will contain the long templates; +// the next TEMPLATE_THRESHOLD packets will include the short templates +#define TEMPLATE_THRESHOLD 3 +// Resend short templates every TEMPLATE_INTERVAL seconds +#define TEMPLATE_INTERVAL 1800 + +// Maximum send size +#define DGRAM_MAX (1500-14-24-8) + +#define PSKREP_QUEUE_FILE "pskrqueue.txt" +#define PSKREP_ID_FILE "pskrkey.txt" + +// ------------------------------------------------------------------------------------------------- + +using namespace std; + +enum status_t { STATUS_NEW, STATUS_PENDING, STATUS_SENT }; +enum rtype_t { PSKREP_AUTO = 1, PSKREP_LOG = 2, PSKREP_MANUAL = 3 }; + +struct rcpt_report_t +{ + rcpt_report_t(trx_mode m = 0, long long f = 0, time_t t = 0, + rtype_t p = PSKREP_AUTO, string loc = "") + : mode(m), freq(f), rtime(t), rtype(p), + status(STATUS_NEW), locator(loc) { } + + trx_mode mode; + long long freq; + time_t rtime; + rtype_t rtype; + + status_t status; + + string locator; +}; + +enum band_t { + BAND_LMW, BAND_160M, BAND_80M, BAND_75M, BAND_60M, BAND_40M, BAND_30M, BAND_20M, + BAND_17M, BAND_15M, BAND_12M, BAND_10M, BAND_6M, BAND_4M, BAND_2M, BAND_125CM, + BAND_70CM, BAND_33CM, BAND_23CM, BAND_13CM, BAND_9CM, BAND_OTHER +}; + +// A band_map_t holds a list of reception reports (for a particular callsign and band) +typedef deque band_map_t; +// A call_map_t holds reception reports for a particular callsign +typedef map call_map_t; +// A container of this type holds all reception reports, sorted by callsign and band +typedef map queue_t; + +class pskrep_sender +{ +public: + pskrep_sender(const string& call, const string& loc, const string& ant, + const string& host_, const string& port_, + const string& long_id_, const string& short_id_); + ~pskrep_sender(); + + bool append(const string& callsign, const band_map_t::value_type& r); + bool send(void); + +private: + void write_station_info(void); + void write_preamble(void); + + string recv_callsign, recv_locator, recv_antenna; + string host, port; + string long_id, short_id; + + static const unsigned char long_station_info_template[]; + static const unsigned char short_station_info_template[]; + static const unsigned char rcpt_record_template[]; + vector long_station_info; + vector short_station_info; + + uint32_t identifier; + uint32_t sequence_number; + + unsigned template_count; + time_t last_template; + + Socket* send_socket; + unsigned char* dgram; + size_t dgram_size; + size_t report_offset; + + void create_socket(void); + pthread_t resolver_thread; + static void* resolver(void* obj); + + static const char hexsym[]; + static const string& printhex(const unsigned char* s, size_t len); + + static size_t pad(size_t len, size_t mult); +}; + + +class pskrep +{ +public: + pskrep(const string& call, const string& loc, const string& ant, + const string& host, const string& port, + const string& long_id, const string& short_id, + bool reg_auto, bool reg_log, bool reg_manual); + ~pskrep(); + + static void recv(int afreq, const char* str, const regmatch_t* calls, size_t len, void* obj); + static void log(const char* call, const char* loc, long long freq, trx_mode mode, time_t rtime, void* obj); + static void manual(const char* call, const char* loc, long long freq, trx_mode mode, time_t rtime, void* obj); + bool progress(void); + + static band_t band(long long freq_hz); + static fre_t locator_re; +private: + + void append(string call, const char* loc, long long freq, trx_mode mode, time_t rtime, rtype_t rtype); + void gc(void); + + void load_queue(void); + void save_queue(void); + + static bool not_sent(const band_map_t::value_type& r) + { + return r.status != STATUS_SENT; + } + + queue_t queue; + pskrep_sender sender; +}; + +fre_t pskrep::locator_re("[a-r]{2}[0-9]{2}[a-x]{2}", REG_EXTENDED | REG_NOSUB | REG_ICASE); + +#define SHORT_ID_SIZE 4 +#define LONG_ID_SIZE 8 + +// ------------------------------------------------------------------------------------------------- + +static string error_string; + +static bool pskrep_check(void) +{ + struct { + const string* var; + const char* msg; + } check[] = { + { &progdefaults.myCall, "callsign" }, + { &progdefaults.myLocator, "locator" }, + { &progdefaults.myAntenna, "antenna info" }, + }; + for (size_t i = 0; i < sizeof(check)/sizeof(*check); i++) { + if (check[i].var->empty()) { + error_string.assign("Error: missing ").append(check[i].msg); + return false; + } + } + if (!pskrep::locator_re.match(progdefaults.myLocator.c_str())) { + error_string = "Error: bad IARU locator"; + return false; + } + + return true; +} + +const char* pskrep_error(void) +{ + return error_string.c_str(); +} + +static void pskrep_progress(void* obj) +{ + if (reinterpret_cast(obj)->progress()) + Fl::add_timeout(SEND_INTERVAL, pskrep_progress, obj); + else + pskrep_stop(); +} + +static void pskrep_make_id(string& id, size_t len) +{ + id.resize(len); + + ifstream f("/dev/urandom"); + if (f) { + for (size_t i = 0; i < len; i++) + while ((id[i] = f.get()) != EOF && !isgraph(id[i])); + f.close(); + } + else { + unsigned seed = time(NULL); + if (!progdefaults.myCall.empty()) + seed ^= simple_hash_str((const unsigned char*)progdefaults.myCall.c_str()); + srandom(seed); + for (size_t i = 0; i < len; i++) + while (!isgraph(id[i] = random() % 0x7F)); + } +} + +static pskrep* pskr = 0; + +bool pskrep_start(void) +{ + if (pskr) + return true; + else if (!pskrep_check()) + return false; + + // get identifier + string fname = HomeDir; + fname.append(PSKREP_ID_FILE); + ifstream in(fname.c_str()); + string long_id, short_id; + if (in) + in >> long_id >> short_id; + if (!in || in.eof()) { + in.close(); + pskrep_make_id(long_id, LONG_ID_SIZE); + pskrep_make_id(short_id, SHORT_ID_SIZE); + + ofstream out(fname.c_str()); + if (out) + out << long_id << ' ' << short_id << '\n'; + else + LOG_ERROR("Could not write identifiers (\"%s\", \"%s\") to %s", + long_id.c_str(), short_id.c_str(), fname.c_str()); + } + + pskr = new pskrep(progdefaults.myCall, progdefaults.myLocator, progdefaults.myAntenna, + progdefaults.pskrep_host, progdefaults.pskrep_port, long_id, short_id, + progdefaults.pskrep_auto, progdefaults.pskrep_log, true); + Fl::add_timeout(SEND_INTERVAL, pskrep_progress, pskr); + + return true; +} + +void pskrep_stop(void) +{ + Fl::remove_timeout(pskrep_progress, pskr); + + delete pskr; + pskr = 0; +} + +// ------------------------------------------------------------------------------------------------- + +pskrep::pskrep(const string& call, const string& loc, const string& ant, + const string& host, const string& port, + const string& long_id, const string& short_id, + bool reg_auto, bool reg_log, bool reg_manual) + : sender(call, loc, ant, host, port, long_id, short_id) +{ + if (reg_auto) + spot_register_recv(pskrep::recv, this, PSKREP_RE, REG_EXTENDED | REG_ICASE); + if (reg_log) + spot_register_log(pskrep::log, this); + if (reg_manual) + spot_register_manual(pskrep::manual, this); + load_queue(); +} + +pskrep::~pskrep() +{ + spot_unregister_recv(pskrep::recv, this); + spot_unregister_log(pskrep::log, this); + spot_unregister_manual(pskrep::manual, this); + save_queue(); +} + +// This function is called by spot_recv() when its buffer matches our PSKREP_RE +void pskrep::recv(int afreq, const char* str, const regmatch_t* calls, size_t len, void* obj) +{ + if (unlikely(calls[2].rm_so == -1 || calls[2].rm_eo == -1)) + return; + + string call(str, calls[2].rm_so, calls[2].rm_eo - calls[2].rm_so); + long long freq = afreq; + if (!wf->USB()) + freq = -freq; + freq += wf->rfcarrier(); + LOG_DEBUG("Spotted \"%s\" in buffer \"%s\"", call.c_str(), str); + + reinterpret_cast(obj)->append(call.c_str(), "", freq, + active_modem->get_mode(), time(NULL), PSKREP_AUTO); +} + +// This function is called by spot_log() +void pskrep::log(const char* call, const char* loc, long long freq, trx_mode mode, time_t rtime, void* obj) +{ + reinterpret_cast(obj)->append(call, loc, freq, mode, rtime, PSKREP_LOG); +} + +// This function is called by spot_manual() +void pskrep::manual(const char* call, const char* loc, long long freq, trx_mode mode, time_t rtime, void* obj) +{ + reinterpret_cast(obj)->append(call, loc, freq, mode, rtime, PSKREP_MANUAL); +} + +void pskrep::append(string call, const char* loc, long long freq, trx_mode mode, time_t rtime, rtype_t rtype) +{ + if (unlikely(call.empty())) + return; + transform(call.begin(), call.end(), call.begin(), static_cast(toupper)); + + if (!progdefaults.pskrep_qrg) + freq = 0LL; + + if (*loc && !locator_re.match(loc)) + loc = ""; + + band_map_t& bandq = queue[call][band(freq)]; + if (bandq.empty() || rtime - bandq.back().rtime >= DUP_INTERVAL) { // add new + bandq.push_back(rcpt_report_t(mode, freq, rtime, rtype, loc)); + LOG_INFO("Added (call=\"%s\", loc=\"%s\", mode=\"%s\", freq=%lld, time=%ld, type=%u)", + call.c_str(), loc, mode_info[mode].adif_name, freq, rtime, rtype); + save_queue(); + } + else if (!bandq.empty()) { + band_map_t::value_type& r = bandq.back(); + if (r.status != STATUS_SENT && *loc && r.locator != loc) { // update last + r.locator = loc; + r.rtype = rtype; + LOG_INFO("Updated (call=\"%s\", loc=\"%s\", mode=\"%s\", freq=%lld, time=%ld, type=%u)", + call.c_str(), loc, mode_info[r.mode].adif_name, r.freq, r.rtime, rtype); + save_queue(); + } + } +} + +// Handle queued reports +bool pskrep::progress(void) +{ + if (queue.empty()) + return true; + + unsigned nrep = 0; + bool sender_full = false; + for (queue_t::iterator i = queue.begin(); i != queue.end(); ++i) { + for (call_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j) { + for (band_map_t::iterator k = j->second.begin(); k != j->second.end(); ++k) { + switch (k->status) { + case STATUS_NEW: + if ((sender_full = !sender.append(i->first, *k))) + goto send_reports; + k->status = STATUS_PENDING; + nrep++; + break; + case STATUS_PENDING: // sent in last cycle + k->status = STATUS_SENT; + default: + break; + } + } + } + } + +send_reports: + LOG_INFO("Found %u new report(s)", nrep); + if (nrep) { + if (!sender.send()) { + LOG_ERROR("Sender failed, disabling pskreporter"); + return false; + } + return progress(); + } + + gc(); + save_queue(); + return true; +} + +// Delete sent reports that are older than DUP_INTERVAL seconds +void pskrep::gc(void) +{ + time_t threshold = time(NULL) - DUP_INTERVAL; + unsigned rm = 0; + + for (queue_t::iterator i = queue.begin(); i != queue.end() ; ) { + for (call_map_t::iterator j = i->second.begin(); j != i->second.end() ; ) { + band_map_t& b = j->second; + band_map_t::iterator k = find_if(b.begin(), b.end(), not_sent); + if (k != b.begin() && k == b.end()) + --k; + rm += k - b.begin(); + k = b.erase(b.begin(), k); + + if (k != b.end() && k->status == STATUS_SENT && k->rtime <= threshold) { + b.erase(k); + rm++; + } + + if (b.empty()) + i->second.erase(j++); + else + ++j; + } + if (i->second.empty()) + queue.erase(i++); + else + ++i; + } + + LOG_DEBUG("Removed %zu sent report(s)", rm); +} + +static ostream& operator<<(ostream& out, const rcpt_report_t& r); +static istream& operator>>(istream& in, rcpt_report_t& r); +static ostream& operator<<(ostream& out, const queue_t& q); +static istream& operator>>(istream& in, queue_t& q); + +void pskrep::save_queue(void) +{ + string fname = HomeDir; + fname.append(PSKREP_QUEUE_FILE); + ofstream out(fname.c_str()); + + if (out) + out << queue; + else + LOG_ERROR("Could not write %s", fname.c_str()); +} + +void pskrep::load_queue(void) +{ + string fname = HomeDir; + fname.append(PSKREP_QUEUE_FILE); + ifstream in(fname.c_str()); + if (!in) + return; + + in >> queue; + // restore pending reports as new + for (queue_t::iterator i = queue.begin(); i != queue.end(); ++i) + for (call_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j) + for (band_map_t::iterator k = j->second.begin(); k != j->second.end(); ++k) + if (k->status == STATUS_PENDING) + k->status = STATUS_NEW; +} + +band_t pskrep::band(long long freq_hz) +{ + switch (freq_hz / 1000000LL) { + case 0: return BAND_LMW; + case 1: return BAND_160M; + case 3: return BAND_80M; + case 4: return BAND_75M; + case 5: return BAND_60M; + case 7: return BAND_40M; + case 10: return BAND_30M; + case 14: return BAND_20M; + case 18: return BAND_17M; + case 21: return BAND_15M; + case 24: return BAND_12M; + case 28 ... 29: return BAND_10M; + case 50 ... 54: return BAND_6M; + case 70 ... 71: return BAND_4M; + case 144 ... 148: return BAND_2M; + case 222 ... 225: return BAND_125CM; + case 420 ... 450: return BAND_70CM; + case 902 ... 928: return BAND_33CM; + case 1240 ... 1325: return BAND_23CM; + case 2300 ... 2450: return BAND_13CM; + case 3300 ... 3500: return BAND_9CM; + } + + return BAND_OTHER; +} + +// ------------------------------------------------------------------------------------------------- + +// Text fields must be <= 254 bytes +#define MAX_TEXT_SIZE 254 +// Records must be padded to a multiple of 4 +#define PAD 4 + +pskrep_sender::pskrep_sender(const string& call, const string& loc, const string& ant, + const string& host_, const string& port_, + const string& long_id_, const string& short_id_) + : recv_callsign(call, 0, MAX_TEXT_SIZE), recv_locator(loc, 0, MAX_TEXT_SIZE), + recv_antenna(ant, 0, MAX_TEXT_SIZE), + host(host_, 0, MAX_TEXT_SIZE), port(port_, 0, MAX_TEXT_SIZE), + long_id(long_id_, 0, LONG_ID_SIZE), short_id(short_id_, 0, SHORT_ID_SIZE), + sequence_number(0), template_count(2 * TEMPLATE_THRESHOLD), last_template(0), + send_socket(0), dgram_size(0), report_offset(0) +{ + create_socket(); + dgram = new unsigned char[DGRAM_MAX]; + write_station_info(); +} + +pskrep_sender::~pskrep_sender() +{ + delete send_socket; + delete [] dgram; +} + +// fldigi uses 0x0219 as the long station info template id (bytes 4,5) +const unsigned char pskrep_sender::long_station_info_template[] = { + 0x00, 0x03, 0x00, 0x34, 0x02, 0x19, 0x00, 0x05, 0x00, 0x00, + 0x80, 0x02, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F, // receiverCallsign + 0x80, 0x04, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F, // receiverLocator + 0x80, 0x0C, 0x00, 0x08, 0x00, 0x00, 0x76, 0x8F, // persistentIdentifier + 0x80, 0x08, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F, // decoderSoftware + 0x80, 0x09, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F, // anntennaInformation + 0x00, 0x00 +}; + +// fldigi uses 0x0218 as the short station info template id (bytes 4,5) +const unsigned char pskrep_sender::short_station_info_template[] = { + 0x00, 0x03, 0x00, 0x24, 0x02, 0x18, 0x00, 0x03, 0x00, 0x00, + 0x80, 0x02, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F, // receiverCallsign + 0x80, 0x04, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F, // receiverLocator + 0x80, 0x0C, 0x00, 0x08, 0x00, 0x00, 0x76, 0x8F, // persistentIdentifier + 0x00, 0x00 +}; + +void pskrep_sender::write_station_info(void) +{ + char prog_info[MAX_TEXT_SIZE]; + size_t prog_len; + + prog_len = snprintf(prog_info, sizeof(prog_info), "%s", PACKAGE_TARNAME "-" PACKAGE_VERSION); + prog_len = MIN(prog_len, sizeof(prog_info)); + struct utsname u; + if (uname(&u) != -1) { + prog_len += snprintf(prog_info+prog_len, sizeof(prog_info)-prog_len, "/%s-%s", u.sysname, u.machine); + prog_len = MIN(prog_len, sizeof(prog_info)); + } + + size_t call_len = recv_callsign.length(), + loc_len = recv_locator.length(), + ant_len = recv_antenna.length(); + + size_t long_len, short_len; + // Long station info length + long_len = 4 + // 4-byte header + 1 + call_len + // 1-byte call length + call string length + 1 + loc_len + // 1-byte loc length + loc string length + 8 + // 8-byte identifier + 1 + prog_len + // 1-byte prog length + prog string length + 1 + ant_len; // 1-byte ant length + ant string length + long_len = pad(long_len, PAD); + // Short station info length + short_len = 4 + // 4-byte header + 1 + call_len + // 1-byte call length + call string length + 1 + loc_len + // 1-byte loc length + loc string length + 8; // 8-byte identifier + short_len = pad(short_len, PAD); + + long_station_info.resize(long_len); + short_station_info.resize(short_len); + unsigned char* p; + size_t npad; + + // Write the long station info + p = &long_station_info[0]; + // header + memcpy(p, long_station_info_template + 4, 2); p += 2; + *reinterpret_cast(p) = htons(long_len); p += sizeof(uint16_t); + // call + *p++ = call_len; memcpy(p, recv_callsign.data(), call_len); p += call_len; + // locator + *p++ = loc_len; memcpy(p, recv_locator.data(), loc_len); p += loc_len; + // identifier + memcpy(p, long_id.data(), LONG_ID_SIZE); p += LONG_ID_SIZE; + // program + *p++ = prog_len; memcpy(p, prog_info, prog_len); p += prog_len; + // antenna + *p++ = ant_len; memcpy(p, recv_antenna.data(), ant_len); p += ant_len; + // pad + npad = &long_station_info[0] + long_len - p; + if (npad) + memset(p, 0, npad); + LOG_DEBUG("long_station_info=\"%s\"", printhex(&long_station_info[0], long_len).c_str()); + + // Write the short station info + p = &short_station_info[0]; + // header + memcpy(p, short_station_info_template + 4, 2); p += 2; + *reinterpret_cast(p) = htons(short_len); p += sizeof(uint16_t); + // call + *p++ = call_len; memcpy(p, recv_callsign.data(), call_len); p += call_len; + // locator + *p++ = loc_len; memcpy(p, recv_locator.data(), loc_len); p += loc_len; + // identifier + memcpy(p, long_id.data(), LONG_ID_SIZE); p += LONG_ID_SIZE; + // pad + npad = &short_station_info[0] + short_len - p; + if (npad) + memset(p, 0, npad); + LOG_DEBUG("short_station_info=\"%s\"", printhex(&short_station_info[0], short_len).c_str()); +} + +// fldigi uses 0x022C as the reception record template id (bytes 4,5) +const unsigned char pskrep_sender::rcpt_record_template[] = { + 0x00, 0x02, 0x00, 0x34, 0x02, 0x2C, 0x00, 0x06, + 0x80, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F, // senderCallsign + 0x00, 0x96, 0x00, 0x04, // flowStartSeconds + 0x80, 0x05, 0x00, 0x04, 0x00, 0x00, 0x76, 0x8F, // frequency + 0x80, 0x0A, 0xFF, 0xFF, 0x00, 0x00, 0x76, 0x8F, // mode (adif string) + 0x80, 0x03, 0xff, 0xff, 0x00, 0x00, 0x76, 0x8F, // senderLocator (if known) + 0x80, 0x0B, 0x00, 0x01, 0x00, 0x00, 0x76, 0x8F // flags (informationSource) +}; + +void pskrep_sender::write_preamble(void) +{ + time_t now = time(NULL); + unsigned char* p = dgram; + + // header + *p++ = 0x00; *p++ = 0x0A; /* length written later */ p += 2; + /* time written later */ p += sizeof(uint32_t); + *reinterpret_cast(p) = htonl(sequence_number); p += sizeof(uint32_t); + memcpy(p, short_id.data(), SHORT_ID_SIZE); p += SHORT_ID_SIZE; + + const unsigned char* station_info_template; + size_t tlen; + vector* station_info; + + if (template_count == 0 && now - last_template >= TEMPLATE_INTERVAL) + template_count = TEMPLATE_THRESHOLD; + if (template_count > TEMPLATE_THRESHOLD) { + station_info_template = long_station_info_template; + tlen = sizeof(long_station_info_template); + station_info = &long_station_info; + } + else if (template_count >= 0) { + station_info_template = short_station_info_template; + tlen = sizeof(short_station_info_template); + station_info = &short_station_info; + } + if (template_count > 0) { + memcpy(p, rcpt_record_template, sizeof(rcpt_record_template)); p += sizeof(rcpt_record_template); + memcpy(p, station_info_template, tlen); p += tlen; + template_count--; + last_template = now; + } + + // station info record + memcpy(p, &(*station_info)[0], station_info->size()); p += station_info->size(); + + report_offset = p - dgram; + // write report record header + memcpy(p, rcpt_record_template + 4, 2); p += 2; /* length written later */ p += sizeof(uint16_t); + + dgram_size = p - dgram; +} + +bool pskrep_sender::append(const string& callsign, const band_map_t::value_type& r) +{ + if (dgram_size == 0) + write_preamble(); + + size_t call_len = callsign.length(); + call_len = MIN(MAX_TEXT_SIZE, call_len); + + const char* mode = mode_info[r.mode].adif_name; + size_t mode_len = strlen(mode); + mode_len = MIN(MAX_TEXT_SIZE, mode_len); + + size_t loc_len = MIN(MAX_TEXT_SIZE, r.locator.length()); + + // call_len + call + time + freq + mode_len + mode + loc_len + loc + info + size_t rlen = 1 + call_len + 4 + 4 + 1 + mode_len + 1 + loc_len + 1; + + if (pad(rlen, PAD) + dgram_size > DGRAM_MAX) // datagram full + return false; + + + LOG_INFO("Appending report (call=%s mode=%s freq=%lld time=%ld type=%u)", + callsign.c_str(), mode_info[r.mode].adif_name, r.freq, r.rtime, r.rtype); + + unsigned char* start = dgram + dgram_size; + unsigned char* p = start; + // call + *p++ = call_len; memcpy(p, callsign.data(), call_len); p += call_len; + // 4-byte reception time + *reinterpret_cast(p) = htonl(r.rtime); p += sizeof(uint32_t); + // 4-byte freq + *reinterpret_cast(p) = htonl(r.freq); p += sizeof(uint32_t); + // mode + *p++ = mode_len; memcpy(p, mode, mode_len); p += mode_len; + // locator + *p++ = loc_len; memcpy(p, r.locator.data(), loc_len); p += loc_len; + // info source + *p++ = r.rtype; + + LOG_DEBUG(" \"%s\"", printhex(start, p - start).c_str()); + + dgram_size += rlen; + return true; +} + +void* pskrep_sender::resolver(void* obj) +{ + pskrep_sender* s = reinterpret_cast(obj); + try { + s->send_socket = new Socket(Address(s->host.c_str(), s->port.c_str(), "udp")); + s->send_socket->connect(); + } + catch (const SocketException& e) { + LOG_ERROR("Could not resolve %s: %s", s->host.c_str(), e.what()); + } + + return NULL; +} + +void pskrep_sender::create_socket(void) +{ + if (pthread_create(&resolver_thread, NULL, resolver, this) != 0) { + LOG_PERROR("pthread_create"); + return; + } +} + +bool pskrep_sender::send(void) +{ + if (!send_socket) + return false; + + // empty dgram or no reports (shouldn't happen) + if (dgram_size == 0 || dgram_size == report_offset + 4) { + LOG_DEBUG("Not sending empty dgram: %zu %zu", dgram_size, report_offset); + return false; + } + + // Finish writing the report record: + // do we need padding? + size_t npad = (dgram_size - report_offset) % PAD; + if (npad) { + npad = PAD - npad; + memset(dgram + dgram_size, 0x0, npad); + dgram_size += npad; + } + // write length + *reinterpret_cast(dgram + report_offset + 2) = htons(dgram_size - report_offset); + + // finish writing the datagram + *reinterpret_cast(dgram + 2) = htons(dgram_size); + *reinterpret_cast(dgram + 4) = htonl(time(NULL)); + + bool ret; + LOG_DEBUG("Sending datagram (%zu): \"%s\"", dgram_size, printhex(dgram, dgram_size).c_str()); + try { + if ((size_t)send_socket->send(dgram, dgram_size) != dgram_size) + throw SocketException("short write"); + ret = true; + } + catch (const SocketException& e) { + LOG_ERROR("Could not send datagram to %s port %s: %s", host.c_str(), port.c_str(), e.what()); + ret = false; + } + + // increment this regardless of any errors + sequence_number++; + dgram_size = 0; + + return ret; +} + +// Pad len to a multiple of mult +size_t pskrep_sender::pad(size_t len, size_t mult) +{ + size_t r = len % mult; + return r ? len + mult - r : len; +} + +const char pskrep_sender::hexsym[] = "0123456789ABCDEF"; +const string& pskrep_sender::printhex(const unsigned char* s, size_t len) +{ + static string hex; + if (unlikely(len == 0)) + return hex.erase(); + + hex.resize(len * 3 - 1); + string::iterator i = hex.begin(); + size_t j; + for (j = 0; j < len-1; j++) { + *i++ = hexsym[s[j] >> 4]; + *i++ = hexsym[s[j] & 0xF]; + *i++ = ' '; + } + *i++ = hexsym[s[j] >> 4]; + *i = hexsym[s[j] & 0xF]; + + return hex; +} + +// ------------------------------------------------------------------------------------------------- + +static istream& operator>>(istream& in, rtype_t& t) +{ + int i; + in >> i; + t = static_cast(i); + return in; +} +static istream& operator>>(istream& in, status_t& t) +{ + int i; + in >> i; + t = static_cast(i); + return in; +} +static istream& operator>>(istream& in, rcpt_report_t& r) +{ + in >> r.mode >> r.freq >> r.rtime >> r.rtype >> r.status >> r.locator; + if (*r.locator.c_str() == '?') r.locator.clear(); + return in; +} + +static ostream& operator<<(ostream& out, const rcpt_report_t& r) +{ + return out << r.mode << ' ' << r.freq << ' ' << r.rtime << ' ' + << r.rtype << ' ' << r.status << ' ' << (r.locator.empty() ? "?" : r.locator); +} +static ostream& operator<<(ostream& out, const queue_t& q) +{ + for (queue_t::const_iterator i = q.begin(); i != q.end(); ++i) + for (call_map_t::const_iterator j = i->second.begin(); j != i->second.end(); ++j) + for (band_map_t::const_iterator k = j->second.begin(); k != j->second.end(); ++k) + out << *k << " " << j->first << " " << i->first << '\n'; + + return out; +} +static istream& operator>>(istream& in, queue_t& q) +{ + rcpt_report_t rep; + int band; + string call; + + while (in >> rep >> band >> call) + q[call][static_cast(band)].push_back(rep); + + return in; +} diff --git a/src/spot/spot.cxx b/src/spot/spot.cxx new file mode 100644 index 00000000..0834a1a4 --- /dev/null +++ b/src/spot/spot.cxx @@ -0,0 +1,203 @@ +// ---------------------------------------------------------------------------- +// spot.cxx +// +// Copyright (C) 2008 +// Stelios Bounanos, M0GLD +// +// This file is part of fldigi. +// +// fldigi 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. +// +// fldigi is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ---------------------------------------------------------------------------- + +#include + +#include +#include + +#include "trx.h" +#include "globals.h" +#include "re.h" +#include "fl_digi.h" +#include "debug.h" +#include "spot.h" + +#define SEARCHLEN 32 +#define DECBUFSIZE 8 * SEARCHLEN + + +using namespace std; + +struct callback_t { + void* data; + + spot_log_cb_t lcb; + + spot_log_cb_t mcb; + + spot_recv_cb_t rcb; + fre_t* re; +}; + +static map buffers; +typedef vector cblist_t; + + +static cblist_t cblist; + +void spot_recv(char c, int decoder, int afreq) +{ + static trx_mode last_mode = NUM_MODES + 1; + + switch (decoder) { + case -1: // mode without multiple decoders + decoder = active_modem->get_mode(); + if (last_mode > NUM_MODES) + last_mode = decoder; + else if (last_mode != decoder) { + buffers.clear(); + last_mode = decoder; + } + break; + default: + if (last_mode > NUM_MODES) + last_mode = active_modem->get_mode(); + else if (last_mode != active_modem->get_mode()) { + buffers.clear(); + last_mode = active_modem->get_mode(); + } + break; + } + if (afreq == 0) + afreq = active_modem->get_freq(); + + string& buf = buffers[decoder]; + buf.reserve(DECBUFSIZE); + + buf += c; + string::size_type n = buf.length(); + if (n == DECBUFSIZE) + buf.erase(0, DECBUFSIZE - SEARCHLEN); + const char* search = buf.c_str() + (n > SEARCHLEN ? n - SEARCHLEN : 0); + + for (cblist_t::iterator i = cblist.begin(); i != cblist.end(); ++i) { + if (i->rcb && unlikely(i->re->match(search))) { + const vector& m = i->re->suboff(); + if (m.empty()) + i->rcb(afreq, search, NULL, 0, i->data); + else + i->rcb(afreq, search, &m[0], m.size(), i->data); + } + } +} + +static void get_log_details(long long& freq, trx_mode& mode, time_t& rtime) +{ + if (mode == NUM_MODES) + mode = active_modem->get_mode(); + if (mode >= MODE_WWV) + return; + + if (freq == 0LL) + freq = active_modem->get_freq(); + if (!wf->USB()) + freq = -freq; + freq += wf->rfcarrier(); + + if (rtime == -1L) + rtime = time(NULL); +} + +void spot_log(const char* callsign, const char* locator, long long freq, trx_mode mode, time_t rtime) +{ + get_log_details(freq, mode, rtime); + for (cblist_t::const_iterator i = cblist.begin(); i != cblist.end(); ++i) + if (i->lcb) + i->lcb(callsign, locator, freq, mode, rtime, i->data); +} + +void spot_manual(const char* callsign, const char* locator, long long freq, trx_mode mode, time_t rtime) +{ + get_log_details(freq, mode, rtime); + for (cblist_t::const_iterator i = cblist.begin(); i != cblist.end(); ++i) + if (i->mcb) + i->mcb(callsign, locator, freq, mode, rtime, i->data); +} + +// +// A callback of type spot_log_cb_t is registered with a data argument. +// The callback is invoked every time a QSO is logged. +// +void spot_register_log(spot_log_cb_t lcb, void* ldata) +{ + callback_t c = { ldata, lcb, 0, 0, 0 }; + cblist.push_back(c); +} +// +// A callback of type spot_log_cb_t is registered with a data argument. +// The callback is invoked every time the user manually spots a callsign. +// +void spot_register_manual(spot_log_cb_t mcb, void* mdata) +{ + callback_t c = { mdata, 0, mcb, 0, 0 }; + cblist.push_back(c); +} + +// +// A callback of type spot_recv_cb_t is registered with a regular +// expression (RE, RE_flags). If the RE matches the spotter's search +// buffer, the callback is invoked with offsets into the search buffer +// indicating substring matches, if the RE defines any, and with its +// data argument. The offset format is described in regexec(3). The +// buffer and offsets are only valid during that particular invocation. +// Clients should use anchoring to avoid repeated calls. +// +void spot_register_recv(spot_recv_cb_t rcb, void* rdata, const char* re, int reflags) +{ + callback_t c = { rdata, 0, 0, rcb, new fre_t(re, reflags) }; + cblist.push_back(c); + show_spot(true); +} + +void spot_unregister_log(spot_log_cb_t lcb, void* ldata) +{ + for (cblist_t::reverse_iterator ri = cblist.rbegin(); ri != cblist.rend(); ++ri) { + if (lcb == ri->lcb && ldata == ri->data) { + cblist.erase((++ri).base()); + break; + } + } +} +void spot_unregister_manual(spot_log_cb_t mcb, void* mdata) +{ + for (cblist_t::reverse_iterator ri = cblist.rbegin(); ri != cblist.rend(); ++ri) { + if (mcb == ri->mcb && mdata == ri->data) { + cblist.erase((++ri).base()); + break; + } + } +} +void spot_unregister_recv(spot_recv_cb_t rcb, void* rdata) +{ + cblist_t::reverse_iterator ri; + for (ri = cblist.rbegin(); ri != cblist.rend(); ++ri) { + if (rcb == ri->rcb && rdata == ri->data) { + cblist.erase((++ri).base()); + break; + } + } + + for (ri = cblist.rbegin(); ri != cblist.rend(); ++ri) + if (ri->rcb) break; + show_spot(ri != cblist.rend()); +} diff --git a/src/trx/trx.cxx b/src/trx/trx.cxx index 4742b170..71a69c7b 100644 --- a/src/trx/trx.cxx +++ b/src/trx/trx.cxx @@ -444,7 +444,7 @@ void macro_timer(void *) btnMacroDummy->show(); FL_UNLOCK(); } else { - snprintf(timermsg, sizeof(timermsg), "Timer: %d", countdown); + snprintf(timermsg, sizeof(timermsg), "%d", countdown); FL_LOCK(); btnMacroTimer->label(timermsg); btnMacroTimer->redraw_label(); @@ -458,7 +458,7 @@ void trx_start_macro_timer() { countdown = progdefaults.timeout; Fl::add_timeout(1.0, macro_timer); - snprintf(timermsg, sizeof(timermsg), "Timer: %d", countdown); + snprintf(timermsg, sizeof(timermsg), "%d", countdown); FL_LOCK(); btnMacroTimer->label(timermsg); btnMacroTimer->redraw_label(); diff --git a/src/widgets/FTextView.cxx b/src/widgets/FTextView.cxx index a11549ab..80affa55 100644 --- a/src/widgets/FTextView.cxx +++ b/src/widgets/FTextView.cxx @@ -417,6 +417,9 @@ Fl_Menu_Item FTextView::view_menu[] = { { make_icon_label(ENTER_SYMBOL "&Call", enter_key_icon), 0, 0, 0, 0, _FL_MULTI_LABEL }, { make_icon_label(ENTER_SYMBOL "&Name", enter_key_icon), 0, 0, 0, 0, _FL_MULTI_LABEL }, { make_icon_label(ENTER_SYMBOL "QT&H", enter_key_icon), 0, 0, 0, 0, _FL_MULTI_LABEL }, + { make_icon_label(ENTER_SYMBOL "&State", enter_key_icon), 0, 0, 0, 0, _FL_MULTI_LABEL }, + { make_icon_label(ENTER_SYMBOL "&Province", enter_key_icon), 0, 0, 0, 0, _FL_MULTI_LABEL }, + { make_icon_label(ENTER_SYMBOL "Serial Nr", enter_key_icon), 0, 0, 0, 0, _FL_MULTI_LABEL }, { make_icon_label(ENTER_SYMBOL "&Locator", enter_key_icon), 0, 0, 0, 0, _FL_MULTI_LABEL }, { make_icon_label(ENTER_SYMBOL "&RST(r)", enter_key_icon), 0, 0, 0, FL_MENU_DIVIDER, _FL_MULTI_LABEL }, { make_icon_label("Insert divider", insert_link_icon), 0, 0, 0, 0, _FL_MULTI_LABEL }, @@ -758,6 +761,15 @@ void FTextView::menu_cb(int val) case RX_MENU_QTH: input = inpQth; break; + case RX_MENU_STATE: + input = inpCnty; + break; + case RX_MENU_PROVINCE: + input = inpVEprov; + break; + case RX_MENU_SERIAL: + input = inpSerNo; + break; case RX_MENU_LOC: input = inpLoc; break; From 1f6e9c6704e1d5fb0d10b38378b1a7978c02994c Mon Sep 17 00:00:00 2001 From: Stelios Bounanos Date: Sun, 23 Nov 2008 06:20:16 +0000 Subject: [PATCH 2/2] Upstream version 3.04BE --- configure.ac | 2 +- src/dialogs/confdialog.cxx | 9 ++++++--- src/dialogs/confdialog.fl | 9 ++++++--- src/dialogs/fl_digi.cxx | 23 +++++++++++++---------- src/include/configuration.h | 1 + src/include/fldigi-config.h | 2 +- src/logger/logger.cxx | 9 +++++++-- src/main.cxx | 8 +++++--- src/misc/lookupcall.cxx | 33 ++++++++++++++++++++++----------- 9 files changed, 62 insertions(+), 34 deletions(-) diff --git a/configure.ac b/configure.ac index 5cdcaa85..510a9c78 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,7 @@ dnl major and minor must be integers; patch may dnl contain other characters or be empty m4_define(FLDIGI_MAJOR, [3]) m4_define(FLDIGI_MINOR, [0]) -m4_define(FLDIGI_PATCH, [4BD]) +m4_define(FLDIGI_PATCH, [4BE]) AC_INIT([fldigi], FLDIGI_MAJOR.FLDIGI_MINOR[FLDIGI_PATCH], [w1hkj AT w1hkj DOT com]) diff --git a/src/dialogs/confdialog.cxx b/src/dialogs/confdialog.cxx index c451f92d..d5309136 100644 --- a/src/dialogs/confdialog.cxx +++ b/src/dialogs/confdialog.cxx @@ -199,12 +199,15 @@ Fl_Button *btnPSKRepInit=(Fl_Button *)0; static void cb_btnPSKRepInit(Fl_Button* o, void*) { pskrep_stop(); -if (!pskrep_start()) +if (!pskrep_start()) { boxPSKRepMsg->copy_label(pskrep_error()); -else { + progdefaults.usepskrep = false; +} else { boxPSKRepMsg->label(0); o->labelcolor(FL_FOREGROUND_COLOR); -}; + progdefaults.usepskrep = true; +} +progdefaults.changed = true; } Fl_Box *boxPSKRepMsg=(Fl_Box *)0; diff --git a/src/dialogs/confdialog.fl b/src/dialogs/confdialog.fl index 53c9edc2..8232bdc6 100644 --- a/src/dialogs/confdialog.fl +++ b/src/dialogs/confdialog.fl @@ -286,12 +286,15 @@ progdefaults.changed = true;} Fl_Button btnPSKRepInit { label Initialize callback {pskrep_stop(); -if (!pskrep_start()) +if (!pskrep_start()) { boxPSKRepMsg->copy_label(pskrep_error()); -else { + progdefaults.usepskrep = false; +} else { boxPSKRepMsg->label(0); o->labelcolor(FL_FOREGROUND_COLOR); -}} + progdefaults.usepskrep = true; +} +progdefaults.changed = true;} xywh {303 186 80 24} } Fl_Box boxPSKRepMsg { diff --git a/src/dialogs/fl_digi.cxx b/src/dialogs/fl_digi.cxx index 4194de4a..b6945ab9 100644 --- a/src/dialogs/fl_digi.cxx +++ b/src/dialogs/fl_digi.cxx @@ -196,14 +196,14 @@ AFCind *AFCindicator; int pad = 1; //wSpace; int x_qsoframe = BTNWIDTH; -int w_inpFreq = 80; -int w_inpTime = 38; -int w_qsoTime = 24; -int w_inpCall = 80; +int w_inpFreq = 80; +int w_inpTime = 38; +int w_qsoTime = 24; +int w_inpCall = 120; int w_inpName = 60; -int w_inpRstIn = 30; +int w_inpRstIn = 30; int w_inpRstOut = 30; -int w_inpSerNo = 40; +int w_inpSerNo = 40; int wf1 = pad + w_inpFreq + pad + w_inpTime + w_qsoTime + pad + w_inpCall + pad + w_inpName + pad + w_inpRstIn + pad + w_inpRstOut + pad + w_inpSerNo; @@ -213,11 +213,12 @@ int w_fm2 = 20; int w_fm3 = 20; int w_fm4 = 25; int w_fm5 = 20; -int w_inpCnty = 24; +int w_inpCnty = 90; +int w_inpProv = 30; int w_inpLOC = 65; int w_inpAZ = 30; int w_inpQth = wf1 - w_fm1 - w_fm2 - w_fm3 - w_fm4 - w_fm5 - - 2*w_inpCnty - w_inpLOC - w_inpAZ; + w_inpCnty - w_inpProv - w_inpLOC - w_inpAZ; int qh = Hqsoframe / 2; int rig_control_width = FREQWIDTH + 4; @@ -2126,11 +2127,13 @@ void create_fl_digi_main() { Fl_Box *fm2box = new Fl_Box(rightof(inpQth), y3, w_fm2, qh - pad, "St"); fm2box->align(FL_ALIGN_INSIDE); inpCnty = new Fl_Input(rightof(fm2box), y3, w_inpCnty, qh - pad, ""); + inpCnty->tooltip("US State or Country"); inpCnty->align(FL_ALIGN_INSIDE); - Fl_Box *fm3box = new Fl_Box(rightof(inpCnty), y3, w_fm3, qh - pad, "Pv"); + Fl_Box *fm3box = new Fl_Box(rightof(inpCnty), y3, w_fm3, qh - pad, "Pr"); fm3box->align(FL_ALIGN_INSIDE); - inpVEprov = new Fl_Input(rightof(fm3box), y3, w_inpCnty, qh - pad, ""); + inpVEprov = new Fl_Input(rightof(fm3box), y3, w_inpProv, qh - pad, ""); + inpVEprov->tooltip("Can. Province"); inpVEprov->align(FL_ALIGN_INSIDE); Fl_Box *fm4box = new Fl_Box(rightof(inpVEprov), y3, w_fm4, qh - pad, "Loc"); diff --git a/src/include/configuration.h b/src/include/configuration.h index a535eec7..49230bd2 100644 --- a/src/include/configuration.h +++ b/src/include/configuration.h @@ -303,6 +303,7 @@ ELEM_(std::string, arq_address, "", "127.0.0.1") \ ELEM_(std::string, arq_port, "", "3122") \ /* PSK reporter */ \ + ELEM_(bool, usepskrep, "USEPSKREP", false) \ ELEM_(bool, pskrep_auto, "PSKREPAUTO", false) \ ELEM_(bool, pskrep_log, "PSKREPLOG", false) \ ELEM_(bool, pskrep_qrg, "PSKREPQRG", false) \ diff --git a/src/include/fldigi-config.h b/src/include/fldigi-config.h index 49561e1f..2294d3f4 100644 --- a/src/include/fldigi-config.h +++ b/src/include/fldigi-config.h @@ -75,7 +75,7 @@ //#define DEFAULT_HWFALL 144 #define DEFAULT_HWFALL 124 #define DEFAULT_HNOM 500 -#define WMIN 600 +#define WMIN 645 #define HMIN 500 //#define Wwfall (DEFAULT_HNOM + 2 * BEZEL) #define DEFAULT_WNOM (Wwfall + 2* DEFAULT_SW) diff --git a/src/logger/logger.cxx b/src/logger/logger.cxx index 93a97ba2..fed1e7af 100644 --- a/src/logger/logger.cxx +++ b/src/logger/logger.cxx @@ -38,6 +38,8 @@ #include "modem.h" #include "debug.h" #include "macros.h" +#include "status.h" +#include "spot.h" #include @@ -102,7 +104,7 @@ FIELD fields[] = { {AGE, "AGE", 3}, // 1 - contacted operators age in years {ARRL_SECT, "ARRL_SECT", 12}, // 2 - contacted stations ARRL section {BAND, "BAND", 6}, // 3 - QSO band - {CALL, "CALL", 10}, // 4 - contacted stations CALLSIGN + {CALL, "CALL", 14}, // 4 - contacted stations CALLSIGN {CNTY, "CNTY", 20}, // 5 - secondary political subdivision, ie: STATE {COMMENT, "COMMENT", 80}, // 6 - comment field for QSO {CONT, "CONT", 10}, // 7 - contacted stations continent @@ -212,6 +214,9 @@ char LOG_MSEPARATOR[2] = {1,0}; int submit_log(void) { + if (progStatus.spot_log) + spot_log(inpCall->value(), inpLoc->value()); + char logdate[32], logtime[32], adifdate[32]; #ifndef __CYGWIN__ int msqid, len; @@ -254,7 +259,7 @@ int submit_log(void) putadif(NAME, inpName->value()); log_msg = log_msg + "qth:" + inpQth->value() + LOG_MSEPARATOR; putadif(QTH, inpQth->value()); - log_msg = log_msg + "state:" + inpCnty->value() + LOG_MSEPARATOR; + log_msg = log_msg + "cnty:" + inpCnty->value() + LOG_MSEPARATOR; putadif(CNTY, inpCnty->value()); log_msg = log_msg + "province:" + inpVEprov->value() + LOG_MSEPARATOR; putadif(VE_PROV, inpVEprov->value()); diff --git a/src/main.cxx b/src/main.cxx index b37fb3bd..2bd8a2fd 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -286,8 +286,9 @@ int main(int argc, char ** argv) XML_RPC_Server::start(progdefaults.xmlrpc_address.c_str(), progdefaults.xmlrpc_port.c_str()); #endif - if (!pskrep_start()) - LOG_ERROR("Could not start PSK reporter: %s", pskrep_error()); + if (progdefaults.usepskrep) + if (!pskrep_start()) + LOG_ERROR("Could not start PSK reporter: %s", pskrep_error()); int ret = Fl::run(); @@ -297,7 +298,8 @@ int main(int argc, char ** argv) XML_RPC_Server::stop(); #endif - pskrep_stop(); + if (progdefaults.usepskrep) + pskrep_stop(); for (int i = 0; i < NUM_QRUNNER_THREADS; i++) { cbq[i]->detach(); diff --git a/src/misc/lookupcall.cxx b/src/misc/lookupcall.cxx index b246e567..dea7a6a9 100644 --- a/src/misc/lookupcall.cxx +++ b/src/misc/lookupcall.cxx @@ -29,6 +29,7 @@ #include #include "signal.h" #include +#include #include #include #include @@ -423,6 +424,8 @@ void QRZ_disp_result() inpQth->value(lookup_qth.c_str()); inpCnty->value(lookup_state.c_str()); + inpCnty->position(0); + inpVEprov->value(lookup_province.c_str()); inpLoc->value(lookup_grid.c_str()); @@ -559,7 +562,8 @@ void QRZquery() if (!qrzalert.empty() || !qrzerror.empty()) REQ(QRZAlert); else { - lookup_qth.clear(); +// lookup_qth.clear(); + lookup_qth = lookup_addr2; REQ(QRZ_disp_result); } } @@ -687,19 +691,20 @@ bool parseQRZdetails(string &htmlpage) lookup_fname.erase(snip, 1); } - snip = htmlpage.find(BEGIN_ADDR1); - if (snip != string::npos) { - snip += strlen(BEGIN_ADDR1); - snip_end = htmlpage.find(snip_end_RECORD, snip); - lookup_addr1 = htmlpage.substr(snip, snip_end - snip); - } +// snip = htmlpage.find(BEGIN_ADDR1); +// if (snip != string::npos) { +// snip += strlen(BEGIN_ADDR1); +// snip_end = htmlpage.find(snip_end_RECORD, snip); +// lookup_addr1 = htmlpage.substr(snip, snip_end - snip); +// } snip = htmlpage.find(BEGIN_ADDR2); if (snip != string::npos) { snip += strlen(BEGIN_ADDR2); snip_end = htmlpage.find(snip_end_RECORD, snip); lookup_addr2 = htmlpage.substr(snip, snip_end - snip); - lookup_qth += lookup_addr2; +// lookup_qth += lookup_addr2; + lookup_qth = lookup_addr2; } string isUS = "aAkKnNwW"; @@ -729,11 +734,17 @@ bool parseQRZdetails(string &htmlpage) lookup_province = lookup_province.substr(0,pos); } } else { + size_t pos = lookup_qth.find(','); + if (pos != string::npos) + lookup_qth = lookup_qth.substr(0, pos); snip = htmlpage.find(BEGIN_COUNTRY); if (snip != string::npos) { snip += strlen(BEGIN_COUNTRY); snip_end = htmlpage.find(snip_end_RECORD, snip); lookup_state = htmlpage.substr(snip, snip_end - snip); + pos = lookup_state.find(','); + if (pos != string::npos) + lookup_state = lookup_state.substr(0, pos); } } @@ -744,7 +755,7 @@ bool parseQRZdetails(string &htmlpage) lookup_grid = htmlpage.substr(snip, snip_end - snip); } - lookup_notes = "Courtesy of WWW.QRZ.COM"; + lookup_notes = "Courtesy of\nWWW.QRZ.COM"; return true; } @@ -834,10 +845,10 @@ void CALLSIGNquery() switch (DB_query = static_cast(progdefaults.QRZ)) { case QRZ_NET_SUB: case QRZ_NET_HTML: - inpNotes->value("Request sent to qrz.com..."); + inpNotes->value("Request sent to\nqrz.com..."); break; case QRZ_HAMCALL: - inpNotes->value("Request sent to www.hamcall.net..."); + inpNotes->value("Request sent to\nwww.hamcall.net..."); break; case QRZ_CD: if (!qCall)