diff --git a/src/include/configuration.h b/src/include/configuration.h index c0ad9433..fc084ed0 100644 --- a/src/include/configuration.h +++ b/src/include/configuration.h @@ -608,6 +608,7 @@ "Single tone at center of modem BW, carrier detect for amplifiers", \ 0.0) \ ELEM_(bool, macroCWid, "", "", false) \ + ELEM_(std::string, DTMFstr, "", "", "") \ ELEM_(int, videowidth, "VIDEOWIDTH", \ "Video ID text width (characters per row)", \ 1) \ diff --git a/src/include/modem.h b/src/include/modem.h index 1b34b19a..91dadb36 100644 --- a/src/include/modem.h +++ b/src/include/modem.h @@ -65,6 +65,9 @@ protected: bool s2n_valid; unsigned cap; + static int DTMF_row[]; + static int DTMF_col[]; + public: modem(); virtual ~modem(){}; @@ -177,6 +180,11 @@ public: void cwid_sendtext (const std::string& s); void cwid(); +// for DTMF transmission + void DTMF_silence(int); + void DTMF_two_tones(int); + void DTMF_send(); + // for noise tests private: void add_noise(double *, int); diff --git a/src/misc/macroedit.cxx b/src/misc/macroedit.cxx index f2d2faf4..f96ddad2 100644 --- a/src/misc/macroedit.cxx +++ b/src/misc/macroedit.cxx @@ -158,6 +158,7 @@ void loadBrowser(Fl_Widget *widget) { w->add(_("\tvideo text")); w->add(_("\tTx RSID on,off,toggle")); w->add(_("\tRx RSID on,off,toggle")); + w->add(_("\tTx digits string")); w->add(LINE_SEP); w->add(_("\tCW QSK post-timing")); diff --git a/src/misc/macros.cxx b/src/misc/macros.cxx index 704ece84..9b1fd87b 100644 --- a/src/misc/macros.cxx +++ b/src/misc/macros.cxx @@ -141,6 +141,7 @@ void pAFC(string &, size_t &); void pLOCK(string &, size_t &); void pRX_RSID(string &, size_t &); void pTX_RSID(string &, size_t &); +void pDTMF(string &, size_t &); #ifdef __WIN32__ void pTALK(string &, size_t &); @@ -227,6 +228,7 @@ MTAGS mtags[] = { {"", pSRCHUP}, {"", pSRCHDN}, {"", pGOHOME}, @@ -627,6 +629,13 @@ void pCWID(string &s, size_t &i) s.replace( i, 6, ""); } +void pDTMF(string &s, size_t &i) +{ + size_t endbracket = s.find('>',i); + progdefaults.DTMFstr = s.substr(i + 6, endbracket - i - 6); + s.replace(i, endbracket - i + 1, ""); +} + void pRX(string &s, size_t &i) { s.replace (i, 4, "^r"); diff --git a/src/trx/modem.cxx b/src/trx/modem.cxx index 10370580..4019130c 100644 --- a/src/trx/modem.cxx +++ b/src/trx/modem.cxx @@ -971,3 +971,89 @@ mfntchr idch2[] = { }; +//====================================================================== +// DTMF tone transmit +//====================================================================== +int modem::DTMF_row[] = { +941, 697, 697, 697, 770, 770, 770, 852, 852, 852, 941, 941, 697, 770, 852, 941}; +//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, *, #, A, B, C, D + +int modem::DTMF_col[] = { +1336, 1209, 1336, 1477, 1209, 1336, 1477, 1209, 1336, 1477, 1209, 1477, 1633, 1633, 1633, 1633}; +// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, *, #, A, B, C, D + +//---------------------------------------------------------------------- +// transmit silence for specified time duration +//---------------------------------------------------------------------- + +void modem::DTMF_silence(int duration) +{ + double sr = active_modem->get_samplerate(); + int length = duration * sr / 1000; + memset(outbuf, 0, length * sizeof(*outbuf)); + active_modem->ModulateXmtr(outbuf, length); +} + +//---------------------------------------------------------------------- +// transmit DTMF tones for specific time interval +//---------------------------------------------------------------------- + +void modem::DTMF_two_tones(int rc) +{ + if (rc < 0 || rc > 15) return; + double sr = active_modem->get_samplerate(); + double phaseincr = 2.0 * M_PI * DTMF_row[rc] / sr; + double phase = 0; +printf("%d %d\n", DTMF_row[rc], DTMF_col[rc]); + int length = 50 * sr / 1000; + + for (int i = 0; i < length; i++) { + outbuf[i] = 0.5 * sin(phase); + phase += phaseincr; + } + + phaseincr = 2.0 * M_PI * DTMF_col[rc] / 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] *= cwid_keyshape[i]; + outbuf[length - 1 - i] *= cwid_keyshape[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 modem::DTMF_send() +{ + if (progdefaults.DTMFstr.empty()) return; + + int c = 0; + + RT = (int) (samplerate * 4 / 1000.0); // 4 msec rise/fall time + cwid_makeshape(); + + for(size_t i = 0; i < progdefaults.DTMFstr.length(); i++) { + c = progdefaults.DTMFstr[i]; + if (c == ' ' || c == ',' || c == '-') DTMF_silence(50); + else if (c >= '0' && c <= '9') DTMF_two_tones(c - '0'); + else if (c == '*') DTMF_two_tones(10); + else if (c == '#') DTMF_two_tones(11); + else if (c >= 'A' && c <= 'D') DTMF_two_tones(12 + c - 'A'); + else if (c >= 'a' && c <= 'd') DTMF_two_tones(12 + c - 'a'); + DTMF_silence(50); + } + progdefaults.DTMFstr.clear(); +} + diff --git a/src/trx/trx.cxx b/src/trx/trx.cxx index 56809044..4f863dc6 100644 --- a/src/trx/trx.cxx +++ b/src/trx/trx.cxx @@ -312,6 +312,8 @@ void trx_trx_transmit_loop() if (progdefaults.TransmitRSid) ReedSolomon->send(true); + active_modem->DTMF_send(); + while (trx_state == STATE_TX) { try { if (active_modem->tx_process() < 0)