kopia lustrzana https://github.com/jamescoxon/dl-fldigi
Merge upstream fldigi 3.21.26
commit
a1cb30c6d4
119
ChangeLog
119
ChangeLog
|
@ -1,7 +1,126 @@
|
|||
|
||||
|
||||
=Version 3.21.26=
|
||||
|
||||
2011-11-14 David Freese <w1hkj@w1hkj.com>
|
||||
|
||||
77551e8: eQSL update
|
||||
|
||||
|
||||
=Version 3.21.25=
|
||||
|
||||
50fa414: guard lock
|
||||
|
||||
2011-11-12 Remi Chateauneu <remi.chateauneu@gmail.com>
|
||||
|
||||
dae542e: Wefax enhancements.
|
||||
e75cc0e: Use Logbook record
|
||||
|
||||
2011-11-12 David Freese <w1hkj@w1hkj.com>
|
||||
|
||||
c2ba559: eQSL
|
||||
|
||||
|
||||
=Version 3.21.24=
|
||||
|
||||
16fc289: Exec macro
|
||||
0859928: QRZ on-line lookup
|
||||
|
||||
|
||||
=Version 3.21.23=
|
||||
|
||||
047543a: HamQTH
|
||||
2ffb4a5: Auto-send
|
||||
|
||||
|
||||
=Version 3.21.22=
|
||||
|
||||
|
||||
2011-10-28 Pavel Milanes Costa <pavel@conas.co.cu>
|
||||
|
||||
b66a4d7: es.po update
|
||||
|
||||
2011-10-28 David Freese <w1hkj@w1hkj.com>
|
||||
|
||||
269ae3a: RSID defaults
|
||||
1b3e852: NBEMS-FLMSG Directories
|
||||
|
||||
|
||||
=Version 3.21.21=
|
||||
|
||||
3163fd2: Resize fault
|
||||
|
||||
|
||||
=Version 3.21.20=
|
||||
|
||||
fba599c: RSID limit fault
|
||||
c32fa63: DTMF debug
|
||||
|
||||
|
||||
=Version 3.21.19=
|
||||
|
||||
7046d49: HamQTH lookup
|
||||
|
||||
|
||||
=Version 3.21.18=
|
||||
|
||||
1247488: REV macro tag
|
||||
9c13f6f: RTTY bandwidth
|
||||
|
||||
|
||||
=Version 3.21.17=
|
||||
|
||||
4ac5f6b: MFSK soft decode
|
||||
07baee2: MACRO code cleanup
|
||||
4d13cb4: <EXEC>...</EXEC>
|
||||
|
||||
|
||||
=Version 3.21.16=
|
||||
|
||||
3e554f8: !Queue reset
|
||||
8ac0558: Timer delay
|
||||
|
||||
|
||||
=Version 3.21.15=
|
||||
|
||||
d0e1c5f: Log Menu Items
|
||||
cebc292: Macro Editor
|
||||
960e580: WWV xmt mode
|
||||
bb258cd: Inline macro tags
|
||||
d2c33e4: RTTY baud
|
||||
ab472e0: CW/RTTY init fault
|
||||
5a9607a: Control-Z bug fix
|
||||
c565815: CW QSK
|
||||
405816e: Log Server lookup
|
||||
|
||||
2011-09-04 Remi Chateauneu <remi.chateauneu@gmail.com>
|
||||
|
||||
e0ee3a9: Added wefax::adjust_metric method.
|
||||
261275e: modem::display_metric now sets the member modem::m
|
||||
|
||||
|
||||
=Version 3.21.14=
|
||||
|
||||
|
||||
2011-09-03 David Freese <w1hkj@w1hkj.com>
|
||||
|
||||
166fe59: DTMF decoder
|
||||
49e2dd2: CW Prosign defaults
|
||||
|
||||
2011-08-30 Remi Chateauneu <remi.chateauneu@gmail.com>
|
||||
|
||||
ff18562: Macros code cleanup
|
||||
|
||||
2011-08-30 David Freese <w1hkj@w1hkj.com>
|
||||
|
||||
74364ee: DTMF class
|
||||
5af9f3a: DTMF encoder
|
||||
39fe31b: Wide Cursor Tracks
|
||||
|
||||
|
||||
=Version 3.21.13=
|
||||
|
||||
|
||||
2011-08-07 Pavel Milanes Costa <co7wt@frcuba.co.cu>
|
||||
|
||||
5f3c3da: Update to Spanish translation
|
||||
|
|
|
@ -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, [21])
|
||||
m4_define(FLDIGI_PATCH, [.13])
|
||||
m4_define(FLDIGI_PATCH, [.26])
|
||||
m4_define(FLARQ_MAJOR, [4])
|
||||
m4_define(FLARQ_MINOR, [3])
|
||||
m4_define(FLARQ_PATCH, [.1])
|
||||
|
|
|
@ -257,6 +257,7 @@ dl_fldigi_SOURCES += \
|
|||
dialogs/Viewer.cxx \
|
||||
dialogs/htmlstrings.cxx \
|
||||
dialogs/notifydialog.cxx \
|
||||
dtmf/dtmf.cxx \
|
||||
thor/thor.cxx \
|
||||
thor/thorvaricode.cxx \
|
||||
dominoex/dominoex.cxx \
|
||||
|
@ -274,6 +275,7 @@ dl_fldigi_SOURCES += \
|
|||
include/htmlstrings.h \
|
||||
include/arq_io.h \
|
||||
include/confdialog.h \
|
||||
include/dtmf.h \
|
||||
include/FTextView.h \
|
||||
include/FTextRXTX.h \
|
||||
include/fileselect.h \
|
||||
|
@ -373,6 +375,7 @@ dl_fldigi_SOURCES += \
|
|||
include/rsid.h \
|
||||
include/rtty.h \
|
||||
include/view_rtty.h \
|
||||
include/nullmodem.h \
|
||||
include/rx_extract.h \
|
||||
include/speak.h \
|
||||
include/serial.h \
|
||||
|
@ -502,6 +505,7 @@ dl_fldigi_SOURCES += \
|
|||
ssb/ssb.cxx \
|
||||
throb/throb.cxx \
|
||||
trx/modem.cxx \
|
||||
trx/nullmodem.cxx \
|
||||
trx/trx.cxx \
|
||||
waterfall/colorbox.cxx \
|
||||
waterfall/digiscope.cxx \
|
||||
|
|
|
@ -95,6 +95,7 @@ void cw::init()
|
|||
rx_init();
|
||||
use_paren = progdefaults.CW_use_paren;
|
||||
prosigns = progdefaults.CW_prosigns;
|
||||
stopflag = false;
|
||||
}
|
||||
|
||||
cw::~cw() {
|
||||
|
@ -661,18 +662,23 @@ void cw::send_symbol(int bits, int len)
|
|||
keydown = symlen + delta ;
|
||||
keyup = symlen - delta;
|
||||
|
||||
kpre = (int)(progdefaults.CWpre * 8);
|
||||
if (kpre > symlen) kpre = symlen;
|
||||
if (progdefaults.QSK) {
|
||||
kpre = (int)(progdefaults.CWpre * 8);
|
||||
if (kpre > symlen) kpre = symlen;
|
||||
|
||||
if (progdefaults.CWnarrow) {
|
||||
if (keydown - 2*knum < 0)
|
||||
kpost = knum + (int)(progdefaults.CWpost * 8);
|
||||
else
|
||||
kpost = keydown - knum + (int)(progdefaults.CWpost * 8);
|
||||
} else
|
||||
kpost = keydown + (int)(progdefaults.CWpost * 8);
|
||||
if (progdefaults.CWnarrow) {
|
||||
if (keydown - 2*knum < 0)
|
||||
kpost = knum + (int)(progdefaults.CWpost * 8);
|
||||
else
|
||||
kpost = keydown - knum + (int)(progdefaults.CWpost * 8);
|
||||
} else
|
||||
kpost = keydown + (int)(progdefaults.CWpost * 8);
|
||||
|
||||
if (kpost < 0) kpost = 0;
|
||||
if (kpost < 0) kpost = 0;
|
||||
} else {
|
||||
kpre = 0;
|
||||
kpost = 0;
|
||||
}
|
||||
|
||||
if (firstelement) {
|
||||
firstelement = false;
|
||||
|
|
|
@ -51,13 +51,13 @@ static CW_TABLE cw_table[] = {
|
|||
/* Prosigns */
|
||||
{'=', "<BT>", "-...-" }, // 0
|
||||
{'~', "<AA>", ".-.-" }, // 1
|
||||
{'%', "<AS>", ".-..." }, // 2
|
||||
{'+', "<AR>", ".-.-." }, // 3
|
||||
{'>', "<SK>", "...-.-" }, // 4
|
||||
{'<', "<KN>", "-.--." }, // 5
|
||||
{'<', "<AS>", ".-..." }, // 2
|
||||
{'>', "<AR>", ".-.-." }, // 3
|
||||
{'%', "<SK>", "...-.-" }, // 4
|
||||
{'+', "<KN>", "-.--." }, // 5
|
||||
{'&', "<INT>", "..-.-" }, // 6
|
||||
{'}', "<HM>", "....--" }, // 7
|
||||
{'{', "<VE>", "...-." }, // 8
|
||||
{'{', "<HM>", "....--" }, // 7
|
||||
{'}', "<VE>", "...-." }, // 8
|
||||
/* ASCII 7bit letters */
|
||||
{'A', "A", ".-" },
|
||||
{'B', "B", "-..." },
|
||||
|
|
|
@ -125,6 +125,7 @@ void rtty::init()
|
|||
bool wfrev = wf->Reverse();
|
||||
bool wfsb = wf->USB();
|
||||
reverse = wfrev ^ !wfsb;
|
||||
stopflag = false;
|
||||
|
||||
if (progdefaults.StartAtSweetSpot)
|
||||
set_freq(progdefaults.RTTYsweetspot);
|
||||
|
@ -138,7 +139,10 @@ void rtty::init()
|
|||
|
||||
rx_init();
|
||||
put_MODEstatus(mode);
|
||||
snprintf(msg1, sizeof(msg1), "%-4.1f / %-4.0f", rtty_baud, rtty_shift);
|
||||
if ((rtty_baud - (int)rtty_baud) == 0)
|
||||
snprintf(msg1, sizeof(msg1), "%-3.0f / %-4.0f", rtty_baud, rtty_shift);
|
||||
else
|
||||
snprintf(msg1, sizeof(msg1), "%-4.2f / %-4.0f", rtty_baud, rtty_shift);
|
||||
put_Status1(msg1);
|
||||
if (progdefaults.PreferXhairScope)
|
||||
set_scope_mode(Digiscope::XHAIRS);
|
||||
|
@ -181,8 +185,9 @@ void rtty::restart()
|
|||
symbollen = (int) (samplerate / rtty_baud + 0.5);
|
||||
set_bandwidth(shift);
|
||||
|
||||
rtty_BW = 1.5 * rtty_baud;
|
||||
progdefaults.RTTY_BW = rtty_BW;
|
||||
if (progdefaults.RTTY_BW < rtty_baud)
|
||||
progdefaults.RTTY_BW = rtty_baud;
|
||||
rtty_BW = progdefaults.RTTY_BW;
|
||||
sldrRTTYbandwidth->value(rtty_BW);
|
||||
|
||||
wf->redraw_marker();
|
||||
|
@ -219,7 +224,10 @@ void rtty::restart()
|
|||
|
||||
metric = 0.0;
|
||||
|
||||
snprintf(msg1, sizeof(msg1), "%-4.1f / %-4.0f", rtty_baud, rtty_shift);
|
||||
if ((rtty_baud - (int)rtty_baud) == 0)
|
||||
snprintf(msg1, sizeof(msg1), "%-3.0f / %-4.0f", rtty_baud, rtty_shift);
|
||||
else
|
||||
snprintf(msg1, sizeof(msg1), "%-4.2f / %-4.0f", rtty_baud, rtty_shift);
|
||||
put_Status1(msg1);
|
||||
put_MODEstatus(mode);
|
||||
for (int i = 0; i < 1024; i++) QI[i].re = QI[i].im = 0.0;
|
||||
|
@ -756,9 +764,10 @@ void rtty::send_char(int c)
|
|||
void rtty::send_idle()
|
||||
{
|
||||
|
||||
if (nbits == 5)
|
||||
if (nbits == 5) {
|
||||
send_char(LETTERS);
|
||||
else
|
||||
txmode = LETTERS;
|
||||
} else
|
||||
send_char(0);
|
||||
}
|
||||
|
||||
|
@ -769,13 +778,13 @@ int rtty::tx_process()
|
|||
int c;
|
||||
|
||||
if (preamble > 0) {
|
||||
preamble--;
|
||||
send_symbol(1);
|
||||
if (preamble == 0 && nbits == 5) {
|
||||
for (int i = 0; i < preamble; i++)
|
||||
send_symbol(1);
|
||||
if (nbits == 5) {
|
||||
send_char(LETTERS);
|
||||
txmode = LETTERS;
|
||||
}
|
||||
return 0;
|
||||
preamble = 0;
|
||||
}
|
||||
|
||||
c = get_tx_char();
|
||||
|
@ -798,16 +807,15 @@ int rtty::tx_process()
|
|||
return -1;
|
||||
}
|
||||
|
||||
// if NOT Baudot
|
||||
if (nbits != 5) {
|
||||
send_char(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// send idle character if c == -1
|
||||
if (c == -1) {
|
||||
send_idle();
|
||||
txmode = LETTERS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if NOT Baudot
|
||||
if (nbits != 5) {
|
||||
send_char(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "confdialog.h"
|
||||
#include <config.h>
|
||||
#include <FL/Fl_Tooltip.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/filename.H>
|
||||
#include <sstream>
|
||||
#include <stdint.h>
|
||||
|
@ -35,7 +36,7 @@ Mode_Browser* mode_browser;
|
|||
void set_qrz_buttons(Fl_Button* b) {
|
||||
Fl_Button* qrzb[] = { btnQRZnotavailable, btnQRZcdrom, btnQRZonline,
|
||||
btnQRZsub, btnHamcall, btnHAMCALLonline,
|
||||
btnCALLOOK};
|
||||
btnCALLOOK, btnHamQTH};
|
||||
|
||||
for (size_t i = 0; i < sizeof(qrzb)/sizeof(*qrzb); i++)
|
||||
qrzb[i]->value(b == qrzb[i]);
|
||||
|
@ -881,6 +882,27 @@ progdefaults.changed = true;
|
|||
};
|
||||
}
|
||||
|
||||
Fl_Check_Button *btnUseWideTracks=(Fl_Check_Button *)0;
|
||||
|
||||
static void cb_btnUseWideTracks(Fl_Check_Button* o, void*) {
|
||||
progdefaults.UseWideTracks = o->value();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Check_Button *btnUseWideCenter=(Fl_Check_Button *)0;
|
||||
|
||||
static void cb_btnUseWideCenter(Fl_Check_Button* o, void*) {
|
||||
progdefaults.UseWideCenter = o->value();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Check_Button *btnUseWideCursor=(Fl_Check_Button *)0;
|
||||
|
||||
static void cb_btnUseWideCursor(Fl_Check_Button* o, void*) {
|
||||
progdefaults.UseWideCursor = o->value();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Check_Button *chkShowAudioScale=(Fl_Check_Button *)0;
|
||||
|
||||
static void cb_chkShowAudioScale(Fl_Check_Button* o, void*) {
|
||||
|
@ -2876,8 +2898,48 @@ static void cb_chkRxStream(Fl_Check_Button* o, void*) {
|
|||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Group *tabDTMF=(Fl_Group *)0;
|
||||
|
||||
Fl_Check_Button *chkDTMFdecode=(Fl_Check_Button *)0;
|
||||
|
||||
static void cb_chkDTMFdecode(Fl_Check_Button* o, void*) {
|
||||
progdefaults.DTMFdecode = o->value();
|
||||
}
|
||||
|
||||
Fl_Group *tabQRZ=(Fl_Group *)0;
|
||||
|
||||
Fl_Round_Button *btnQRZnotavailable=(Fl_Round_Button *)0;
|
||||
|
||||
static void cb_btnQRZnotavailable(Fl_Round_Button* o, void*) {
|
||||
set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZNONE;
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Round_Button *btnQRZonline=(Fl_Round_Button *)0;
|
||||
|
||||
static void cb_btnQRZonline(Fl_Round_Button* o, void*) {
|
||||
set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZHTML;
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Round_Button *btnHAMCALLonline=(Fl_Round_Button *)0;
|
||||
|
||||
static void cb_btnHAMCALLonline(Fl_Round_Button* o, void*) {
|
||||
set_qrz_buttons(o);
|
||||
progdefaults.QRZ = HAMCALLHTML;
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Round_Button *btnCALLOOK=(Fl_Round_Button *)0;
|
||||
|
||||
static void cb_btnCALLOOK(Fl_Round_Button* o, void*) {
|
||||
set_qrz_buttons(o);
|
||||
progdefaults.QRZ = CALLOOK;
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Round_Button *btnQRZcdrom=(Fl_Round_Button *)0;
|
||||
|
||||
static void cb_btnQRZcdrom(Fl_Round_Button* o, void*) {
|
||||
|
@ -2932,38 +2994,63 @@ inpQRZuserpassword->redraw();
|
|||
o->label((inpQRZuserpassword->type() & FL_SECRET_INPUT) ? "Show" : "Hide");
|
||||
}
|
||||
|
||||
Fl_Round_Button *btnQRZnotavailable=(Fl_Round_Button *)0;
|
||||
Fl_Round_Button *btnHamQTH=(Fl_Round_Button *)0;
|
||||
|
||||
static void cb_btnQRZnotavailable(Fl_Round_Button* o, void*) {
|
||||
static void cb_btnHamQTH(Fl_Round_Button* o, void*) {
|
||||
set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZNONE;
|
||||
progdefaults.QRZ = HAMQTH;
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Round_Button *btnQRZonline=(Fl_Round_Button *)0;
|
||||
Fl_Input2 *inpEQSL_id=(Fl_Input2 *)0;
|
||||
|
||||
static void cb_btnQRZonline(Fl_Round_Button* o, void*) {
|
||||
set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZHTML;
|
||||
static void cb_inpEQSL_id(Fl_Input2* o, void*) {
|
||||
progdefaults.eqsl_id = o->value();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Round_Button *btnHAMCALLonline=(Fl_Round_Button *)0;
|
||||
Fl_Input2 *inpEQSL_pwd=(Fl_Input2 *)0;
|
||||
|
||||
static void cb_btnHAMCALLonline(Fl_Round_Button* o, void*) {
|
||||
set_qrz_buttons(o);
|
||||
progdefaults.QRZ = HAMCALLHTML;
|
||||
static void cb_inpEQSL_pwd(Fl_Input2* o, void*) {
|
||||
progdefaults.eqsl_pwd = o->value();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Round_Button *btnCALLOOK=(Fl_Round_Button *)0;
|
||||
Fl_Button *btnEQSL_pwd_show=(Fl_Button *)0;
|
||||
|
||||
static void cb_btnCALLOOK(Fl_Round_Button* o, void*) {
|
||||
set_qrz_buttons(o);
|
||||
progdefaults.QRZ = CALLOOK;
|
||||
static void cb_btnEQSL_pwd_show(Fl_Button* o, void*) {
|
||||
inpEQSL_pwd->type(inpEQSL_pwd->type() ^ FL_SECRET_INPUT);
|
||||
inpEQSL_pwd->redraw();
|
||||
o->label((inpEQSL_pwd->type() & FL_SECRET_INPUT) ? "Show" : "Hide");
|
||||
}
|
||||
|
||||
Fl_Input2 *inpEQSL_nick=(Fl_Input2 *)0;
|
||||
|
||||
static void cb_inpEQSL_nick(Fl_Input2* o, void*) {
|
||||
progdefaults.eqsl_nick = o->value();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Check_Button *btn_send_when_logged=(Fl_Check_Button *)0;
|
||||
|
||||
static void cb_btn_send_when_logged(Fl_Check_Button* o, void*) {
|
||||
progdefaults.eqsl_when_logged = o->value();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Input2 *txt_eqsl_default_message=(Fl_Input2 *)0;
|
||||
|
||||
static void cb_txt_eqsl_default_message(Fl_Input2* o, void*) {
|
||||
progdefaults.eqsl_default_message = o->value();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
||||
Fl_Box *eqsl_txt1=(Fl_Box *)0;
|
||||
|
||||
Fl_Box *eqsl_txt2=(Fl_Box *)0;
|
||||
|
||||
Fl_Box *eqsl_txt3=(Fl_Box *)0;
|
||||
|
||||
Fl_Group *tabDL=(Fl_Group *)0;
|
||||
|
||||
Fl_Tabs *tabsDL=(Fl_Tabs *)0;
|
||||
|
@ -3944,17 +4031,17 @@ ab and newline are automatically included."));
|
|||
} // Fl_Tabs* tabsUI
|
||||
tabUI->end();
|
||||
} // Fl_Group* tabUI
|
||||
{ tabWaterfall = new Fl_Group(0, 25, 500, 347, _("Waterfall"));
|
||||
{ tabWaterfall = new Fl_Group(0, 25, 501, 347, _("Waterfall"));
|
||||
tabWaterfall->labelsize(12);
|
||||
tabWaterfall->hide();
|
||||
{ tabsWaterfall = new Fl_Tabs(0, 25, 500, 347);
|
||||
{ tabsWaterfall = new Fl_Tabs(0, 25, 501, 347);
|
||||
tabsWaterfall->color((Fl_Color)FL_LIGHT1);
|
||||
tabsWaterfall->selection_color((Fl_Color)FL_LIGHT1);
|
||||
{ Fl_Group* o = new Fl_Group(0, 50, 500, 320, _("Display"));
|
||||
{ Fl_Group* o = new Fl_Group(5, 60, 490, 162, _("Colors and cursors"));
|
||||
{ Fl_Group* o = new Fl_Group(0, 50, 501, 320, _("Display"));
|
||||
{ Fl_Group* o = new Fl_Group(5, 60, 496, 162, _("Colors and cursors"));
|
||||
o->box(FL_ENGRAVED_FRAME);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ colorbox* o = WF_Palette = new colorbox(15, 98, 260, 24);
|
||||
{ colorbox* o = WF_Palette = new colorbox(15, 93, 260, 24, _("aa"));
|
||||
WF_Palette->box(FL_DOWN_BOX);
|
||||
WF_Palette->color((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
WF_Palette->selection_color((Fl_Color)FL_BACKGROUND_COLOR);
|
||||
|
@ -3968,89 +4055,107 @@ ab and newline are automatically included."));
|
|||
o->label(progdefaults.PaletteName.c_str());
|
||||
o->labelsize(FL_NORMAL_SIZE);
|
||||
} // colorbox* WF_Palette
|
||||
{ btnColor[0] = new Fl_Button(15, 128, 20, 24);
|
||||
{ btnColor[0] = new Fl_Button(15, 120, 20, 24);
|
||||
btnColor[0]->tooltip(_("Change color"));
|
||||
btnColor[0]->callback((Fl_Callback*)cb_btnColor);
|
||||
} // Fl_Button* btnColor[0]
|
||||
{ btnColor[1] = new Fl_Button(45, 128, 20, 24);
|
||||
{ btnColor[1] = new Fl_Button(45, 120, 20, 24);
|
||||
btnColor[1]->tooltip(_("Change color"));
|
||||
btnColor[1]->callback((Fl_Callback*)cb_btnColor1);
|
||||
} // Fl_Button* btnColor[1]
|
||||
{ btnColor[2] = new Fl_Button(75, 128, 20, 24);
|
||||
{ btnColor[2] = new Fl_Button(75, 120, 20, 24);
|
||||
btnColor[2]->tooltip(_("Change color"));
|
||||
btnColor[2]->callback((Fl_Callback*)cb_btnColor2);
|
||||
} // Fl_Button* btnColor[2]
|
||||
{ btnColor[3] = new Fl_Button(105, 128, 20, 24);
|
||||
{ btnColor[3] = new Fl_Button(105, 120, 20, 24);
|
||||
btnColor[3]->tooltip(_("Change color"));
|
||||
btnColor[3]->callback((Fl_Callback*)cb_btnColor3);
|
||||
} // Fl_Button* btnColor[3]
|
||||
{ btnColor[4] = new Fl_Button(135, 128, 20, 24);
|
||||
{ btnColor[4] = new Fl_Button(135, 120, 20, 24);
|
||||
btnColor[4]->tooltip(_("Change color"));
|
||||
btnColor[4]->callback((Fl_Callback*)cb_btnColor4);
|
||||
} // Fl_Button* btnColor[4]
|
||||
{ btnColor[5] = new Fl_Button(165, 128, 20, 24);
|
||||
{ btnColor[5] = new Fl_Button(165, 120, 20, 24);
|
||||
btnColor[5]->tooltip(_("Change color"));
|
||||
btnColor[5]->callback((Fl_Callback*)cb_btnColor5);
|
||||
} // Fl_Button* btnColor[5]
|
||||
{ btnColor[6] = new Fl_Button(195, 128, 20, 24);
|
||||
{ btnColor[6] = new Fl_Button(195, 120, 20, 24);
|
||||
btnColor[6]->tooltip(_("Change color"));
|
||||
btnColor[6]->callback((Fl_Callback*)cb_btnColor6);
|
||||
} // Fl_Button* btnColor[6]
|
||||
{ btnColor[7] = new Fl_Button(225, 128, 20, 24);
|
||||
{ btnColor[7] = new Fl_Button(225, 120, 20, 24);
|
||||
btnColor[7]->tooltip(_("Change color"));
|
||||
btnColor[7]->callback((Fl_Callback*)cb_btnColor7);
|
||||
} // Fl_Button* btnColor[7]
|
||||
{ btnColor[8] = new Fl_Button(256, 128, 20, 24);
|
||||
{ btnColor[8] = new Fl_Button(256, 120, 20, 24);
|
||||
btnColor[8]->tooltip(_("Change color"));
|
||||
btnColor[8]->callback((Fl_Callback*)cb_btnColor8);
|
||||
} // Fl_Button* btnColor[8]
|
||||
{ btnLoadPalette = new Fl_Button(314, 96, 70, 24, _("Load..."));
|
||||
{ btnLoadPalette = new Fl_Button(314, 93, 70, 24, _("Load..."));
|
||||
btnLoadPalette->tooltip(_("Load a new palette"));
|
||||
btnLoadPalette->callback((Fl_Callback*)cb_btnLoadPalette);
|
||||
} // Fl_Button* btnLoadPalette
|
||||
{ btnSavePalette = new Fl_Button(314, 128, 70, 24, _("Save..."));
|
||||
{ btnSavePalette = new Fl_Button(314, 120, 70, 24, _("Save..."));
|
||||
btnSavePalette->tooltip(_("Save this palette"));
|
||||
btnSavePalette->callback((Fl_Callback*)cb_btnSavePalette);
|
||||
} // Fl_Button* btnSavePalette
|
||||
{ Fl_Check_Button* o = btnUseCursorLines = new Fl_Check_Button(15, 161, 150, 20, _("Bandwidth cursor"));
|
||||
{ Fl_Check_Button* o = btnUseCursorLines = new Fl_Check_Button(15, 149, 150, 20, _("Bandwidth cursor"));
|
||||
btnUseCursorLines->tooltip(_("Show cursor with bandwidth lines"));
|
||||
btnUseCursorLines->down_box(FL_DOWN_BOX);
|
||||
btnUseCursorLines->callback((Fl_Callback*)cb_btnUseCursorLines);
|
||||
o->value(progdefaults.UseCursorLines);
|
||||
} // Fl_Check_Button* btnUseCursorLines
|
||||
{ Fl_Button* o = btnCursorBWcolor = new Fl_Button(15, 191, 20, 20, _("Cursor color"));
|
||||
{ Fl_Button* o = btnCursorBWcolor = new Fl_Button(15, 172, 20, 20, _("Cursor color"));
|
||||
btnCursorBWcolor->tooltip(_("Change color"));
|
||||
btnCursorBWcolor->color((Fl_Color)3);
|
||||
btnCursorBWcolor->callback((Fl_Callback*)cb_btnCursorBWcolor);
|
||||
btnCursorBWcolor->align(FL_ALIGN_RIGHT);
|
||||
o->color(fl_rgb_color(progdefaults.cursorLineRGBI.R,progdefaults.cursorLineRGBI.G,progdefaults.cursorLineRGBI.B));
|
||||
} // Fl_Button* btnCursorBWcolor
|
||||
{ Fl_Check_Button* o = btnUseCursorCenterLine = new Fl_Check_Button(185, 161, 149, 20, _("Cursor center line"));
|
||||
{ Fl_Check_Button* o = btnUseCursorCenterLine = new Fl_Check_Button(185, 149, 149, 20, _("Cursor center line"));
|
||||
btnUseCursorCenterLine->tooltip(_("Show cursor with center line"));
|
||||
btnUseCursorCenterLine->down_box(FL_DOWN_BOX);
|
||||
btnUseCursorCenterLine->callback((Fl_Callback*)cb_btnUseCursorCenterLine);
|
||||
o->value(progdefaults.UseCursorCenterLine);
|
||||
} // Fl_Check_Button* btnUseCursorCenterLine
|
||||
{ Fl_Button* o = btnCursorCenterLineColor = new Fl_Button(185, 191, 20, 20, _("Center line color"));
|
||||
{ Fl_Button* o = btnCursorCenterLineColor = new Fl_Button(185, 172, 20, 20, _("Center line color"));
|
||||
btnCursorCenterLineColor->tooltip(_("Change color"));
|
||||
btnCursorCenterLineColor->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
btnCursorCenterLineColor->callback((Fl_Callback*)cb_btnCursorCenterLineColor);
|
||||
btnCursorCenterLineColor->align(FL_ALIGN_RIGHT);
|
||||
o->color(fl_rgb_color(progdefaults.cursorCenterRGBI.R,progdefaults.cursorCenterRGBI.G,progdefaults.cursorCenterRGBI.B));
|
||||
} // Fl_Button* btnCursorCenterLineColor
|
||||
{ Fl_Check_Button* o = btnUseBWTracks = new Fl_Check_Button(346, 161, 145, 20, _("Bandwidth tracks"));
|
||||
{ Fl_Check_Button* o = btnUseBWTracks = new Fl_Check_Button(346, 149, 145, 20, _("Bandwidth tracks"));
|
||||
btnUseBWTracks->tooltip(_("Show bandwidth tracks on waterfall"));
|
||||
btnUseBWTracks->down_box(FL_DOWN_BOX);
|
||||
btnUseBWTracks->callback((Fl_Callback*)cb_btnUseBWTracks);
|
||||
o->value(progdefaults.UseBWTracks);
|
||||
} // Fl_Check_Button* btnUseBWTracks
|
||||
{ Fl_Button* o = btnBwTracksColor = new Fl_Button(346, 191, 20, 20, _("Tracks color"));
|
||||
{ Fl_Button* o = btnBwTracksColor = new Fl_Button(346, 172, 20, 20, _("Tracks color"));
|
||||
btnBwTracksColor->tooltip(_("Change color"));
|
||||
btnBwTracksColor->color((Fl_Color)1);
|
||||
btnBwTracksColor->callback((Fl_Callback*)cb_btnBwTracksColor);
|
||||
btnBwTracksColor->align(FL_ALIGN_RIGHT);
|
||||
o->color(fl_rgb_color(progdefaults.bwTrackRGBI.R,progdefaults.bwTrackRGBI.G,progdefaults.bwTrackRGBI.B));
|
||||
} // Fl_Button* btnBwTracksColor
|
||||
{ Fl_Check_Button* o = btnUseWideTracks = new Fl_Check_Button(346, 196, 145, 20, _("Wide tracks"));
|
||||
btnUseWideTracks->tooltip(_("Show bandwidth tracks on waterfall"));
|
||||
btnUseWideTracks->down_box(FL_DOWN_BOX);
|
||||
btnUseWideTracks->callback((Fl_Callback*)cb_btnUseWideTracks);
|
||||
o->value(progdefaults.UseWideTracks);
|
||||
} // Fl_Check_Button* btnUseWideTracks
|
||||
{ Fl_Check_Button* o = btnUseWideCenter = new Fl_Check_Button(185, 197, 145, 20, _("Wide center line"));
|
||||
btnUseWideCenter->tooltip(_("Show bandwidth tracks on waterfall"));
|
||||
btnUseWideCenter->down_box(FL_DOWN_BOX);
|
||||
btnUseWideCenter->callback((Fl_Callback*)cb_btnUseWideCenter);
|
||||
o->value(progdefaults.UseWideCenter);
|
||||
} // Fl_Check_Button* btnUseWideCenter
|
||||
{ Fl_Check_Button* o = btnUseWideCursor = new Fl_Check_Button(15, 195, 145, 20, _("Wide cursor"));
|
||||
btnUseWideCursor->tooltip(_("Show bandwidth tracks on waterfall"));
|
||||
btnUseWideCursor->down_box(FL_DOWN_BOX);
|
||||
btnUseWideCursor->callback((Fl_Callback*)cb_btnUseWideCursor);
|
||||
o->value(progdefaults.UseWideCursor);
|
||||
} // Fl_Check_Button* btnUseWideCursor
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
{ Fl_Group* o = new Fl_Group(5, 222, 490, 62, _("Frequency scale"));
|
||||
|
@ -6731,122 +6836,240 @@ d frequency"));
|
|||
} // Fl_Group* o
|
||||
tabText_IO->end();
|
||||
} // Fl_Group* tabText_IO
|
||||
{ tabDTMF = new Fl_Group(0, 50, 500, 320, _("DTMF"));
|
||||
tabDTMF->hide();
|
||||
{ Fl_Check_Button* o = chkDTMFdecode = new Fl_Check_Button(175, 71, 175, 20, _("Decode DTMF tones"));
|
||||
chkDTMFdecode->tooltip(_("Send rx text to file: textout.txt"));
|
||||
chkDTMFdecode->down_box(FL_DOWN_BOX);
|
||||
chkDTMFdecode->callback((Fl_Callback*)cb_chkDTMFdecode);
|
||||
o->value(progdefaults.DTMFdecode);
|
||||
} // Fl_Check_Button* chkDTMFdecode
|
||||
tabDTMF->end();
|
||||
} // Fl_Group* tabDTMF
|
||||
tabsMisc->end();
|
||||
} // Fl_Tabs* tabsMisc
|
||||
tabMisc->end();
|
||||
} // Fl_Group* tabMisc
|
||||
{ tabQRZ = new Fl_Group(0, 25, 500, 345, _("Callsign DB"));
|
||||
{ tabQRZ = new Fl_Group(0, 25, 500, 345, _("Web"));
|
||||
tabQRZ->tooltip(_("Callsign database"));
|
||||
tabQRZ->labelsize(12);
|
||||
tabQRZ->hide();
|
||||
{ Fl_Group* o = new Fl_Group(5, 180, 490, 75, _("CDROM"));
|
||||
o->box(FL_ENGRAVED_FRAME);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ Fl_Round_Button* o = btnQRZcdrom = new Fl_Round_Button(25, 215, 70, 20, _("QRZ"));
|
||||
btnQRZcdrom->tooltip(_("Use CD or hard drive CD image"));
|
||||
btnQRZcdrom->down_box(FL_DOWN_BOX);
|
||||
btnQRZcdrom->callback((Fl_Callback*)cb_btnQRZcdrom);
|
||||
o->value(progdefaults.QRZ == QRZCD);
|
||||
} // Fl_Round_Button* btnQRZcdrom
|
||||
{ Fl_Input2* o = txtQRZpathname = new Fl_Input2(104, 215, 300, 20, _("at:"));
|
||||
txtQRZpathname->tooltip(_("ie: /home/dave/CALLBK/ or C:/CALLBK/\nLeave blank to search for database"));
|
||||
txtQRZpathname->box(FL_DOWN_BOX);
|
||||
txtQRZpathname->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
txtQRZpathname->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
txtQRZpathname->labeltype(FL_NORMAL_LABEL);
|
||||
txtQRZpathname->labelfont(0);
|
||||
txtQRZpathname->labelsize(14);
|
||||
txtQRZpathname->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
txtQRZpathname->callback((Fl_Callback*)cb_txtQRZpathname);
|
||||
txtQRZpathname->align(FL_ALIGN_LEFT);
|
||||
txtQRZpathname->when(FL_WHEN_RELEASE);
|
||||
o->value(progdefaults.QRZpathname.c_str());
|
||||
txtQRZpathname->labelsize(FL_NORMAL_SIZE);
|
||||
} // Fl_Input2* txtQRZpathname
|
||||
{ Fl_Tabs* o = new Fl_Tabs(0, 25, 500, 345);
|
||||
{ Fl_Group* o = new Fl_Group(0, 46, 500, 324, _("QRZ/etal"));
|
||||
{ Fl_Group* o = new Fl_Group(5, 55, 490, 120);
|
||||
o->box(FL_ENGRAVED_FRAME);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ Fl_Round_Button* o = btnQRZnotavailable = new Fl_Round_Button(25, 64, 337, 20, _("Not available"));
|
||||
btnQRZnotavailable->tooltip(_("Do not use callsign database"));
|
||||
btnQRZnotavailable->down_box(FL_DOWN_BOX);
|
||||
btnQRZnotavailable->value(1);
|
||||
btnQRZnotavailable->callback((Fl_Callback*)cb_btnQRZnotavailable);
|
||||
o->value(progdefaults.QRZ == QRZNONE);
|
||||
} // Fl_Round_Button* btnQRZnotavailable
|
||||
{ Fl_Round_Button* o = btnQRZonline = new Fl_Round_Button(25, 92, 337, 20, _("QRZ online via default Internet Browser"));
|
||||
btnQRZonline->tooltip(_("Visit QRZ web site"));
|
||||
btnQRZonline->down_box(FL_DOWN_BOX);
|
||||
btnQRZonline->callback((Fl_Callback*)cb_btnQRZonline);
|
||||
o->value(progdefaults.QRZ == QRZHTML);
|
||||
} // Fl_Round_Button* btnQRZonline
|
||||
{ Fl_Round_Button* o = btnHAMCALLonline = new Fl_Round_Button(25, 120, 337, 20, _("HamCall online via default Internet Browser"));
|
||||
btnHAMCALLonline->tooltip(_("Visit Hamcall web site"));
|
||||
btnHAMCALLonline->down_box(FL_DOWN_BOX);
|
||||
btnHAMCALLonline->callback((Fl_Callback*)cb_btnHAMCALLonline);
|
||||
o->value(progdefaults.QRZ == HAMCALLHTML);
|
||||
} // Fl_Round_Button* btnHAMCALLonline
|
||||
{ Fl_Round_Button* o = btnCALLOOK = new Fl_Round_Button(25, 148, 337, 20, _("Callook.info lookup (US callsigns only)"));
|
||||
btnCALLOOK->tooltip(_("Visit Hamcall web site"));
|
||||
btnCALLOOK->down_box(FL_DOWN_BOX);
|
||||
btnCALLOOK->callback((Fl_Callback*)cb_btnCALLOOK);
|
||||
o->value(progdefaults.QRZ == CALLOOK);
|
||||
} // Fl_Round_Button* btnCALLOOK
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
{ Fl_Group* o = new Fl_Group(5, 176, 490, 55, _("CDROM"));
|
||||
o->box(FL_ENGRAVED_FRAME);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ Fl_Round_Button* o = btnQRZcdrom = new Fl_Round_Button(25, 196, 70, 20, _("QRZ"));
|
||||
btnQRZcdrom->tooltip(_("Use CD or hard drive CD image"));
|
||||
btnQRZcdrom->down_box(FL_DOWN_BOX);
|
||||
btnQRZcdrom->callback((Fl_Callback*)cb_btnQRZcdrom);
|
||||
o->value(progdefaults.QRZ == QRZCD);
|
||||
} // Fl_Round_Button* btnQRZcdrom
|
||||
{ Fl_Input2* o = txtQRZpathname = new Fl_Input2(104, 196, 300, 20, _("at:"));
|
||||
txtQRZpathname->tooltip(_("ie: /home/dave/CALLBK/ or C:/CALLBK/\nLeave blank to search for database"));
|
||||
txtQRZpathname->box(FL_DOWN_BOX);
|
||||
txtQRZpathname->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
txtQRZpathname->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
txtQRZpathname->labeltype(FL_NORMAL_LABEL);
|
||||
txtQRZpathname->labelfont(0);
|
||||
txtQRZpathname->labelsize(14);
|
||||
txtQRZpathname->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
txtQRZpathname->callback((Fl_Callback*)cb_txtQRZpathname);
|
||||
txtQRZpathname->align(FL_ALIGN_LEFT);
|
||||
txtQRZpathname->when(FL_WHEN_RELEASE);
|
||||
o->value(progdefaults.QRZpathname.c_str());
|
||||
txtQRZpathname->labelsize(FL_NORMAL_SIZE);
|
||||
} // Fl_Input2* txtQRZpathname
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
{ Fl_Group* o = new Fl_Group(5, 232, 490, 134, _("Subscriber data"));
|
||||
o->box(FL_ENGRAVED_FRAME);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ Fl_Round_Button* o = btnQRZsub = new Fl_Round_Button(25, 263, 90, 20, _("QRZ.com"));
|
||||
btnQRZsub->tooltip(_("You need a paid QRZ online\nsubscription to access"));
|
||||
btnQRZsub->down_box(FL_DOWN_BOX);
|
||||
btnQRZsub->callback((Fl_Callback*)cb_btnQRZsub);
|
||||
o->value(progdefaults.QRZ == QRZNET);
|
||||
} // Fl_Round_Button* btnQRZsub
|
||||
{ Fl_Round_Button* o = btnHamcall = new Fl_Round_Button(25, 297, 105, 20, _("Hamcall.net"));
|
||||
btnHamcall->tooltip(_("You need a paid Hamcall online\nsubscription to access"));
|
||||
btnHamcall->down_box(FL_DOWN_BOX);
|
||||
btnHamcall->callback((Fl_Callback*)cb_btnHamcall);
|
||||
o->value(progdefaults.QRZ == HAMCALLNET);
|
||||
} // Fl_Round_Button* btnHamcall
|
||||
{ Fl_Input2* o = inpQRZusername = new Fl_Input2(235, 263, 150, 20, _("User name"));
|
||||
inpQRZusername->tooltip(_("Your login name"));
|
||||
inpQRZusername->box(FL_DOWN_BOX);
|
||||
inpQRZusername->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
inpQRZusername->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
inpQRZusername->labeltype(FL_NORMAL_LABEL);
|
||||
inpQRZusername->labelfont(0);
|
||||
inpQRZusername->labelsize(14);
|
||||
inpQRZusername->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
inpQRZusername->callback((Fl_Callback*)cb_inpQRZusername);
|
||||
inpQRZusername->align(FL_ALIGN_LEFT);
|
||||
inpQRZusername->when(FL_WHEN_RELEASE);
|
||||
o->value(progdefaults.QRZusername.c_str());
|
||||
inpQRZusername->labelsize(FL_NORMAL_SIZE);
|
||||
} // Fl_Input2* inpQRZusername
|
||||
{ Fl_Input2* o = inpQRZuserpassword = new Fl_Input2(235, 297, 150, 20, _("Password"));
|
||||
inpQRZuserpassword->tooltip(_("Your login password"));
|
||||
inpQRZuserpassword->box(FL_DOWN_BOX);
|
||||
inpQRZuserpassword->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
inpQRZuserpassword->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
inpQRZuserpassword->labeltype(FL_NORMAL_LABEL);
|
||||
inpQRZuserpassword->labelfont(0);
|
||||
inpQRZuserpassword->labelsize(14);
|
||||
inpQRZuserpassword->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
inpQRZuserpassword->callback((Fl_Callback*)cb_inpQRZuserpassword);
|
||||
inpQRZuserpassword->align(FL_ALIGN_LEFT);
|
||||
inpQRZuserpassword->when(FL_WHEN_RELEASE);
|
||||
o->value(progdefaults.QRZuserpassword.c_str());
|
||||
o->type(FL_SECRET_INPUT);
|
||||
inpQRZuserpassword->labelsize(FL_NORMAL_SIZE);
|
||||
} // Fl_Input2* inpQRZuserpassword
|
||||
{ btnQRZpasswordShow = new Fl_Button(395, 297, 70, 20, _("Show"));
|
||||
btnQRZpasswordShow->tooltip(_("Show password in plain text"));
|
||||
btnQRZpasswordShow->callback((Fl_Callback*)cb_btnQRZpasswordShow);
|
||||
} // Fl_Button* btnQRZpasswordShow
|
||||
{ Fl_Round_Button* o = btnHamQTH = new Fl_Round_Button(26, 332, 121, 20, _("HamQTH.com (free service http://www.hamqth.com)"));
|
||||
btnHamQTH->tooltip(_("You need a paid Hamcall online\nsubscription to access"));
|
||||
btnHamQTH->down_box(FL_DOWN_BOX);
|
||||
btnHamQTH->callback((Fl_Callback*)cb_btnHamQTH);
|
||||
o->value(progdefaults.QRZ == HAMQTH);
|
||||
} // Fl_Round_Button* btnHamQTH
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
{ Fl_Group* o = new Fl_Group(0, 50, 500, 320, _("eQSL"));
|
||||
o->hide();
|
||||
{ Fl_Input2* o = inpEQSL_id = new Fl_Input2(176, 75, 150, 20, _("User ID"));
|
||||
inpEQSL_id->tooltip(_("Your login name"));
|
||||
inpEQSL_id->box(FL_DOWN_BOX);
|
||||
inpEQSL_id->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
inpEQSL_id->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
inpEQSL_id->labeltype(FL_NORMAL_LABEL);
|
||||
inpEQSL_id->labelfont(0);
|
||||
inpEQSL_id->labelsize(14);
|
||||
inpEQSL_id->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
inpEQSL_id->callback((Fl_Callback*)cb_inpEQSL_id);
|
||||
inpEQSL_id->align(FL_ALIGN_LEFT);
|
||||
inpEQSL_id->when(FL_WHEN_RELEASE);
|
||||
o->value(progdefaults.eqsl_id.c_str());
|
||||
inpEQSL_id->labelsize(FL_NORMAL_SIZE);
|
||||
} // Fl_Input2* inpEQSL_id
|
||||
{ Fl_Input2* o = inpEQSL_pwd = new Fl_Input2(176, 106, 150, 20, _("Password"));
|
||||
inpEQSL_pwd->tooltip(_("Your login password"));
|
||||
inpEQSL_pwd->box(FL_DOWN_BOX);
|
||||
inpEQSL_pwd->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
inpEQSL_pwd->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
inpEQSL_pwd->labeltype(FL_NORMAL_LABEL);
|
||||
inpEQSL_pwd->labelfont(0);
|
||||
inpEQSL_pwd->labelsize(14);
|
||||
inpEQSL_pwd->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
inpEQSL_pwd->callback((Fl_Callback*)cb_inpEQSL_pwd);
|
||||
inpEQSL_pwd->align(FL_ALIGN_LEFT);
|
||||
inpEQSL_pwd->when(FL_WHEN_RELEASE);
|
||||
o->value(progdefaults.eqsl_pwd.c_str());
|
||||
o->type(FL_SECRET_INPUT);
|
||||
inpEQSL_pwd->labelsize(FL_NORMAL_SIZE);
|
||||
} // Fl_Input2* inpEQSL_pwd
|
||||
{ btnEQSL_pwd_show = new Fl_Button(344, 106, 70, 20, _("Show"));
|
||||
btnEQSL_pwd_show->tooltip(_("Show password in plain text"));
|
||||
btnEQSL_pwd_show->callback((Fl_Callback*)cb_btnEQSL_pwd_show);
|
||||
} // Fl_Button* btnEQSL_pwd_show
|
||||
{ Fl_Input2* o = inpEQSL_nick = new Fl_Input2(176, 137, 150, 20, _("QTH Nickname"));
|
||||
inpEQSL_nick->tooltip(_("Your login name"));
|
||||
inpEQSL_nick->box(FL_DOWN_BOX);
|
||||
inpEQSL_nick->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
inpEQSL_nick->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
inpEQSL_nick->labeltype(FL_NORMAL_LABEL);
|
||||
inpEQSL_nick->labelfont(0);
|
||||
inpEQSL_nick->labelsize(14);
|
||||
inpEQSL_nick->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
inpEQSL_nick->callback((Fl_Callback*)cb_inpEQSL_nick);
|
||||
inpEQSL_nick->align(FL_ALIGN_LEFT);
|
||||
inpEQSL_nick->when(FL_WHEN_RELEASE);
|
||||
o->value(progdefaults.eqsl_nick.c_str());
|
||||
inpEQSL_nick->labelsize(FL_NORMAL_SIZE);
|
||||
} // Fl_Input2* inpEQSL_nick
|
||||
{ Fl_Group* o = new Fl_Group(4, 170, 492, 194, _("Options"));
|
||||
o->box(FL_ENGRAVED_FRAME);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ Fl_Check_Button* o = btn_send_when_logged = new Fl_Check_Button(29, 191, 70, 15, _("send when logged (log button, <LOG>, <LNW>)"));
|
||||
btn_send_when_logged->tooltip(_("eQSL upload when record logged"));
|
||||
btn_send_when_logged->down_box(FL_DOWN_BOX);
|
||||
btn_send_when_logged->callback((Fl_Callback*)cb_btn_send_when_logged);
|
||||
o->value(progdefaults.eqsl_when_logged);
|
||||
} // Fl_Check_Button* btn_send_when_logged
|
||||
{ Fl_Input2* o = txt_eqsl_default_message = new Fl_Input2(33, 226, 451, 40, _("Default message"));
|
||||
txt_eqsl_default_message->tooltip(_("Default message sent with eQSL"));
|
||||
txt_eqsl_default_message->type(4);
|
||||
txt_eqsl_default_message->box(FL_DOWN_BOX);
|
||||
txt_eqsl_default_message->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
txt_eqsl_default_message->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
txt_eqsl_default_message->labeltype(FL_NORMAL_LABEL);
|
||||
txt_eqsl_default_message->labelfont(0);
|
||||
txt_eqsl_default_message->labelsize(14);
|
||||
txt_eqsl_default_message->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
txt_eqsl_default_message->callback((Fl_Callback*)cb_txt_eqsl_default_message);
|
||||
txt_eqsl_default_message->align(FL_ALIGN_TOP_LEFT);
|
||||
txt_eqsl_default_message->when(FL_WHEN_CHANGED);
|
||||
o->value(progdefaults.eqsl_default_message.c_str());
|
||||
} // Fl_Input2* txt_eqsl_default_message
|
||||
{ Fl_Group* o = new Fl_Group(8, 270, 484, 90, _("Text Tags (tags use {} delimiters)"));
|
||||
o->box(FL_THIN_DOWN_BOX);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ eqsl_txt1 = new Fl_Box(14, 317, 220, 17, _("{CALL} other ops call sign"));
|
||||
eqsl_txt1->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
|
||||
} // Fl_Box* eqsl_txt1
|
||||
{ eqsl_txt2 = new Fl_Box(12, 336, 220, 17, _("{MODE} full mode / submode"));
|
||||
eqsl_txt2->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
|
||||
} // Fl_Box* eqsl_txt2
|
||||
{ eqsl_txt3 = new Fl_Box(260, 317, 220, 17, _("{NAME} other ops name"));
|
||||
eqsl_txt3->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
|
||||
} // Fl_Box* eqsl_txt3
|
||||
{ new Fl_Box(28, 293, 440, 17, _("These tags can also be used in <EQSL:[message]>"));
|
||||
} // Fl_Box* o
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
{ Fl_Group* o = new Fl_Group(5, 260, 490, 95, _("Paid online subscription"));
|
||||
o->box(FL_ENGRAVED_FRAME);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ Fl_Round_Button* o = btnQRZsub = new Fl_Round_Button(25, 291, 90, 20, _("QRZ.com"));
|
||||
btnQRZsub->tooltip(_("You need a paid QRZ online\nsubscription to access"));
|
||||
btnQRZsub->down_box(FL_DOWN_BOX);
|
||||
btnQRZsub->callback((Fl_Callback*)cb_btnQRZsub);
|
||||
o->value(progdefaults.QRZ == QRZNET);
|
||||
} // Fl_Round_Button* btnQRZsub
|
||||
{ Fl_Round_Button* o = btnHamcall = new Fl_Round_Button(25, 321, 105, 20, _("Hamcall.net"));
|
||||
btnHamcall->tooltip(_("You need a paid Hamcall online\nsubscription to access"));
|
||||
btnHamcall->down_box(FL_DOWN_BOX);
|
||||
btnHamcall->callback((Fl_Callback*)cb_btnHamcall);
|
||||
o->value(progdefaults.QRZ == HAMCALLNET);
|
||||
} // Fl_Round_Button* btnHamcall
|
||||
{ Fl_Input2* o = inpQRZusername = new Fl_Input2(235, 291, 90, 20, _("User name"));
|
||||
inpQRZusername->tooltip(_("Your login name"));
|
||||
inpQRZusername->box(FL_DOWN_BOX);
|
||||
inpQRZusername->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
inpQRZusername->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
inpQRZusername->labeltype(FL_NORMAL_LABEL);
|
||||
inpQRZusername->labelfont(0);
|
||||
inpQRZusername->labelsize(14);
|
||||
inpQRZusername->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
inpQRZusername->callback((Fl_Callback*)cb_inpQRZusername);
|
||||
inpQRZusername->align(FL_ALIGN_LEFT);
|
||||
inpQRZusername->when(FL_WHEN_RELEASE);
|
||||
o->value(progdefaults.QRZusername.c_str());
|
||||
inpQRZusername->labelsize(FL_NORMAL_SIZE);
|
||||
} // Fl_Input2* inpQRZusername
|
||||
{ Fl_Input2* o = inpQRZuserpassword = new Fl_Input2(236, 321, 90, 20, _("Password"));
|
||||
inpQRZuserpassword->tooltip(_("Your login password"));
|
||||
inpQRZuserpassword->box(FL_DOWN_BOX);
|
||||
inpQRZuserpassword->color((Fl_Color)FL_BACKGROUND2_COLOR);
|
||||
inpQRZuserpassword->selection_color((Fl_Color)FL_SELECTION_COLOR);
|
||||
inpQRZuserpassword->labeltype(FL_NORMAL_LABEL);
|
||||
inpQRZuserpassword->labelfont(0);
|
||||
inpQRZuserpassword->labelsize(14);
|
||||
inpQRZuserpassword->labelcolor((Fl_Color)FL_FOREGROUND_COLOR);
|
||||
inpQRZuserpassword->callback((Fl_Callback*)cb_inpQRZuserpassword);
|
||||
inpQRZuserpassword->align(FL_ALIGN_LEFT);
|
||||
inpQRZuserpassword->when(FL_WHEN_RELEASE);
|
||||
o->value(progdefaults.QRZuserpassword.c_str());
|
||||
o->type(FL_SECRET_INPUT);
|
||||
inpQRZuserpassword->labelsize(FL_NORMAL_SIZE);
|
||||
} // Fl_Input2* inpQRZuserpassword
|
||||
{ btnQRZpasswordShow = new Fl_Button(336, 321, 70, 20, _("Show"));
|
||||
btnQRZpasswordShow->tooltip(_("Show password in plain text"));
|
||||
btnQRZpasswordShow->callback((Fl_Callback*)cb_btnQRZpasswordShow);
|
||||
} // Fl_Button* btnQRZpasswordShow
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
{ Fl_Group* o = new Fl_Group(5, 35, 490, 140);
|
||||
o->box(FL_ENGRAVED_FRAME);
|
||||
o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
|
||||
{ Fl_Round_Button* o = btnQRZnotavailable = new Fl_Round_Button(25, 45, 337, 20, _("Not available"));
|
||||
btnQRZnotavailable->tooltip(_("Do not use callsign database"));
|
||||
btnQRZnotavailable->down_box(FL_DOWN_BOX);
|
||||
btnQRZnotavailable->value(1);
|
||||
btnQRZnotavailable->callback((Fl_Callback*)cb_btnQRZnotavailable);
|
||||
o->value(progdefaults.QRZ == QRZNONE);
|
||||
} // Fl_Round_Button* btnQRZnotavailable
|
||||
{ Fl_Round_Button* o = btnQRZonline = new Fl_Round_Button(25, 75, 337, 20, _("QRZ online via default Internet Browser"));
|
||||
btnQRZonline->tooltip(_("Visit QRZ web site"));
|
||||
btnQRZonline->down_box(FL_DOWN_BOX);
|
||||
btnQRZonline->callback((Fl_Callback*)cb_btnQRZonline);
|
||||
o->value(progdefaults.QRZ == QRZHTML);
|
||||
} // Fl_Round_Button* btnQRZonline
|
||||
{ Fl_Round_Button* o = btnHAMCALLonline = new Fl_Round_Button(25, 106, 337, 20, _("HamCall online via default Internet Browser"));
|
||||
btnHAMCALLonline->tooltip(_("Visit Hamcall web site"));
|
||||
btnHAMCALLonline->down_box(FL_DOWN_BOX);
|
||||
btnHAMCALLonline->callback((Fl_Callback*)cb_btnHAMCALLonline);
|
||||
o->value(progdefaults.QRZ == HAMCALLHTML);
|
||||
} // Fl_Round_Button* btnHAMCALLonline
|
||||
{ Fl_Round_Button* o = btnCALLOOK = new Fl_Round_Button(25, 137, 337, 20, _("Callook.info lookup (US callsigns only)"));
|
||||
btnCALLOOK->tooltip(_("Visit Hamcall web site"));
|
||||
btnCALLOOK->down_box(FL_DOWN_BOX);
|
||||
btnCALLOOK->callback((Fl_Callback*)cb_btnCALLOOK);
|
||||
o->value(progdefaults.QRZ == CALLOOK);
|
||||
} // Fl_Round_Button* btnCALLOOK
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
} // Fl_Tabs* o
|
||||
tabQRZ->end();
|
||||
} // Fl_Group* tabQRZ
|
||||
{ tabDL = new Fl_Group(0, 25, 500, 350, _("DL Client"));
|
||||
|
|
|
@ -9,6 +9,8 @@ decl {\#include <config.h>} {}
|
|||
|
||||
decl {\#include <FL/Fl_Tooltip.H>} {}
|
||||
|
||||
decl {\#include <FL/Fl_Box.H>} {}
|
||||
|
||||
decl {\#include <FL/filename.H>} {}
|
||||
|
||||
decl {\#include <sstream>} {}
|
||||
|
@ -89,7 +91,7 @@ Function {set_qrz_buttons(Fl_Button* b)} {open return_type void
|
|||
} {
|
||||
code {Fl_Button* qrzb[] = { btnQRZnotavailable, btnQRZcdrom, btnQRZonline,
|
||||
btnQRZsub, btnHamcall, btnHAMCALLonline,
|
||||
btnCALLOOK};
|
||||
btnCALLOOK, btnHamQTH};
|
||||
|
||||
for (size_t i = 0; i < sizeof(qrzb)/sizeof(*qrzb); i++)
|
||||
qrzb[i]->value(b == qrzb[i]);} {}
|
||||
|
@ -111,14 +113,14 @@ static const char szProsigns[] = "~|%|&|+|=|{|}|<|>|[|]| ";} {}
|
|||
code {static const int flight_browser_columns[] = { 170, 150, 170 };} {}
|
||||
Fl_Window {} {
|
||||
label {Fldigi configuration} open
|
||||
xywh {644 190 500 400} type Double color 45 selection_color 51 labelsize 18 align 80 non_modal visible
|
||||
xywh {592 125 500 400} type Double color 45 selection_color 51 labelsize 18 align 80 non_modal visible
|
||||
} {
|
||||
Fl_Tabs tabsConfigure {open
|
||||
xywh {-4 0 521 372} color 50 selection_color 50
|
||||
} {
|
||||
Fl_Group tabOperator {
|
||||
label Operator
|
||||
callback {progdefaults.changed = true;}
|
||||
callback {progdefaults.changed = true;} open selected
|
||||
tooltip {Operator information} xywh {0 25 500 345} labelsize 12 when 1
|
||||
} {
|
||||
Fl_Group {} {
|
||||
|
@ -216,7 +218,7 @@ btnApplyConfig->activate();}
|
|||
}
|
||||
}
|
||||
Fl_Group tabUI {
|
||||
label UI open
|
||||
label UI
|
||||
xywh {0 25 502 346} labelsize 12 hide
|
||||
} {
|
||||
Fl_Tabs tabsUI {open
|
||||
|
@ -935,22 +937,23 @@ connect_to_log_server();}
|
|||
}
|
||||
Fl_Group tabWaterfall {
|
||||
label Waterfall
|
||||
xywh {0 25 500 347} labelsize 12 hide
|
||||
xywh {0 25 501 347} labelsize 12 hide
|
||||
} {
|
||||
Fl_Tabs tabsWaterfall {open
|
||||
xywh {0 25 500 347} color 50 selection_color 50
|
||||
xywh {0 25 501 347} color 50 selection_color 50
|
||||
} {
|
||||
Fl_Group {} {
|
||||
label Display open
|
||||
xywh {0 50 500 320}
|
||||
xywh {0 50 501 320}
|
||||
} {
|
||||
Fl_Group {} {
|
||||
label {Colors and cursors} open
|
||||
xywh {5 60 490 162} box ENGRAVED_FRAME align 21
|
||||
xywh {5 60 496 162} box ENGRAVED_FRAME align 21
|
||||
} {
|
||||
Fl_Button WF_Palette {
|
||||
label aa
|
||||
callback {progdefaults.changed = true;}
|
||||
xywh {15 98 260 24} box DOWN_BOX color 0 labelsize 12 align 5
|
||||
xywh {15 93 260 24} box DOWN_BOX color 0 labelsize 12 align 5
|
||||
code0 {\#include "colorbox.h"}
|
||||
code1 {o->label(progdefaults.PaletteName.c_str());}
|
||||
code2 {o->labelsize(FL_NORMAL_SIZE);}
|
||||
|
@ -959,59 +962,59 @@ connect_to_log_server();}
|
|||
Fl_Button {btnColor[0]} {
|
||||
callback {selectColor(0);
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Change color} xywh {15 128 20 24}
|
||||
tooltip {Change color} xywh {15 120 20 24}
|
||||
}
|
||||
Fl_Button {btnColor[1]} {
|
||||
callback {selectColor(1);
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Change color} xywh {45 128 20 24}
|
||||
tooltip {Change color} xywh {45 120 20 24}
|
||||
}
|
||||
Fl_Button {btnColor[2]} {
|
||||
callback {selectColor(2);
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Change color} xywh {75 128 20 24}
|
||||
tooltip {Change color} xywh {75 120 20 24}
|
||||
}
|
||||
Fl_Button {btnColor[3]} {
|
||||
callback {selectColor(3);
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Change color} xywh {105 128 20 24}
|
||||
tooltip {Change color} xywh {105 120 20 24}
|
||||
}
|
||||
Fl_Button {btnColor[4]} {
|
||||
callback {selectColor(4);
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Change color} xywh {135 128 20 24}
|
||||
tooltip {Change color} xywh {135 120 20 24}
|
||||
}
|
||||
Fl_Button {btnColor[5]} {
|
||||
callback {selectColor(5);
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Change color} xywh {165 128 20 24}
|
||||
tooltip {Change color} xywh {165 120 20 24}
|
||||
}
|
||||
Fl_Button {btnColor[6]} {
|
||||
callback {selectColor(6);
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Change color} xywh {195 128 20 24}
|
||||
tooltip {Change color} xywh {195 120 20 24}
|
||||
}
|
||||
Fl_Button {btnColor[7]} {
|
||||
callback {selectColor(7);
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Change color} xywh {225 128 20 24}
|
||||
tooltip {Change color} xywh {225 120 20 24}
|
||||
}
|
||||
Fl_Button {btnColor[8]} {
|
||||
callback {selectColor(8);
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Change color} xywh {256 128 20 24}
|
||||
tooltip {Change color} xywh {256 120 20 24}
|
||||
}
|
||||
Fl_Button btnLoadPalette {
|
||||
label {Load...}
|
||||
callback {loadPalette();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Load a new palette} xywh {314 96 70 24}
|
||||
tooltip {Load a new palette} xywh {314 93 70 24}
|
||||
code0 {\#include "colorbox.h"}
|
||||
}
|
||||
Fl_Button btnSavePalette {
|
||||
label {Save...}
|
||||
callback {savePalette();}
|
||||
tooltip {Save this palette} xywh {314 128 70 24}
|
||||
tooltip {Save this palette} xywh {314 120 70 24}
|
||||
code0 {\#include "colorbox.h"}
|
||||
}
|
||||
Fl_Check_Button btnUseCursorLines {
|
||||
|
@ -1022,7 +1025,7 @@ if (o->value())
|
|||
else
|
||||
btnCursorBWcolor->deactivate();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Show cursor with bandwidth lines} xywh {15 161 150 20} down_box DOWN_BOX
|
||||
tooltip {Show cursor with bandwidth lines} xywh {15 149 150 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.UseCursorLines);}
|
||||
}
|
||||
Fl_Button btnCursorBWcolor {
|
||||
|
@ -1035,7 +1038,7 @@ o->color(fl_rgb_color(progdefaults.cursorLineRGBI.R,progdefaults.cursorLineRGBI.
|
|||
o->redraw();
|
||||
progdefaults.changed = true;
|
||||
}}
|
||||
tooltip {Change color} xywh {15 191 20 20} color 3 align 8
|
||||
tooltip {Change color} xywh {15 172 20 20} color 3 align 8
|
||||
code0 {\#include <FL/Fl_Color_Chooser.H>}
|
||||
code1 {o->color(fl_rgb_color(progdefaults.cursorLineRGBI.R,progdefaults.cursorLineRGBI.G,progdefaults.cursorLineRGBI.B));}
|
||||
}
|
||||
|
@ -1043,7 +1046,7 @@ progdefaults.changed = true;
|
|||
label {Cursor center line}
|
||||
callback {progdefaults.UseCursorCenterLine = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Show cursor with center line} xywh {185 161 149 20} down_box DOWN_BOX
|
||||
tooltip {Show cursor with center line} xywh {185 149 149 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.UseCursorCenterLine);}
|
||||
}
|
||||
Fl_Button btnCursorCenterLineColor {
|
||||
|
@ -1056,14 +1059,14 @@ o->color(fl_rgb_color(progdefaults.cursorCenterRGBI.R,progdefaults.cursorCenterR
|
|||
o->redraw();
|
||||
progdefaults.changed = true;
|
||||
}}
|
||||
tooltip {Change color} xywh {185 191 20 20} color 7 align 8
|
||||
tooltip {Change color} xywh {185 172 20 20} color 7 align 8
|
||||
code0 {o->color(fl_rgb_color(progdefaults.cursorCenterRGBI.R,progdefaults.cursorCenterRGBI.G,progdefaults.cursorCenterRGBI.B));}
|
||||
}
|
||||
Fl_Check_Button btnUseBWTracks {
|
||||
label {Bandwidth tracks}
|
||||
callback {progdefaults.UseBWTracks = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Show bandwidth tracks on waterfall} xywh {346 161 145 20} down_box DOWN_BOX
|
||||
tooltip {Show bandwidth tracks on waterfall} xywh {346 149 145 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.UseBWTracks);}
|
||||
}
|
||||
Fl_Button btnBwTracksColor {
|
||||
|
@ -1077,9 +1080,30 @@ o->redraw();
|
|||
wf->redraw_marker();
|
||||
progdefaults.changed = true;
|
||||
}}
|
||||
tooltip {Change color} xywh {346 191 20 20} color 1 align 8
|
||||
tooltip {Change color} xywh {346 172 20 20} color 1 align 8
|
||||
code0 {o->color(fl_rgb_color(progdefaults.bwTrackRGBI.R,progdefaults.bwTrackRGBI.G,progdefaults.bwTrackRGBI.B));}
|
||||
}
|
||||
Fl_Check_Button btnUseWideTracks {
|
||||
label {Wide tracks}
|
||||
callback {progdefaults.UseWideTracks = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Show bandwidth tracks on waterfall} xywh {346 196 145 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.UseWideTracks);}
|
||||
}
|
||||
Fl_Check_Button btnUseWideCenter {
|
||||
label {Wide center line}
|
||||
callback {progdefaults.UseWideCenter = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Show bandwidth tracks on waterfall} xywh {185 197 145 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.UseWideCenter);}
|
||||
}
|
||||
Fl_Check_Button btnUseWideCursor {
|
||||
label {Wide cursor}
|
||||
callback {progdefaults.UseWideCursor = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Show bandwidth tracks on waterfall} xywh {15 195 145 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.UseWideCursor);}
|
||||
}
|
||||
}
|
||||
Fl_Group {} {
|
||||
label {Frequency scale} open
|
||||
|
@ -1247,7 +1271,7 @@ behaves inside the waterfall} xywh {15 196 150 22} down_box BORDER_BOX align 8
|
|||
}
|
||||
}
|
||||
Fl_Group tabModems {
|
||||
label Modems open
|
||||
label Modems
|
||||
xywh {-4 25 521 347} labelsize 12 hide
|
||||
} {
|
||||
Fl_Tabs tabsModems {open
|
||||
|
@ -2184,7 +2208,7 @@ o->color(fl_rgb_color(progdefaults.rttymarkRGBI.R,progdefaults.rttymarkRGBI.G,pr
|
|||
o->redraw();
|
||||
wf->redraw_marker();
|
||||
progdefaults.changed = true;
|
||||
}} selected
|
||||
}}
|
||||
tooltip {Change color} xywh {403 208 18 18} color 2 align 8
|
||||
code0 {o->color(fl_rgb_color(progdefaults.rttymarkRGBI.R,progdefaults.rttymarkRGBI.G,progdefaults.rttymarkRGBI.B));}
|
||||
}
|
||||
|
@ -3342,7 +3366,7 @@ progdefaults.changed = true;}
|
|||
}
|
||||
}
|
||||
Fl_Group tabMisc {
|
||||
label Misc open
|
||||
label Misc
|
||||
xywh {0 25 500 345} labelsize 12 hide
|
||||
} {
|
||||
Fl_Tabs tabsMisc {open
|
||||
|
@ -3660,119 +3684,229 @@ progdefaults.changed = true;}
|
|||
}
|
||||
}
|
||||
}
|
||||
Fl_Group tabDTMF {
|
||||
label DTMF open
|
||||
xywh {0 50 500 320} hide
|
||||
} {
|
||||
Fl_Check_Button chkDTMFdecode {
|
||||
label {Decode DTMF tones}
|
||||
callback {progdefaults.DTMFdecode = o->value();}
|
||||
tooltip {Send rx text to file: textout.txt} xywh {175 71 175 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.DTMFdecode);}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Fl_Group tabQRZ {
|
||||
label {Callsign DB}
|
||||
label Web open
|
||||
tooltip {Callsign database} xywh {0 25 500 345} labelsize 12 hide
|
||||
} {
|
||||
Fl_Group {} {
|
||||
label CDROM open
|
||||
xywh {5 180 490 75} box ENGRAVED_FRAME align 21
|
||||
} {
|
||||
Fl_Tabs {} {open
|
||||
xywh {0 25 500 345}
|
||||
} {
|
||||
Fl_Round_Button btnQRZcdrom {
|
||||
label QRZ
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZCD;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Use CD or hard drive CD image} xywh {25 215 70 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == QRZCD);}
|
||||
}
|
||||
Fl_Input txtQRZpathname {
|
||||
label {at:}
|
||||
callback {progdefaults.QRZpathname = o->value();
|
||||
progdefaults.QRZchanged = true;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {ie: /home/dave/CALLBK/ or C:/CALLBK/
|
||||
Leave blank to search for database} xywh {104 215 300 20}
|
||||
code0 {o->value(progdefaults.QRZpathname.c_str());}
|
||||
code1 {txtQRZpathname->labelsize(FL_NORMAL_SIZE);}
|
||||
class Fl_Input2
|
||||
}
|
||||
}
|
||||
Fl_Group {} {
|
||||
label {Paid online subscription} open
|
||||
xywh {5 260 490 95} box ENGRAVED_FRAME align 21
|
||||
} {
|
||||
Fl_Round_Button btnQRZsub {
|
||||
label {QRZ.com}
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZNET;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {You need a paid QRZ online
|
||||
subscription to access} xywh {25 291 90 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == QRZNET);}
|
||||
}
|
||||
Fl_Round_Button btnHamcall {
|
||||
label {Hamcall.net}
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = HAMCALLNET;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {You need a paid Hamcall online
|
||||
subscription to access} xywh {25 321 105 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == HAMCALLNET);}
|
||||
}
|
||||
Fl_Input inpQRZusername {
|
||||
label {User name}
|
||||
callback {progdefaults.QRZusername = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Your login name} xywh {235 291 90 20}
|
||||
code0 {o->value(progdefaults.QRZusername.c_str());}
|
||||
code1 {inpQRZusername->labelsize(FL_NORMAL_SIZE);}
|
||||
class Fl_Input2
|
||||
}
|
||||
Fl_Input inpQRZuserpassword {
|
||||
label Password
|
||||
callback {progdefaults.QRZuserpassword = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Your login password} xywh {236 321 90 20}
|
||||
code0 {o->value(progdefaults.QRZuserpassword.c_str());}
|
||||
code1 {o->type(FL_SECRET_INPUT);}
|
||||
code2 {inpQRZuserpassword->labelsize(FL_NORMAL_SIZE);}
|
||||
class Fl_Input2
|
||||
}
|
||||
Fl_Button btnQRZpasswordShow {
|
||||
label Show
|
||||
callback {inpQRZuserpassword->type(inpQRZuserpassword->type() ^ FL_SECRET_INPUT);
|
||||
inpQRZuserpassword->redraw();
|
||||
o->label((inpQRZuserpassword->type() & FL_SECRET_INPUT) ? "Show" : "Hide");}
|
||||
tooltip {Show password in plain text} xywh {336 321 70 20}
|
||||
}
|
||||
}
|
||||
Fl_Group {} {open
|
||||
xywh {5 35 490 140} box ENGRAVED_FRAME align 21
|
||||
} {
|
||||
Fl_Round_Button btnQRZnotavailable {
|
||||
label {Not available}
|
||||
callback {set_qrz_buttons(o);
|
||||
Fl_Group {} {
|
||||
label {QRZ/etal} open
|
||||
xywh {0 46 500 324}
|
||||
} {
|
||||
Fl_Group {} {open
|
||||
xywh {5 55 490 120} box ENGRAVED_FRAME align 21
|
||||
} {
|
||||
Fl_Round_Button btnQRZnotavailable {
|
||||
label {Not available}
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZNONE;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Do not use callsign database} xywh {25 45 337 20} down_box DOWN_BOX value 1
|
||||
code0 {o->value(progdefaults.QRZ == QRZNONE);}
|
||||
}
|
||||
Fl_Round_Button btnQRZonline {
|
||||
label {QRZ online via default Internet Browser}
|
||||
callback {set_qrz_buttons(o);
|
||||
tooltip {Do not use callsign database} xywh {25 64 337 20} down_box DOWN_BOX value 1
|
||||
code0 {o->value(progdefaults.QRZ == QRZNONE);}
|
||||
}
|
||||
Fl_Round_Button btnQRZonline {
|
||||
label {QRZ online via default Internet Browser}
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZHTML;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Visit QRZ web site} xywh {25 75 337 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == QRZHTML);}
|
||||
}
|
||||
Fl_Round_Button btnHAMCALLonline {
|
||||
label {HamCall online via default Internet Browser}
|
||||
callback {set_qrz_buttons(o);
|
||||
tooltip {Visit QRZ web site} xywh {25 92 337 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == QRZHTML);}
|
||||
}
|
||||
Fl_Round_Button btnHAMCALLonline {
|
||||
label {HamCall online via default Internet Browser}
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = HAMCALLHTML;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Visit Hamcall web site} xywh {25 106 337 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == HAMCALLHTML);}
|
||||
}
|
||||
Fl_Round_Button btnCALLOOK {
|
||||
label {Callook.info lookup (US callsigns only)}
|
||||
callback {set_qrz_buttons(o);
|
||||
tooltip {Visit Hamcall web site} xywh {25 120 337 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == HAMCALLHTML);}
|
||||
}
|
||||
Fl_Round_Button btnCALLOOK {
|
||||
label {Callook.info lookup (US callsigns only)}
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = CALLOOK;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Visit Hamcall web site} xywh {25 137 337 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == CALLOOK);}
|
||||
tooltip {Visit Hamcall web site} xywh {25 148 337 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == CALLOOK);}
|
||||
}
|
||||
}
|
||||
Fl_Group {} {
|
||||
label CDROM open
|
||||
xywh {5 176 490 55} box ENGRAVED_FRAME align 21
|
||||
} {
|
||||
Fl_Round_Button btnQRZcdrom {
|
||||
label QRZ
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZCD;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Use CD or hard drive CD image} xywh {25 196 70 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == QRZCD);}
|
||||
}
|
||||
Fl_Input txtQRZpathname {
|
||||
label {at:}
|
||||
callback {progdefaults.QRZpathname = o->value();
|
||||
progdefaults.QRZchanged = true;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {ie: /home/dave/CALLBK/ or C:/CALLBK/
|
||||
Leave blank to search for database} xywh {104 196 300 20}
|
||||
code0 {o->value(progdefaults.QRZpathname.c_str());}
|
||||
code1 {txtQRZpathname->labelsize(FL_NORMAL_SIZE);}
|
||||
class Fl_Input2
|
||||
}
|
||||
}
|
||||
Fl_Group {} {
|
||||
label {Subscriber data} open
|
||||
xywh {5 232 490 134} box ENGRAVED_FRAME align 21
|
||||
} {
|
||||
Fl_Round_Button btnQRZsub {
|
||||
label {QRZ.com}
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = QRZNET;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {You need a paid QRZ online
|
||||
subscription to access} xywh {25 263 90 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == QRZNET);}
|
||||
}
|
||||
Fl_Round_Button btnHamcall {
|
||||
label {Hamcall.net}
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = HAMCALLNET;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {You need a paid Hamcall online
|
||||
subscription to access} xywh {25 297 105 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == HAMCALLNET);}
|
||||
}
|
||||
Fl_Input inpQRZusername {
|
||||
label {User name}
|
||||
callback {progdefaults.QRZusername = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Your login name} xywh {235 263 150 20}
|
||||
code0 {o->value(progdefaults.QRZusername.c_str());}
|
||||
code1 {inpQRZusername->labelsize(FL_NORMAL_SIZE);}
|
||||
class Fl_Input2
|
||||
}
|
||||
Fl_Input inpQRZuserpassword {
|
||||
label Password
|
||||
callback {progdefaults.QRZuserpassword = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Your login password} xywh {235 297 150 20}
|
||||
code0 {o->value(progdefaults.QRZuserpassword.c_str());}
|
||||
code1 {o->type(FL_SECRET_INPUT);}
|
||||
code2 {inpQRZuserpassword->labelsize(FL_NORMAL_SIZE);}
|
||||
class Fl_Input2
|
||||
}
|
||||
Fl_Button btnQRZpasswordShow {
|
||||
label Show
|
||||
callback {inpQRZuserpassword->type(inpQRZuserpassword->type() ^ FL_SECRET_INPUT);
|
||||
inpQRZuserpassword->redraw();
|
||||
o->label((inpQRZuserpassword->type() & FL_SECRET_INPUT) ? "Show" : "Hide");}
|
||||
tooltip {Show password in plain text} xywh {395 297 70 20}
|
||||
}
|
||||
Fl_Round_Button btnHamQTH {
|
||||
label {HamQTH.com (free service http://www.hamqth.com)}
|
||||
callback {set_qrz_buttons(o);
|
||||
progdefaults.QRZ = HAMQTH;
|
||||
progdefaults.changed = true;}
|
||||
tooltip {You need a paid Hamcall online
|
||||
subscription to access} xywh {26 332 121 20} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.QRZ == HAMQTH);}
|
||||
}
|
||||
}
|
||||
}
|
||||
Fl_Group {} {
|
||||
label eQSL open
|
||||
xywh {0 50 500 320} hide
|
||||
} {
|
||||
Fl_Input inpEQSL_id {
|
||||
label {User ID}
|
||||
callback {progdefaults.eqsl_id = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Your login name} xywh {176 75 150 20}
|
||||
code0 {o->value(progdefaults.eqsl_id.c_str());}
|
||||
code1 {inpEQSL_id->labelsize(FL_NORMAL_SIZE);}
|
||||
class Fl_Input2
|
||||
}
|
||||
Fl_Input inpEQSL_pwd {
|
||||
label Password
|
||||
callback {progdefaults.eqsl_pwd = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Your login password} xywh {176 106 150 20}
|
||||
code0 {o->value(progdefaults.eqsl_pwd.c_str());}
|
||||
code1 {o->type(FL_SECRET_INPUT);}
|
||||
code2 {inpEQSL_pwd->labelsize(FL_NORMAL_SIZE);}
|
||||
class Fl_Input2
|
||||
}
|
||||
Fl_Button btnEQSL_pwd_show {
|
||||
label Show
|
||||
callback {inpEQSL_pwd->type(inpEQSL_pwd->type() ^ FL_SECRET_INPUT);
|
||||
inpEQSL_pwd->redraw();
|
||||
o->label((inpEQSL_pwd->type() & FL_SECRET_INPUT) ? "Show" : "Hide");}
|
||||
tooltip {Show password in plain text} xywh {344 106 70 20}
|
||||
}
|
||||
Fl_Input inpEQSL_nick {
|
||||
label {QTH Nickname}
|
||||
callback {progdefaults.eqsl_nick = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Your login name} xywh {176 137 150 20}
|
||||
code0 {o->value(progdefaults.eqsl_nick.c_str());}
|
||||
code1 {inpEQSL_nick->labelsize(FL_NORMAL_SIZE);}
|
||||
class Fl_Input2
|
||||
}
|
||||
Fl_Group {} {
|
||||
label Options open
|
||||
xywh {4 170 492 194} box ENGRAVED_FRAME align 21
|
||||
} {
|
||||
Fl_Check_Button btn_send_when_logged {
|
||||
label {send when logged (log button, <LOG>, <LNW>)}
|
||||
callback {progdefaults.eqsl_when_logged = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {eQSL upload when record logged} xywh {29 191 70 15} down_box DOWN_BOX
|
||||
code0 {o->value(progdefaults.eqsl_when_logged);}
|
||||
}
|
||||
Fl_Input txt_eqsl_default_message {
|
||||
label {Default message}
|
||||
callback {progdefaults.eqsl_default_message = o->value();
|
||||
progdefaults.changed = true;}
|
||||
tooltip {Default message sent with eQSL} xywh {33 226 451 40} type Multiline align 5 when 1
|
||||
code0 {o->value(progdefaults.eqsl_default_message.c_str());}
|
||||
class Fl_Input2
|
||||
}
|
||||
Fl_Group {} {
|
||||
label {Text Tags (tags use {} delimiters)} open
|
||||
xywh {8 270 484 90} box THIN_DOWN_BOX align 21
|
||||
} {
|
||||
Fl_Box eqsl_txt1 {
|
||||
label {{CALL} other ops call sign}
|
||||
xywh {14 317 220 17} align 20
|
||||
}
|
||||
Fl_Box eqsl_txt2 {
|
||||
label {{MODE} full mode / submode}
|
||||
xywh {12 336 220 17} align 20
|
||||
}
|
||||
Fl_Box eqsl_txt3 {
|
||||
label {{NAME} other ops name}
|
||||
xywh {260 317 220 17} align 20
|
||||
}
|
||||
Fl_Box {} {
|
||||
label {These tags can also be used in <EQSL:[message]>}
|
||||
xywh {28 293 440 17}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
#endif
|
||||
#include "rigio.h"
|
||||
#include "rigMEM.h"
|
||||
#include "nullmodem.h"
|
||||
#include "psk.h"
|
||||
#include "cw.h"
|
||||
#include "mfsk.h"
|
||||
|
@ -1034,6 +1035,11 @@ void init_modem(trx_mode mode, int freq)
|
|||
mode = NUM_MODES - 1;
|
||||
return init_modem(mode, freq);
|
||||
|
||||
case MODE_NULL:
|
||||
startup_modem(*mode_info[mode].modem ? *mode_info[mode].modem :
|
||||
*mode_info[mode].modem = new NULLMODEM, freq);
|
||||
break;
|
||||
|
||||
case MODE_CW:
|
||||
startup_modem(*mode_info[mode].modem ? *mode_info[mode].modem :
|
||||
*mode_info[mode].modem = new cw, freq);
|
||||
|
@ -1856,6 +1862,19 @@ void cb_ShowNBEMS(Fl_Widget*, void*)
|
|||
cb_mnuVisitURL(0, (void*)NBEMS_dir.c_str());
|
||||
}
|
||||
|
||||
void cb_ShowFLMSG(Fl_Widget*, void*)
|
||||
{
|
||||
DIR *flmsg_dir;
|
||||
flmsg_dir = opendir(FLMSG_dir.c_str());
|
||||
if (!flmsg_dir) {
|
||||
int ans = fl_choice2(_("Do not exist, create?"), _("No"), _("Yes"), 0);
|
||||
if (!ans) return;
|
||||
check_nbems_dirs();
|
||||
}
|
||||
closedir(flmsg_dir);
|
||||
cb_mnuVisitURL(0, (void*)FLMSG_dir.c_str());
|
||||
}
|
||||
|
||||
void cbTune(Fl_Widget *w, void *) {
|
||||
Fl_Button *b = (Fl_Button *)w;
|
||||
if (!(active_modem->get_cap() & modem::CAP_TX)) {
|
||||
|
@ -2342,6 +2361,7 @@ void stopMacroTimer()
|
|||
progStatus.timer = 0;
|
||||
progStatus.repeatMacro = -1;
|
||||
Fl::remove_timeout(macro_timer);
|
||||
Fl::remove_timeout(macro_timed_execute);
|
||||
|
||||
btnMacroTimer->label(0);
|
||||
btnMacroTimer->color(FL_BACKGROUND_COLOR);
|
||||
|
@ -2362,6 +2382,32 @@ void macro_timer(void*)
|
|||
Fl::repeat_timeout(1.0, macro_timer);
|
||||
}
|
||||
|
||||
void macro_timed_execute(void *)
|
||||
{
|
||||
if (exec_date == zdate() && exec_time == ztime()) {
|
||||
macros.timed_execute();
|
||||
btnMacroTimer->label(0);
|
||||
btnMacroTimer->color(FL_BACKGROUND_COLOR);
|
||||
btnMacroTimer->set_output();
|
||||
} else {
|
||||
Fl::repeat_timeout(1.0, macro_timed_execute);
|
||||
}
|
||||
}
|
||||
|
||||
void startTimedExecute(std::string &title)
|
||||
{
|
||||
ENSURE_THREAD(FLMAIN_TID);
|
||||
Fl::add_timeout(0.0, macro_timed_execute);
|
||||
string txt = "Macro '";
|
||||
txt.append(title).append("' scheduled at ");
|
||||
txt.append(exec_time).append(", on ").append(exec_date).append("\n");
|
||||
btnMacroTimer->label("SKED");
|
||||
btnMacroTimer->color(fl_rgb_color(240, 240, 0));
|
||||
btnMacroTimer->redraw_label();
|
||||
ReceiveText->clear();
|
||||
ReceiveText->add(txt.c_str(), FTextBase::CTRL);
|
||||
}
|
||||
|
||||
void cbMacroTimerButton(Fl_Widget*, void*)
|
||||
{
|
||||
stopMacroTimer();
|
||||
|
@ -2993,6 +3039,7 @@ Fl_Menu_Item menu_[] = {
|
|||
|
||||
{ make_icon_label(_("Folders")), 0, 0, 0, FL_SUBMENU, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Fldigi config..."), folder_open_icon), 0, cb_ShowConfig, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("FLMSG files..."), folder_open_icon), 0, cb_ShowFLMSG, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("NBEMS files..."), folder_open_icon), 0, cb_ShowNBEMS, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{0,0,0,0,0,0,0,0,0},
|
||||
|
||||
|
@ -3142,6 +3189,7 @@ Fl_Menu_Item menu_[] = {
|
|||
{ mode_info[MODE_PSK250].name, 0, cb_init_mode, (void *)MODE_PSK250, 0, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{0,0,0,0,0,0,0,0,0},
|
||||
|
||||
{ mode_info[MODE_NULL].name, 0, cb_init_mode, (void *)MODE_NULL, 0, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{ mode_info[MODE_SSB].name, 0, cb_init_mode, (void *)MODE_SSB, 0, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
|
||||
{ mode_info[MODE_WWV].name, 0, cb_init_mode, (void *)MODE_WWV, 0, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
|
@ -3163,7 +3211,7 @@ Fl_Menu_Item menu_[] = {
|
|||
{ make_icon_label(_("Misc")), 0, (Fl_Callback*)cb_mnuConfigMisc, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Notifications")), 0, (Fl_Callback*)cb_mnuConfigNotify, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(CONTEST_MLABEL), 0, (Fl_Callback*)cb_mnuConfigContest, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("QRZ"), net_icon), 0, (Fl_Callback*)cb_mnuConfigQRZ, 0, FL_MENU_DIVIDER, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("QRZ/eQSL"), net_icon), 0, (Fl_Callback*)cb_mnuConfigQRZ, 0, FL_MENU_DIVIDER, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Save Config"), save_icon), 0, (Fl_Callback*)cb_mnuSaveConfig, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{0,0,0,0,0,0,0,0,0},
|
||||
|
||||
|
@ -3194,23 +3242,24 @@ Fl_Menu_Item menu_[] = {
|
|||
{0,0,0,0,0,0,0,0,0},
|
||||
|
||||
{_("&Logbook"), 0, 0, 0, FL_SUBMENU, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{ LOG_CONNECT_SERVER, 0, cb_log_server, 0, FL_MENU_TOGGLE | FL_MENU_DIVIDER, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("View")), 'l', (Fl_Callback*)cb_mnuShowLogbook, 0, FL_MENU_DIVIDER, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("New")), 0, (Fl_Callback*)cb_mnuNewLogbook, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Open...")), 0, (Fl_Callback*)cb_mnuOpenLogbook, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Save")), 0, (Fl_Callback*)cb_mnuSaveLogbook, 0, FL_MENU_DIVIDER, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
|
||||
{"ADIF", 0, 0, 0, FL_SUBMENU, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Merge...")), 0, (Fl_Callback*)cb_mnuMergeADIF_log, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Export...")), 0, (Fl_Callback*)cb_mnuExportADIF_log, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{0,0,0,0,0,0,0,0,0},
|
||||
|
||||
{"Reports", 0, 0, 0, FL_SUBMENU, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{"Reports", 0, 0, 0, FL_SUBMENU | FL_MENU_DIVIDER, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Text...")), 0, (Fl_Callback*)cb_mnuExportTEXT_log, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("CSV...")), 0, (Fl_Callback*)cb_mnuExportCSV_log, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Cabrillo...")), 0, (Fl_Callback*)cb_Export_Cabrillo, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{0,0,0,0,0,0,0,0,0},
|
||||
|
||||
{ make_icon_label(_("New")), 0, (Fl_Callback*)cb_mnuNewLogbook, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Open...")), 0, (Fl_Callback*)cb_mnuOpenLogbook, 0, 0, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
{ make_icon_label(_("Save")), 0, (Fl_Callback*)cb_mnuSaveLogbook, 0, FL_MENU_DIVIDER, _FL_MULTI_LABEL, 0, 14, 0},
|
||||
|
||||
{ LOG_CONNECT_SERVER, 0, cb_log_server, 0, FL_MENU_TOGGLE, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{0,0,0,0,0,0,0,0,0},
|
||||
|
||||
{_("DL Client"), 0, 0, 0, FL_SUBMENU, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
|
@ -3673,6 +3722,12 @@ void showMacroSet() {
|
|||
set_macroLabels();
|
||||
}
|
||||
|
||||
void showDTMF(const string s) {
|
||||
string dtmfstr = "\n<DTMF> ";
|
||||
dtmfstr.append(s);
|
||||
ReceiveText->add(dtmfstr.c_str());
|
||||
}
|
||||
|
||||
void setwfrange() {
|
||||
wf->opmode();
|
||||
}
|
||||
|
@ -3762,7 +3817,7 @@ void create_fl_digi_main_primary() {
|
|||
int Hmacrobtn;
|
||||
int xpos;
|
||||
int ypos;
|
||||
int wblank;
|
||||
int wBLANK;
|
||||
|
||||
int fnt = fl_font();
|
||||
int fsize = fl_size();
|
||||
|
@ -4404,14 +4459,14 @@ void create_fl_digi_main_primary() {
|
|||
Fl_Group *btngroup2 = new Fl_Group(0, Y + 1, progStatus.mainW - Hmacros, Hmacros - 1);
|
||||
Wmacrobtn = (btngroup2->w()) / NUMMACKEYS;
|
||||
Hmacrobtn = btngroup2->h() - 1;
|
||||
wblank = (btngroup2->w() - NUMMACKEYS * Wmacrobtn) / 2;
|
||||
wBLANK = (btngroup2->w() - NUMMACKEYS * Wmacrobtn) / 2;
|
||||
xpos = 0;
|
||||
ypos = btngroup2->y();
|
||||
for (int i = 0; i < NUMMACKEYS; i++) {
|
||||
if (i == 4 || i == 8) {
|
||||
bx = new Fl_Box(xpos, ypos, wblank, Hmacrobtn);
|
||||
bx = new Fl_Box(xpos, ypos, wBLANK, Hmacrobtn);
|
||||
bx->box(FL_FLAT_BOX);
|
||||
xpos += wblank;
|
||||
xpos += wBLANK;
|
||||
}
|
||||
btnMacro[NUMMACKEYS + i] = new Fl_Button(xpos, ypos, Wmacrobtn, Hmacrobtn,
|
||||
macros.name[NUMMACKEYS + i].c_str());
|
||||
|
@ -4427,6 +4482,7 @@ void create_fl_digi_main_primary() {
|
|||
btnAltMacros2->tooltip(_("Shift-key macro set"));
|
||||
macroFrame2->resizable(btngroup2);
|
||||
macroFrame2->end();
|
||||
|
||||
Y += Hmacros;
|
||||
int Htext = progStatus.mainH - Hwfall - Hmenu - Hstatus - Hmacros*NUMKEYROWS - Hqsoframe - 4;
|
||||
int Hrcvtxt = Htext / 2;
|
||||
|
@ -4465,7 +4521,6 @@ void create_fl_digi_main_primary() {
|
|||
text_panel->x(), text_panel->y(),
|
||||
text_panel->w()/2, Htext, "");
|
||||
|
||||
// mainViewer = new pskBrowser(mvgroup->x(), mvgroup->y(), mvgroup->w(), Htext-22, "");
|
||||
mainViewer = new pskBrowser(mvgroup->x(), mvgroup->y(), mvgroup->w(), Htext-42, "");
|
||||
mainViewer->box(FL_DOWN_BOX);
|
||||
mainViewer->has_scrollbar(Fl_Browser_::VERTICAL);
|
||||
|
@ -4477,9 +4532,6 @@ void create_fl_digi_main_primary() {
|
|||
|
||||
Fl_Group* gseek = new Fl_Group(mvgroup->x(), mvgroup->y() + Htext - 42, mvgroup->w(), 20);
|
||||
// search field
|
||||
// const char* label = _("Find: ");
|
||||
// fl_font(FL_HELVETICA, FL_NORMAL_SIZE);
|
||||
// int label_w = static_cast<int>(fl_width(label));
|
||||
int seek_x = mvgroup->x() + 2;
|
||||
int seek_y = mvgroup->y() + Htext - 42;
|
||||
int seek_w = mvgroup->w() - 4;
|
||||
|
@ -4567,8 +4619,8 @@ void create_fl_digi_main_primary() {
|
|||
TransmitText->align(FL_ALIGN_CLIP);
|
||||
|
||||
Fl_Box *minbox = new Fl_Box(
|
||||
text_panel->x(), text_panel->y() + 66,
|
||||
text_panel->w() - 100, text_panel->h() - 66 - 80);
|
||||
text_panel->x(), text_panel->y() + 66, // fixed by Raster min height
|
||||
text_panel->w() - 100, text_panel->h() - 66 - 60); // fixed by HMIN & Hwfall max
|
||||
minbox->hide();
|
||||
|
||||
text_panel->resizable(minbox);
|
||||
|
@ -4583,14 +4635,14 @@ void create_fl_digi_main_primary() {
|
|||
Fl_Group *btngroup1 = new Fl_Group(0, Y+1, progStatus.mainW - Hmacros, Hmacros-1);
|
||||
Wmacrobtn = (btngroup1->w()) / NUMMACKEYS;
|
||||
Hmacrobtn = btngroup1->h() - 1;
|
||||
wblank = (btngroup1->w() - NUMMACKEYS * Wmacrobtn) / 2;
|
||||
wBLANK = (btngroup1->w() - NUMMACKEYS * Wmacrobtn) / 2;
|
||||
xpos = 0;
|
||||
ypos = btngroup1->y();
|
||||
for (int i = 0; i < NUMMACKEYS; i++) {
|
||||
if (i == 4 || i == 8) {
|
||||
bx = new Fl_Box(xpos, ypos, wblank, Hmacrobtn);
|
||||
bx = new Fl_Box(xpos, ypos, wBLANK, Hmacrobtn);
|
||||
bx->box(FL_FLAT_BOX);
|
||||
xpos += wblank;
|
||||
xpos += wBLANK;
|
||||
}
|
||||
btnMacro[i] = new Fl_Button(xpos, ypos, Wmacrobtn, Hmacrobtn,
|
||||
macros.name[i].c_str());
|
||||
|
@ -4975,6 +5027,7 @@ Fl_Menu_Item alt_menu_[] = {
|
|||
{ mode_info[MODE_PSK250].name, 0, cb_init_mode, (void *)MODE_PSK250, 0, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{0,0,0,0,0,0,0,0,0},
|
||||
|
||||
{ mode_info[MODE_NULL].name, 0, cb_init_mode, (void *)MODE_NULL, 0, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
{ mode_info[MODE_SSB].name, 0, cb_init_mode, (void *)MODE_SSB, 0, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
|
||||
{ mode_info[MODE_WWV].name, 0, cb_init_mode, (void *)MODE_WWV, 0, FL_NORMAL_LABEL, 0, 14, 0},
|
||||
|
@ -5901,7 +5954,7 @@ void put_Bandwidth(int bandwidth)
|
|||
wf->Bandwidth ((int)bandwidth);
|
||||
}
|
||||
|
||||
static void set_metric(double metric)
|
||||
static void callback_set_metric(double metric)
|
||||
{
|
||||
pgrsSquelch->value(metric);
|
||||
if (!progStatus.sqlonoff)
|
||||
|
@ -5913,10 +5966,10 @@ static void set_metric(double metric)
|
|||
btnSQL->redraw_label();
|
||||
}
|
||||
|
||||
void display_metric(double metric)
|
||||
void global_display_metric(double metric)
|
||||
{
|
||||
FL_LOCK_D();
|
||||
REQ_DROP(set_metric, metric);
|
||||
REQ_DROP(callback_set_metric, metric);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -6305,10 +6358,6 @@ void put_rx_data(int *data, int len)
|
|||
FHdisp->data(data, len);
|
||||
}
|
||||
|
||||
extern bool macro_idle_on;
|
||||
extern string text2repeat;
|
||||
extern size_t repeatchar;
|
||||
|
||||
bool idling = false;
|
||||
|
||||
void get_tx_char_idle(void *)
|
||||
|
@ -6317,10 +6366,55 @@ void get_tx_char_idle(void *)
|
|||
progStatus.repeatIdleTime = 0;
|
||||
}
|
||||
|
||||
int Qwait_time = 0;
|
||||
int Qidle_time = 0;
|
||||
|
||||
static int que_timeout = 0;
|
||||
bool que_ok = true;
|
||||
|
||||
void post_queue_execute(void*)
|
||||
{
|
||||
if (!que_timeout) {
|
||||
LOG_ERROR("%s", "timed out");
|
||||
return;
|
||||
}
|
||||
while (!que_ok && trx_state != STATE_RX) {
|
||||
que_timeout--;
|
||||
Fl::repeat_timeout(0.05, post_queue_execute);
|
||||
}
|
||||
trx_transmit();
|
||||
}
|
||||
|
||||
void queue_execute_after_rx(void*)
|
||||
{
|
||||
if (!que_timeout) {
|
||||
LOG_ERROR("%s", "timed out");
|
||||
return;
|
||||
}
|
||||
while (trx_state == STATE_TX) {
|
||||
que_timeout--;
|
||||
Fl::repeat_timeout(0.05, queue_execute_after_rx);
|
||||
return;
|
||||
}
|
||||
que_ok = false;
|
||||
que_timeout = 100; // 5 seconds
|
||||
Fl::add_timeout(0.05, post_queue_execute);
|
||||
queue_execute();
|
||||
}
|
||||
|
||||
char szTestChar[] = "E|I|S|T|M|O|A|V";
|
||||
int get_tx_char(void)
|
||||
{
|
||||
if (macro_idle_on) return -1;
|
||||
int c;
|
||||
static int pending = -1;
|
||||
enum { STATE_CHAR, STATE_CTRL };
|
||||
static int state = STATE_CHAR;
|
||||
|
||||
if (!que_ok) { return -1; }
|
||||
if (Qwait_time) { return -1; }
|
||||
if (Qidle_time) { return -1; }
|
||||
if (macro_idle_on) { return -1; }
|
||||
if (idling) { return -1; }
|
||||
|
||||
if (arq_text_available)
|
||||
return arq_get_char();
|
||||
|
@ -6328,24 +6422,19 @@ int get_tx_char(void)
|
|||
if (active_modem == cw_modem && progdefaults.QSKadjust)
|
||||
return szTestChar[2 * progdefaults.TestChar];
|
||||
|
||||
int c;
|
||||
static int pending = -1;
|
||||
if ( progStatus.repeatMacro && progStatus.repeatIdleTime > 0 &&
|
||||
!idling ) {
|
||||
Fl::add_timeout(progStatus.repeatIdleTime, get_tx_char_idle);
|
||||
idling = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pending >= 0) {
|
||||
c = pending;
|
||||
pending = -1;
|
||||
return c;
|
||||
}
|
||||
|
||||
enum { STATE_CHAR, STATE_CTRL };
|
||||
static int state = STATE_CHAR;
|
||||
|
||||
if ( progStatus.repeatMacro && progStatus.repeatIdleTime > 0 &&
|
||||
!idling ) {
|
||||
Fl::add_timeout(progStatus.repeatIdleTime, get_tx_char_idle);
|
||||
idling = true;
|
||||
}
|
||||
if (idling) return -1;
|
||||
|
||||
if (progStatus.repeatMacro > -1 && text2repeat.length()) {
|
||||
c = text2repeat[repeatchar];
|
||||
repeatchar++;
|
||||
|
@ -6357,12 +6446,15 @@ int get_tx_char(void)
|
|||
}
|
||||
|
||||
c = TransmitText->nextChar();
|
||||
|
||||
if (c == '^' && state == STATE_CHAR) {
|
||||
state = STATE_CTRL;
|
||||
c = TransmitText->nextChar();
|
||||
}
|
||||
switch (c) {
|
||||
case -1: break; // no character available
|
||||
case -1: // no character available
|
||||
queue_reset();
|
||||
break;
|
||||
case '\n':
|
||||
pending = '\n';
|
||||
return '\r';
|
||||
|
@ -6372,6 +6464,8 @@ int get_tx_char(void)
|
|||
REQ_SYNC(&FTextTX::clear_sent, TransmitText);
|
||||
state = STATE_CHAR;
|
||||
c = 3; // ETX
|
||||
// if (progStatus.timer)
|
||||
// REQ(startMacroTimer);
|
||||
break;
|
||||
case 'R':
|
||||
if (state != STATE_CTRL)
|
||||
|
@ -6380,6 +6474,8 @@ int get_tx_char(void)
|
|||
if (TransmitText->eot()) {
|
||||
REQ_SYNC(&FTextTX::clear_sent, TransmitText);
|
||||
c = 3; // ETX
|
||||
// if (progStatus.timer)
|
||||
// REQ(startMacroTimer);
|
||||
} else
|
||||
c = -1;
|
||||
break;
|
||||
|
@ -6397,6 +6493,19 @@ int get_tx_char(void)
|
|||
c = -1;
|
||||
REQ(clearQSO);
|
||||
break;
|
||||
case '!':
|
||||
if (state != STATE_CTRL)
|
||||
break;
|
||||
state = STATE_CHAR;
|
||||
if (queue_must_rx()) {
|
||||
c = 3;
|
||||
que_timeout = 400; // 20 seconds
|
||||
Fl::add_timeout(0.0, queue_execute_after_rx);
|
||||
} else {
|
||||
c = -1;
|
||||
queue_execute();
|
||||
}
|
||||
break;
|
||||
case '^':
|
||||
state = STATE_CHAR;
|
||||
break;
|
||||
|
@ -6580,7 +6689,6 @@ void start_tx()
|
|||
if (!(active_modem->get_cap() & modem::CAP_TX))
|
||||
return;
|
||||
trx_transmit();
|
||||
REQ(&waterfall::set_XmtRcvBtn, wf, true);
|
||||
}
|
||||
|
||||
void abort_tx()
|
||||
|
@ -6591,6 +6699,7 @@ void abort_tx()
|
|||
return;
|
||||
}
|
||||
if (trx_state == STATE_TX) {
|
||||
queue_reset();
|
||||
trx_start_modem(active_modem);
|
||||
}
|
||||
}
|
||||
|
@ -6832,6 +6941,12 @@ void set_rtty_bits(int bits)
|
|||
}
|
||||
}
|
||||
|
||||
void set_rtty_bw(float bw)
|
||||
{
|
||||
sldrRTTYbandwidth->value(bw);
|
||||
sldrRTTYbandwidth->do_callback();
|
||||
}
|
||||
|
||||
void set_menu_dl_online(bool val)
|
||||
{
|
||||
Fl_Menu_Item *m;
|
||||
|
|
|
@ -0,0 +1,274 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// DTMF.cxx
|
||||
//
|
||||
// Copyright (C) 2011
|
||||
// Dave Freese, W1HKJ
|
||||
//
|
||||
// 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 fldigi. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <float.h>
|
||||
#include <samplerate.h>
|
||||
|
||||
#include "trx.h"
|
||||
|
||||
#include "dtmf.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "fl_digi.h"
|
||||
#include "configuration.h"
|
||||
#include "qrunner.h"
|
||||
#include "debug.h"
|
||||
#include "status.h"
|
||||
|
||||
#include "main.h"
|
||||
|
||||
LOG_FILE_SOURCE(debug::LOG_MODEM);
|
||||
|
||||
// tones in 4x4 array
|
||||
// 697 770 842 941 1209 1336 1447 1633
|
||||
|
||||
int cDTMF::row[] = {697, 770, 852, 941};
|
||||
|
||||
int cDTMF::col[] = {1209, 1336, 1477, 1633};
|
||||
|
||||
const char cDTMF::rc[] = "123A456B789C*0#D";
|
||||
|
||||
//======================================================================
|
||||
// DTMF tone receive
|
||||
//======================================================================
|
||||
// tone #s and coefficients
|
||||
// 8000 Hz sampling N == 240
|
||||
// 11025 Hz sampling N == 331
|
||||
|
||||
/*
|
||||
* calculate the power of each tone using Goertzel filters
|
||||
*/
|
||||
void cDTMF::calc_power()
|
||||
{
|
||||
double sr = active_modem->get_samplerate();
|
||||
// reset row freq filters
|
||||
for (int i = 0; i < 4; i++) filt[i]->reset(240, row[i], sr);
|
||||
// reset col freq filters
|
||||
for (int i = 0; i < 4; i++) filt[i+4]->reset(240, col[i], sr);
|
||||
|
||||
for (int i = 0; i < framesize; i++)
|
||||
for (int j = 0; j < NUMTONES; j++)
|
||||
filt[j]->run(data[i]);
|
||||
|
||||
for (int i = 0; i < NUMTONES; i++)
|
||||
power[i] = filt[i]->mag();
|
||||
|
||||
maxpower = 0;
|
||||
minpower = 1e6;
|
||||
for (int i = 0; i < NUMTONES;i++) {
|
||||
if (power[i] > maxpower)
|
||||
maxpower = power[i];
|
||||
if (power[i] < minpower)
|
||||
minpower = power[i];
|
||||
}
|
||||
if ( minpower == 0 ) minpower = 1e-3;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* detect which signals are present.
|
||||
*
|
||||
*/
|
||||
|
||||
int cDTMF::decode()
|
||||
{
|
||||
calc_power();
|
||||
|
||||
if (maxpower < (10 * progStatus.sldrSquelchValue))
|
||||
return ' ';
|
||||
|
||||
int r = -1, c = -1;
|
||||
double pwr = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (power[i] > pwr) {
|
||||
pwr = power[i];
|
||||
r = i;
|
||||
}
|
||||
pwr = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (power[i+4] > pwr) {
|
||||
pwr = power[i+4];
|
||||
c = i;
|
||||
}
|
||||
if (r == -1 || c == -1)
|
||||
return ' ';
|
||||
return rc[r*4 + c];
|
||||
}
|
||||
|
||||
/*
|
||||
* read in frames, output the decoded
|
||||
* results
|
||||
*/
|
||||
void cDTMF::receive(const float* buf, size_t len)
|
||||
{
|
||||
int x;
|
||||
static size_t dptr = 0;
|
||||
size_t bufptr = 0;
|
||||
|
||||
if (!progdefaults.DTMFdecode) return;
|
||||
|
||||
framesize = (active_modem->get_samplerate() == 8000) ? 240 : 331;
|
||||
|
||||
while (1) {
|
||||
int i;
|
||||
for ( i = dptr; i < framesize; i++) {
|
||||
data[i] = buf[bufptr];
|
||||
bufptr++;
|
||||
if (bufptr == len) break;
|
||||
}
|
||||
if (i < framesize) {
|
||||
dptr = i + 1;
|
||||
return;
|
||||
}
|
||||
dptr = 0;
|
||||
|
||||
x = decode();
|
||||
if (x == ' ') {
|
||||
silence_time++;
|
||||
if (silence_time == 4 && !dtmfchars.empty()) dtmfchars += ' ';
|
||||
if (silence_time == FLUSH_TIME) {
|
||||
if (!dtmfchars.empty()) {
|
||||
REQ(showDTMF, dtmfchars);
|
||||
dtmfchars.clear();
|
||||
}
|
||||
silence_time = 0;
|
||||
}
|
||||
} else {
|
||||
silence_time = 0;
|
||||
if (x != last && last == ' ')
|
||||
dtmfchars += x;
|
||||
}
|
||||
last = x;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// DTMF tone transmit
|
||||
//======================================================================
|
||||
|
||||
void cDTMF::makeshape()
|
||||
{
|
||||
for (int i = 0; i < 128; i++) shape[i] = 1.0;
|
||||
for (int i = 0; i < RT; i++)
|
||||
shape[i] = 0.5 * (1.0 - cos (M_PI * i / RT));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// transmit silence for specified time duration in milliseconds
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void cDTMF::silence(int len)
|
||||
{
|
||||
double sr = active_modem->get_samplerate();
|
||||
int length = len * sr / 1000;
|
||||
if (length > 16384) length = 16384;
|
||||
memset(outbuf, 0, length * sizeof(*outbuf));
|
||||
active_modem->ModulateXmtr(outbuf, length);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// transmit DTMF tones for specific time interval
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void cDTMF::two_tones(int ch)
|
||||
{
|
||||
if (!strchr(rc, ch)) return;
|
||||
int pos = strchr(rc, ch) - rc;
|
||||
int r = pos / 4;
|
||||
int c = pos % 4;
|
||||
double sr = active_modem->get_samplerate();
|
||||
double phaseincr = 2.0 * M_PI * row[r] / sr;
|
||||
double phase = 0;
|
||||
int length = duration * sr / 1000;
|
||||
if (length > 16384) length = 16384;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
outbuf[i] = 0.5 * sin(phase);
|
||||
phase += phaseincr;
|
||||
}
|
||||
|
||||
phaseincr = 2.0 * M_PI * col[c] / sr;
|
||||
phase = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
outbuf[i] += 0.5 * sin(phase);
|
||||
phase += phaseincr;
|
||||
}
|
||||
for (int i = 0; i < RT; i++) {
|
||||
outbuf[i] *= shape[i];
|
||||
outbuf[length - 1 - i] *= shape[i];
|
||||
}
|
||||
|
||||
active_modem->ModulateXmtr(outbuf, length);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// transmit the string contained in progdefaults.DTMFstr and output as
|
||||
// dtmf valid characters, 0-9, *, #, A-D
|
||||
// each pair of tones is separated by 50ms silence
|
||||
// 500 msec silence for ' ', ',' or '-'
|
||||
// 50 msec silence for invalid characters
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void cDTMF::send()
|
||||
{
|
||||
int c = 0, delay = 0;
|
||||
duration = 50;
|
||||
RT = (int)(active_modem->get_samplerate() * 4 / 1000.0); // 4 msec edge
|
||||
makeshape();
|
||||
size_t colon = std::string::npos;
|
||||
|
||||
size_t modifier = progdefaults.DTMFstr.find("W");
|
||||
if (modifier != std::string::npos) {
|
||||
delay = atoi(&progdefaults.DTMFstr[modifier + 1]);
|
||||
colon = progdefaults.DTMFstr.find(':', modifier);
|
||||
progdefaults.DTMFstr.erase(modifier, colon - modifier + 1);
|
||||
}
|
||||
|
||||
modifier = progdefaults.DTMFstr.find('L');
|
||||
if (modifier != std::string::npos) {
|
||||
duration = atoi(&progdefaults.DTMFstr[modifier + 1]);
|
||||
colon = progdefaults.DTMFstr.find(':', modifier);
|
||||
progdefaults.DTMFstr.erase(modifier, colon - modifier + 1);
|
||||
}
|
||||
|
||||
while (delay > 50) { silence(50); delay -= 50;}
|
||||
if (delay) silence(delay);
|
||||
|
||||
for(size_t i = 0; i < progdefaults.DTMFstr.length(); i++) {
|
||||
c = progdefaults.DTMFstr[i];
|
||||
if (c == ' ' || c == ',' || c == '-')
|
||||
silence(duration);
|
||||
else if ( (c >= '0' && c <= '9') ||
|
||||
c == '*' ||
|
||||
c == '#' ||
|
||||
(c >= 'A' && c <= 'D') )
|
||||
two_tones(c);
|
||||
silence(duration);
|
||||
}
|
||||
progdefaults.DTMFstr.clear();
|
||||
}
|
||||
|
|
@ -43,6 +43,8 @@ using namespace std;
|
|||
// ... doing so will break the Fl_menu_item table 'menu_'. -Kamal
|
||||
|
||||
const struct mode_info_t mode_info[NUM_MODES] = {
|
||||
{ MODE_NULL, &null_modem, "NULL", "NULL", "", "NULL", "" },
|
||||
|
||||
{ MODE_CW, &cw_modem, "CW", "CW", "CW", "CW", "CW" },
|
||||
|
||||
{ MODE_CONTESTIA, &contestia_modem, "CTSTIA", "Contestia", "", "CONTESTI", "CT" },
|
||||
|
|
|
@ -127,6 +127,9 @@ extern Fl_Check_Button *btnUseCursorCenterLine;
|
|||
extern Fl_Button *btnCursorCenterLineColor;
|
||||
extern Fl_Check_Button *btnUseBWTracks;
|
||||
extern Fl_Button *btnBwTracksColor;
|
||||
extern Fl_Check_Button *btnUseWideTracks;
|
||||
extern Fl_Check_Button *btnUseWideCenter;
|
||||
extern Fl_Check_Button *btnUseWideCursor;
|
||||
extern Fl_Check_Button *chkShowAudioScale;
|
||||
extern Fl_Button *btnWaterfallFont;
|
||||
extern Fl_Check_Button *btnViewXmtSignal;
|
||||
|
@ -400,7 +403,13 @@ extern void close_talker();
|
|||
extern Fl_Light_Button *btnConnectTalker;
|
||||
extern Fl_Check_Button *btn_auto_talk;
|
||||
extern Fl_Check_Button *chkRxStream;
|
||||
extern Fl_Group *tabDTMF;
|
||||
extern Fl_Check_Button *chkDTMFdecode;
|
||||
extern Fl_Group *tabQRZ;
|
||||
extern Fl_Round_Button *btnQRZnotavailable;
|
||||
extern Fl_Round_Button *btnQRZonline;
|
||||
extern Fl_Round_Button *btnHAMCALLonline;
|
||||
extern Fl_Round_Button *btnCALLOOK;
|
||||
extern Fl_Round_Button *btnQRZcdrom;
|
||||
extern Fl_Input2 *txtQRZpathname;
|
||||
extern Fl_Round_Button *btnQRZsub;
|
||||
|
@ -408,10 +417,16 @@ extern Fl_Round_Button *btnHamcall;
|
|||
extern Fl_Input2 *inpQRZusername;
|
||||
extern Fl_Input2 *inpQRZuserpassword;
|
||||
extern Fl_Button *btnQRZpasswordShow;
|
||||
extern Fl_Round_Button *btnQRZnotavailable;
|
||||
extern Fl_Round_Button *btnQRZonline;
|
||||
extern Fl_Round_Button *btnHAMCALLonline;
|
||||
extern Fl_Round_Button *btnCALLOOK;
|
||||
extern Fl_Round_Button *btnHamQTH;
|
||||
extern Fl_Input2 *inpEQSL_id;
|
||||
extern Fl_Input2 *inpEQSL_pwd;
|
||||
extern Fl_Button *btnEQSL_pwd_show;
|
||||
extern Fl_Input2 *inpEQSL_nick;
|
||||
extern Fl_Check_Button *btn_send_when_logged;
|
||||
extern Fl_Input2 *txt_eqsl_default_message;
|
||||
extern Fl_Box *eqsl_txt1;
|
||||
extern Fl_Box *eqsl_txt2;
|
||||
extern Fl_Box *eqsl_txt3;
|
||||
extern Fl_Group *tabDL;
|
||||
extern Fl_Tabs *tabsDL;
|
||||
extern Fl_Group *tabDLEnable;
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
+20.0) \
|
||||
ELEM_(bool, rsidWideSearch, "RSIDWIDESEARCH", \
|
||||
"RSID detector searches the entire passband", \
|
||||
true) \
|
||||
false) \
|
||||
ELEM_(int, rsid_squelch, "RSIDSQUELCH", \
|
||||
"RSID detection opens squelch for nn seconds", \
|
||||
5) \
|
||||
|
@ -88,8 +88,8 @@
|
|||
"Trigger RSID notifications but do not change modem and frequency", \
|
||||
false) \
|
||||
ELEM_(bool, rsid_auto_disable, "RSIDAUTODISABLE", \
|
||||
"Disable RSID detection when changing modem and/or frequency", \
|
||||
true) \
|
||||
"Disable RSID detection when RsID signal is detected", \
|
||||
false) \
|
||||
ELEM_(bool, rsid_post, "RSIDPOST", \
|
||||
"Transmit an RSID signal when modem data is concluded", \
|
||||
false) \
|
||||
|
@ -239,9 +239,12 @@
|
|||
ELEM_(int, rtty_custom_shift, "RTTYCUSTOMSHIFT", \
|
||||
"Custom shift (Hz)", \
|
||||
450) \
|
||||
ELEM_(double, RTTY_BW, "RTTYBW", \
|
||||
"Receive filter bandwidth (Hz)", \
|
||||
68.0) \
|
||||
ELEM_(int, rtty_baud, "RTTYBAUD", \
|
||||
"Carrier baud rate. Values are as follows:\n" \
|
||||
" 0: 45; 1: 45.45; 2: 50; 3: 56; 4: 75; 5: 100; 6: 110; 7: 150; \n" \
|
||||
" 1: 45; 1: 45.45; 2: 50; 3: 56; 4: 75; 5: 100; 6: 110; 7: 150; \n" \
|
||||
" 8: 200; 9: 300", \
|
||||
0) /* 45 */ \
|
||||
ELEM_(int, rtty_bits, "RTTYBITS", \
|
||||
|
@ -293,13 +296,10 @@
|
|||
true) \
|
||||
ELEM_(bool, useMARKfreq, "USEMARKFREQ", \
|
||||
"Use MARK frequency for logging", \
|
||||
true) \
|
||||
true) \
|
||||
ELEM_(bool, Xagc, "XAGC", \
|
||||
"This setting is currently unused", \
|
||||
false) \
|
||||
ELEM_(double, RTTY_BW, "RTTYBW", \
|
||||
"Receive filter bandwidth (Hz)", \
|
||||
400.0) \
|
||||
/* CW */ \
|
||||
ELEM_(bool, useCWkeylineRTS, "", "", false) \
|
||||
ELEM_(bool, useCWkeylineDTR, "", "", false) \
|
||||
|
@ -523,6 +523,15 @@
|
|||
ELEM_(bool, UseBWTracks, "USEBWTRACKS", \
|
||||
"Draw bandwidth marker with vertical lines", \
|
||||
true) \
|
||||
ELEM_(bool, UseWideTracks, "USEWIDETRACKS", \
|
||||
"Draw bandwidth marker with 3x vertical lines", \
|
||||
false) \
|
||||
ELEM_(bool, UseWideCursor, "USEWIDECURSOR", \
|
||||
"Draw cursor with 3x vertical lines", \
|
||||
false) \
|
||||
ELEM_(bool, UseWideCenter, "USEWIDECENTER", \
|
||||
"Draw center line marker with 3x vertical lines", \
|
||||
false) \
|
||||
ELEM_(RGBI, cursorLineRGBI, "CLCOLORS", \
|
||||
"Color of cursor lines (RGBI)", \
|
||||
{255, 255, 0, 255}) \
|
||||
|
@ -557,6 +566,10 @@
|
|||
"Single tone at center of modem BW, carrier detect for amplifiers", \
|
||||
0.0) \
|
||||
ELEM_(bool, macroCWid, "", "", false) \
|
||||
ELEM_(std::string, DTMFstr, "", "", "") \
|
||||
ELEM_(bool, DTMFdecode, "DTMFDECODE", \
|
||||
"Decode received DTMF tones", \
|
||||
false) \
|
||||
ELEM_(int, videowidth, "VIDEOWIDTH", \
|
||||
"Video ID text width (characters per row)", \
|
||||
1) \
|
||||
|
@ -652,6 +665,22 @@
|
|||
"QRZ or HamCall subscriber password", \
|
||||
"") \
|
||||
ELEM_(bool, QRZchanged, "", "", false) \
|
||||
/* eQSL */ \
|
||||
ELEM_(std::string, eqsl_id, "EQSL_ID", \
|
||||
"eQSL login id", \
|
||||
"") \
|
||||
ELEM_(std::string, eqsl_pwd, "EQSL_PASSWORD", \
|
||||
"eQSL login password", \
|
||||
"") \
|
||||
ELEM_(std::string, eqsl_nick, "EQSL_NICKNAME", \
|
||||
"eQSL nickname", \
|
||||
"") \
|
||||
ELEM_(std::string, eqsl_default_message, "EQSL_DEF_MSG", \
|
||||
"eQSl default message", \
|
||||
"") \
|
||||
ELEM_(bool, eqsl_when_logged, "EQSL_WHEN_LOGGED", \
|
||||
"Send eQSL when other log action invoked", \
|
||||
false) \
|
||||
/* Rig control */ \
|
||||
ELEM_(bool, btnusb, "BTNUSB", \
|
||||
"This setting is currently unused", \
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
#include <string>
|
||||
|
||||
#include "filters.h"
|
||||
|
||||
class cDTMF {
|
||||
public:
|
||||
#define N 240 // 30 msec interval at 8000 sps
|
||||
|
||||
#define RANGE 0.5 /* any thing higher than RANGE*peak is "on" */
|
||||
#define THRESH 1000 /* 6 dB s/n for detection */
|
||||
#define FLUSH_TIME 10 /* 10 frames ~ 330 millisecond */
|
||||
|
||||
#define NUMTONES 8
|
||||
|
||||
private:
|
||||
double power[NUMTONES];
|
||||
double thresh;
|
||||
double maxpower;
|
||||
double minpower;
|
||||
double data[350];
|
||||
|
||||
goertzel *filt[NUMTONES];
|
||||
|
||||
int framesize;
|
||||
|
||||
static double coef[];
|
||||
static int k[];
|
||||
static const char *dtran[];
|
||||
|
||||
static int row[];
|
||||
static int col[];
|
||||
static const char rc[];
|
||||
|
||||
double outbuf[16384];
|
||||
double shape[128];
|
||||
int RT;
|
||||
int duration;
|
||||
int silence_time;
|
||||
int last;
|
||||
std::string dtmfchars;
|
||||
|
||||
public:
|
||||
cDTMF() {
|
||||
for (int i = 0; i < 4; i++) filt[i] = new goertzel(240, row[i], 8000);
|
||||
for (int i = 0; i < 4; i++) filt[i+4] = new goertzel(240, col[i], 8000);
|
||||
for (int i = 0; i < N; i++) data[i] = 0;
|
||||
dtmfchars.clear();
|
||||
framesize = 240; // 8000 sr default
|
||||
silence_time = 0;
|
||||
last = ' ';
|
||||
}
|
||||
~cDTMF() {};
|
||||
// receive
|
||||
void calc_power();
|
||||
int decode();
|
||||
void receive(const float* buf, size_t len);
|
||||
// transmit
|
||||
void makeshape();
|
||||
void silence(int);
|
||||
void two_tones(int);
|
||||
void send();
|
||||
};
|
|
@ -172,6 +172,9 @@ extern Digiscope *digiscope;
|
|||
|
||||
extern std::string main_window_title;
|
||||
|
||||
extern int Qwait_time;
|
||||
extern int Qidle_time;
|
||||
|
||||
extern void toggleRSID();
|
||||
|
||||
extern void set_menus();
|
||||
|
@ -190,7 +193,7 @@ extern void cb_mnuVisitURL(Fl_Widget*, void* arg);
|
|||
|
||||
extern void put_freq(double frequency);
|
||||
extern void put_Bandwidth(int bandwidth);
|
||||
extern void display_metric(double metric);
|
||||
extern void global_display_metric(double metric);
|
||||
extern void put_cwRcvWPM(double wpm);
|
||||
|
||||
extern void set_scope_mode(Digiscope::scope_mode md);
|
||||
|
@ -224,6 +227,7 @@ extern void show_bw(const std::string& sWidth);
|
|||
extern void show_spot(bool v);
|
||||
extern void showMacroSet();
|
||||
extern void setwfrange();
|
||||
extern void showDTMF(const std::string s);
|
||||
|
||||
extern void xmtrcv_selection_color();
|
||||
extern void rev_selection_color();
|
||||
|
@ -239,6 +243,10 @@ extern void put_WARNstatus(double);
|
|||
|
||||
extern void qsoSave_cb(Fl_Widget *b, void *);
|
||||
|
||||
extern bool que_ok;
|
||||
extern void post_queue_execute(void*);
|
||||
extern void queue_execute_after_rx(void*);
|
||||
|
||||
extern void put_rx_data(int *data, int len);
|
||||
extern int get_tx_char();
|
||||
extern int get_secondary_char();
|
||||
|
@ -284,6 +292,10 @@ extern void set_contestia_default_integ();
|
|||
|
||||
extern void startMacroTimer();
|
||||
extern void stopMacroTimer();
|
||||
extern void macro_timer(void *);
|
||||
extern void macro_timed_execute(void *);
|
||||
extern void startTimedExecute(std::string &);
|
||||
|
||||
extern void cb_ResetSerNbr();
|
||||
extern void updateOutSerNo();
|
||||
|
||||
|
@ -314,6 +326,7 @@ void set_contestia_tones(int tones);
|
|||
void set_rtty_shift(int shift);
|
||||
void set_rtty_baud(float baud);
|
||||
void set_rtty_bits(int bits);
|
||||
void set_rtty_bw(float bw);
|
||||
|
||||
void sync_cw_parameters();
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ enum {
|
|||
MODE_PREV = -2,
|
||||
MODE_NEXT,
|
||||
|
||||
MODE_NULL,
|
||||
|
||||
MODE_CW,
|
||||
|
||||
MODE_CONTESTIA,
|
||||
|
|
|
@ -83,6 +83,8 @@ extern void cb_btnUpdateCancel(Fl_Button*, void*);
|
|||
extern Fl_Button *bUpdateCancel;
|
||||
extern void cb_btnDelete(Fl_Button*, void*);
|
||||
extern Fl_Button *bDelete;
|
||||
extern void cb_btnDialFreq(Fl_Button*, void*);
|
||||
extern Fl_Button *bDialFreq;
|
||||
extern Fl_Input2 *txtNbrRecs_log;
|
||||
extern Fl_Input2 *inpSerNoOut_log;
|
||||
extern Fl_Input2 *inpMyXchg_log;
|
||||
|
|
|
@ -52,6 +52,7 @@ extern void clearRecord ();
|
|||
extern void updateRecord ();
|
||||
extern void deleteRecord ();
|
||||
extern void AddRecord ();
|
||||
extern void DisplayRecord (int idxRec);
|
||||
extern void SearchLastQSO (const char *);
|
||||
extern cQsoRec* SearchLog(const char *callsign);
|
||||
extern void DupCheck();
|
||||
|
|
|
@ -16,6 +16,9 @@ extern std::string lookup_country;
|
|||
extern void clear_Lookup();
|
||||
|
||||
extern void CALLSIGNquery();
|
||||
enum qrz_query_t { QRZ_EXIT = -1, QRZNONE, QRZNET, QRZCD, HAMCALLNET, QRZHTML, HAMCALLHTML, CALLOOK };
|
||||
enum qrz_query_t { QRZ_EXIT = -1, QRZNONE, QRZNET, QRZCD, HAMCALLNET, QRZHTML, HAMCALLHTML, CALLOOK, HAMQTH };
|
||||
|
||||
extern void sendEQSL(const char *url);
|
||||
extern void makeEQSL(const char *msg);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Hold_Browser.H>
|
||||
#include <FL/Fl_Pixmap.H>
|
||||
#include <FL/Fl_Group.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
|
||||
#include "flinput2.h"
|
||||
|
||||
extern void loadBrowser(Fl_Widget *widget);
|
||||
|
|
|
@ -36,13 +36,14 @@ struct MACROTEXT {
|
|||
void openMacroFile();
|
||||
void saveMacroFile();
|
||||
void saveMacros(const std::string& fname);
|
||||
std::string expandMacro(int n);
|
||||
std::string expandMacro(std::string &s);
|
||||
void execute(int n);
|
||||
void repeat(int n);
|
||||
void timed_execute();
|
||||
MACROTEXT();
|
||||
private:
|
||||
std::string expanded;
|
||||
void loadnewMACROS(std::string& s, size_t &i);
|
||||
void loadnewMACROS(std::string& s, size_t &i, size_t endbracket);
|
||||
};
|
||||
|
||||
extern MACROTEXT macros;
|
||||
|
@ -52,7 +53,20 @@ extern std::string info1msg;
|
|||
extern std::string info2msg;
|
||||
extern std::string qso_time;
|
||||
extern std::string qso_exchange;
|
||||
extern std::string exec_date;
|
||||
extern std::string exec_time;
|
||||
extern std::string exec_string;
|
||||
extern std::string text2repeat;
|
||||
|
||||
extern bool macro_idle_on;
|
||||
extern size_t repeatchar;
|
||||
|
||||
|
||||
void set_macro_env(void);
|
||||
|
||||
void queue_reset();
|
||||
void queue_execute();
|
||||
bool queue_must_rx();
|
||||
void idleTimer(void *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,6 +38,15 @@ extern std::string ICS_dir;
|
|||
extern std::string ICS_msg_dir;
|
||||
extern std::string ICS_tmp_dir;
|
||||
|
||||
extern std::string FLMSG_dir;
|
||||
extern std::string FLMSG_WRAP_dir;
|
||||
extern std::string FLMSG_WRAP_recv_dir;
|
||||
extern std::string FLMSG_WRAP_send_dir;
|
||||
extern std::string FLMSG_WRAP_auto_dir;
|
||||
extern std::string FLMSG_ICS_dir;
|
||||
extern std::string FLMSG_ICS_msg_dir;
|
||||
extern std::string FLMSG_ICS_tmp_dir;
|
||||
|
||||
extern std::string xmlfname;
|
||||
|
||||
extern std::string scDevice[2];
|
||||
|
|
|
@ -87,17 +87,11 @@ public:
|
|||
virtual void searchDown() {};
|
||||
virtual void searchUp() {};
|
||||
|
||||
// void update_syncscope();
|
||||
|
||||
void HistoryON(bool val) {historyON = val;}
|
||||
bool HistoryON() { return historyON;}
|
||||
|
||||
// void set_mode(trx_mode);
|
||||
trx_mode get_mode();
|
||||
const char *get_mode_name() { return mode_info[get_mode()].sname;}
|
||||
// void set_state(state_t);
|
||||
// void set_state_wait(state_t);
|
||||
// state_t get_state();
|
||||
virtual void set_freq(double);
|
||||
int get_freq();
|
||||
void init_freqlock();
|
||||
|
@ -107,6 +101,7 @@ public:
|
|||
double get_txfreq();
|
||||
double get_txfreq_woffset();
|
||||
void set_metric(double);
|
||||
void display_metric(double);
|
||||
double get_metric();
|
||||
void set_reverse(bool on);
|
||||
bool get_reverse() { return reverse; }
|
||||
|
@ -157,8 +152,6 @@ private:
|
|||
|
||||
void wfid_make_tones(int numchars);
|
||||
void wfid_send(int numchars);
|
||||
// double peakval(int symbol, int mask);
|
||||
// int findmask(int symbol);
|
||||
|
||||
void wfid_sendchars(std::string s);
|
||||
|
||||
|
@ -192,6 +185,8 @@ protected:
|
|||
virtual void s2nreport(void);
|
||||
};
|
||||
|
||||
extern modem *null_modem;
|
||||
|
||||
extern modem *cw_modem;
|
||||
|
||||
extern modem *mfsk8_modem;
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// NULLMODEM.h -- BASIS FOR ALL MODEMS
|
||||
//
|
||||
// Copyright (C) 2006
|
||||
// Dave Freese, W1HKJ
|
||||
//
|
||||
// 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 fldigi. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _NULLMODEM_H
|
||||
#define _NULLMODEM_H
|
||||
|
||||
#include "trx.h"
|
||||
#include "modem.h"
|
||||
#include "fft.h"
|
||||
#include "filters.h"
|
||||
#include "complex.h"
|
||||
|
||||
#define NULLMODEMSampleRate 8000
|
||||
|
||||
class NULLMODEM : public modem {
|
||||
protected:
|
||||
public:
|
||||
NULLMODEM();
|
||||
~NULLMODEM();
|
||||
void init();
|
||||
void rx_init();
|
||||
void restart();
|
||||
void tx_init(SoundBase *sc);
|
||||
int rx_process(const double *buf, int len);
|
||||
int tx_process();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -30,7 +30,7 @@ public:
|
|||
void putField (int, const char *);
|
||||
void putField (int, const char *, int);
|
||||
void addtoField (int, const char *);
|
||||
const char *getField (int);
|
||||
const char *getField (int) const;
|
||||
void trimFields();
|
||||
void clearRec ();
|
||||
int validRec();
|
||||
|
|
|
@ -49,7 +49,7 @@ int pthread_cond_timedwait_rel(pthread_cond_t* cond, pthread_mutex_t* mutex, dou
|
|||
//};
|
||||
enum {
|
||||
INVALID_TID = -1,
|
||||
TRX_TID, QRZ_TID, RIGCTL_TID, NORIGCTL_TID,
|
||||
TRX_TID, QRZ_TID, RIGCTL_TID, NORIGCTL_TID, EQSL_TID,
|
||||
#if USE_XMLRPC
|
||||
XMLRPC_TID,
|
||||
#endif
|
||||
|
@ -125,4 +125,28 @@ bool thread_in_list(int id, const int* list);
|
|||
|
||||
#include "fl_lock.h"
|
||||
|
||||
/// This ensures that a mutex is always unlocked when leaving a function or block.
|
||||
class guard_lock
|
||||
{
|
||||
public:
|
||||
guard_lock(pthread_mutex_t* m);
|
||||
~guard_lock(void);
|
||||
private:
|
||||
pthread_mutex_t* mutex;
|
||||
};
|
||||
|
||||
/// This wraps together a mutex and a condition variable which are used
|
||||
/// together very often for queues etc...
|
||||
class syncobj
|
||||
{
|
||||
pthread_mutex_t m_mutex ;
|
||||
pthread_cond_t m_cond ;
|
||||
public:
|
||||
syncobj();
|
||||
~syncobj();
|
||||
pthread_mutex_t * mtxp(void) { return & m_mutex; }
|
||||
void signal();
|
||||
bool wait( double seconds );
|
||||
};
|
||||
|
||||
#endif // !THREADS_H_
|
||||
|
|
|
@ -43,11 +43,8 @@ extern void trx_tune();
|
|||
extern void trx_receive();
|
||||
|
||||
extern void trx_reset(void);
|
||||
extern void trx_start_macro_timer();
|
||||
|
||||
extern void trx_wait_state(void);
|
||||
|
||||
extern void macro_timer(void *);
|
||||
extern void trx_wait_state(void);
|
||||
|
||||
extern state_t trx_state;
|
||||
extern modem *active_modem;
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
static void setpicture_link(wefax *me);
|
||||
static void save_image(const std::string & fil_name, const std::string & extra_comments);
|
||||
static void power( double start, double phase, double image, double black, double stop );
|
||||
static void send_image( const std::string & fil_name );
|
||||
static void restore_max_lines(void);
|
||||
};
|
||||
|
||||
#endif // _WEFAX_PIC_H
|
||||
|
|
|
@ -28,6 +28,11 @@ class wefax : public modem {
|
|||
|
||||
/// For updating the logbook when loading/saving an image file.
|
||||
cQsoRec m_qso_rec ;
|
||||
|
||||
/// Non-copiable object.
|
||||
wefax ();
|
||||
wefax ( const wefax & );
|
||||
wefax & operator=( const wefax & );
|
||||
public:
|
||||
wefax (trx_mode md);
|
||||
virtual ~wefax ();
|
||||
|
@ -103,6 +108,27 @@ public:
|
|||
{
|
||||
m_adif_log = the_flag ;
|
||||
}
|
||||
|
||||
/// Helper string indicating the internal state of the wefax engine.
|
||||
std::string state_string(void) const;
|
||||
|
||||
/// Maximum wait time when getting information about received and sent files.
|
||||
static const int max_delay = 3600 * 24 * 365 ;
|
||||
|
||||
/// Called by the engine when a file is received.
|
||||
void put_received_file(const std::string & filnam);
|
||||
|
||||
/// Used by XML-RPC to get the list of received files.
|
||||
std::string get_received_file(double max_seconds=max_delay);
|
||||
|
||||
/// Called by XML-RPC to send a file which resides on the machine where fldigi runs.
|
||||
std::string send_file( const std::string & filnam, double max_seconds=max_delay);
|
||||
|
||||
/// Called before sending a file. Transmitting is an exclusive process.
|
||||
bool transmit_lock_acquire( const std::string & filnam, double max_seconds=max_delay);
|
||||
|
||||
/// Called after sending a file so another sending can take place.
|
||||
void transmit_lock_release( const std::string & err_msg );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -69,6 +69,15 @@ protected:
|
|||
bool calc;
|
||||
bool zoom;
|
||||
|
||||
double keyshape[32]; // 4 msec rise and fall time for pulse
|
||||
double audio[400];
|
||||
double quiet[400];
|
||||
double play[400];
|
||||
|
||||
double nco(double freq);
|
||||
void makeshape();
|
||||
void makeaudio();
|
||||
|
||||
public:
|
||||
wwv();
|
||||
~wwv();
|
||||
|
@ -77,7 +86,7 @@ public:
|
|||
void tx_init(SoundBase *sc);
|
||||
void restart() {};
|
||||
int rx_process(const double *buf, int len);
|
||||
int tx_process() {return -1;}
|
||||
int tx_process();
|
||||
void update_syncscope();
|
||||
void set1(int x, int y);
|
||||
void set2(int x, int y);
|
||||
|
|
|
@ -90,13 +90,13 @@ FIELD fields[] = {
|
|||
{XCHG1, 0, &btnSelectXchgIn} // contest exchange #1 / free1 in xlog
|
||||
};
|
||||
|
||||
void initfields()
|
||||
static void initfields()
|
||||
{
|
||||
for (int i = 0; i < NUMFIELDS; i++)
|
||||
fields[i].name = new string(fieldnames[i]);
|
||||
}
|
||||
|
||||
int findfield( char *p )
|
||||
static int findfield( const char *p )
|
||||
{
|
||||
int m;
|
||||
int test;
|
||||
|
|
|
@ -261,6 +261,8 @@ Fl_Button *bUpdateCancel=(Fl_Button *)0;
|
|||
|
||||
Fl_Button *bDelete=(Fl_Button *)0;
|
||||
|
||||
Fl_Button *bDialFreq=(Fl_Button *)0;
|
||||
|
||||
Fl_Input2 *txtNbrRecs_log=(Fl_Input2 *)0;
|
||||
|
||||
Fl_Input2 *inpSerNoOut_log=(Fl_Input2 *)0;
|
||||
|
@ -818,23 +820,33 @@ void create_logbook_dialogs() {
|
|||
inpNotes_log->when(FL_WHEN_RELEASE);
|
||||
} // Fl_Input2* inpNotes_log
|
||||
{ bNewSave = new Fl_Button(163, 263, 55, 22, _("New"));
|
||||
bNewSave->tooltip(_("New record / Save record"));
|
||||
bNewSave->shortcut(0x8004e);
|
||||
bNewSave->color((Fl_Color)FL_LIGHT1);
|
||||
bNewSave->selection_color((Fl_Color)48);
|
||||
bNewSave->callback((Fl_Callback*)cb_btnNewSave);
|
||||
} // Fl_Button* bNewSave
|
||||
{ bUpdateCancel = new Fl_Button(235, 263, 55, 22, _("Update"));
|
||||
bUpdateCancel->tooltip(_("Update the current record"));
|
||||
bUpdateCancel->shortcut(0x80055);
|
||||
bUpdateCancel->color((Fl_Color)FL_LIGHT1);
|
||||
bUpdateCancel->selection_color((Fl_Color)48);
|
||||
bUpdateCancel->callback((Fl_Callback*)cb_btnUpdateCancel);
|
||||
} // Fl_Button* bUpdateCancel
|
||||
{ bDelete = new Fl_Button(307, 263, 55, 22, _("Delete"));
|
||||
bDelete->tooltip(_("Delete the current record"));
|
||||
bDelete->shortcut(0x80044);
|
||||
bDelete->color((Fl_Color)FL_LIGHT1);
|
||||
bDelete->selection_color((Fl_Color)48);
|
||||
bDelete->callback((Fl_Callback*)cb_btnDelete);
|
||||
} // Fl_Button* bDelete
|
||||
{ bDialFreq = new Fl_Button(380, 263, 55, 22, _("Dial"));
|
||||
bDialFreq->tooltip(_("Retrieve for active modem use"));
|
||||
bDialFreq->shortcut(0x50066);
|
||||
bDialFreq->color((Fl_Color)FL_LIGHT1);
|
||||
bDialFreq->selection_color((Fl_Color)48);
|
||||
bDialFreq->callback((Fl_Callback*)cb_btnDialFreq);
|
||||
} // Fl_Button* bDialFreq
|
||||
{ txtNbrRecs_log = new Fl_Input2(41, 263, 65, 22, _("Recs"));
|
||||
txtNbrRecs_log->tooltip(_("# Records in logbook"));
|
||||
txtNbrRecs_log->box(FL_DOWN_BOX);
|
||||
|
|
|
@ -20,7 +20,7 @@ Function {create_logbook_dialogs()} {open return_type void
|
|||
} {
|
||||
Fl_Window wExport {
|
||||
label {Export Setup} open
|
||||
xywh {588 534 655 385} type Double modal visible
|
||||
xywh {588 534 655 385} type Double hide modal
|
||||
} {
|
||||
Fl_Group {} {
|
||||
label {Select Records to Export} open
|
||||
|
@ -283,7 +283,7 @@ btnSelectNotes->value(0);}
|
|||
label Logbook open
|
||||
xywh {574 55 585 410} type Double color 47 resizable visible
|
||||
} {
|
||||
Fl_Group editGroup {open selected
|
||||
Fl_Group editGroup {open
|
||||
xywh {2 2 602 290} box ENGRAVED_FRAME color 52
|
||||
} {
|
||||
Fl_Input inpDate_log {
|
||||
|
@ -420,17 +420,22 @@ btnSelectNotes->value(0);}
|
|||
Fl_Button bNewSave {
|
||||
label New
|
||||
callback cb_btnNewSave
|
||||
xywh {163 263 55 22} shortcut 0x8004e color 50 selection_color 48
|
||||
tooltip {New record / Save record} xywh {163 263 55 22} shortcut 0x8004e color 50 selection_color 48
|
||||
}
|
||||
Fl_Button bUpdateCancel {
|
||||
label Update
|
||||
callback cb_btnUpdateCancel
|
||||
xywh {235 263 55 22} shortcut 0x80055 color 50 selection_color 48
|
||||
tooltip {Update the current record} xywh {235 263 55 22} shortcut 0x80055 color 50 selection_color 48
|
||||
}
|
||||
Fl_Button bDelete {
|
||||
label Delete
|
||||
callback cb_btnDelete
|
||||
xywh {307 263 55 22} shortcut 0x80044 color 50 selection_color 48
|
||||
tooltip {Delete the current record} xywh {307 263 55 22} shortcut 0x80044 color 50 selection_color 48
|
||||
}
|
||||
Fl_Button bDialFreq {
|
||||
label Dial
|
||||
callback cb_btnDialFreq
|
||||
tooltip {Retrieve for active modem use} xywh {380 263 55 22} shortcut 0x50066 color 50 selection_color 48
|
||||
}
|
||||
Fl_Input txtNbrRecs_log {
|
||||
label Recs
|
||||
|
@ -475,7 +480,7 @@ btnSelectNotes->value(0);}
|
|||
code0 {bSearchPrev->image(new Fl_Pixmap(left_arrow_icon));}
|
||||
}
|
||||
Fl_Button bSearchNext {
|
||||
callback cb_search
|
||||
callback cb_search selected
|
||||
tooltip {Find next} xywh {550 263 24 22} color 50 selection_color 48 align 16
|
||||
code0 {bSearchNext->image(new Fl_Pixmap(right_arrow_icon));}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "adif_io.h"
|
||||
#include "textio.h"
|
||||
#include "logbook.h"
|
||||
#include "rigsupport.h"
|
||||
|
||||
#include "logger.h"
|
||||
#include "fl_digi.h"
|
||||
|
@ -165,6 +166,9 @@ static void dxcc_entity_cache_rm(cQsoRec* r);
|
|||
static void dxcc_entity_cache_add(cQsoDb& db);
|
||||
|
||||
void cb_mnuNewLogbook(Fl_Menu_* m, void* d){
|
||||
if (!fl_choice2(_("Create New Logbook?"), _("No"), _("Yes"), NULL))
|
||||
return;
|
||||
|
||||
saveLogbook();
|
||||
|
||||
logbook_filename = LogsDir;
|
||||
|
@ -544,7 +548,51 @@ int log_search_handler(int)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int editNbr = 0;
|
||||
static int editNbr = 0;
|
||||
|
||||
void cb_btnDialFreq(Fl_Button* b, void* d)
|
||||
{
|
||||
double drf = atof(inpFreq_log->value());
|
||||
if (!drf) return;
|
||||
|
||||
int rf1, rf, audio;
|
||||
rf1 = drf * 1e6;
|
||||
rf = rf1 / 10000;
|
||||
rf *= 10000;
|
||||
audio = rf1 - rf;
|
||||
// try to keep within normal xcvr bw, 500 - 3000 Hz
|
||||
while (audio > 3000) {
|
||||
audio -= 3000;
|
||||
rf += 3000;
|
||||
}
|
||||
if (audio < 500) {
|
||||
audio += 500;
|
||||
rf -= 500;
|
||||
}
|
||||
qsy(rf, audio);
|
||||
|
||||
std::string mode_name = inpMode_log->value();
|
||||
trx_mode m;
|
||||
for (m = 0; m < NUM_MODES; m++)
|
||||
if (mode_name == mode_info[m].adif_name)
|
||||
break;
|
||||
// do we have a valid modem?
|
||||
if (m < NUM_MODES && active_modem->get_mode() != mode_info[m].mode)
|
||||
init_modem(mode_info[m].mode);
|
||||
|
||||
const cQsoRec *qsoPtr = qsodb.getRec(editNbr);
|
||||
inpCall->value(qsoPtr->getField(CALL));
|
||||
inpName->value (qsoPtr->getField(NAME));
|
||||
inpTimeOn->value (inpTimeOff->value());
|
||||
inpState->value (qsoPtr->getField(STATE));
|
||||
inpCountry->value (qsoPtr->getField(COUNTRY));
|
||||
inpXchgIn->value(qsoPtr->getField(XCHG1));
|
||||
inpQth->value (qsoPtr->getField(QTH));
|
||||
inpLoc->value (qsoPtr->getField(GRIDSQUARE));
|
||||
inpNotes->value (qsoPtr->getField(NOTES));
|
||||
|
||||
wBrowser->take_focus();
|
||||
}
|
||||
|
||||
void clearRecord() {
|
||||
Date tdy;
|
||||
|
|
|
@ -106,7 +106,7 @@ void cQsoRec::trimFields () {
|
|||
}
|
||||
}
|
||||
|
||||
const char * cQsoRec::getField (int n) {
|
||||
const char * cQsoRec::getField (int n) const {
|
||||
if (n < 0 || n >= NUMFIELDS) return 0;
|
||||
return (qsofield[n].c_str());
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "util.h"
|
||||
#include "date.h"
|
||||
#include "logbook.h"
|
||||
#include "logger.h"
|
||||
#include "locator.h"
|
||||
#include "fl_digi.h"
|
||||
#include "adif_io.h"
|
||||
#include "modem.h"
|
||||
|
@ -119,6 +121,19 @@ bool xml_get_record(const char *callsign)
|
|||
inpLoc->value("");
|
||||
inpNotes->value("");
|
||||
}
|
||||
if (inpLoc->value()[0]) {
|
||||
double lon1, lat1, lon2, lat2;
|
||||
double azimuth, distance;
|
||||
char szAZ[4];
|
||||
if ( locator2longlat(&lon1, &lat1, progdefaults.myLocator.c_str()) == RIG_OK &&
|
||||
locator2longlat(&lon2, &lat2, inpLoc->value()) == RIG_OK &&
|
||||
qrb(lon1, lat1, lon2, lat2, &distance, &azimuth) == RIG_OK ) {
|
||||
snprintf(szAZ,sizeof(szAZ),"%0.f", azimuth);
|
||||
inpAZ->value(szAZ);
|
||||
} else
|
||||
inpAZ->value("");
|
||||
} else
|
||||
inpAZ->value("");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "configuration.h"
|
||||
|
||||
#include "logsupport.h"
|
||||
#include "lookupcall.h"
|
||||
|
||||
#include <FL/fl_ask.H>
|
||||
|
||||
|
@ -215,6 +216,9 @@ void submit_log(void)
|
|||
|
||||
logmode = mode_info[active_modem->get_mode()].adif_name;
|
||||
|
||||
if (progdefaults.eqsl_when_logged)
|
||||
makeEQSL("");
|
||||
|
||||
if (progdefaults.xml_logbook)
|
||||
xml_add_record();
|
||||
else
|
||||
|
|
|
@ -104,7 +104,7 @@ void rx_extract_add(int c)
|
|||
gmtime_r(&t, &tim);
|
||||
strftime(dttm, sizeof(dttm), "%Y%m%d-%H%M%S", &tim);
|
||||
|
||||
string outfilename = WRAP_recv_dir;
|
||||
string outfilename = FLMSG_WRAP_recv_dir;
|
||||
outfilename.append("extract-");
|
||||
outfilename.append(dttm);
|
||||
outfilename.append(".wrap");
|
||||
|
@ -114,11 +114,11 @@ void rx_extract_add(int c)
|
|||
extractstream.close();
|
||||
}
|
||||
rx_extract_msg = "File saved in ";
|
||||
rx_extract_msg.append(WRAP_recv_dir);
|
||||
rx_extract_msg.append(FLMSG_WRAP_recv_dir);
|
||||
put_status(rx_extract_msg.c_str(), 20, STATUS_CLEAR);
|
||||
|
||||
if (progdefaults.open_nbems_folder)
|
||||
open_recv_folder(WRAP_recv_dir.c_str());
|
||||
open_recv_folder(FLMSG_WRAP_recv_dir.c_str());
|
||||
|
||||
if ((progdefaults.open_flmsg || progdefaults.open_flmsg_print) &&
|
||||
(rx_buff.find(flmsg) != string::npos) &&
|
||||
|
|
111
src/main.cxx
111
src/main.cxx
|
@ -120,30 +120,41 @@ string appname;
|
|||
|
||||
string scDevice[2];
|
||||
|
||||
string HomeDir;
|
||||
string RigsDir;
|
||||
string ScriptsDir;
|
||||
string PalettesDir;
|
||||
string LogsDir;
|
||||
string PicsDir;
|
||||
string HelpDir;
|
||||
string MacrosDir;
|
||||
string WrapDir;
|
||||
string TalkDir;
|
||||
string TempDir;
|
||||
string PskMailDir;
|
||||
string NBEMS_dir;
|
||||
string ARQ_dir;
|
||||
string ARQ_files_dir;
|
||||
string ARQ_recv_dir;
|
||||
string ARQ_send;
|
||||
string WRAP_dir;
|
||||
string WRAP_recv_dir;
|
||||
string WRAP_send_dir;
|
||||
string WRAP_auto_dir;
|
||||
string ICS_dir;
|
||||
string ICS_msg_dir;
|
||||
string ICS_tmp_dir;
|
||||
string HomeDir = "";
|
||||
string RigsDir = "";
|
||||
string ScriptsDir = "";
|
||||
string PalettesDir = "";
|
||||
string LogsDir = "";
|
||||
string PicsDir = "";
|
||||
string HelpDir = "";
|
||||
string MacrosDir = "";
|
||||
string WrapDir = "";
|
||||
string TalkDir = "";
|
||||
string TempDir = "";
|
||||
string PskMailDir = "";
|
||||
|
||||
string NBEMS_dir = "";
|
||||
string ARQ_dir = "";
|
||||
string ARQ_files_dir = "";
|
||||
string ARQ_recv_dir = "";
|
||||
string ARQ_send = "";
|
||||
string WRAP_dir = "";
|
||||
string WRAP_recv_dir = "";
|
||||
string WRAP_send_dir = "";
|
||||
string WRAP_auto_dir = "";
|
||||
string ICS_dir = "";
|
||||
string ICS_msg_dir = "";
|
||||
string ICS_tmp_dir = "";
|
||||
|
||||
string FLMSG_dir = "";
|
||||
string FLMSG_dir_default = "";
|
||||
string FLMSG_WRAP_dir = "";
|
||||
string FLMSG_WRAP_recv_dir = "";
|
||||
string FLMSG_WRAP_send_dir = "";
|
||||
string FLMSG_WRAP_auto_dir = "";
|
||||
string FLMSG_ICS_dir = "";
|
||||
string FLMSG_ICS_msg_dir = "";
|
||||
string FLMSG_ICS_tmp_dir = "";
|
||||
|
||||
string PskMailFile;
|
||||
string ArqFilename;
|
||||
|
@ -223,6 +234,7 @@ int main(int argc, char ** argv)
|
|||
NBEMS_dir = dirbuf;
|
||||
fl_filename_expand(dirbuf, sizeof(dirbuf) - 1, "$USERPROFILE/");
|
||||
PskMailDir = dirbuf;
|
||||
FLMSG_dir_default = "$USERPROFILE/NBEMS.files/";
|
||||
#else
|
||||
fl_filename_expand(dirbuf, sizeof(dirbuf) - 1, "$HOME/.dl-fldigi/");
|
||||
HomeDir = dirbuf;
|
||||
|
@ -230,6 +242,7 @@ int main(int argc, char ** argv)
|
|||
NBEMS_dir = dirbuf;
|
||||
fl_filename_expand(dirbuf, sizeof(dirbuf) - 1, "$HOME/");
|
||||
PskMailDir = dirbuf;
|
||||
FLMSG_dir_default = "$HOME/.nbems/";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -245,6 +258,13 @@ int main(int argc, char ** argv)
|
|||
if (main_window_title.empty())
|
||||
main_window_title = PACKAGE_TARNAME;
|
||||
|
||||
{
|
||||
char dirbuf[FL_PATH_MAX + 1];
|
||||
if (FLMSG_dir_default[FLMSG_dir_default.length()-1] != '/')
|
||||
FLMSG_dir_default += '/';
|
||||
fl_filename_expand(dirbuf, sizeof(dirbuf) - 1, FLMSG_dir_default.c_str());
|
||||
FLMSG_dir = dirbuf;
|
||||
}
|
||||
checkdirectories();
|
||||
check_nbems_dirs();
|
||||
|
||||
|
@ -467,6 +487,12 @@ void generate_option_help(void) {
|
|||
<< " --arq-server-port PORT\n"
|
||||
<< " Set the ARQ TCP server port\n"
|
||||
<< " The default is: " << progdefaults.arq_port << "\n\n"
|
||||
<< " --flmsg-dir DIRECTORY\n"
|
||||
<< " Look for flmsg files in DIRECTORY\n"
|
||||
<< " The default is " << FLMSG_dir_default << "\n\n"
|
||||
<< " --auto-dir DIRECTORY\n"
|
||||
<< " Look for auto-send files in DIRECTORY\n"
|
||||
<< " The default is " << HomeDir << "/autosend" << "\n\n"
|
||||
|
||||
#if USE_XMLRPC
|
||||
<< " --xmlrpc-server-address HOSTNAME\n"
|
||||
|
@ -619,6 +645,8 @@ int parse_args(int argc, char **argv, int& idx)
|
|||
OPT_CONFIG_DIR,
|
||||
OPT_ARQ_ADDRESS, OPT_ARQ_PORT,
|
||||
OPT_SHOW_CPU_CHECK,
|
||||
OPT_FLMSG_DIR,
|
||||
OPT_AUTOSEND_DIR,
|
||||
|
||||
#if USE_XMLRPC
|
||||
OPT_CONFIG_XMLRPC_ADDRESS, OPT_CONFIG_XMLRPC_PORT,
|
||||
|
@ -651,6 +679,8 @@ int parse_args(int argc, char **argv, int& idx)
|
|||
|
||||
{ "arq-server-address", 1, 0, OPT_ARQ_ADDRESS },
|
||||
{ "arq-server-port", 1, 0, OPT_ARQ_PORT },
|
||||
{ "flmsg-dir", 1, 0, OPT_FLMSG_DIR },
|
||||
{ "auto-dir", 1, 0, OPT_AUTOSEND_DIR },
|
||||
|
||||
{ "cpu-speed-test", 0, 0, OPT_SHOW_CPU_CHECK },
|
||||
|
||||
|
@ -740,6 +770,14 @@ int parse_args(int argc, char **argv, int& idx)
|
|||
progdefaults.arq_port = optarg;
|
||||
break;
|
||||
|
||||
case OPT_FLMSG_DIR:
|
||||
FLMSG_dir_default = optarg;
|
||||
break;
|
||||
|
||||
case OPT_AUTOSEND_DIR:
|
||||
FLMSG_WRAP_auto_dir = optarg;
|
||||
break;
|
||||
|
||||
#if USE_XMLRPC
|
||||
case OPT_CONFIG_XMLRPC_ADDRESS:
|
||||
progdefaults.xmlrpc_address = optarg;
|
||||
|
@ -1164,6 +1202,31 @@ void check_nbems_dirs(void)
|
|||
else if (r == 0 && NBEMS_dirs[i].new_dir_func)
|
||||
NBEMS_dirs[i].new_dir_func();
|
||||
}
|
||||
|
||||
DIRS FLMSG_dirs[] = {
|
||||
{ FLMSG_dir, 0, 0 },
|
||||
{ FLMSG_WRAP_dir, "WRAP", 0 },
|
||||
{ FLMSG_WRAP_recv_dir, "WRAP/recv", 0 },
|
||||
{ FLMSG_WRAP_send_dir, "WRAP/send", 0 },
|
||||
{ FLMSG_WRAP_auto_dir, "WRAP/auto", 0 },
|
||||
{ FLMSG_ICS_dir, "ICS", 0 },
|
||||
{ FLMSG_ICS_msg_dir, "ICS/messages", 0 },
|
||||
{ FLMSG_ICS_tmp_dir, "ICS/templates", 0 },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(FLMSG_dirs)/sizeof(*FLMSG_dirs); i++) {
|
||||
if (FLMSG_dirs[i].dir.empty() && FLMSG_dirs[i].suffix)
|
||||
FLMSG_dirs[i].dir.assign(FLMSG_dir).append(FLMSG_dirs[i].suffix).append("/");
|
||||
|
||||
if ((r = mkdir(FLMSG_dirs[i].dir.c_str(), 0777)) == -1 && errno != EEXIST) {
|
||||
cerr << _("Could not make directory") << ' ' << FLMSG_dirs[i].dir
|
||||
<< ": " << strerror(errno) << '\n';
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (r == 0 && FLMSG_dirs[i].new_dir_func)
|
||||
FLMSG_dirs[i].new_dir_func();
|
||||
}
|
||||
|
||||
nbems_dirs_checked = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -517,7 +517,7 @@ void mfsk::softdecode(complex *bins)
|
|||
// shift to range 0...255
|
||||
for (i = 0; i < symbits; i++)
|
||||
if (staticburst)
|
||||
symbols[i] = 0; // puncturing
|
||||
symbols[i] = 128; // puncturing 128 is neither 0 nor a 1
|
||||
else
|
||||
symbols[i] = (unsigned char)clamp(128.0 + (b[i] / sum * 128.0), 0, 255);
|
||||
|
||||
|
|
|
@ -380,7 +380,7 @@ bool WRAP_auto_arqRx()
|
|||
{
|
||||
time_t start_time, prog_time;
|
||||
static char mailline[1000];
|
||||
string sAutoFile = WRAP_auto_dir;
|
||||
string sAutoFile = FLMSG_WRAP_auto_dir;
|
||||
sAutoFile += "wrap_auto_file";
|
||||
|
||||
ifstream autofile(sAutoFile.c_str());
|
||||
|
|
|
@ -654,6 +654,9 @@ int configuration::setDefaults()
|
|||
case CALLOOK:
|
||||
qrzb = btnCALLOOK;
|
||||
break;
|
||||
case HAMQTH:
|
||||
qrzb = btnHamQTH;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -44,10 +44,12 @@
|
|||
#include "configuration.h"
|
||||
|
||||
#include "lookupcall.h"
|
||||
#include "logsupport.h"
|
||||
#include "main.h"
|
||||
#include "confdialog.h"
|
||||
#include "fl_digi.h"
|
||||
#include "qrzlib.h"
|
||||
#include "trx.h"
|
||||
|
||||
#include "xmlreader.h"
|
||||
|
||||
|
@ -150,7 +152,7 @@ bool parseSessionKey(const string& sessionpage)
|
|||
{
|
||||
case EXN_TEXT:
|
||||
case EXN_CDATA:
|
||||
switch (tag)
|
||||
switch (tag)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
@ -188,7 +190,7 @@ bool parseSessionKey(const string& sessionpage)
|
|||
}
|
||||
delete xml;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool parse_xml(const string& xmlpage)
|
||||
|
@ -196,7 +198,7 @@ bool parse_xml(const string& xmlpage)
|
|||
//printf("%s\n", xmlpage.c_str());
|
||||
IrrXMLReader* xml = createIrrXMLReader(new IIrrXMLStringReader(xmlpage));
|
||||
|
||||
// If we got any result back, clear the session key so that it will be
|
||||
// If we got any result back, clear the session key so that it will be
|
||||
// refreshed by this response, or if not present, will be removed and we'll
|
||||
// know to log in next time.
|
||||
if (xml) {
|
||||
|
@ -207,7 +209,7 @@ bool parse_xml(const string& xmlpage)
|
|||
}
|
||||
|
||||
TAG tag = QRZ_IGNORE;
|
||||
|
||||
|
||||
// parse the file until end reached
|
||||
while(xml && xml->read()) {
|
||||
switch(xml->getNodeType()) {
|
||||
|
@ -269,12 +271,12 @@ bool parse_xml(const string& xmlpage)
|
|||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case EXN_ELEMENT_END:
|
||||
tag=QRZ_IGNORE;
|
||||
break;
|
||||
|
||||
case EXN_ELEMENT:
|
||||
case EXN_ELEMENT:
|
||||
{
|
||||
const char *nodeName = xml->getNodeName();
|
||||
if (!strcmp("call", nodeName)) tag = QRZ_CALL;
|
||||
|
@ -390,11 +392,11 @@ void QRZ_disp_result()
|
|||
}
|
||||
|
||||
inpQth->value(lookup_qth.c_str());
|
||||
|
||||
|
||||
inpState->value(lookup_state.c_str());
|
||||
|
||||
inpVEprov->value(lookup_province.c_str());
|
||||
|
||||
|
||||
inpLoc->value(lookup_grid.c_str());
|
||||
|
||||
if (!lookup_country.empty())
|
||||
|
@ -419,7 +421,7 @@ void QRZ_CD_query()
|
|||
|
||||
char srch[20];
|
||||
size_t snip;
|
||||
|
||||
|
||||
memset( srch, 0, sizeof(srch) );
|
||||
strncpy( srch, callsign.c_str(), 6 );
|
||||
for (size_t i = 0; i < strlen(srch); i ++ )
|
||||
|
@ -652,36 +654,36 @@ void CALLOOKquery()
|
|||
void parse_html(const string& htmlpage)
|
||||
{
|
||||
size_t p;
|
||||
|
||||
|
||||
clear_Lookup();
|
||||
|
||||
|
||||
if ((p = htmlpage.find(HAMCALL_FIRST)) != string::npos) {
|
||||
p++;
|
||||
while ((uchar)htmlpage[p] < 128 && p < htmlpage.length() )
|
||||
lookup_fname += htmlpage[p++];
|
||||
camel_case(lookup_fname);
|
||||
}
|
||||
if ((p = htmlpage.find(HAMCALL_CITY)) != string::npos) {
|
||||
if ((p = htmlpage.find(HAMCALL_CITY)) != string::npos) {
|
||||
p++;
|
||||
while ((uchar)htmlpage[p] < 128 && p < htmlpage.length())
|
||||
lookup_qth += htmlpage[p++];
|
||||
}
|
||||
if ((p = htmlpage.find(HAMCALL_STATE)) != string::npos) {
|
||||
if ((p = htmlpage.find(HAMCALL_STATE)) != string::npos) {
|
||||
p++;
|
||||
while ((uchar)htmlpage[p] < 128 && p < htmlpage.length())
|
||||
lookup_state += htmlpage[p++];
|
||||
}
|
||||
if ((p = htmlpage.find(HAMCALL_GRID)) != string::npos) {
|
||||
if ((p = htmlpage.find(HAMCALL_GRID)) != string::npos) {
|
||||
p++;
|
||||
while ((uchar)htmlpage[p] < 128 && p < htmlpage.length())
|
||||
lookup_grid += htmlpage[p++];
|
||||
}
|
||||
if ((p = htmlpage.find(HAMCALL_DOB)) != string::npos) {
|
||||
if ((p = htmlpage.find(HAMCALL_DOB)) != string::npos) {
|
||||
p++;
|
||||
lookup_notes = "DOB: ";
|
||||
while ((uchar)htmlpage[p] < 128 && p < htmlpage.length())
|
||||
lookup_notes += htmlpage[p++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HAMCALLget(string& htmlpage)
|
||||
|
@ -713,11 +715,186 @@ void HAMCALLquery()
|
|||
REQ(QRZ_disp_result);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Hamcall specific functions
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
static string HAMQTH_session_id = "";
|
||||
static string HAMQTH_reply = "";
|
||||
|
||||
#define HAMQTH_DEBUG 1
|
||||
#undef HAMQTH_DEBUG
|
||||
|
||||
bool HAMQTH_get_session_id()
|
||||
{
|
||||
string url = "";
|
||||
string retstr = "";
|
||||
size_t p1 = string::npos;
|
||||
size_t p2 = string::npos;
|
||||
|
||||
url.append("http://www.hamqth.com/xml.php?u=").append(progdefaults.QRZusername);
|
||||
url.append("&p=").append(progdefaults.QRZuserpassword);
|
||||
|
||||
HAMQTH_session_id.clear();
|
||||
if (!fetch_http(url, retstr, 5.0)) {
|
||||
return false;
|
||||
}
|
||||
if ((p1 = retstr.find("<error>")) != string::npos) {
|
||||
p2 = retstr.find("</error>");
|
||||
lookup_notes = retstr.substr(p1 + 7, p2 - p1 - 7);
|
||||
return false;
|
||||
}
|
||||
if ((p1 = retstr.find("<session_id>")) == string::npos) {
|
||||
lookup_notes = "HamQTH not available";
|
||||
return false;
|
||||
}
|
||||
p2 = retstr.find("</session_id>");
|
||||
HAMQTH_session_id = retstr.substr(p1 + 12, p2 - p1 - 12);
|
||||
//#ifdef HAMQTH_DEBUG
|
||||
// printf("session id = %s\n", HAMQTH_session_id.c_str());
|
||||
//#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void parse_HAMQTH_html(const string& htmlpage)
|
||||
{
|
||||
size_t p = string::npos;
|
||||
size_t p1 = string::npos;
|
||||
|
||||
clear_Lookup();
|
||||
|
||||
lookup_fname.clear();
|
||||
lookup_qth.clear();
|
||||
lookup_state.clear();
|
||||
lookup_grid.clear();
|
||||
lookup_notes.clear();
|
||||
lookup_country.clear();
|
||||
|
||||
if ((p = htmlpage.find("<error>")) != string::npos) {
|
||||
p += 7;
|
||||
p1 = htmlpage.find("</error>");
|
||||
if (p1 != string::npos)
|
||||
lookup_notes.append(htmlpage.substr(p, p1 - p));
|
||||
return;
|
||||
}
|
||||
if ((p = htmlpage.find("<nick>")) != string::npos) {
|
||||
p += 6;
|
||||
p1 = htmlpage.find("</nick>", p);
|
||||
if (p1 != string::npos) {
|
||||
lookup_fname = htmlpage.substr(p, p1 - p);
|
||||
camel_case(lookup_fname);
|
||||
}
|
||||
}
|
||||
if ((p = htmlpage.find("<qth>")) != string::npos) {
|
||||
p += 5;
|
||||
p1 = htmlpage.find("</qth>", p);
|
||||
if (p1 != string::npos)
|
||||
lookup_qth = htmlpage.substr(p, p1 - p);
|
||||
}
|
||||
if ((p = htmlpage.find("<country>")) != string::npos) {
|
||||
p += 9;
|
||||
p1 = htmlpage.find("</country>", p);
|
||||
if (p1 != string::npos)
|
||||
lookup_country = htmlpage.substr(p, p1 - p);
|
||||
}
|
||||
if ((p = htmlpage.find("<us_state>")) != string::npos) {
|
||||
p += 10;
|
||||
p1 = htmlpage.find("</us_state>");
|
||||
if (p1 != string::npos)
|
||||
lookup_state = htmlpage.substr(p, p1 - p);
|
||||
}
|
||||
if ((p = htmlpage.find("<grid>")) != string::npos) {
|
||||
p += 6;
|
||||
p1 = htmlpage.find("</grid>");
|
||||
if (p1 != string::npos)
|
||||
lookup_grid = htmlpage.substr(p, p1 - p);
|
||||
}
|
||||
if ((p = htmlpage.find("<qsl_via>")) != string::npos) {
|
||||
p += 9;
|
||||
p1 = htmlpage.find("</qsl_via>");
|
||||
if (p1 != string::npos)
|
||||
lookup_notes.append("QSL via: ").append(htmlpage.substr(p, p1 - p)).append("\n");
|
||||
}
|
||||
if ((p = htmlpage.find("<adr_name>")) != string::npos) {
|
||||
p += 10;
|
||||
p1 = htmlpage.find("</adr_name>");
|
||||
if (p1 != string::npos)
|
||||
lookup_notes.append(htmlpage.substr(p, p1 - p)).append("\n");
|
||||
}
|
||||
if ((p = htmlpage.find("<adr_street1>")) != string::npos) {
|
||||
p += 13;
|
||||
p1 = htmlpage.find("</adr_street1>");
|
||||
if (p1 != string::npos)
|
||||
lookup_notes.append(htmlpage.substr(p, p1 - p)).append("\n");
|
||||
}
|
||||
if ((p = htmlpage.find("<adr_city>")) != string::npos) {
|
||||
p += 10;
|
||||
p1 = htmlpage.find("</adr_city>");
|
||||
if (p1 != string::npos)
|
||||
lookup_notes.append(htmlpage.substr(p, p1 - p)).append(", ").append(lookup_state);
|
||||
}
|
||||
if ((p = htmlpage.find("<adr_zip>")) != string::npos) {
|
||||
p += 9;
|
||||
p1 = htmlpage.find("</adr_zip>");
|
||||
if (p1 != string::npos)
|
||||
lookup_notes.append(" ").append(htmlpage.substr(p, p1 - p));
|
||||
}
|
||||
if ((p = htmlpage.find("<adr_country>")) != string::npos) {
|
||||
p += 13;
|
||||
p1 = htmlpage.find("</adr_country>");
|
||||
if (p1 != string::npos)
|
||||
lookup_notes.append(" ").append(htmlpage.substr(p, p1 - p));
|
||||
}
|
||||
}
|
||||
|
||||
bool HAMQTHget(string& htmlpage)
|
||||
{
|
||||
string url = "";
|
||||
bool ret;
|
||||
if (HAMQTH_session_id.empty()) {
|
||||
if (!HAMQTH_get_session_id()) return false;
|
||||
}
|
||||
url.append("http://www.hamqth.com/xml.php?id=").append(HAMQTH_session_id);
|
||||
url.append("&callsign=").append(callsign);
|
||||
url.append("&prg=fldigi-").append(VERSION);
|
||||
|
||||
ret = fetch_http(url, htmlpage, 5.0);
|
||||
if (htmlpage.find("<error>") != string::npos) {
|
||||
htmlpage.clear();
|
||||
if (!HAMQTH_get_session_id()) {
|
||||
lookup_notes = "Get session id failed!\n";
|
||||
return false;
|
||||
}
|
||||
ret = fetch_http(url, htmlpage, 5.0);
|
||||
}
|
||||
#ifdef HAMQTH_DEBUG
|
||||
FILE *fetchit = fopen("fetchit.txt", "a");
|
||||
fprintf(fetchit, "%s\n", htmlpage.c_str());
|
||||
fclose(fetchit);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HAMQTHquery()
|
||||
{
|
||||
ENSURE_THREAD(QRZ_TID);
|
||||
|
||||
string htmlpage;
|
||||
|
||||
if (!HAMQTHget(htmlpage)) return;
|
||||
|
||||
parse_HAMQTH_html(htmlpage);
|
||||
REQ(QRZ_disp_result);
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void QRZ_DETAILS_query()
|
||||
{
|
||||
string qrzurl = "http://www.qrz.com/callsign.html?callsign=";
|
||||
string qrzurl = "http://www.qrz.com/db/";
|
||||
qrzurl.append(callsign);
|
||||
|
||||
|
||||
cb_mnuVisitURL(0, (void*)qrzurl.c_str());
|
||||
}
|
||||
|
||||
|
@ -725,7 +902,7 @@ void HAMCALL_DETAILS_query()
|
|||
{
|
||||
string hamcallurl = "http://www.hamcall.net/call?callsign=";
|
||||
hamcallurl.append(callsign);
|
||||
|
||||
|
||||
cb_mnuVisitURL(0, (void*)hamcallurl.c_str());
|
||||
}
|
||||
|
||||
|
@ -762,6 +939,9 @@ static void *LOOKUP_loop(void *args)
|
|||
case CALLOOK:
|
||||
CALLOOKquery();
|
||||
break;
|
||||
case HAMQTH:
|
||||
HAMQTHquery();
|
||||
break;
|
||||
case QRZ_EXIT:
|
||||
return NULL;
|
||||
default:
|
||||
|
@ -815,6 +995,9 @@ void CALLSIGNquery()
|
|||
case CALLOOK:
|
||||
inpNotes->value("Request sent to\nhttp://callook.info...");
|
||||
break;
|
||||
case HAMQTH:
|
||||
inpNotes->value("Request sent to \nhttp://hamqth.com...");
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Bad query type %d", DB_query);
|
||||
return;
|
||||
|
@ -824,3 +1007,201 @@ void CALLSIGNquery()
|
|||
pthread_cond_signal(&qrz_cond);
|
||||
pthread_mutex_unlock(&qrz_mutex);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// thread to support sending log entry to eQSL
|
||||
//======================================================================
|
||||
|
||||
pthread_t* EQSLthread = 0;
|
||||
pthread_mutex_t EQSLmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t EQSLcond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
static void *EQSL_loop(void *args);
|
||||
static void EQSL_init(void);
|
||||
|
||||
void EQSL_close(void);
|
||||
void EQSL_send();
|
||||
|
||||
static std::string EQSL_url = "";
|
||||
static std::string EQSL_xmlpage = "";
|
||||
|
||||
static bool EQSLEXIT = false;
|
||||
|
||||
static void *EQSL_loop(void *args)
|
||||
{
|
||||
SET_THREAD_ID(EQSL_TID);
|
||||
|
||||
SET_THREAD_CANCEL();
|
||||
|
||||
for (;;) {
|
||||
TEST_THREAD_CANCEL();
|
||||
pthread_mutex_lock(&EQSLmutex);
|
||||
pthread_cond_wait(&EQSLcond, &EQSLmutex);
|
||||
pthread_mutex_unlock(&EQSLmutex);
|
||||
|
||||
if (EQSLEXIT)
|
||||
return NULL;
|
||||
|
||||
size_t p;
|
||||
if (fetch_http(EQSL_url, EQSL_xmlpage, 5.0) == -1)
|
||||
LOG_ERROR("%s", "eQSL not available");
|
||||
|
||||
else if ((p = EQSL_xmlpage.find("Error:")) != std::string::npos) {
|
||||
size_t p2 = EQSL_xmlpage.find('\n', p);
|
||||
LOG_ERROR("%s\n%s", EQSL_xmlpage.substr(p, p2 - p - 1).c_str(), EQSL_url.c_str());
|
||||
} else
|
||||
LOG_INFO("eQSL logged %s", EQSL_url.c_str());
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EQSL_close(void)
|
||||
{
|
||||
ENSURE_THREAD(FLMAIN_TID);
|
||||
|
||||
if (!EQSLthread)
|
||||
return;
|
||||
|
||||
CANCEL_THREAD(*EQSLthread);
|
||||
|
||||
pthread_mutex_lock(&qrz_mutex);
|
||||
EQSLEXIT = true;
|
||||
pthread_cond_signal(&qrz_cond);
|
||||
pthread_mutex_unlock(&qrz_mutex);
|
||||
|
||||
pthread_join(*QRZ_thread, NULL);
|
||||
delete QRZ_thread;
|
||||
QRZ_thread = 0;
|
||||
}
|
||||
|
||||
static void EQSL_init(void)
|
||||
{
|
||||
ENSURE_THREAD(FLMAIN_TID);
|
||||
|
||||
if (EQSLthread)
|
||||
return;
|
||||
EQSLthread = new pthread_t;
|
||||
EQSLEXIT = false;
|
||||
if (pthread_create(EQSLthread, NULL, EQSL_loop, NULL) != 0) {
|
||||
LOG_PERROR("pthread_create");
|
||||
return;
|
||||
}
|
||||
MilliSleep(10);
|
||||
}
|
||||
|
||||
void sendEQSL(const char *url)
|
||||
{
|
||||
ENSURE_THREAD(FLMAIN_TID);
|
||||
|
||||
if (!EQSLthread)
|
||||
EQSL_init();
|
||||
|
||||
pthread_mutex_lock(&EQSLmutex);
|
||||
EQSL_url = url;
|
||||
pthread_cond_signal(&EQSLcond);
|
||||
pthread_mutex_unlock(&EQSLmutex);
|
||||
}
|
||||
|
||||
// this function may be called from several places including macro
|
||||
// expansion and execution
|
||||
|
||||
void makeEQSL(const char *message)
|
||||
{
|
||||
char sztemp[100];
|
||||
std::string tempstr;
|
||||
std::string eQSL_url;
|
||||
std::string msg;
|
||||
size_t p = 0;
|
||||
|
||||
msg = message;
|
||||
|
||||
if (msg.empty()) msg = progdefaults.eqsl_default_message;
|
||||
|
||||
// replace message tags {CALL}, {NAME}, {MODE}
|
||||
while ((p = msg.find("{CALL}")) != std::string::npos)
|
||||
msg.replace(p, 6, inpCall->value());
|
||||
while ((p = msg.find("{NAME}")) != std::string::npos)
|
||||
msg.replace(p, 6, inpName->value());
|
||||
while ((p = msg.find("{MODE}")) != std::string::npos)
|
||||
msg.replace(p, 6, mode_info[active_modem->get_mode()].adif_name);
|
||||
|
||||
|
||||
// eqsl url header
|
||||
eQSL_url = "http://www.eqsl.cc/qslcard/importADIF.cfm?ADIFdata=upload <adIF_ver:5>2.1.9";
|
||||
snprintf(sztemp, sizeof(sztemp),"<EQSL_USER:%d>%s<EQSL_PSWD:%d>%s",
|
||||
progdefaults.eqsl_id.length(), progdefaults.eqsl_id.c_str(),
|
||||
progdefaults.eqsl_pwd.length(), progdefaults.eqsl_pwd.c_str());
|
||||
eQSL_url.append(sztemp);
|
||||
// eqsl nickname
|
||||
if (!progdefaults.eqsl_nick.empty()) {
|
||||
snprintf(sztemp, sizeof(sztemp), "<APP_EQSL_QTH_NICKNAME:%d>%s",
|
||||
progdefaults.eqsl_nick.length(), progdefaults.eqsl_nick.c_str());
|
||||
eQSL_url.append(sztemp);
|
||||
}
|
||||
eQSL_url.append("<PROGRAMID:6>FLDIGI<EOH>");
|
||||
|
||||
// eqsl record
|
||||
// band
|
||||
tempstr = band_name(band(wf->rfcarrier()));
|
||||
snprintf(sztemp, sizeof(sztemp), "<BAND:%d>%s", tempstr.length(), tempstr.c_str());
|
||||
eQSL_url.append(sztemp);
|
||||
// call
|
||||
tempstr = inpCall->value();
|
||||
snprintf(sztemp, sizeof(sztemp), "<CALL:%d>%s", tempstr.length(), tempstr.c_str());
|
||||
eQSL_url.append(sztemp);
|
||||
// mode
|
||||
tempstr = mode_info[active_modem->get_mode()].adif_name;
|
||||
// test for modes not supported by eQSL
|
||||
if ((tempstr.find("MFSK4") != std::string::npos) ||
|
||||
(tempstr.find("MFSK11") != std::string::npos) ||
|
||||
(tempstr.find("MFSK22") != std::string::npos) ||
|
||||
(tempstr.find("MFSK31") != std::string::npos) ||
|
||||
(tempstr.find("MFSK32") != std::string::npos) ||
|
||||
(tempstr.find("MFSK64") != std::string::npos) )
|
||||
tempstr = "MFSK16";
|
||||
if ((tempstr.find("PSK250") != std::string::npos) ||
|
||||
(tempstr.find("PSK500") != std::string::npos) ||
|
||||
(tempstr.find("PSK125R") != std::string::npos) ||
|
||||
(tempstr.find("PSK250R") != std::string::npos) ||
|
||||
(tempstr.find("PSK500R") != std::string::npos))
|
||||
tempstr = "PSK125";
|
||||
if ((tempstr.find("QPSK250") != std::string::npos) ||
|
||||
(tempstr.find("QPSK500") != std::string::npos) ||
|
||||
(tempstr.find("QPSK125R") != std::string::npos) ||
|
||||
(tempstr.find("QPSK250R") != std::string::npos) ||
|
||||
(tempstr.find("QPSK500R") != std::string::npos))
|
||||
tempstr = "QPSK125";
|
||||
|
||||
snprintf(sztemp, sizeof(sztemp), "<MODE:%d>%s", tempstr.length(), tempstr.c_str());
|
||||
eQSL_url.append(sztemp);
|
||||
// qso date
|
||||
snprintf(sztemp, sizeof(sztemp), "<QSO_DATE:%d>%s", sDate_on.length(), sDate_on.c_str());
|
||||
eQSL_url.append(sztemp);
|
||||
// qso time
|
||||
tempstr = inpTimeOn->value();
|
||||
snprintf(sztemp, sizeof(sztemp), "<TIME_ON:%d>%s", tempstr.length(), tempstr.c_str());
|
||||
eQSL_url.append(sztemp);
|
||||
// rst sent
|
||||
tempstr = inpRstOut->value();
|
||||
snprintf(sztemp, sizeof(sztemp), "<RST_SENT:%d>%s", tempstr.length(), tempstr.c_str());
|
||||
eQSL_url.append(sztemp);
|
||||
// message
|
||||
if (!msg.empty()) {
|
||||
snprintf(sztemp, sizeof(sztemp), "<QSLMSG:%d>%s", msg.length(), msg.c_str());
|
||||
eQSL_url.append(sztemp);
|
||||
}
|
||||
eQSL_url.append("<EOR>");
|
||||
|
||||
tempstr.clear();
|
||||
for (size_t n = 0; n < eQSL_url.length(); n++) {
|
||||
if (eQSL_url[n] == ' ') tempstr.append("%20");
|
||||
else if (eQSL_url[n] == '<') tempstr.append("%3c");
|
||||
else if (eQSL_url[n] == '>') tempstr.append("%3e");
|
||||
else tempstr += eQSL_url[n];
|
||||
}
|
||||
|
||||
sendEQSL(tempstr.c_str());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include <FL/Fl_Pixmap.H>
|
||||
|
||||
#include "macros.h"
|
||||
#include "macroedit.h"
|
||||
#include "globals.h"
|
||||
|
@ -52,12 +50,12 @@ using namespace std;
|
|||
|
||||
Fl_Double_Window *MacroEditDialog = (Fl_Double_Window *)0;
|
||||
|
||||
Fl_Button *btnMacroEditOK = (Fl_Button *)0;
|
||||
Fl_Button *btnMacroEditCancel = (Fl_Button *)0;
|
||||
Fl_Button *btnMacroEditApply = (Fl_Button *)0;
|
||||
Fl_Button *btnMacroEditClose = (Fl_Button *)0;
|
||||
Fl_Button *btnInsertMacro = (Fl_Button *)0;
|
||||
Fl_Input2 *macrotext = (Fl_Input2 *)0;
|
||||
Fl_Input2 *labeltext = (Fl_Input2 *)0;
|
||||
static int widths[] = {130, 0};
|
||||
static int widths[] = {150, 0};
|
||||
|
||||
Fl_Hold_Browser *macroDefs=(Fl_Hold_Browser *)0;
|
||||
|
||||
|
@ -106,6 +104,7 @@ void loadBrowser(Fl_Widget *widget) {
|
|||
w->add(_("<LOG>\tsave QSO data"));
|
||||
w->add(_("<LNW>\tlog at xmt time"));
|
||||
w->add(_("<CLRLOG>\tclear log fields"));
|
||||
w->add(_("<EQSL:[msg]>\tlog eQSL optional msg"));
|
||||
|
||||
w->add(LINE_SEP);
|
||||
w->add(_("<QSOTIME>\tQSO time (HHMM))"));
|
||||
|
@ -151,6 +150,7 @@ void loadBrowser(Fl_Widget *widget) {
|
|||
w->add(_("<TUNE:NN>\ttune signal for NN sec"));
|
||||
w->add(_("<WAIT:NN>\tdelay xmt for NN sec"));
|
||||
w->add(_("<REPEAT>\trepeat macro continuously"));
|
||||
w->add(_("<SKED:hhmm[:YYYYDDMM]>\tschedule execution"));
|
||||
|
||||
w->add(LINE_SEP);
|
||||
w->add(_("<CWID>\tCW identifier"));
|
||||
|
@ -158,6 +158,7 @@ void loadBrowser(Fl_Widget *widget) {
|
|||
w->add(_("<TEXT>\tvideo text"));
|
||||
w->add(_("<TXRSID:on|off|t>\tTx RSID on,off,toggle"));
|
||||
w->add(_("<RXRSID:on|off|t>\tRx RSID on,off,toggle"));
|
||||
w->add(_("<DTMF:[Wn:][Ln:]chrs>\t[Wait][Len](ms)"));
|
||||
|
||||
w->add(LINE_SEP);
|
||||
w->add(_("<POST:+/-nn.n>\tCW QSK post-timing"));
|
||||
|
@ -168,6 +169,7 @@ void loadBrowser(Fl_Widget *widget) {
|
|||
w->add(LINE_SEP);
|
||||
w->add(_("<AFC:on|off|t>\tAFC on,off,toggle"));
|
||||
w->add(_("<LOCK:on|off|t>\tLOCK on,off,toggle"));
|
||||
w->add(_("<REV:on|off|t>\tRev on,off,toggle"));
|
||||
|
||||
w->add(LINE_SEP);
|
||||
w->add(_("<MACROS:>\tchange macro defs file"));
|
||||
|
@ -201,7 +203,7 @@ void loadBrowser(Fl_Widget *widget) {
|
|||
w->add(s);
|
||||
}
|
||||
// add some RTTY macros
|
||||
const char* rtty[] = { "170:45.45:5", "170:50:5", "850:75:5" };
|
||||
const char* rtty[] = { "170:45.45:5:90", "170:50:5:100", "850:75:5:150" };
|
||||
for (size_t i = 0; i < sizeof(rtty)/sizeof(*rtty); i++) {
|
||||
snprintf(s, sizeof(s), "<MODEM:%s:%s>", mode_info[MODE_RTTY].sname, rtty[i]);
|
||||
w->add(s);
|
||||
|
@ -239,8 +241,10 @@ void loadBrowser(Fl_Widget *widget) {
|
|||
|
||||
void cbMacroEditOK(Fl_Widget *w, void *)
|
||||
{
|
||||
if (w == btnMacroEditCancel)
|
||||
goto ret;
|
||||
if (w == btnMacroEditClose) {
|
||||
MacroEditDialog->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (iType == MACRO_EDIT_BUTTON) {
|
||||
macros.text[iMacro] = macrotext->value();
|
||||
|
@ -263,8 +267,6 @@ void cbMacroEditOK(Fl_Widget *w, void *)
|
|||
}
|
||||
else if (iType == MACRO_EDIT_INPUT)
|
||||
iInput->value(macrotext->value());
|
||||
ret:
|
||||
MacroEditDialog->hide();
|
||||
}
|
||||
|
||||
void cbInsertMacro(Fl_Widget *, void *)
|
||||
|
@ -312,35 +314,65 @@ void cbInsertMacro(Fl_Widget *, void *)
|
|||
macrotext->take_focus();
|
||||
}
|
||||
|
||||
#include <FL/Fl_Tile.H>
|
||||
|
||||
Fl_Double_Window* make_macroeditor(void)
|
||||
{
|
||||
Fl_Double_Window* w = new Fl_Double_Window(768, 190, "");
|
||||
Fl_Double_Window* w = new Fl_Double_Window(800, 190, "");
|
||||
|
||||
macrotext = new Fl_Input2(2, 22, 450, 140, _("Text:"));
|
||||
macrotext->type(FL_MULTILINE_INPUT);
|
||||
macrotext->textfont(FL_COURIER);
|
||||
macrotext->align(FL_ALIGN_TOP_LEFT);
|
||||
|
||||
btnInsertMacro = new Fl_Button(454, 86, 20, 20);
|
||||
Fl_Group *grpA = new Fl_Group(0, 0, 800, 22);
|
||||
Fl_Group *grpB = new Fl_Group(450, 0, 350, 22);
|
||||
btnInsertMacro = new Fl_Button(450, 2, 40, 20);
|
||||
btnInsertMacro->image(new Fl_Pixmap(left_arrow_icon));
|
||||
btnInsertMacro->callback(cbInsertMacro);
|
||||
grpB->end();
|
||||
grpA->end();
|
||||
|
||||
macroDefs = new Fl_Hold_Browser(476, 22, 290, 140, _("Select Tags:"));
|
||||
Fl_Group *grpC = new Fl_Group(0, 22, 800, 140);
|
||||
Fl_Tile *tile = new Fl_Tile(0,22,800,140);
|
||||
macrotext = new Fl_Input2(0, 22, 450, 140, _("Macro Text"));
|
||||
macrotext->type(FL_MULTILINE_INPUT);
|
||||
macrotext->textfont(FL_COURIER);
|
||||
macrotext->align(FL_ALIGN_TOP);
|
||||
|
||||
macroDefs = new Fl_Hold_Browser(450, 22, 350, 140, _("Select Tag"));
|
||||
macroDefs->column_widths(widths);
|
||||
macroDefs->align(FL_ALIGN_TOP_LEFT);
|
||||
loadBrowser(macroDefs);
|
||||
macroDefs->align(FL_ALIGN_TOP);
|
||||
|
||||
labeltext = new Fl_Input2(2 + 450 - 115, 164, 115, 24, _("Macro Button Label:"));
|
||||
Fl_Box *minbox = new Fl_Box(200, 22, 400, 140);
|
||||
minbox->hide();
|
||||
tile->end();
|
||||
tile->resizable(minbox);
|
||||
grpC->end();
|
||||
|
||||
Fl_Group *grpD = new Fl_Group(0, 164, 452, 24);
|
||||
Fl_Box *box3a = new Fl_Box(0, 164, 327, 24, "");
|
||||
labeltext = new Fl_Input2(337, 164, 115, 24, _("Macro Button Label"));
|
||||
labeltext->textfont(FL_COURIER);
|
||||
grpD->end();
|
||||
grpD->resizable(box3a);
|
||||
|
||||
btnMacroEditOK = new Fl_Button(476 + 145 - 80 - 1, 164, 80, 24, _("OK"));
|
||||
btnMacroEditOK->callback(cbMacroEditOK);
|
||||
Fl_Group *grpE = new Fl_Group(452, 164, 348, 24);
|
||||
Fl_Box *box4a = new Fl_Box(452, 164, 92, 24, "");
|
||||
|
||||
btnMacroEditCancel = new Fl_Button(476 + 145 + 1 , 164, 80, 24, _("Cancel"));
|
||||
btnMacroEditCancel->callback(cbMacroEditOK);
|
||||
btnMacroEditApply = new Fl_Button(544, 164, 80, 24, _("Apply"));
|
||||
btnMacroEditApply->callback(cbMacroEditOK);
|
||||
|
||||
btnMacroEditClose = new Fl_Button(626 , 164, 80, 24, _("Close"));
|
||||
btnMacroEditClose->callback(cbMacroEditOK);
|
||||
grpE->end();
|
||||
grpE->resizable(box4a);
|
||||
|
||||
w->end();
|
||||
|
||||
w->resizable(grpC);
|
||||
|
||||
w->size_range( 600, 120);
|
||||
|
||||
w->xclass(PACKAGE_NAME);
|
||||
|
||||
loadBrowser(macroDefs);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
3039
src/misc/macros.cxx
3039
src/misc/macros.cxx
Plik diff jest za duży
Load Diff
|
@ -21,6 +21,7 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <cmath>
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "threads.h"
|
||||
|
||||
THREAD_ID_TYPE thread_id_;
|
||||
|
@ -99,3 +101,50 @@ void linux_log_tid(void)
|
|||
LOG_DEBUG(PACKAGE_TARNAME " thread %" PRIdPTR " is LWP %ld", GET_THREAD_ID(), syscall(SYS_gettid));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Synchronization objects.
|
||||
|
||||
guard_lock::guard_lock(pthread_mutex_t* m) : mutex(m)
|
||||
{
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
guard_lock::~guard_lock(void)
|
||||
{
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
syncobj::syncobj()
|
||||
{
|
||||
pthread_mutex_init( & m_mutex, NULL );
|
||||
pthread_cond_init( & m_cond, NULL );
|
||||
}
|
||||
|
||||
syncobj::~syncobj()
|
||||
{
|
||||
pthread_mutex_destroy( & m_mutex );
|
||||
pthread_cond_destroy( & m_cond );
|
||||
}
|
||||
|
||||
void syncobj::signal()
|
||||
{
|
||||
int rc = pthread_cond_signal( &m_cond );
|
||||
if( rc )
|
||||
{
|
||||
throw std::runtime_error(strerror(rc));
|
||||
}
|
||||
}
|
||||
|
||||
bool syncobj::wait( double seconds )
|
||||
{
|
||||
int rc = pthread_cond_timedwait_rel( &m_cond, &m_mutex, seconds );
|
||||
switch( rc )
|
||||
{
|
||||
case 0 : return true ;
|
||||
default : throw std::runtime_error(strerror(rc));
|
||||
case ETIMEDOUT: return false ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
#include "waterfall.h"
|
||||
#include "macros.h"
|
||||
#include "qrunner.h"
|
||||
#include "wefax.h"
|
||||
#include "wefax-pic.h"
|
||||
|
||||
#if USE_HAMLIB
|
||||
#include "hamlib.h"
|
||||
|
@ -189,16 +191,8 @@ ostream& XML_RPC_Server::list_methods(ostream& out)
|
|||
|
||||
// =============================================================================
|
||||
// Methods that change the server state must call XMLRPC_LOCK
|
||||
|
||||
class xmlrpc_lock
|
||||
{
|
||||
public:
|
||||
xmlrpc_lock(pthread_mutex_t* m) : mutex(m) { pthread_mutex_lock(mutex); }
|
||||
~xmlrpc_lock(void) { pthread_mutex_unlock(mutex); }
|
||||
private:
|
||||
pthread_mutex_t* mutex;
|
||||
};
|
||||
#define XMLRPC_LOCK SET_THREAD_ID(XMLRPC_TID); xmlrpc_lock autolock_(server_mutex)
|
||||
// guard_lock (include/threads.h) ensures that mutex are always unlocked.
|
||||
#define XMLRPC_LOCK SET_THREAD_ID(XMLRPC_TID); guard_lock autolock_(server_mutex)
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
@ -2433,6 +2427,206 @@ public:
|
|||
|
||||
// =============================================================================
|
||||
|
||||
// Returns the current wefax modem pointer.
|
||||
static wefax * get_wefax(void)
|
||||
{
|
||||
if( ( active_modem->get_mode() >= MODE_WEFAX_FIRST )
|
||||
&& ( active_modem->get_mode() <= MODE_WEFAX_LAST ) )
|
||||
{
|
||||
wefax * ptr = dynamic_cast<wefax *>( active_modem );
|
||||
if( ptr == NULL ) throw runtime_error("Inconsistent wefax object");
|
||||
return ptr ;
|
||||
}
|
||||
throw runtime_error("Not in wefax mode");
|
||||
}
|
||||
|
||||
struct Wefax_state_string : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_state_string() {
|
||||
_signature = "s:n";
|
||||
_help = "Returns Wefax engine state (tx and rx) for information."; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( get_wefax()->state_string() );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what());
|
||||
}
|
||||
};
|
||||
|
||||
struct Wefax_skip_apt : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_skip_apt() {
|
||||
_signature = "s:n";
|
||||
_help = "Skip APT during Wefax reception"; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
get_wefax()->skip_apt();
|
||||
*retval = xmlrpc_c::value_string( "" );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what() );
|
||||
}
|
||||
};
|
||||
|
||||
/// TODO: Refresh the screen with the new value.
|
||||
struct Wefax_skip_phasing : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_skip_phasing() {
|
||||
_signature = "s:n";
|
||||
_help = "Skip phasing during Wefax reception"; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
get_wefax()->skip_phasing(true);
|
||||
*retval = xmlrpc_c::value_string( "" );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what() );
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: The image should be reloaded just like cancelling from the GUI.
|
||||
struct Wefax_set_tx_abort_flag : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_set_tx_abort_flag() {
|
||||
_signature = "s:n";
|
||||
_help = "Cancels Wefax image transmission"; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
get_wefax()->set_tx_abort_flag();
|
||||
*retval = xmlrpc_c::value_string( "" );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what() );
|
||||
}
|
||||
};
|
||||
|
||||
struct Wefax_end_reception : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_end_reception() {
|
||||
_signature = "s:n";
|
||||
_help = "End Wefax image reception"; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
get_wefax()->end_reception();
|
||||
*retval = xmlrpc_c::value_string( "" );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what() );
|
||||
}
|
||||
};
|
||||
|
||||
struct Wefax_start_manual_reception : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_start_manual_reception() {
|
||||
_signature = "s:n";
|
||||
_help = "Starts fax image reception in manual mode"; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
get_wefax()->set_rx_manual_mode(true);
|
||||
get_wefax()->skip_apt();
|
||||
get_wefax()->skip_phasing(true);
|
||||
*retval = xmlrpc_c::value_string( "" );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what() );
|
||||
}
|
||||
};
|
||||
|
||||
struct Wefax_set_adif_log : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_set_adif_log() {
|
||||
_signature = "s:b";
|
||||
_help = "Set/reset logging to received/transmit images to ADIF log file"; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
get_wefax()->set_adif_log( params.getBoolean(0));
|
||||
*retval = xmlrpc_c::value_string( "" );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what() );
|
||||
}
|
||||
};
|
||||
|
||||
struct Wefax_set_max_lines : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_set_max_lines() {
|
||||
_signature = "s:i";
|
||||
_help = "Set maximum lines for fax image reception"; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
get_wefax()->set_max_lines( params.getInt(0));
|
||||
/// This updates the GUI.
|
||||
REQ( wefax_pic::restore_max_lines );
|
||||
*retval = xmlrpc_c::value_string( "" );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what() );
|
||||
}
|
||||
};
|
||||
|
||||
struct Wefax_get_received_file : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_get_received_file() {
|
||||
_signature = "s:i";
|
||||
_help = "Waits for next received fax file, returns its name with a delay. Empty string if timeout."; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
std::string filename = get_wefax()->get_received_file( params.getInt(0));
|
||||
*retval = xmlrpc_c::value_string( filename );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what() );
|
||||
}
|
||||
};
|
||||
|
||||
struct Wefax_send_file : public xmlrpc_c::method
|
||||
{
|
||||
Wefax_send_file() {
|
||||
_signature = "s:si";
|
||||
_help = "Send file. returns an empty string if OK otherwise an error message."; }
|
||||
|
||||
void execute(const xmlrpc_c::paramList& params, xmlrpc_c::value* retval)
|
||||
try
|
||||
{
|
||||
std::string status = get_wefax()->send_file( params.getString(0), params.getInt(1) );
|
||||
*retval = xmlrpc_c::value_string( status );
|
||||
}
|
||||
catch( const exception & e )
|
||||
{
|
||||
*retval = xmlrpc_c::value_string( e.what() );
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// End XML-RPC interface
|
||||
|
||||
// method list: ELEM_(class_name, "method_name")
|
||||
|
@ -2586,7 +2780,18 @@ public:
|
|||
ELEM_(Spot_get_auto, "spot.get_auto") \
|
||||
ELEM_(Spot_set_auto, "spot.set_auto") \
|
||||
ELEM_(Spot_toggle_auto, "spot.toggle_auto") \
|
||||
ELEM_(Spot_pskrep_get_count, "spot.pskrep.get_count")
|
||||
ELEM_(Spot_pskrep_get_count, "spot.pskrep.get_count") \
|
||||
\
|
||||
ELEM_(Wefax_state_string, "wefax.state_string") \
|
||||
ELEM_(Wefax_skip_apt, "wefax.skip_apt") \
|
||||
ELEM_(Wefax_skip_phasing, "wefax.skip_phasing") \
|
||||
ELEM_(Wefax_set_tx_abort_flag, "wefax.set_tx_abort_flag") \
|
||||
ELEM_(Wefax_end_reception, "wefax.end_reception") \
|
||||
ELEM_(Wefax_start_manual_reception, "wefax.start_manual_reception") \
|
||||
ELEM_(Wefax_set_adif_log, "wefax.set_adif_log") \
|
||||
ELEM_(Wefax_set_max_lines, "wefax.set_max_lines") \
|
||||
ELEM_(Wefax_get_received_file, "wefax.get_received_file") \
|
||||
ELEM_(Wefax_send_file, "wefax.send_file") \
|
||||
|
||||
|
||||
struct rm_pred
|
||||
|
|
|
@ -79,13 +79,22 @@ int mt63::tx_process()
|
|||
if (c == 0x03) {
|
||||
stopflag = true;
|
||||
flush = Tx->DataInterleave;
|
||||
c = 0;
|
||||
}
|
||||
|
||||
if (c == -1 || stopflag == true) c = 0;
|
||||
|
||||
if (stopflag && flush-- == 0) {
|
||||
if (stopflag) {
|
||||
stopflag = false;
|
||||
while (--flush) {
|
||||
Tx->SendChar(0);
|
||||
for (int i = 0; i < Tx->Comb.Output.Len; i++)
|
||||
if (fabs(Tx->Comb.Output.Data[i]) > maxval)
|
||||
maxval = fabs(Tx->Comb.Output.Data[i]);
|
||||
for (int i = 0; i < Tx->Comb.Output.Len; i++) {
|
||||
Tx->Comb.Output.Data[i] /= maxval;
|
||||
}
|
||||
ModulateXmtr((Tx->Comb.Output.Data), Tx->Comb.Output.Len);
|
||||
}
|
||||
Tx->SendJam();
|
||||
for (int i = 0; i < Tx->Comb.Output.Len; i++)
|
||||
if (fabs(Tx->Comb.Output.Data[i]) > maxval)
|
||||
|
|
|
@ -435,7 +435,9 @@ void cRsId::search(void)
|
|||
else {
|
||||
double centerfreq = active_modem->get_freq();
|
||||
nBinLow = (int)((centerfreq - 100.0 * RSID_RESOL) * 2048.0 / RSID_SAMPLE_RATE);
|
||||
if (nBinLow < RSID_RESOL + 1) nBinLow = RSID_RESOL + 1;
|
||||
nBinHigh = (int)((centerfreq + 100.0 * RSID_RESOL) * 2048.0 / RSID_SAMPLE_RATE);
|
||||
if (nBinHigh > RSID_FFT_SIZE -32) nBinHigh = RSID_FFT_SIZE;
|
||||
}
|
||||
|
||||
bool bReverse = !(wf->Reverse() ^ wf->USB());
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
modem *null_modem = 0;
|
||||
modem *cw_modem = 0;
|
||||
|
||||
modem *mfsk8_modem = 0;
|
||||
|
@ -248,6 +249,12 @@ void modem::set_metric(double m)
|
|||
metric = m;
|
||||
}
|
||||
|
||||
void modem::display_metric(double m)
|
||||
{
|
||||
set_metric(m);
|
||||
::global_display_metric(m);
|
||||
}
|
||||
|
||||
double modem::get_metric(void)
|
||||
{
|
||||
return metric;
|
||||
|
@ -990,5 +997,3 @@ mfntchr idch2[] = {
|
|||
{'}', { 0x00, 0x80, 0xC0, 0x40, 0x40, 0x40, 0x60, 0x60, 0x40, 0x40, 0x40, 0xC0, 0x80, 0x00 }, },
|
||||
{'~', { 0x00, 0x98, 0xFC, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// NULLMODEM.cxx -- NULLMODEM modem
|
||||
//
|
||||
// Copyright (C) 2006
|
||||
// Dave Freese, W1HKJ
|
||||
//
|
||||
// This file is part of fldigi. Adapted from code contained in gMFSK source code
|
||||
// distribution.
|
||||
// gMFSK Copyright (C) 2001, 2002, 2003
|
||||
// Tomi Manninen (oh2bns@sral.fi)
|
||||
//
|
||||
// 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 fldigi. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "nullmodem.h"
|
||||
#include "fl_digi.h"
|
||||
#include "ascii.h"
|
||||
|
||||
#define null_bw 1
|
||||
|
||||
NULLMODEM:: NULLMODEM() : modem()
|
||||
{
|
||||
mode = MODE_NULL;
|
||||
samplerate = 8000;
|
||||
restart();
|
||||
}
|
||||
|
||||
NULLMODEM::~NULLMODEM() {};
|
||||
|
||||
void NULLMODEM::tx_init(SoundBase *sc)
|
||||
{
|
||||
scard = sc;
|
||||
}
|
||||
|
||||
void NULLMODEM::rx_init()
|
||||
{
|
||||
put_MODEstatus(mode);
|
||||
}
|
||||
|
||||
void NULLMODEM::init()
|
||||
{
|
||||
modem::init();
|
||||
rx_init();
|
||||
digiscope->mode(Digiscope::SCOPE);
|
||||
}
|
||||
|
||||
void NULLMODEM::restart()
|
||||
{
|
||||
set_bandwidth(null_bw);
|
||||
}
|
||||
|
||||
|
||||
//=====================================================================
|
||||
// receive processing
|
||||
//=====================================================================
|
||||
|
||||
int NULLMODEM::rx_process(const double *buf, int len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
// transmit processing
|
||||
//=====================================================================
|
||||
|
||||
|
||||
int NULLMODEM::tx_process()
|
||||
{
|
||||
MilliSleep(10);
|
||||
if ( get_tx_char() == 0x03 || stopflag) {
|
||||
stopflag = false;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -37,6 +37,7 @@
|
|||
#include "misc.h"
|
||||
#include "configuration.h"
|
||||
#include "status.h"
|
||||
#include "dtmf.h"
|
||||
|
||||
#include "soundconf.h"
|
||||
#include "ringbuffer.h"
|
||||
|
@ -68,6 +69,7 @@ state_t trx_state;
|
|||
|
||||
modem *active_modem = 0;
|
||||
cRsId *ReedSolomon = 0;
|
||||
cDTMF *dtmf = 0;
|
||||
SoundBase *scard;
|
||||
static int _trx_tune;
|
||||
|
||||
|
@ -156,7 +158,6 @@ static void trx_xmit_wfall_end(int samplerate)
|
|||
void trx_xmit_wfall_queue(int samplerate, const double* buf, size_t len)
|
||||
{
|
||||
ENSURE_THREAD(TRX_TID);
|
||||
|
||||
ringbuffer<double>::vector_type wv[2];
|
||||
wv[0].buf = wv[1].buf = 0;
|
||||
|
||||
|
@ -256,6 +257,7 @@ void trx_trx_receive_loop()
|
|||
active_modem->rx_process(rbvec[0].buf, numread);
|
||||
if (progdefaults.rsid)
|
||||
ReedSolomon->receive(fbuf, numread);
|
||||
dtmf->receive(fbuf, numread);
|
||||
}
|
||||
else {
|
||||
bool afc = progStatus.afconoff;
|
||||
|
@ -286,7 +288,6 @@ void trx_trx_transmit_loop()
|
|||
MilliSleep(10);
|
||||
return;
|
||||
}
|
||||
|
||||
if (active_modem) {
|
||||
try {
|
||||
current_samplerate = active_modem->get_samplerate();
|
||||
|
@ -299,13 +300,21 @@ void trx_trx_transmit_loop()
|
|||
return;
|
||||
}
|
||||
|
||||
push2talk->set(true);
|
||||
if (active_modem != ssb_modem) {
|
||||
push2talk->set(true);
|
||||
REQ(&waterfall::set_XmtRcvBtn, wf, true);
|
||||
}
|
||||
active_modem->tx_init(scard);
|
||||
|
||||
if (progdefaults.TransmitRSid)
|
||||
if ((active_modem != null_modem &&
|
||||
active_modem != ssb_modem &&
|
||||
active_modem != wwv_modem ) &&
|
||||
progdefaults.TransmitRSid)
|
||||
ReedSolomon->send(true);
|
||||
|
||||
while (trx_state == STATE_TX) {
|
||||
if (active_modem != ssb_modem && !progdefaults.DTMFstr.empty())
|
||||
dtmf->send();
|
||||
try {
|
||||
if (active_modem->tx_process() < 0)
|
||||
trx_state = STATE_RX;
|
||||
|
@ -321,9 +330,6 @@ void trx_trx_transmit_loop()
|
|||
|
||||
trx_xmit_wfall_end(current_samplerate);
|
||||
|
||||
// if (progdefaults.TransmitRSid)
|
||||
// ReedSolomon->send(false);
|
||||
|
||||
scard->flush();
|
||||
if (scard->must_close(O_WRONLY))
|
||||
scard->Close(O_WRONLY);
|
||||
|
@ -333,6 +339,8 @@ void trx_trx_transmit_loop()
|
|||
|
||||
push2talk->set(false);
|
||||
REQ(&waterfall::set_XmtRcvBtn, wf, false);
|
||||
if (progStatus.timer)
|
||||
REQ(startMacroTimer);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@ -402,6 +410,17 @@ void *trx_loop(void *args)
|
|||
trxrb.reset();
|
||||
trx_signal_state();
|
||||
}
|
||||
/*
|
||||
printf("trx state %s\n",
|
||||
trx_state == STATE_ABORT ? "abort" :
|
||||
trx_state == STATE_ENDED ? "ended" :
|
||||
trx_state == STATE_RESTART ? "restart" :
|
||||
trx_state == STATE_NEW_MODEM ? "new modem" :
|
||||
trx_state == STATE_TX ? "tx" :
|
||||
trx_state == STATE_TUNE ? "tune" :
|
||||
trx_state == STATE_RX ? "rx" :
|
||||
"unknown");
|
||||
*/
|
||||
switch (trx_state) {
|
||||
case STATE_ABORT:
|
||||
delete scard;
|
||||
|
@ -421,8 +440,6 @@ void *trx_loop(void *args)
|
|||
break;
|
||||
case STATE_TX:
|
||||
trx_trx_transmit_loop();
|
||||
if (progStatus.timer)
|
||||
REQ(startMacroTimer);
|
||||
break;
|
||||
case STATE_TUNE:
|
||||
trx_tune_loop();
|
||||
|
@ -527,6 +544,7 @@ void trx_start(void)
|
|||
|
||||
if (scard) delete scard;
|
||||
if (ReedSolomon) delete ReedSolomon;
|
||||
if (dtmf) delete dtmf;
|
||||
|
||||
|
||||
switch (progdefaults.btnAudioIOis) {
|
||||
|
@ -553,6 +571,8 @@ void trx_start(void)
|
|||
}
|
||||
|
||||
ReedSolomon = new cRsId;
|
||||
dtmf = new cDTMF;
|
||||
|
||||
#endif // !BENCHMARK_MODE
|
||||
|
||||
#if USE_NAMED_SEMAPHORES
|
||||
|
|
|
@ -857,13 +857,25 @@ void WFdisp::update_waterfall() {
|
|||
if (active_modem->get_reverse()) {
|
||||
*pos1 = progdefaults.rttymarkRGBI;
|
||||
*pos2 = progdefaults.bwTrackRGBI;
|
||||
if (progdefaults.UseWideTracks) {
|
||||
*(pos1 + 1) = *pos1;
|
||||
*(pos2 - 1) = *pos2;
|
||||
}
|
||||
} else {
|
||||
*pos1 = progdefaults.bwTrackRGBI;
|
||||
*pos2 = progdefaults.rttymarkRGBI;
|
||||
if (progdefaults.UseWideTracks) {
|
||||
*(pos1 + 1) = *pos1;
|
||||
*(pos2 - 1) = *pos2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*pos1 = progdefaults.bwTrackRGBI;
|
||||
*pos2 = progdefaults.bwTrackRGBI;
|
||||
if (progdefaults.UseWideTracks) {
|
||||
*(pos1 + 1) = *pos1;
|
||||
*(pos2 - 1) = *pos2;
|
||||
}
|
||||
}
|
||||
pos1 += disp_width;
|
||||
pos2 += disp_width;
|
||||
|
@ -895,10 +907,16 @@ void WFdisp::drawcolorWF() {
|
|||
RGBI *pos2 = (fft_img + cursorpos + bw_hi/step);
|
||||
if (pos1 >= fft_img && pos2 < fft_img + disp_width)
|
||||
for (int y = 0; y < image_height; y ++) {
|
||||
if (progdefaults.UseCursorLines)
|
||||
if (progdefaults.UseCursorLines) {
|
||||
*pos1 = *pos2 = progdefaults.cursorLineRGBI;
|
||||
if (progdefaults.UseCursorCenterLine)
|
||||
if (progdefaults.UseWideCursor)
|
||||
*(pos1 + 1) = *(pos2 - 1) = *pos1;
|
||||
}
|
||||
if (progdefaults.UseCursorCenterLine) {
|
||||
*pos0 = progdefaults.cursorCenterRGBI;
|
||||
if (progdefaults.UseWideCenter)
|
||||
*(pos0 - 1) = *(pos0 + 1) = *pos0;
|
||||
}
|
||||
pos0 += disp_width;
|
||||
pos1 += disp_width;
|
||||
pos2 += disp_width;
|
||||
|
@ -1059,9 +1077,14 @@ void WFdisp::drawspectrum() {
|
|||
if (progdefaults.UseBWTracks) {
|
||||
uchar *pos1 = pixmap + (carrierfreq - offset - bandwidth/2) / step;
|
||||
uchar *pos2 = pixmap + (carrierfreq - offset + bandwidth/2) / step;
|
||||
if (pos1 >= pixmap && pos2 < pixmap + disp_width)
|
||||
if (pos1 >= pixmap &&
|
||||
pos2 < pixmap + disp_width)
|
||||
for (int y = 0; y < image_height; y ++) {
|
||||
*pos1 = *pos2 = 255;
|
||||
if (progdefaults.UseWideTracks) {
|
||||
*(pos1 + 1) = 255;
|
||||
*(pos2 - 1) = 255;
|
||||
}
|
||||
pos1 += IMAGE_WIDTH/step;
|
||||
pos2 += IMAGE_WIDTH/step;
|
||||
}
|
||||
|
@ -1076,10 +1099,15 @@ void WFdisp::drawspectrum() {
|
|||
uchar *pos1 = (pixmap + cursorpos - bw_lo/step);
|
||||
uchar *pos2 = (pixmap + cursorpos + bw_hi/step);
|
||||
for (int y = 0; y < h1; y ++) {
|
||||
if (progdefaults.UseCursorLines)
|
||||
if (progdefaults.UseCursorLines) {
|
||||
*pos1 = *pos2 = 255;
|
||||
if (progdefaults.UseCursorCenterLine)
|
||||
if (progdefaults.UseWideCursor)
|
||||
*(pos1 + 1) = *(pos2 - 1) = *pos1;
|
||||
}
|
||||
if (progdefaults.UseCursorCenterLine) {
|
||||
*pos0 = 255;
|
||||
if (progdefaults.UseWideCenter) *(pos0-1) = *(pos0+1) = *(pos0);
|
||||
}
|
||||
pos0 += IMAGE_WIDTH/step;
|
||||
pos1 += IMAGE_WIDTH/step;
|
||||
pos2 += IMAGE_WIDTH/step;
|
||||
|
|
|
@ -91,14 +91,20 @@ static Fl_Choice *wefax_choice_tx_lpm = (Fl_Choice *)0;
|
|||
static Fl_Round_Button *wefax_round_tx_adif_log = (Fl_Round_Button *)0;
|
||||
static Fl_Button *wefax_btn_tx_send_color = (Fl_Button *)0;
|
||||
static Fl_Button *wefax_btn_tx_send_grey = (Fl_Button *)0;
|
||||
static Fl_Output *wefax_out_tx_row_num = (Fl_Output *)0;
|
||||
static Fl_Button *wefax_btn_tx_send_abort = (Fl_Button *)0;
|
||||
static Fl_Button *wefax_btn_tx_load = (Fl_Button *)0;
|
||||
static Fl_Button *wefax_btn_tx_clear = (Fl_Button *)0;
|
||||
static Fl_Button *wefax_btn_tx_close = (Fl_Button *)0;
|
||||
|
||||
static Fl_Shared_Image *wefax_shared_tx_img = (Fl_Shared_Image *)0;
|
||||
static unsigned char *wefax_xmtimg = (unsigned char *)0;
|
||||
static unsigned char *wefax_xmtpicbuff = (unsigned char *)0;
|
||||
|
||||
/// This indicates whether an image to send is loaded in the GUI.
|
||||
/// It allows to acquire twice when re-loading an image without sending.
|
||||
static bool wefax_image_loaded_in_gui = false ;
|
||||
|
||||
/// Used for shifting the received image left and right.
|
||||
static volatile int center_val_prev = 0 ;
|
||||
|
||||
|
@ -144,6 +150,43 @@ static const int mini_max_fax_lines = 1000 ;
|
|||
/// However, when the printing resumes, the position is not altered.
|
||||
static volatile bool reception_paused = false ;
|
||||
|
||||
/// Sets the label of the received or sent image.
|
||||
static void set_win_label( Fl_Double_Window * wefax_pic, const std::string & lab)
|
||||
{
|
||||
char* label = strdup(lab.c_str());
|
||||
wefax_pic->copy_label(label);
|
||||
free(label);
|
||||
wefax_pic->redraw();
|
||||
}
|
||||
|
||||
/// Called when clearing the image to send.
|
||||
static void clear_image(void)
|
||||
{
|
||||
if (wefax_xmtimg)
|
||||
{
|
||||
delete [] wefax_xmtimg;
|
||||
wefax_xmtimg = NULL ;
|
||||
}
|
||||
if (wefax_shared_tx_img) {
|
||||
wefax_shared_tx_img->release();
|
||||
wefax_shared_tx_img = 0;
|
||||
}
|
||||
set_win_label(wefax_pic_tx_win,"");
|
||||
}
|
||||
|
||||
/// Clears the loaded image. It allows XML-RPC clients to send an image.
|
||||
static void wefax_cb_pic_tx_clear( Fl_Widget *, void *)
|
||||
{
|
||||
FL_LOCK_D();
|
||||
wefax_image_loaded_in_gui = false ;
|
||||
clear_image();
|
||||
wefax_pic_tx_picture->clear();
|
||||
wefax_pic::restart_tx_viewer();
|
||||
/// Now the lock can be acquired by XML-RPC.
|
||||
wefax_serviceme->transmit_lock_release( "Cleared" );
|
||||
FL_UNLOCK_D();
|
||||
}
|
||||
|
||||
static void wefax_cb_pic_tx_close( Fl_Widget *, void *)
|
||||
{
|
||||
FL_LOCK_D();
|
||||
|
@ -386,8 +429,7 @@ void wefax_pic::update_rx_pic_bw(unsigned char data, int pix_pos )
|
|||
/// Prints the row number sometimes only, to save CPU.
|
||||
if( ( pix_pos % 1000 ) == 0 ) {
|
||||
char row_num_buffer[20];
|
||||
snprintf( row_num_buffer, sizeof(row_num_buffer),
|
||||
"%d", row_number );
|
||||
snprintf( row_num_buffer, sizeof(row_num_buffer), "%d", row_number );
|
||||
wefax_out_rx_row_num->value( row_num_buffer );
|
||||
}
|
||||
|
||||
|
@ -439,6 +481,15 @@ static void wefax_cb_pic_rx_resume( Fl_Widget *, void *)
|
|||
wefax_serviceme->update_rx_label();
|
||||
}
|
||||
|
||||
static void LocalSleep( int seconds )
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
MilliSleep(seconds);
|
||||
#else
|
||||
usleep(100000*seconds);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Displays the latest image file saved.
|
||||
static void add_to_files_list( const std::string & the_fil_nam )
|
||||
{
|
||||
|
@ -459,22 +510,21 @@ static void add_to_files_list( const std::string & the_fil_nam )
|
|||
/// This window is hidden/shown to signal that a file was added.
|
||||
static const int nb_blink = 5 ;
|
||||
for( int ix_blink = 0 ; ix_blink < nb_blink ; ++ix_blink ) {
|
||||
#ifdef __MINGW32__
|
||||
wefax_browse_rx_events->hide();
|
||||
wefax_browse_rx_events->redraw();
|
||||
MilliSleep(1);
|
||||
LocalSleep(1);
|
||||
wefax_browse_rx_events->show();
|
||||
wefax_browse_rx_events->redraw();
|
||||
MilliSleep(1);
|
||||
#else
|
||||
wefax_browse_rx_events->hide();
|
||||
wefax_browse_rx_events->redraw();
|
||||
usleep(100000);
|
||||
wefax_browse_rx_events->show();
|
||||
wefax_browse_rx_events->redraw();
|
||||
usleep(100000);
|
||||
#endif
|
||||
LocalSleep(1);
|
||||
}
|
||||
|
||||
/// If there is not directory specification, adds the default dir.
|
||||
if( the_fil_nam.empty() )
|
||||
LOG_WARN("Empty file name");
|
||||
else if( the_fil_nam[0] != '/' )
|
||||
wefax_serviceme->put_received_file( progdefaults.wefax_save_dir + '/' + the_fil_nam );
|
||||
else
|
||||
wefax_serviceme->put_received_file( the_fil_nam );
|
||||
};
|
||||
|
||||
static void wefax_cb_pic_rx_abort( Fl_Widget *, void *)
|
||||
|
@ -628,7 +678,7 @@ static void wefax_cb_rx_set_filter( Fl_Widget *, void * )
|
|||
wefax_serviceme->set_rx_filter(ix_filter);
|
||||
}
|
||||
|
||||
static void restore_max_lines(void)
|
||||
void wefax_pic::restore_max_lines(void)
|
||||
{
|
||||
char buf_max_lines[20];
|
||||
snprintf( buf_max_lines, sizeof(buf_max_lines), "%d", wefax_serviceme->get_max_lines() );
|
||||
|
@ -643,15 +693,15 @@ static void wefax_cb_pic_max_lines( Fl_Widget *, void * )
|
|||
|
||||
/// The value given by FLTK should be an integer, but better to be sure.
|
||||
if( 1 != sscanf( ptr_val_gui, "%d", &max_val_gui ) ) {
|
||||
LOG_ERROR( "Cannot parse: %s", ptr_val_gui ) ;
|
||||
restore_max_lines();
|
||||
LOG_ERROR( _("Cannot parse: %s"), ptr_val_gui ) ;
|
||||
wefax_pic::restore_max_lines();
|
||||
return ;
|
||||
}
|
||||
|
||||
/// Faxes should not be too small otherwise we will spend all our time
|
||||
/// saving automatic image files.
|
||||
if( max_val_gui < mini_max_fax_lines ) {
|
||||
restore_max_lines();
|
||||
wefax_pic::restore_max_lines();
|
||||
return ;
|
||||
}
|
||||
|
||||
|
@ -952,7 +1002,7 @@ void wefax_pic::create_rx_viewer(void)
|
|||
/// This buffer will never change so it does not matter if it is static.
|
||||
static char tooltip_max_lines[256];
|
||||
snprintf(tooltip_max_lines, sizeof(tooltip_max_lines),
|
||||
"Maximum number of lines per image. Must be bigger than %d",
|
||||
"Maximum number of lines per image. Minimum value is %d",
|
||||
mini_max_fax_lines );
|
||||
wefax_int_rx_max->tooltip(tooltip_max_lines);
|
||||
|
||||
|
@ -1068,11 +1118,7 @@ void wefax_pic::set_rx_label(const std::string & win_label)
|
|||
}
|
||||
|
||||
/// This copy seems strange, but otherwise the label is not updated.
|
||||
char* label = strdup(tmp_label.c_str());
|
||||
wefax_pic_rx_win->copy_label(label);
|
||||
free(label);
|
||||
|
||||
wefax_pic_rx_win->redraw_label();
|
||||
set_win_label(wefax_pic_rx_win, tmp_label);
|
||||
FL_UNLOCK_D();
|
||||
}
|
||||
|
||||
|
@ -1090,33 +1136,31 @@ void wefax_pic::save_image(const std::string & fil_name, const std::string & ext
|
|||
wefax_serviceme->qso_rec_save();
|
||||
}
|
||||
|
||||
static void wefax_load_image(const char *fil_name)
|
||||
/// Protected by an exclusive mutex.
|
||||
static std::string wefax_load_image_after_acquire(const char * fil_name)
|
||||
{
|
||||
if (wefax_serviceme != active_modem) return;
|
||||
if (wefax_serviceme != active_modem) return "Not in WEFAX mode";
|
||||
|
||||
wefax_serviceme->qso_rec_init();
|
||||
qso_notes( "TX:", fil_name );
|
||||
|
||||
if (wefax_shared_tx_img) {
|
||||
wefax_shared_tx_img->release();
|
||||
wefax_shared_tx_img = 0;
|
||||
}
|
||||
clear_image();
|
||||
wefax_shared_tx_img = Fl_Shared_Image::get(fil_name);
|
||||
if (!wefax_shared_tx_img) {
|
||||
LOG_ERROR("Could not Fl_Shared_Image::get %s", fil_name);
|
||||
return;
|
||||
std::string err_msg("Cannot call Fl_Shared_Image::get on file:" + std::string(fil_name) );
|
||||
LOG_ERROR("%s",err_msg.c_str());
|
||||
return err_msg;
|
||||
}
|
||||
if (wefax_shared_tx_img->count() > 1) { // we only handle rgb images
|
||||
LOG_ERROR("Handle only RGB images: %s", fil_name );
|
||||
wefax_shared_tx_img->release();
|
||||
wefax_shared_tx_img = 0;
|
||||
return;
|
||||
std::string err_msg("Handle only RGB images: " + std::string(fil_name) );
|
||||
LOG_ERROR("%s",err_msg.c_str());
|
||||
clear_image();
|
||||
return err_msg;
|
||||
}
|
||||
unsigned char * img_data = (unsigned char *)wefax_shared_tx_img->data()[0];
|
||||
int img_wid = wefax_shared_tx_img->w();
|
||||
int img_hei = wefax_shared_tx_img->h();
|
||||
int img_depth = wefax_shared_tx_img->d();
|
||||
if (wefax_xmtimg) delete [] wefax_xmtimg;
|
||||
wefax_xmtimg = new unsigned char [img_wid * img_hei * bytes_per_pix];
|
||||
if (img_depth == bytes_per_pix)
|
||||
memcpy(wefax_xmtimg, img_data, img_wid*img_hei*bytes_per_pix);
|
||||
|
@ -1135,22 +1179,23 @@ static void wefax_load_image(const char *fil_name)
|
|||
wefax_xmtimg[j] = wefax_xmtimg[j+1] = wefax_xmtimg[j+2] = img_data[i];
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR( "Inconsistent img_depth=%d\n", img_depth );
|
||||
exit(EXIT_FAILURE);
|
||||
std::stringstream err_strm ;
|
||||
err_strm << "Inconsistent img_depth=" << img_depth << " for " << fil_name ;
|
||||
std::string err_msg = err_strm.str();
|
||||
LOG_ERROR("%s",err_msg.c_str());
|
||||
return err_msg ;
|
||||
};
|
||||
|
||||
wefax_pic::tx_viewer_resize(img_wid, img_hei);
|
||||
|
||||
char* label = strdup(fil_name);
|
||||
wefax_pic_tx_win->copy_label(basename(label));
|
||||
free(label);
|
||||
set_win_label(wefax_pic_tx_win, fil_name);
|
||||
|
||||
wefax_pic_tx_box->label(0);
|
||||
|
||||
// load the picture widget with the rgb image
|
||||
FL_LOCK_D();
|
||||
wefax_pic_tx_picture->show();
|
||||
wefax_pic_tx_picture->clear();
|
||||
wefax_pic_tx_win->redraw();
|
||||
wefax_pic_tx_picture->video(wefax_xmtimg, img_wid * img_hei * bytes_per_pix);
|
||||
|
||||
int tim_color = wefax_serviceme->tx_time( img_wid * img_hei * bytes_per_pix );
|
||||
|
@ -1167,7 +1212,22 @@ static void wefax_load_image(const char *fil_name)
|
|||
wefax_btn_tx_send_grey->tooltip(wefax_txgry_tooltip);
|
||||
wefax_btn_tx_send_grey->activate();
|
||||
|
||||
wefax_btn_tx_clear->activate();
|
||||
|
||||
FL_UNLOCK_D();
|
||||
return std::string();
|
||||
}
|
||||
|
||||
static void wefax_load_image(const char * fil_name)
|
||||
{
|
||||
if (wefax_serviceme != active_modem) return;
|
||||
if( false == wefax_image_loaded_in_gui )
|
||||
{
|
||||
/// So we do not re-acquire the exclusive access to wefax transmission.
|
||||
wefax_serviceme->transmit_lock_acquire(fil_name);
|
||||
wefax_image_loaded_in_gui = true ;
|
||||
}
|
||||
wefax_load_image_after_acquire(fil_name);
|
||||
}
|
||||
|
||||
void wefax_pic::set_tx_pic(unsigned char data, int col, int row, int tx_img_col, bool is_color )
|
||||
|
@ -1190,6 +1250,15 @@ void wefax_pic::set_tx_pic(unsigned char data, int col, int row, int tx_img_col,
|
|||
wefax_pic_tx_picture->pixel( data, tripleOffset + 1 );
|
||||
wefax_pic_tx_picture->pixel( data, tripleOffset + 2 );
|
||||
}
|
||||
|
||||
static int previous_row = -1 ;
|
||||
if( row != previous_row )
|
||||
{
|
||||
previous_row = row ;
|
||||
char row_num_buffer[20];
|
||||
snprintf( row_num_buffer, sizeof(row_num_buffer), "%d", row );
|
||||
wefax_out_tx_row_num->value( row_num_buffer );
|
||||
}
|
||||
}
|
||||
|
||||
static void wefax_cb_pic_tx_load(Fl_Widget *, void *)
|
||||
|
@ -1218,13 +1287,18 @@ static void wefax_pic_tx_send_common(
|
|||
FL_LOCK_D();
|
||||
|
||||
wefax_choice_tx_lpm->hide();
|
||||
wefax_round_tx_adif_log->hide();
|
||||
wefax_btn_tx_send_color->hide();
|
||||
wefax_btn_tx_send_grey->hide();
|
||||
wefax_btn_tx_load->hide();
|
||||
wefax_btn_tx_clear->hide();
|
||||
wefax_btn_tx_close->hide();
|
||||
wefax_out_tx_row_num->show();
|
||||
wefax_btn_tx_send_abort->show();
|
||||
wefax_pic_tx_picture->clear();
|
||||
|
||||
wefax_out_tx_row_num->value( "Init" );
|
||||
|
||||
wefax_serviceme->set_tx_parameters(
|
||||
get_choice_lpm_value( wefax_choice_tx_lpm ),
|
||||
wefax_xmtpicbuff,
|
||||
|
@ -1306,12 +1380,27 @@ static void wefax_cb_pic_tx_adif_log( Fl_Widget *, void *)
|
|||
|
||||
void wefax_pic::restart_tx_viewer(void)
|
||||
{
|
||||
wefax_out_tx_row_num->hide();
|
||||
wefax_btn_tx_send_abort->hide();
|
||||
wefax_choice_tx_lpm->show();
|
||||
wefax_btn_tx_send_color->show();
|
||||
wefax_btn_tx_send_grey->show();
|
||||
wefax_round_tx_adif_log->show();
|
||||
wefax_btn_tx_load->show();
|
||||
wefax_btn_tx_close->show();
|
||||
if( wefax_image_loaded_in_gui )
|
||||
{
|
||||
// If the image was loaded from the GUI.
|
||||
wefax_choice_tx_lpm->show();
|
||||
wefax_btn_tx_send_color->show();
|
||||
wefax_btn_tx_send_grey->show();
|
||||
wefax_btn_tx_clear->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
/// If the image was loaded and sent from XML-RPC, or no image present.
|
||||
wefax_choice_tx_lpm->deactivate();
|
||||
wefax_btn_tx_send_color->deactivate();
|
||||
wefax_btn_tx_send_grey->deactivate();
|
||||
wefax_btn_tx_clear->deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void wefax_pic::create_tx_viewer(void)
|
||||
|
@ -1351,7 +1440,7 @@ void wefax_pic::create_tx_viewer(void)
|
|||
static const int hei_tx_btn = 24 ;
|
||||
|
||||
int width_btn = 0;
|
||||
int width_offset = 35;
|
||||
int width_offset = 30;
|
||||
|
||||
width_btn = 70 ;
|
||||
wefax_choice_tx_lpm = make_lpm_choice( width_offset, y_btn, width_btn, hei_tx_btn );
|
||||
|
@ -1366,33 +1455,46 @@ void wefax_pic::create_tx_viewer(void)
|
|||
wefax_round_tx_adif_log->align(FL_ALIGN_LEFT);
|
||||
|
||||
width_offset += width_btn ;
|
||||
width_btn = 60 ;
|
||||
wefax_btn_tx_send_color = new Fl_Button(width_offset, y_btn, width_btn, hei_tx_btn, "Xmt Color");
|
||||
width_btn = 50 ;
|
||||
wefax_btn_tx_send_color = new Fl_Button(width_offset, y_btn, width_btn, hei_tx_btn, "Tx Color");
|
||||
wefax_btn_tx_send_color->callback(wefax_cb_pic_tx_send_color, 0);
|
||||
|
||||
width_offset += width_btn ;
|
||||
width_btn = 60 ;
|
||||
wefax_btn_tx_send_grey = new Fl_Button(width_offset, y_btn, width_btn, hei_tx_btn, "Xmt Grey");
|
||||
width_btn = 50 ;
|
||||
wefax_btn_tx_send_grey = new Fl_Button(width_offset, y_btn, width_btn, hei_tx_btn, "Tx B/W");
|
||||
wefax_btn_tx_send_grey->callback( wefax_cb_pic_tx_send_grey, 0);
|
||||
|
||||
width_offset += width_btn ;
|
||||
width_btn = 40 ;
|
||||
width_btn = 35 ;
|
||||
wefax_btn_tx_load = new Fl_Button(width_offset, y_btn, width_btn, hei_tx_btn, _("Load"));
|
||||
wefax_btn_tx_load->callback(wefax_cb_pic_tx_load, 0);
|
||||
wefax_btn_tx_load->tooltip("Load image to send");
|
||||
|
||||
width_offset += width_btn ;
|
||||
width_btn = 40 ;
|
||||
width_btn = 35 ;
|
||||
wefax_btn_tx_clear = new Fl_Button(width_offset, y_btn, width_btn, hei_tx_btn, _("Clear"));
|
||||
wefax_btn_tx_clear->callback(wefax_cb_pic_tx_clear, 0);
|
||||
|
||||
width_offset += width_btn ;
|
||||
width_btn = 35 ;
|
||||
wefax_btn_tx_close = new Fl_Button(width_offset, y_btn, width_btn, hei_tx_btn, _("Close"));
|
||||
wefax_btn_tx_close->callback(wefax_cb_pic_tx_close, 0);
|
||||
|
||||
wefax_btn_tx_send_abort = new Fl_Button(84, y_btn, 122, hei_tx_btn, "Abort Xmt");
|
||||
static const char * title_row_num = "" ;
|
||||
width_offset += fl_width( title_row_num );
|
||||
wefax_out_tx_row_num = new Fl_Output(20, y_btn, 100, hei_tx_btn, _(title_row_num));
|
||||
wefax_out_tx_row_num->align(FL_ALIGN_LEFT);
|
||||
wefax_out_tx_row_num->tooltip("Fax line number being sent.");
|
||||
|
||||
wefax_btn_tx_send_abort = new Fl_Button(180, y_btn, 122, hei_tx_btn, "Abort Xmt");
|
||||
wefax_btn_tx_send_abort->callback(wefax_cb_pic_tx_send_abort, 0);
|
||||
wefax_btn_tx_send_abort->tooltip("Abort transmission");
|
||||
|
||||
wefax_out_tx_row_num->hide();
|
||||
wefax_btn_tx_send_abort->hide();
|
||||
wefax_btn_tx_send_color->deactivate();
|
||||
wefax_btn_tx_send_grey->deactivate();
|
||||
wefax_btn_tx_clear->deactivate();
|
||||
|
||||
wefax_pic_tx_win->end();
|
||||
FL_UNLOCK_D();
|
||||
|
@ -1511,4 +1613,21 @@ void wefax_pic::cb_mnu_pic_viewer(Fl_Menu_ *, void *) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Called from XML-RPC thread.
|
||||
void wefax_pic::send_image( const std::string & fil_nam )
|
||||
{
|
||||
LOG_INFO("%s", fil_nam.c_str() );
|
||||
/// Here, transmit_lock_acquire is called by the XML-RPC client.
|
||||
std::string err_msg = wefax_load_image_after_acquire( fil_nam.c_str() );
|
||||
if( ! err_msg.empty() )
|
||||
{
|
||||
if (wefax_serviceme == active_modem)
|
||||
{
|
||||
/// Allows another XML-RPC client or the GUI to send an image.
|
||||
wefax_serviceme->transmit_lock_release( err_msg );
|
||||
}
|
||||
return ;
|
||||
}
|
||||
wefax_cb_pic_tx_send_grey( NULL, NULL );
|
||||
}
|
||||
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -273,6 +273,7 @@ void Fl_Text_Buffer_mod::replace( int start, int end, const char *s ) {
|
|||
// Range check...
|
||||
if (!s) return;
|
||||
if (start < 0) start = 0;
|
||||
if (end < 0) end = 0;
|
||||
if (end > mLength) end = mLength;
|
||||
|
||||
call_predelete_callbacks( start, end-start );
|
||||
|
|
|
@ -335,6 +335,8 @@ void Fl_Text_Buffer_mod::replace(int start, int end, const char *text)
|
|||
return;
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (end < 0)
|
||||
end = 0;
|
||||
if (end > mLength)
|
||||
end = mLength;
|
||||
|
||||
|
|
|
@ -46,8 +46,6 @@ void wwv::rx_init()
|
|||
phaseacc = 0.0;
|
||||
smpl_ctr = 0; // sample counter for timing wwv rx
|
||||
agc = 0.0; // threshold for tick detection
|
||||
// sync = 0;
|
||||
// sync0 = 0;
|
||||
ticks = 0;
|
||||
calc = false;
|
||||
zoom = false;
|
||||
|
@ -87,8 +85,8 @@ wwv::wwv() : modem()
|
|||
lpfilter->init_lowpass (FIRLEN_1, DEC_1, lp);
|
||||
|
||||
vidfilter = new Cmovavg(16);
|
||||
|
||||
cap &= ~CAP_TX;
|
||||
|
||||
makeaudio();
|
||||
}
|
||||
|
||||
|
||||
|
@ -165,3 +163,58 @@ void wwv::set2(int x, int y)
|
|||
zoom = !zoom;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// transmit time tick
|
||||
//======================================================================
|
||||
|
||||
void wwv::makeshape()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
keyshape[i] = 0.5 * (1.0 - cos (M_PI * i / 32));
|
||||
}
|
||||
|
||||
double wwv::nco(double freq)
|
||||
{
|
||||
phaseacc += 2.0 * M_PI * freq / samplerate;
|
||||
|
||||
if (phaseacc > M_PI)
|
||||
phaseacc -= 2.0 * M_PI;
|
||||
|
||||
return sin(phaseacc);
|
||||
}
|
||||
|
||||
void wwv::makeaudio()
|
||||
{
|
||||
phaseacc = 0.0;
|
||||
makeshape();
|
||||
for (int i = 0; i < 400; i++) {
|
||||
audio[i] = (i < 200 ? nco(1000) : 0);
|
||||
quiet[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < 32; i++) {
|
||||
audio[i] *= keyshape[i];
|
||||
audio[199 - i] *= keyshape[i];
|
||||
}
|
||||
}
|
||||
|
||||
int wwv::tx_process()
|
||||
{
|
||||
static int cycle = 4;
|
||||
int c = get_tx_char();
|
||||
|
||||
if (c == 0x03 || stopflag) {
|
||||
stopflag = false;
|
||||
return -1;
|
||||
}
|
||||
if (--cycle == 0) {
|
||||
memcpy(play, audio, 400 * sizeof(double));
|
||||
ModulateXmtr(play, 400);
|
||||
cycle = 4;
|
||||
} else
|
||||
ModulateXmtr(quiet, 400);
|
||||
ModulateXmtr(quiet, 400);
|
||||
ModulateXmtr(quiet, 400);
|
||||
ModulateXmtr(quiet, 400);
|
||||
ModulateXmtr(quiet, 400);
|
||||
return 0;
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue