Inline macro tags

* Created ability to delay execution of designated tags
    until the time of occurrence in the transmit character
    stream.  These include:
      - <DTMF    - dual tones
      - <!WPM    - CW words per minute
      - <!POST   - CW post delay
      - <!PRE    - CW pre delay
      - <!RISE   - CW rise/decay time
      - <!MODEM  - change to specified modem
      - <!GOHOME - move to mode sweet spot audio frequency
      - <!GOFREQ - move to a specific audio frequency
      - <!IDLE   - idle for specified number of seconds
      - <!WAIT   - wait for specified number of seconds
      - <!QSY    - move to specifed RF and Audio frequency
    The <! tags use the same parameters as their non delayed
    counterparts
  * Added NULL modem, a device which does not receive
    but can enable transmit.
    - used as modem type before !QSY, !GOFREQ etc to suppress
      transmit of audio stream
    - used with <DTMF... to transmit DTMF tones and suppress any
      other modem audio stream
  * Changed end of transmission logic to MT63 modem to allow it
    to be specified in <!MODEM
  * Corrected string to numeric conversion
  * Added abort processing / queue reset
  * Modified macro parsing to allow multiple
    invocations of macro containing <! tags
  * Added ability to schedule a single macro execution
    at a specifice GMT date and time
    tag format <SKED:hhmm[:YYYYDDMM]>
    where the date defaults to current date.
pull/2/head
David Freese 2011-09-21 08:39:40 -05:00
rodzic d2c33e4889
commit bb258cd1fc
16 zmienionych plików z 794 dodań i 86 usunięć

Wyświetl plik

@ -368,6 +368,7 @@ 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 \
@ -480,6 +481,7 @@ fldigi_SOURCES += \
ssb/ssb.cxx \
throb/throb.cxx \
trx/modem.cxx \
trx/nullmodem.cxx \
trx/trx.cxx \
waterfall/colorbox.cxx \
waterfall/digiscope.cxx \

Wyświetl plik

@ -77,6 +77,7 @@
#endif
#include "rigio.h"
#include "rigMEM.h"
#include "nullmodem.h"
#include "psk.h"
#include "cw.h"
#include "mfsk.h"
@ -970,6 +971,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);
@ -2220,6 +2226,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);
@ -2240,6 +2247,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();
@ -3017,6 +3050,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},
@ -3631,7 +3665,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();
@ -4273,14 +4307,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());
@ -4452,14 +4486,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());
@ -4817,6 +4851,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},
@ -5608,10 +5643,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();
@ -5619,24 +5699,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++;
@ -5648,12 +5723,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';
@ -5663,6 +5741,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)
@ -5671,6 +5751,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;
@ -5688,6 +5770,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;
@ -5870,7 +5965,6 @@ void start_tx()
if (!(active_modem->get_cap() & modem::CAP_TX))
return;
trx_transmit();
REQ(&waterfall::set_XmtRcvBtn, wf, true);
}
void abort_tx()
@ -5881,6 +5975,7 @@ void abort_tx()
return;
}
if (trx_state == STATE_TX) {
queue_reset();
trx_start_modem(active_modem);
}
}

Wyświetl plik

@ -235,8 +235,6 @@ void cDTMF::two_tones(int ch)
void cDTMF::send()
{
if (progdefaults.DTMFstr.empty()) return;
int c = 0, delay = 0;
duration = 50;
RT = (int)(active_modem->get_samplerate() * 4 / 1000.0); // 4 msec edge

Wyświetl plik

@ -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" },

Wyświetl plik

@ -148,6 +148,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();
@ -214,6 +217,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();
@ -259,6 +266,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();

Wyświetl plik

@ -49,6 +49,8 @@ enum {
MODE_PREV = -2,
MODE_NEXT,
MODE_NULL,
MODE_CW,
MODE_CONTESTIA,

Wyświetl plik

@ -36,9 +36,10 @@ 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;
@ -53,6 +54,15 @@ 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;
void set_macro_env(void);
void queue_reset();
void queue_execute();
bool queue_must_rx();
void idleTimer(void *);
#endif

Wyświetl plik

@ -181,6 +181,8 @@ protected:
virtual void s2nreport(void);
};
extern modem *null_modem;
extern modem *cw_modem;
extern modem *mfsk8_modem;

Wyświetl plik

@ -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

Wyświetl plik

@ -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;

Wyświetl plik

@ -52,12 +52,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;
@ -151,6 +151,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"));
@ -240,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();
@ -264,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 *)
@ -315,30 +316,30 @@ void cbInsertMacro(Fl_Widget *, void *)
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 = new Fl_Input2(2, 22, 450, 140, _("Macro Text"));
macrotext->type(FL_MULTILINE_INPUT);
macrotext->textfont(FL_COURIER);
macrotext->align(FL_ALIGN_TOP_LEFT);
macrotext->align(FL_ALIGN_TOP);
btnInsertMacro = new Fl_Button(454, 86, 20, 20);
btnInsertMacro = new Fl_Button(434, 2, 40, 20);
btnInsertMacro->image(new Fl_Pixmap(left_arrow_icon));
btnInsertMacro->callback(cbInsertMacro);
macroDefs = new Fl_Hold_Browser(476, 22, 290, 140, _("Select Tags:"));
macroDefs = new Fl_Hold_Browser(452, 22, 346, 140, _("Select Tag"));
macroDefs->column_widths(widths);
macroDefs->align(FL_ALIGN_TOP_LEFT);
macroDefs->align(FL_ALIGN_TOP);
loadBrowser(macroDefs);
labeltext = new Fl_Input2(2 + 450 - 115, 164, 115, 24, _("Macro Button Label:"));
labeltext->textfont(FL_COURIER);
btnMacroEditOK = new Fl_Button(476 + 145 - 80 - 1, 164, 80, 24, _("OK"));
btnMacroEditOK->callback(cbMacroEditOK);
btnMacroEditApply = new Fl_Button(452 + macroDefs->w()/2 - 80 - 1, 164, 80, 24, _("Apply"));
btnMacroEditApply->callback(cbMacroEditOK);
btnMacroEditCancel = new Fl_Button(476 + 145 + 1 , 164, 80, 24, _("Cancel"));
btnMacroEditCancel->callback(cbMacroEditOK);
btnMacroEditClose = new Fl_Button(452 + macroDefs->w()/2 + 1 , 164, 80, 24, _("Close"));
btnMacroEditClose->callback(cbMacroEditOK);
w->end();
w->xclass(PACKAGE_NAME);

Wyświetl plik

@ -55,6 +55,7 @@
#include <unistd.h>
#include <string>
#include <fstream>
#include <queue>
#ifdef __WIN32__
#include "speak.h"
@ -62,6 +63,17 @@
using namespace std;
struct CMDS { string cmd; void (*fp)(string); };
queue<CMDS> cmds;
// following used for debugging and development
//void pushcmd(CMDS cmd)
//{
// LOG_INFO("%s, # = %d", cmd.cmd.c_str(), (int)cmds.size());
// cmds.push(cmd);
//}
#define pushcmd(a) cmds.push((a))
MACROTEXT macros;
CONTESTCNTR contest_count;
static bool TransmitON = false;
@ -70,20 +82,24 @@ static int mNbr;
std::string qso_time = "";
std::string qso_exchange = "";
static bool save_xchg;
static size_t xbeg = 0, xend = 0;
string text2send = "";
string text2repeat = "";
string text2save = "";
std::string exec_date = "";
std::string exec_time = "";
std::string exec_string = "";
std::string text2send = "";
std::string text2repeat = "";
//std::string text2save = "";
std::string info1msg = "";
std::string info2msg = "";
size_t repeatchar = 0;
static size_t xbeg = 0, xend = 0;
static bool save_xchg;
static bool expand;
static bool GET = false;
string info1msg = "";
string info2msg = "";
static bool timed_exec = false;
static char cutnumbers[] = "T12345678N";
static string cutstr;
@ -204,6 +220,107 @@ static void pPOST(string &s, size_t &i, size_t endbracket)
s.replace(i, endbracket - i + 1, "");
}
static void setwpm(int d)
{
sldrCWxmtWPM->value(d);
cntCW_WPM->value(d);
}
static void doWPM(string s)
{
int number;
string sTime = s.substr(6);
if (sTime.length() > 0) {
sscanf(sTime.c_str(), "%d", &number);
if (number < 5) number = 5;
if (number > 200) number = 200;
progdefaults.CWspeed = number;
REQ(setwpm, number);
}
}
static void pQueWPM(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doWPM };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static void setRISETIME(int d)
{
cntCWrisetime->value(d);
}
static void doRISETIME(string s)
{
float number;
string sVal = s.substr(7, s.length() - 8);
if (sVal.length() > 0) {
sscanf(sVal.c_str(), "%f", &number);
if (number < 0) number = 0;
if (number > 20) number = 20;
progdefaults.CWrisetime = number;
REQ(setRISETIME, number);
}
}
static void pQueRISETIME(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doRISETIME };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static void setPRE(int d)
{
cntPreTiming->value(d);
}
static void doPRE(string s)
{
float number;
string sVal = s.substr(6, s.length() - 7);
if (sVal.length() > 0) {
sscanf(sVal.c_str(), "%f", &number);
if (number < 0) number = 0;
if (number > 20) number = 20;
progdefaults.CWpre = number;
REQ(setPRE, number);
}
}
static void pQuePRE(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doPRE };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static void setPOST(int d)
{
cntPostTiming->value(d);
}
static void doPOST(string s)
{
float number;
string sVal = s.substr(7, s.length() - 8);
if (sVal.length() > 0) {
sscanf(sVal.c_str(), "%f", &number);
if (number < -20) number = -20;
if (number > 20) number = 20;
progdefaults.CWpost = number;
REQ(setPOST, number);
}
}
static void pQuePOST(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doPOST };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
bool macro_idle_on = false;
static float idleTime = 0;
@ -219,6 +336,31 @@ static void pIDLE(string &s, size_t &i, size_t endbracket)
s.replace(i, endbracket - i + 1, "");
}
static void doneIDLE(void *)
{
Qidle_time = 0;
}
static void doIDLE(string s)
{
float number;
string sTime = s.substr(7, s.length() - 8);
if (sTime.length() > 0) {
sscanf(sTime.c_str(), "%f", &number);
Qidle_time = 1;
Fl::add_timeout(number, doneIDLE);
} else {
Qidle_time = 0;
}
}
static void pQueIDLE(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doIDLE };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static bool useTune = false;
static int tuneTime = 0;
@ -249,6 +391,33 @@ static void pWAIT(string &s, size_t &i, size_t endbracket)
s.replace(i, endbracket - i + 1, "");
}
static void doneWAIT(void *)
{
Qwait_time = 0;
start_tx();
}
static void doWAIT(string s)
{
int number;
string sTime = s.substr(7, s.length() - 8);
if (sTime.length() > 0) {
sscanf(sTime.c_str(), "%d", &number);
Qwait_time = number;
Fl::add_timeout (number * 1.0, doneWAIT);
} else
Qwait_time = 0;
que_ok = true;
}
static void pQueWAIT(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doWAIT };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static void pINFO1(string &s, size_t &i, size_t endbracket)
{
s.replace( i, 7, info1msg );
@ -440,7 +609,6 @@ static void pID(string &s, size_t &i, size_t endbracket)
static void pTEXT(string &s, size_t &i, size_t endbracket)
{
progdefaults.macrotextid = true;
s.replace( i, 6, "");
}
@ -450,10 +618,16 @@ static void pCWID(string &s, size_t &i, size_t endbracket)
s.replace( i, 6, "");
}
static void doDTMF(string s)
{
progdefaults.DTMFstr = s.substr(6, s.length() - 7);
}
static void pDTMF(string &s, size_t &i, size_t endbracket)
{
progdefaults.DTMFstr = s.substr(i + 6, endbracket - i - 6);
s.replace(i, endbracket - i + 1, "");
CMDS cmd = {s.substr(i, endbracket - i + 1), doDTMF};
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static void pRX(string &s, size_t &i, size_t endbracket)
@ -557,7 +731,7 @@ static void pCLRLOG(string &s, size_t &i, size_t endbracket)
s.replace(i, 10, "^C");
}
static void pMODEM_compat(string &s, size_t &i, size_t endbracket)
static void pMODEM_compSKED(string &s, size_t &i, size_t endbracket)
{
size_t j, k,
len = s.length();
@ -584,6 +758,84 @@ static void pMODEM_compat(string &s, size_t &i, size_t endbracket)
#include <float.h>
#include "re.h"
static void doMODEM(string s)
{
static fre_t re("<!MODEM:([[:alnum:]-]+)((:[[:digit:].+-]*)*)>", REG_EXTENDED);
string tomatch = s;
if (!re.match(tomatch.c_str())) {
que_ok = true;
return;
}
const std::vector<regmatch_t>& o = re.suboff();
string name = tomatch.substr(o[1].rm_so, o[1].rm_eo - o[1].rm_so);
trx_mode m;
for (m = 0; m < NUM_MODES; m++)
if (name == mode_info[m].sname)
break;
// do we have arguments and a valid modem?
if (o.size() == 2 || m == NUM_MODES) {
que_ok = true;
return;
}
// parse arguments
vector<double> args;
args.reserve(8);
char* end;
double d;
for (const char* p = s.c_str() + o[2].rm_so + 1; *p; p++) {
errno = 0;
d = strtod(p, &end);
if (!errno && p != end) {
args.push_back(d);
p = end;
}
else // push an invalid value
args.push_back(DBL_MIN);
}
try {
switch (m) {
case MODE_RTTY: // carrier shift, baud rate, bits per char
if (args.at(0) != DBL_MIN)
set_rtty_shift((int)args[0]);
if (args.at(1) != DBL_MIN)
set_rtty_baud((float)args[1]);
if (args.at(2) != DBL_MIN)
set_rtty_bits((int)args[2]);
break;
case MODE_CONTESTIA: // bandwidth, tones
if (args.at(0) != DBL_MIN)
set_contestia_bw((int)args[0]);
if (args.at(1) != DBL_MIN)
set_contestia_tones((int)args[1]);
break;
case MODE_OLIVIA: // bandwidth, tones
if (args.at(0) != DBL_MIN)
set_olivia_bw((int)args[0]);
if (args.at(1) != DBL_MIN)
set_olivia_tones((int)args[1]);
break;
default:
break;
}
}
catch (const exception& e) { }
if (active_modem->get_mode() != mode_info[m].mode)
init_modem_sync(mode_info[m].mode);
que_ok = true;
}
static void pQueMODEM(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doMODEM };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static void pMODEM(string &s, size_t &i, size_t endbracket)
{
static fre_t re("<MODEM:([[:alnum:]-]+)((:[[:digit:].+-]*)*)>", REG_EXTENDED);
@ -677,6 +929,8 @@ static void pAFC(string &s, size_t &i, size_t endbracket)
btnAFC->do_callback();
}
//pushcmd(s.substr(i, endbracket - i + 1));
//s.replace(i, endbracket - i + 1, "^!");
s.replace(i, endbracket - i + 1, "");
}
@ -695,6 +949,8 @@ static void pLOCK(string &s, size_t &i, size_t endbracket)
wf->xmtlock->damage();
wf->xmtlock->do_callback();
}
//pushcmd(s.substr(i, endbracket - i + 1));
//s.replace(i, endbracket - i + 1, "^!");
s.replace(i, endbracket - i + 1, "");
}
@ -712,6 +968,8 @@ static void pTX_RSID(string &s, size_t &i, size_t endbracket)
btnTxRSID->do_callback();
}
//pushcmd(s.substr(i, endbracket - i + 1));
//s.replace(i, endbracket - i + 1, "^!");
s.replace(i, endbracket - i + 1, "");
}
@ -776,6 +1034,24 @@ static void pGOHOME(string &s, size_t &i, size_t endbracket)
active_modem->set_freq(progdefaults.PSKsweetspot);
}
static void doGOHOME(string s)
{
if (active_modem == cw_modem)
active_modem->set_freq(progdefaults.CWsweetspot);
else if (active_modem == rtty_modem)
active_modem->set_freq(progdefaults.RTTYsweetspot);
else
active_modem->set_freq(progdefaults.PSKsweetspot);
que_ok = true;
}
static void pQueGOHOME(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doGOHOME };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static void pGOFREQ(string &s, size_t &i, size_t endbracket)
{
int number;
@ -791,6 +1067,28 @@ static void pGOFREQ(string &s, size_t &i, size_t endbracket)
s.replace(i, endbracket - i + 1, "");
}
static void doGOFREQ(string s)
{
int number;
string sGoFreq = s.substr(9, s.length() - 10);
if (sGoFreq.length() > 0) {
sscanf(sGoFreq.c_str(), "%d", &number);
if (number < progdefaults.LowFreqCutoff)
number = progdefaults.LowFreqCutoff;
if (number > progdefaults.HighFreqCutoff)
number = progdefaults.HighFreqCutoff;
active_modem->set_freq(number);
}
que_ok = true;
}
static void pQueGOFREQ(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doGOFREQ };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static void pQSYTO(string &s, size_t &i, size_t endbracket)
{
s.replace( i, 7, "");
@ -830,7 +1128,6 @@ static void pQSY(string &s, size_t &i, size_t endbracket)
if (audio > progdefaults.HighFreqCutoff)
audio = progdefaults.HighFreqCutoff;
}
if (rf && rf != wf->rfcarrier())
qsy(rf, audio);
else
@ -839,6 +1136,48 @@ static void pQSY(string &s, size_t &i, size_t endbracket)
s.replace(i, endbracket - i + 1, "");
}
static void doQSY(string s)
{
int rf = 0;
int audio = 0;
float rfd = 0;
string sGoFreq;
sGoFreq = s.substr(6, s.length() - 7);
// no frequency(s) specified
if (sGoFreq.length() == 0) {
que_ok = true;
return;
}
// rf first value
sscanf(sGoFreq.c_str(), "%f", &rfd);
if (rfd > 0)
rf = (int)(1000*rfd);
size_t pos;
if ((pos = sGoFreq.find(":")) != string::npos) {
// af second value
sGoFreq.erase(0, pos+1);
if (sGoFreq.length())
sscanf(sGoFreq.c_str(), "%d", &audio);
if (audio < 0) audio = 0;
if (audio < progdefaults.LowFreqCutoff)
audio = progdefaults.LowFreqCutoff;
if (audio > progdefaults.HighFreqCutoff)
audio = progdefaults.HighFreqCutoff;
}
if (rf && rf != wf->rfcarrier())
qsy(rf, audio);
else
active_modem->set_freq(audio);
que_ok = true;
}
static void pQueQSY(string &s, size_t &i, size_t endbracket)
{
struct CMDS cmd = { s.substr(i, endbracket - i + 1), doQSY };
pushcmd(cmd);
s.replace(i, endbracket - i + 1, "^!");
}
static void pRIGMODE(string& s, size_t& i, size_t endbracket)
{
string sMode = s.substr(i+9, endbracket - i - 9);
@ -859,7 +1198,7 @@ void set_macro_env(void)
{
enum {
#ifndef __WOE32__
PATH, FLDIGI_RX_IPC_KEY, FLDIGI_TX_IPC_KEY,
pSKEDH, FLDIGI_RX_IPC_KEY, FLDIGI_TX_IPC_KEY,
#endif
FLDIGI_XMLRPC_ADDRESS, FLDIGI_XMLRPC_PORT,
FLDIGI_ARQ_ADDRESS, FLDIGI_ARQ_PORT,
@ -881,7 +1220,7 @@ void set_macro_env(void)
const char* val;
} env[] = {
#ifndef __WOE32__
{ "PATH", "" },
{ "pSKEDH", "" },
{ "FLDIGI_RX_IPC_KEY", "" },
{ "FLDIGI_TX_IPC_KEY", "" },
#endif
@ -919,13 +1258,13 @@ void set_macro_env(void)
};
#ifndef __WOE32__
// PATH
static string path = ScriptsDir;
path.erase(path.length()-1,1);
// pSKEDH
static string pSKEDh = ScriptsDir;
pSKEDh.erase(pSKEDh.length()-1,1);
const char* p;
if ((p = getenv("PATH")))
path.append(":").append(p);
env[PATH].val = path.c_str();
if ((p = getenv("pSKEDH")))
pSKEDh.append(":").append(p);
env[pSKEDH].val = pSKEDh.c_str();
// IPC keys
char key[2][8];
@ -1132,6 +1471,65 @@ static void pCONT(string &s, size_t &i, size_t endbracket)
expand = true;
}
static void pSKED(string &s, size_t &i, size_t endbracket)
{
string data = s.substr(i+6, endbracket - i - 6);
size_t p = data.find(":");
if (p == std::string::npos) {
exec_date = zdate();
exec_time = data;
if (exec_time.empty()) exec_time = ztime();
} else {
exec_time = data.substr(0, p);
exec_date = data.substr(p+1);
}
timed_exec = true;
s.replace(i, endbracket - i + 1, "");
}
void queue_reset()
{
if (!cmds.empty()) {
Fl::remove_timeout(post_queue_execute);
Fl::remove_timeout(queue_execute_after_rx);
Fl::remove_timeout(doneIDLE);
Fl::remove_timeout(doneWAIT);
while (!cmds.empty()) cmds.pop();
}
Qwait_time = 0;
Qidle_time = 0;
que_ok = true;
}
void postQueue(string s)
{
ReceiveText->add(s.c_str(), FTextBase::CTRL);
}
void queue_execute()
{
if (cmds.empty()) {
Qwait_time = 0;
Qidle_time = 0;
que_ok = true;
return;
}
CMDS cmd = cmds.front();
cmds.pop();
cmd.fp(cmd.cmd);
LOG_INFO("%s", cmd.cmd.c_str());
REQ(postQueue, cmd.cmd.append("\n"));
return;
}
bool queue_must_rx()
{
static string rxcmds = "<!MOD<!WAI<!GOH<!QSY<!GOF";
if (cmds.empty()) return false;
CMDS cmd = cmds.front();
return (rxcmds.find(cmd.cmd.substr(0,5)) != string::npos);
}
struct MTAGS { const char *mTAG; void (*fp)(string &, size_t&, size_t );};
MTAGS mtags[] = {
@ -1181,7 +1579,7 @@ MTAGS mtags[] = {
{"<IDLE:", pIDLE},
{"<TUNE:", pTUNE},
{"<WAIT:", pWAIT},
{"<MODEM>", pMODEM_compat},
{"<MODEM>", pMODEM_compSKED},
{"<MODEM:", pMODEM},
{"<EXEC>", pEXEC},
{"<STOP>", pSTOP},
@ -1211,9 +1609,20 @@ MTAGS mtags[] = {
{"<MAPIT:", pMAPIT},
{"<MAPIT>", pMAPIT},
{"<REPEAT>", pREPEAT},
{"<SKED:", pSKED},
#ifdef __WIN32__
{"<TALK:", pTALK},
#endif
{"<!WPM:", pQueWPM},
{"<!RISE:", pQueRISETIME},
{"<!PRE:", pQuePRE},
{"<!POST:", pQuePOST},
{"<!GOHOME>", pQueGOHOME},
{"<!GOFREQ:", pQueGOFREQ},
{"<!QSY:", pQueQSY},
{"<!IDLE:", pQueIDLE},
{"<!WAIT:", pQueWAIT},
{"<!MODEM:", pQueMODEM},
{0, 0}
};
@ -1328,14 +1737,14 @@ void MACROTEXT::loadnewMACROS(string &s, size_t &i, size_t endbracket)
showMacroSet();
}
string MACROTEXT::expandMacro(int n)
string MACROTEXT::expandMacro(std::string &s)
{
size_t idx = 0;
expand = true;
TransmitON = false;
ToggleTXRX = false;
mNbr = n;
expanded = text[n];
// mNbr = n;
expanded = s;//text[n];
MTAGS *pMtags;
xbeg = xend = -1;
@ -1455,9 +1864,30 @@ static void set_button(Fl_Button* button, bool value)
button->do_callback();
}
void MACROTEXT::timed_execute()
{
queue_reset();
TransmitText->clear();
text2send = expandMacro(exec_string);
TransmitText->add(text2send.c_str());
exec_string.clear();
active_modem->set_stopflag(false);
start_tx();
}
void MACROTEXT::execute(int n)
{
text2save = text2send = expandMacro(n);
mNbr = n;
// text2save =
text2send = expandMacro(text[n]);
if (timed_exec) {
progStatus.repeatMacro = -1;
exec_string = text[n];
timed_exec = false;
startTimedExecute(name[n]);
return;
}
if (progStatus.repeatMacro == -1)
TransmitText->add( text2send.c_str() );
@ -1505,8 +1935,8 @@ void MACROTEXT::execute(int n)
void MACROTEXT::repeat(int n)
{
expandMacro(n);
LOG_INFO("%s",text2repeat.c_str());
expandMacro(text[n]);
LOG_WARN("%s",text2repeat.c_str());
macro_idle_on = false;
if (idleTime) progStatus.repeatIdleTime = idleTime;
}

Wyświetl plik

@ -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)

Wyświetl plik

@ -42,6 +42,7 @@
using namespace std;
modem *null_modem = 0;
modem *cw_modem = 0;
modem *mfsk8_modem = 0;

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -158,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;
@ -302,15 +301,19 @@ 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) &&
progdefaults.TransmitRSid)
ReedSolomon->send(true);
dtmf->send();
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;
@ -326,9 +329,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);
@ -407,6 +407,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;
@ -423,8 +434,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();