jtdx/TCITransceiver.cpp
2021-11-12 21:02:34 +02:00

1949 lines
84 KiB
C++

#include "TCITransceiver.hpp"
#include <QRegularExpression>
#include <QLocale>
#include <QThread>
#include <qmath.h>
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
#include <QRandomGenerator>
#endif
#include "commons.h"
#include "NetworkServerLookup.hpp"
#include "moc_TCITransceiver.cpp"
namespace
{
char const * const TCI_transceiver_1_name {"TCI Client RX1"};
char const * const TCI_transceiver_2_name {"TCI Client RX2"};
QString map_mode (Transceiver::MODE mode)
{
switch (mode)
{
case Transceiver::AM: return "am";
case Transceiver::CW: return "cw";
// case Transceiver::CW_R: return "CW-R";
case Transceiver::USB: return "usb";
case Transceiver::LSB: return "lsb";
// case Transceiver::FSK: return "RTTY";
// case Transceiver::FSK_R: return "RTTY-R";
case Transceiver::DIG_L: return "digl";
case Transceiver::DIG_U: return "digu";
case Transceiver::FM: return "wfm";
case Transceiver::DIG_FM:
return "nfm";
default: break;
}
return "";
}
static const QString SmTZ(";");
static const QString SmDP(":");
static const QString SmCM(",");
static const QString SmTrue("true");
static const QString SmFalse("false");
// Command maps
static const QString CmdDevice("device");
static const QString CmdReceiveOnly("receive_only");
static const QString CmdTrxCount("trx_count");
static const QString CmdChannelCount("channels_count");
static const QString CmdVfoLimits("vfo_limits");
static const QString CmdIfLimits("if_limits");
static const QString CmdModeList("modulations_list");
static const QString CmdMode("modulation");
static const QString CmdReady("ready");
static const QString CmdStop("stop");
static const QString CmdStart("start");
static const QString CmdPreamp("preamp");
static const QString CmdDds("dds");
static const QString CmdIf("if");
static const QString CmdTrx("trx");
static const QString CmdRxEnable("rx_enable");
static const QString CmdTxEnable("tx_enable");
static const QString CmdRxChannelEnable("rx_channel_enable");
static const QString CmdRitEnable("rit_enable");
static const QString CmdRitOffset("rit_offset");
static const QString CmdXitEnable("xit_enable");
static const QString CmdXitOffset("xit_offset");
static const QString CmdSplitEnable("split_enable");
static const QString CmdIqSR("iq_samplerate");
static const QString CmdIqStart("iq_start");
static const QString CmdIqStop("iq_stop");
static const QString CmdCWSpeed("cw_macros_speed");
static const QString CmdCWDelay("cw_macros_delay");
static const QString CmdSpot("spot");
static const QString CmdSpotDelete("spot_delete");
static const QString CmdFilterBand("rx_filter_band");
static const QString CmdVFO("vfo");
static const QString CmdVersion("protocol"); //protocol:esdr,1.2;
static const QString CmdTune("tune");
static const QString CmdRxMute("rx_mute");
static const QString CmdSmeter("rx_smeter");
static const QString CmdPower("tx_power");
static const QString CmdSWR("tx_swr");
static const QString CmdECoderRX("ecoder_switch_rx");
static const QString CmdECoderVFO("ecoder_switch_channel");
static const QString CmdAudioSR("audio_samplerate");
static const QString CmdAudioStart("audio_start");
static const QString CmdAudioStop("audio_stop");
static const QString CmdAppFocus("app_focus");
static const QString CmdVolume("volume");
static const QString CmdSqlEnable("sql_enable");
static const QString CmdSqlLevel("sql_level");
static const QString CmdDrive("drive");
static const QString CmdTuneDrive("tune_drive");
static const QString CmdMute("mute");
static const QString CmdRxSensorsEnable("rx_sensors_enable");
static const QString CmdTxSensorsEnable("tx_sensors_enable");
static const QString CmdRxSensors("rx_sensors");
static const QString CmdTxSensors("tx_sensors");
static const QString CmdAgcMode("agc_mode");
static const QString CmdAgcGain("agc_gain");
static const QString CmdLock("lock");
}
extern "C" {
void fil4_(qint16*, qint32*, qint16*, qint32*, float*);
}
extern dec_data dec_data;
extern float gran(); // Noise generator (for tests only)
#define RAMP_INCREMENT 64 // MUST be an integral factor of 2^16
#if defined (WSJT_SOFT_KEYING)
# define SOFT_KEYING WSJT_SOFT_KEYING
#else
# define SOFT_KEYING 1
#endif
double constexpr TCITransceiver::m_twoPi;
void TCITransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, unsigned id1, unsigned id2)
{
(*registry)[TCI_transceiver_1_name] = TransceiverFactory::Capabilities {id1, TransceiverFactory::Capabilities::tci, true};
(*registry)[TCI_transceiver_2_name] = TransceiverFactory::Capabilities {id2, TransceiverFactory::Capabilities::tci, true};
}
static constexpr quint32 AudioHeaderSize = 16u*sizeof(quint32);
TCITransceiver::TCITransceiver (std::unique_ptr<TransceiverBase> wrapped,QString const& rignr,
QString const& address, bool use_for_ptt,
int poll_interval, QObject * parent)
: PollingTransceiver {poll_interval, parent}
, wrapped_ {std::move (wrapped)}
, rx_ {rignr}
, server_ {address}
, use_for_ptt_ {use_for_ptt}
, errortable {tr("ConnectionRefused"),
tr("RemoteHostClosed"),
tr("HostNotFound"),
tr("SocketAccess"),
tr("SocketResource"),
tr("SocketTimeout"),
tr("DatagramTooLarge"),
tr("Network"),
tr("AddressInUse"),
tr("SocketAddressNotAvailable"),
tr("UnsupportedSocketOperation"),
tr("UnfinishedSocketOperation"),
tr("ProxyAuthenticationRequired"),
tr("SslHandshakeFailed"),
tr("ProxyConnectionRefused"),
tr("ProxyConnectionClosed"),
tr("ProxyConnectionTimeout"),
tr("ProxyNotFound"),
tr("ProxyProtocol"),
tr("Operation"),
tr("SslInternal"),
tr("SslInvalidUserData"),
tr("Temporary"),
tr("UnknownSocket") }
, error_ {""}
, do_snr_ {(poll_interval & do__snr) == do__snr}
, do_pwr_ {(poll_interval & do__pwr) == do__pwr}
, rig_power_ {(poll_interval & rig__power) == rig__power}
, rig_power_off_ {(poll_interval & rig__power_off) == rig__power_off}
, tci_audio_ {(poll_interval & tci__audio) == tci__audio}
, commander_ {nullptr}
, tci_timer1_ {nullptr}
, tci_loop1_ {nullptr}
, tci_timer2_ {nullptr}
, tci_loop2_ {nullptr}
, tci_timer3_ {nullptr}
, tci_loop3_ {nullptr}
, wavptr_ {nullptr}
, m_jtdxtime {nullptr}
, m_downSampleFactor {4}
, m_buffer ((m_downSampleFactor > 1) ?
new short [max_buffer_size * m_downSampleFactor] : nullptr)
, m_quickClose {false}
, m_phi {0.0}
, m_toneSpacing {0.0}
, m_fSpread {0.0}
, m_state {Idle}
, m_tuning {false}
, m_cwLevel {false}
, m_j0 {-1}
, m_toneFrequency0 {1500.0}
, debug_file_ {QDir(QStandardPaths::writableLocation (QStandardPaths::DataLocation)).absoluteFilePath ("jtdx_debug.txt").toStdString()}
, wav_file_ {QDir(QStandardPaths::writableLocation (QStandardPaths::DataLocation)).absoluteFilePath ("tx.wav").toStdString()}
{
m_samplesPerFFT = 6912 / 2;
m_period = 120.0;
tci_Ready = false;
trxA = 0;
trxB = 0;
cntIQ = 0;
bIQ = false;
inConnected = false;
audioSampleRate = 48000u;
mapCmd_[CmdDevice] = Cmd_Device;
mapCmd_[CmdReceiveOnly] = Cmd_ReceiveOnly;
mapCmd_[CmdTrxCount] = Cmd_TrxCount;
mapCmd_[CmdChannelCount] = Cmd_ChannelCount;
mapCmd_[CmdVfoLimits] = Cmd_VfoLimits;
mapCmd_[CmdIfLimits] = Cmd_IfLimits;
mapCmd_[CmdModeList] = Cmd_ModeList;
mapCmd_[CmdMode] = Cmd_Mode;
mapCmd_[CmdReady] = Cmd_Ready;
mapCmd_[CmdStop] = Cmd_Stop;
mapCmd_[CmdStart] = Cmd_Start;
mapCmd_[CmdPreamp] = Cmd_Preamp;
mapCmd_[CmdDds] = Cmd_Dds;
mapCmd_[CmdIf] = Cmd_If;
mapCmd_[CmdTrx] = Cmd_Trx;
mapCmd_[CmdRxEnable] = Cmd_RxEnable;
mapCmd_[CmdTxEnable] = Cmd_TxEnable;
mapCmd_[CmdRxChannelEnable] = Cmd_RxChannelEnable;
mapCmd_[CmdRitEnable] = Cmd_RitEnable;
mapCmd_[CmdRitOffset] = Cmd_RitOffset;
mapCmd_[CmdXitEnable] = Cmd_XitEnable;
mapCmd_[CmdXitOffset] = Cmd_XitOffset;
mapCmd_[CmdSplitEnable] = Cmd_SplitEnable;
mapCmd_[CmdIqSR] = Cmd_IqSR;
mapCmd_[CmdIqStart] = Cmd_IqStart;
mapCmd_[CmdIqStop] = Cmd_IqStop;
mapCmd_[CmdCWSpeed] = Cmd_CWSpeed;
mapCmd_[CmdCWDelay] = Cmd_CWDelay;
mapCmd_[CmdFilterBand] = Cmd_FilterBand;
mapCmd_[CmdVFO] = Cmd_VFO;
mapCmd_[CmdVersion] = Cmd_Version;
mapCmd_[CmdTune] = Cmd_Tune;
mapCmd_[CmdRxMute] = Cmd_RxMute;
mapCmd_[CmdSmeter] = Cmd_Smeter;
mapCmd_[CmdPower] = Cmd_Power;
mapCmd_[CmdSWR] = Cmd_SWR;
mapCmd_[CmdECoderRX] = Cmd_ECoderRX;
mapCmd_[CmdECoderVFO] = Cmd_ECoderVFO;
mapCmd_[CmdAudioSR] = Cmd_AudioSR;
mapCmd_[CmdAudioStart] = Cmd_AudioStart;
mapCmd_[CmdAudioStop] = Cmd_AudioStop;
mapCmd_[CmdAppFocus] = Cmd_AppFocus;
mapCmd_[CmdVolume] = Cmd_Volume;
mapCmd_[CmdSqlEnable] = Cmd_SqlEnable;
mapCmd_[CmdSqlLevel] = Cmd_SqlLevel;
mapCmd_[CmdDrive] = Cmd_Drive;
mapCmd_[CmdTuneDrive] = Cmd_TuneDrive;
mapCmd_[CmdMute] = Cmd_Mute;
mapCmd_[CmdRxSensorsEnable] = Cmd_RxSensorsEnable;
mapCmd_[CmdTxSensorsEnable] = Cmd_TxSensorsEnable;
mapCmd_[CmdRxSensors] = Cmd_RxSensors;
mapCmd_[CmdTxSensors] = Cmd_TxSensors;
mapCmd_[CmdAgcMode] = Cmd_AgcMode;
mapCmd_[CmdAgcGain] = Cmd_AgcGain;
mapCmd_[CmdLock] = Cmd_Lock;
}
void TCITransceiver::onConnected()
{
inConnected = true;
// printf("%s(%0.1f) TCI connected\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI connected\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
fclose (pFile);
#endif
}
void TCITransceiver::onDisconnected()
{
inConnected = false;
// printf("%s(%0.1f) TCI disconnected\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI disconnected\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
fclose (pFile);
#endif
}
void TCITransceiver::onError(QAbstractSocket::SocketError err)
{
//qDebug() << "WebInThread::onError";
// printf("%s(%0.1f) TCI error:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),err);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI error:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),err);
fclose (pFile);
#endif
error_ = tr ("TCI websocket error: %1").arg (errortable.at (err));
}
int TCITransceiver::do_start (JTDXDateTime * jtdxtime)
{
if (tci_audio_) QThread::currentThread()->setPriority(QThread::HighPriority);
// printf("do_start tci_Ready:%d\n",tci_Ready);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"do_start tci_Ready:%d\n",tci_Ready);
fclose (pFile);
#endif
TRACE_CAT ("TCITransceiver", "starting");
m_jtdxtime = jtdxtime;
if (wrapped_) wrapped_->start (0,m_jtdxtime);
url_.setUrl("ws://" + server_); //server_
if (url_.host() == "") url_.setHost("localhost");
if (url_.port() == -1) url_.setPort(40001);
if (!commander_)
{
commander_ = new QWebSocket {}; // QObject takes ownership
// printf ("commander created");
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"commander created");
fclose (pFile);
#endif
connect(commander_,SIGNAL(connected()),this,SLOT(onConnected()));
connect(commander_,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
connect(commander_,SIGNAL(binaryMessageReceived(QByteArray)),this,SLOT(onBinaryReceived(QByteArray)));
connect(commander_,SIGNAL(textMessageReceived(QString)),this,SLOT(onMessageReceived(QString)));
connect(commander_,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(onError(QAbstractSocket::SocketError)));
}
if (!tci_loop1_) {
tci_loop1_ = new QEventLoop {this};
}
if (!tci_timer1_) {
tci_timer1_ = new QTimer {this};
tci_timer1_ -> setSingleShot(true);
connect( tci_timer1_, &QTimer::timeout, tci_loop1_, &QEventLoop::quit);
connect( this, &TCITransceiver::tci_done1, tci_loop1_, &QEventLoop::quit);
}
if (!tci_loop2_) {
tci_loop2_ = new QEventLoop {this};
}
if (!tci_timer2_) {
tci_timer2_ = new QTimer {this};
tci_timer2_ -> setSingleShot(true);
connect( tci_timer2_, &QTimer::timeout, tci_loop2_, &QEventLoop::quit);
connect( this, &TCITransceiver::tci_done2, tci_loop2_, &QEventLoop::quit);
}
if (!tci_loop3_) {
tci_loop3_ = new QEventLoop {this};
}
if (!tci_timer3_) {
tci_timer3_ = new QTimer {this};
tci_timer3_ -> setSingleShot(true);
connect( tci_timer3_, &QTimer::timeout, tci_loop3_, &QEventLoop::quit);
connect( this, &TCITransceiver::tci_done3, tci_loop3_, &QEventLoop::quit);
}
tx_fifo = 0; tx_top_ = true;
tci_Ready = false;
ESDR3 = false;
band_change = false;
trxA = 0;
trxB = 0;
busy_rx_frequency_ = false;
busy_mode_ = false;
busy_other_frequency_ = false;
busy_split_ = false;
busy_drive_ = false;
busy_PTT_ = false;
busy_rx2_ = false;
rx2_ = false;
split_ = false;
requested_split_ = false;
PTT_ = false;
requested_PTT_ = false;
requested_rx2_ = false;
requested_mode_ = "";
started_rx2_ = false;
mode_ = "";
requested_rx_frequency_ = "";
rx_frequency_ = "";
requested_other_frequency_ = "";
other_frequency_ = "";
level_ = -54;
power_ = 0;
m_bufferPos = 0;
m_downSampleFactor =4;
m_ns = 999;
audio_ = false;
requested_stream_audio_ = false;
stream_audio_ = false;
_power_ = false;
// printf ("%s(%0.1f) TCI open %s rig_power:%d rig_power_off:%d tci_audio:%d do_snr:%d do_pwr:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),url_.toString().toStdString().c_str(),rig_power_,rig_power_off_,tci_audio_,do_snr_,do_pwr_);
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI open %s rig_power:%d rig_power_off:%d tci_audio:%d do_snr:%d do_pwr:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),url_.toString().toStdString().c_str(),rig_power_,rig_power_off_,tci_audio_,do_snr_,do_pwr_);
fclose (pFile);
#endif
commander_->open (url_);
mysleep1 (1500);
if (ESDR3) mysleep1 (500); else mysleep1 (100);
// mysleep1 (100);
tci_Ready = true;
if (tci_Ready) {
if (!_power_) {
if (rig_power_) {
rig_power(true);
mysleep1(1000);
if(!_power_) throw error {tr ("TCI SDR could not be switched on")};
} else {
tci_Ready = false;
throw error {tr ("TCI SDR is not switched on")};
}
}
if (rx_ == "1" && !rx2_) {
rx2_enable (true);
if (!rx2_) {
tci_Ready = false;
throw error {tr ("TCI RX2 could not be enabled")};
}
}
if (tci_audio_) {
stream_audio (true);
mysleep1(500);
if (!stream_audio_) {
tci_Ready = false;
throw error {tr ("TCI Audio could not be switched on")};
}
}
if (ESDR3) {
const QString cmd = CmdRxSensorsEnable + SmDP + (do_snr_ ? "true" : "false") + SmCM + "500" + SmTZ;
sendTextMessage(cmd);
} else if (do_snr_) {
const QString cmd = CmdSmeter + SmDP + rx_ + SmCM + "0" + SmTZ;
sendTextMessage(cmd);
}
if (!requested_rx_frequency_.isEmpty()) do_frequency(string_to_frequency (requested_rx_frequency_),get_mode(true),false);
if (!requested_other_frequency_.isEmpty()) do_tx_frequency(string_to_frequency (requested_other_frequency_),get_mode(true),false);
// else if (requested_split_ != split_) {/*printf("splt from start %d\n",requested_split_);*/ rig_split();} // split_ = requested_split_; mysleep2(100);}
do_poll ();
if (ESDR3) {
const QString cmd = CmdTxSensorsEnable + SmDP + (do_pwr_ ? "true" : "false") + SmCM + "500" + SmTZ;
sendTextMessage(cmd);
}
if (stream_audio_) do_audio(true);
TRACE_CAT ("TCITransceiver", "started");
// printf("%s(%0.1f) TCI Transceiver started\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI Transceiver started\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
fclose (pFile);
#endif
return 0;
} else {
// printf("%s(%0.1f) TCI Transceiver not started %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),error_.toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI Transceiver not started %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),error_.toStdString().c_str());
fclose (pFile);
#endif
if (error_.isEmpty())
throw error {tr ("TCI could not be opened")};
else
throw error {error_};
}
}
void TCITransceiver::do_stop ()
{
// printf ("TCI close\n");
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"TCI close\n");
#endif
if (stream_audio_ && tci_Ready && inConnected && _power_) {
stream_audio (false);
mysleep1(500);
// printf ("TCI audio closed\n");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"TCI audio closed\n");
#endif
}
if (tci_Ready && inConnected && _power_) {
requested_split_ = false;
requested_other_frequency_ = "";
if (requested_split_ != split_) rig_split();
}
if (!started_rx2_ && rx2_) {
rx2_enable (false);
}
if (_power_ && rig_power_off_ && tci_Ready && inConnected && _power_) {
rig_power(false);
mysleep1(500);
// printf ("TCI power down\n");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"TCI power down\n");
#endif
}
tci_Ready = false;
if (commander_)
{
if (inConnected) commander_->close(QWebSocketProtocol::CloseCodeNormal,"end");
delete commander_, commander_ = nullptr;
// printf ("commander ");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"commander ");
#endif
}
if (tci_timer1_)
{
if (tci_timer1_->isActive()) tci_timer1_->stop();
delete tci_timer1_, tci_timer1_ = nullptr;
// printf ("timer1 ");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"timer1 ");
#endif
}
if (tci_loop1_)
{
tci_loop1_->quit();
delete tci_loop1_, tci_loop1_ = nullptr;
// printf ("loop1 ");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"loop1 ");
#endif
}
if (tci_timer2_)
{
if (tci_timer2_->isActive()) tci_timer2_->stop();
delete tci_timer2_, tci_timer2_ = nullptr;
// printf ("timer2 ");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"timer2 ");
#endif
}
if (tci_loop2_)
{
tci_loop2_->quit();
delete tci_loop2_, tci_loop2_ = nullptr;
// printf ("loop2 ");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"loop2 ");
#endif
}
if (tci_timer3_)
{
if (tci_timer3_->isActive()) tci_timer3_->stop();
delete tci_timer3_, tci_timer3_ = nullptr;
// printf ("timer3 ");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"timer3 ");
#endif
}
if (tci_loop3_)
{
tci_loop3_->quit();
delete tci_loop3_, tci_loop3_ = nullptr;
// printf ("loop3 ");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"loop3 ");
#endif
}
if (wrapped_) wrapped_->stop ();
TRACE_CAT ("TCITransceiver", "stopped");
// printf ("deleted\nTCI closed\n");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"deleted\nTCI closed\n");
fclose (pFile);
#endif
}
void TCITransceiver::onMessageReceived(const QString &str)
{
//qDebug() << "From WEB" << str;
QStringList cmd_list = str.split(";", SkipEmptyParts);
#if JTDX_DEBUG_TO_FILE
FILE * pFile;
#endif
for (QString cmds : cmd_list){
QStringList cmd = cmds.split(":", SkipEmptyParts);
QStringList args = cmd.last().split(",", SkipEmptyParts);
Tci_Cmd idCmd = mapCmd_[cmd.first()];
// if (idCmd != Cmd_Power && idCmd != Cmd_SWR && idCmd != Cmd_Smeter && idCmd != Cmd_AppFocus && idCmd != Cmd_RxSensors && idCmd != Cmd_TxSensors) { printf ("%s(%0.1f) TCI message received:|%s| ",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),str.toStdString().c_str()); printf("idCmd : %d args : %s\n",idCmd,args.join("|").toStdString().c_str());}
#if JTDX_DEBUG_TO_FILE
if (idCmd != Cmd_Power && idCmd != Cmd_SWR && idCmd != Cmd_Smeter && idCmd != Cmd_AppFocus && idCmd != Cmd_RxSensors && idCmd != Cmd_TxSensors) {
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI message received:|%s| ",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),str.toStdString().c_str());
fprintf (pFile,"idCmd : %d args : %s\n",idCmd,args.join("|").toStdString().c_str());
fclose (pFile);
}
#endif
//qDebug() << cmds << idCmd;
if (idCmd <=0) continue;
switch (idCmd) {
case Cmd_Smeter:
if(args.at(0)==rx_ && args.at(1) == "0") level_ = args.at(2).toInt() + 73;
break;
case Cmd_RxSensors:
if(args.at(0)==rx_) level_ = args.at(1).split(".")[0].toInt() + 73;
// printf("Smeter=%d\n",level_);
break;
case Cmd_TxSensors:
if(args.at(0)==rx_) {
power_ = 10 * args.at(3).split(".")[0].toInt() + args.at(3).split(".")[1].toInt();
swr_ = 10 * args.at(4).split(".")[0].toInt() + args.at(4).split(".")[1].toInt();
// printf("Power=%d SWR=%d\n",power_,swr_);
}
break;
case Cmd_SWR:
// printf("%s(%0.1f) Cmd_SWR : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
swr_ = 10 * args.at(0).split(".")[0].toInt() + args.at(0).split(".")[1].toInt();
break;
case Cmd_Power:
power_ = 10 * args.at(0).split(".")[0].toInt() + args.at(0).split(".")[1].toInt();
// printf("%s(%0.1f) Cmd_Power : %s %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str(),power_);
break;
case Cmd_VFO:
// printf("%s(%0.1f) Cmd_VFO : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) Cmd_VFO : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if(args.at(0)==rx_ && args.at(1) == "0") {
rx_frequency_ = args.at(2);
if (requested_rx_frequency_.isEmpty()) {requested_rx_frequency_ = rx_frequency_; }
if (busy_rx_frequency_) {/*printf ("cmdvfo0 done1\n");*/ tci_done1();}
}
else if (args.at(0)==rx_ && args.at(1) == "1") {
other_frequency_ = args.at(2);
// if (requested_other_frequency_.isEmpty()) requested_other_frequency_ = other_frequency_;
if (band_change) tci_done1();
else if (busy_other_frequency_) tci_done2();
}
break;
case Cmd_Mode:
// printf("%s(%0.1f) Cmd_Mode : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) Cmd_Mode : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if(args.at(0)==rx_) {
if (ESDR3) {
if (args.at(1) == "0" ) mode_ = args.at(2).toLower(); else mode_ = args.at(1).toLower();
} else mode_ = args.at(1);
if (requested_mode_.isEmpty()) requested_mode_ = mode_;
if (busy_mode_) tci_done1();
else if (requested_mode_ != mode_ && !band_change) {
sendTextMessage(mode_to_command(requested_mode_));
}
}
break;
case Cmd_SplitEnable:
// printf("%s(%0.1f) Cmd_SplitEnable : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) Cmd_SplitEnable : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if(args.at(0)==rx_) {
if (args.at(1) == "false") split_ = false;
else if (args.at(1) == "true") split_ = true;
if (busy_split_) tci_done2();
}
break;
case Cmd_Drive:
// printf("%s(%0.1f) Cmd_Drive : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) Cmd_Drive : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if(!ESDR3 || args.at(0)==rx_) {
if (ESDR3)drive_ = args.at(1); else drive_ = args.at(0);
busy_drive_ = false;
}
break;
case Cmd_Trx:
// printf("%s(%0.1f) Cmd_Trx : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) Cmd_Trx : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if(args.at(0)==rx_) {
if (args.at(1) == "false") PTT_ = false;
else if (args.at(1) == "true") PTT_ = true;
if (tci_Ready && requested_PTT_ == PTT_) tci_done3();
else if (tci_Ready && !PTT_) {
requested_PTT_ = PTT_;
update_PTT(PTT_);
power_ = 0; if (do_pwr_) update_power (0);
}
}
break;
case Cmd_AudioStart:
// printf("%s(%0.1f) Cmd_AudioStart : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) Cmd_AudioStart : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if(args.at(0)==rx_) {
stream_audio_ = true;
// printf ("cmdaudiostart done1\n");
tci_done1();
}
break;
case Cmd_RxEnable:
// printf("%s(%0.1f) Cmd_RxEnable : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) Cmd_RxEnable : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if(args.at(0)=="1") {
if (args.at(1) == "false") rx2_ = false;
else if (args.at(1) == "true") rx2_ = true;
if(!tci_Ready) {requested_rx2_ = rx2_; started_rx2_ = rx2_;}
else if (tci_Ready && busy_rx2_ && requested_rx2_ == rx2_) tci_done1();
}
break;
case Cmd_AudioStop:
// printf("%s(%0.1f) CmdAudioStop : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) CmdAudioStop : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if(args.at(0)==rx_) {
stream_audio_ = false;
// printf ("cmdaudiostop done1\n");
tci_done1();
}
break;
case Cmd_Start:
// printf("%s(%0.1f) CmdStart : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) CmdStart : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
_power_ = true;
// printf ("cmdstart done1\n");
if (tci_Ready) tci_done1();
break;
case Cmd_Stop:
// printf("%s(%0.1f) CmdStop : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) CmdStop : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if (tci_Ready && PTT_) {
PTT_ = false;
requested_PTT_ = PTT_;
update_PTT(PTT_);
power_ = 0; if (do_pwr_) update_power (0);
m_state = Idle;
Q_EMIT tci_mod_active(m_state != Idle);
}
_power_ = false;
if (tci_timer1_->isActive()) { /*printf ("cmdstop done1\n");*/ tci_done1();}
else {
tci_Ready = false;
}
break;
case Cmd_Version:
// printf("%s(%0.1f) CmdVersion : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) CmdVersion : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if(args.at(0)=="ExpertSDR3") ESDR3 = true;
break;
case Cmd_Device:
// printf("%s(%0.1f) CmdDevice : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) CmdVersion : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
if((args.at(0)=="SunSDR2DX" || args.at(0)=="SunSDR2PRO") && !ESDR3) tx_top_ = false;
// printf ("tx_top_:%d\n",tx_top_);
break;
case Cmd_Ready:
// printf("%s(%0.1f) CmdReady : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) CmdReady : %s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),args.join("|").toStdString().c_str());
fclose (pFile);
#endif
tci_done1();
break;
default:
break;
}
}
}
void TCITransceiver::sendTextMessage(const QString &message)
{
if (inConnected) commander_->sendTextMessage(message);
}
void TCITransceiver::onBinaryReceived(const QByteArray &data)
{
/* if (++cntIQ % 50 == 0){
bIQ = !bIQ;
nIqBytes+=data.size();
printf("receiveIQ\n");
emit receiveIQ(bIQ,nIqBytes);
nIqBytes = 0;
} else {
nIqBytes+=data.size();
} */
Data_Stream *pStream = (Data_Stream*)(data.data());
if (pStream->type != last_type) {
// printf ("%s(%0.1f) binary resceived type=%d last_type=%d %d samplerate %d stream_size %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),pStream->type,last_type,data.size(),pStream->sampleRate,pStream->length);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) binary resceived type=%d last_type=%d %d samplerate %d stream_size %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),pStream->type,last_type,data.size(),pStream->sampleRate,pStream->length);
fclose (pFile);
#endif
last_type = pStream->type;
#if JTDX_DEBUG_TO_FILE
if (last_type == TxChrono) { // audio transmit starts
struct {
char ariff[4]; //ChunkID: "RIFF"
int nchunk; //ChunkSize: 36+SubChunk2Size
char awave[4]; //Format: "WAVE"
char afmt[4]; //Subchunk1ID: "fmt "
int lenfmt; //Subchunk1Size: 16
short int nfmt2; //AudioFormat: 1
short int nchan2; //NumChannels: 1
int nsamrate; //SampleRate: 12000
int nbytesec; //ByteRate: SampleRate*NumChannels*BitsPerSample/8
short int nbytesam2; //BlockAlign: NumChannels*BitsPerSample/8
short int nbitsam2; //BitsPerSample: 16
char adata[4]; //Subchunk2ID: "data"
int ndata; //Subchunk2Size: numSamples*NumChannels*BitsPerSample/8
} hdr;
int npts=static_cast<int>(m_period) * 48000;
wavptr_ = fopen(wav_file_.c_str(),"wb");
if (wavptr_ != NULL) {
// Write a WAV header
hdr.ariff[0]='R';
hdr.ariff[1]='I';
hdr.ariff[2]='F';
hdr.ariff[3]='F';
hdr.nchunk=36 + 2*npts;
hdr.awave[0]='W';
hdr.awave[1]='A';
hdr.awave[2]='V';
hdr.awave[3]='E';
hdr.afmt[0]='f';
hdr.afmt[1]='m';
hdr.afmt[2]='t';
hdr.afmt[3]=' ';
hdr.lenfmt=16;
hdr.nfmt2=1;
hdr.nchan2=1;
hdr.nsamrate=48000;
hdr.nbytesec=2*48000;
hdr.nbytesam2=2;
hdr.nbitsam2=16;
hdr.adata[0]='d';
hdr.adata[1]='a';
hdr.adata[2]='t';
hdr.adata[3]='a';
hdr.ndata=2*npts;
fwrite(&hdr,sizeof(hdr),1,wavptr_);
}
}
else if (last_type == RxAudioStream) { // audio switched back to resceive
if (wavptr_ != NULL) {
fclose(wavptr_);
wavptr_ = nullptr;
}
}
#endif
}
if (pStream->type == Iq_Stream){
bool tx = false;
if (pStream->receiver == 0){
tx = trxA == 0;
trxA = 1;
}
if (pStream->receiver == 1) {
tx = trxB == 0;
trxB = 1;
}
// printf("sendIqData\n");
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"sendIqData\n");
fclose (pFile);
#endif
emit sendIqData(pStream->receiver,pStream->length,pStream->data,tx);
qDebug() << "IQ" << data.size() << pStream->length;
} else if (pStream->type == RxAudioStream && audio_ && pStream->receiver == rx_.toUInt()){
// printf("%s(%0.1f) writeAudioData\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
writeAudioData(pStream->data,pStream->length);
qDebug() << "Audio" << data.size() << pStream->length;
} else if (pStream->type == TxChrono && pStream->receiver == rx_.toUInt()){
tx_fifo += 1; tx_fifo &= 7;
int ssize = AudioHeaderSize+pStream->length*sizeof(float)*2;
// printf("%s(%0.1f) TxChrono ",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
quint16 tehtud;
if (m_tx1[tx_fifo].size() != ssize) m_tx1[tx_fifo].resize(ssize);
Data_Stream * pOStream1 = (Data_Stream*)(m_tx1[tx_fifo].data());
pOStream1->receiver = pStream->receiver;
pOStream1->sampleRate = pStream->sampleRate;
pOStream1->format = pStream->format;
pOStream1->codec = 0;
pOStream1->crc = 0;
pOStream1->length = pStream->length;
pOStream1->type = TxAudioStream;
// for (size_t i = 0; i < pStream->length; i++) pOStream1->data[i] = 0;
// printf("%s(%0.1f) txAudioChrono %d %d %d",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),ssize,pStream->length,pStream->sampleRate);
tehtud = readAudioData(pOStream1->data,pOStream1->length);
// printf(" %s(%0.1f) tehtud%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),tehtud);
if (tehtud && tehtud != pOStream1->length) {
quint32 valmis = tehtud;
// printf("%s(%0.1f) Audio build 1 mismatch requested %d done %d",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),pOStream1->length,tehtud);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) Audio build 1 mismatch requested %d done %d",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),pOStream1->length,tehtud);
#endif
tehtud = readAudioData(pOStream1->data + valmis,pOStream1->length - valmis);
// printf("got %d\n",tehtud);
#if JTDX_DEBUG_TO_FILE
fprintf (pFile,"got %d\n",tehtud);
fclose (pFile);
#endif
// if (tehtud && tehtud != pOStream1->length - valmis) {
// valmis += tehtud;
// for (size_t i = 0; i < pOStream1->length - valmis; i++) pOStream1->data[i+valmis] = 0;
// }
// else if (tehtud == 0) for (size_t i = 0; i < pOStream1->length - valmis; i++) pOStream1->data[i+valmis] = 0;
// }
// else if (tehtud == 0) {
// for (size_t i = 0; i < pStream->length; i++) pOStream1->data[i] = 0;
}
#if JTDX_DEBUG_TO_FILE
if (wavptr_ != NULL) {
static constexpr float K = 0x7FFF;
for (size_t i = 0; i < pOStream1->length; i+=2) {
qint16 value = static_cast<int16_t>(K*pOStream1->data[i]);
fwrite(&value,2,1,wavptr_);
}
}
#endif
if (!inConnected || commander_->sendBinaryMessage(m_tx1[tx_fifo]) != m_tx1[tx_fifo].size()) {
// printf("%s(%0.1f) Sent 1 loaded failed\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) Sent 1 loaded failed\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
fclose (pFile);
#endif
}
}
}
void TCITransceiver::txAudioData(quint32 len, float * data)
{
QByteArray tx;
// printf("%s(%0.1f) txAudioData %d %ld\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),len,(AudioHeaderSize+len*sizeof(float)*2));
tx.resize(AudioHeaderSize+len*sizeof(float)*2);
// printf("%s(%0.1f) txAudioData %d %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),len,tx.size());
// Data_Stream * pStream = reinterpret_cast<Data_Stream*>(tx.data());
Data_Stream * pStream = (Data_Stream*)(tx.data());
pStream->receiver = 0;
pStream->sampleRate = audioSampleRate;
pStream->format = 3;
pStream->codec = 0;
pStream->crc = 0;
pStream->length = len;
pStream->type = TxAudioStream;
memcpy(pStream->data,data,len*sizeof(float)*2);
commander_->sendBinaryMessage(tx);
}
quint32 TCITransceiver::writeAudioData (float * data, qint32 maxSize)
{
static unsigned mstr0=999999;
qint64 ms0 = m_jtdxtime->currentMSecsSinceEpoch2() % 86400000; //m_jtdxtime -> currentMSecsSinceEpoch2() % 86400000;
unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time
if(mstr < mstr0) { //When mstr has wrapped around to 0, restart the buffer
dec_data.params.kin = 0;
m_bufferPos = 0;
// printf("%s(%0.1f) reset buffer mstr:%d mstr0:%d maxSize:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),mstr,mstr0,maxSize);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) reset buffer mstr:%d mstr0:%d maxSize:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),mstr,mstr0,maxSize);
fclose (pFile);
#endif
}
mstr0=mstr;
// no torn frames
Q_ASSERT (!(maxSize % static_cast<qint32> (bytesPerFrame)));
// these are in terms of input frames (not down sampled)
size_t framesAcceptable ((sizeof (dec_data.d2) /
sizeof (dec_data.d2[0]) - dec_data.params.kin) * m_downSampleFactor);
size_t framesAccepted (qMin (static_cast<size_t> (maxSize /
bytesPerFrame), framesAcceptable));
if (framesAccepted < static_cast<size_t> (maxSize / bytesPerFrame)) {
qDebug () << "dropped " << maxSize / bytesPerFrame - framesAccepted
<< " frames of data on the floor!"
<< dec_data.params.kin << mstr;
// printf("%s(%0.1f) dropped %ld frames of data %d %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),maxSize / bytesPerFrame - framesAccepted,dec_data.params.kin,mstr);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) dropped %ld frames of data %d %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),maxSize / bytesPerFrame - framesAccepted,dec_data.params.kin,mstr);
fclose (pFile);
#endif
}
for (unsigned remaining = framesAccepted; remaining; ) {
size_t numFramesProcessed (qMin (m_samplesPerFFT *
m_downSampleFactor - m_bufferPos, remaining));
if(m_downSampleFactor > 1) {
// printf ("%s(%0.1f) writeAudioData maxs %d bytesPerFrame %ld Accepted %ld remaining %d Processed %ld Bufferpos %d kin %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),
// m_jtdxtime->GetOffset(),maxSize,bytesPerFrame,framesAccepted,remaining,numFramesProcessed,m_bufferPos,dec_data.params.kin);
store (&data[(framesAccepted - remaining) * bytesPerFrame],
numFramesProcessed, &m_buffer[m_bufferPos]);
m_bufferPos += numFramesProcessed;
if(m_bufferPos==m_samplesPerFFT*m_downSampleFactor) {
qint32 framesToProcess (m_samplesPerFFT * m_downSampleFactor);
qint32 framesAfterDownSample (m_samplesPerFFT);
if(m_downSampleFactor > 1 && dec_data.params.kin>=0 &&
dec_data.params.kin < (NTMAX*12000 - framesAfterDownSample)) {
fil4_(&m_buffer[0], &framesToProcess, &dec_data.d2[dec_data.params.kin],
&framesAfterDownSample, &dec_data.dd2[dec_data.params.kin]);
dec_data.params.kin += framesAfterDownSample;
} else {
// qDebug() << "framesToProcess = " << framesToProcess;
// qDebug() << "dec_data.params.kin = " << dec_data.params.kin;
// qDebug() << "secondInPeriod = " << secondInPeriod();
// qDebug() << "framesAfterDownSample" << framesAfterDownSample;
}
// printf("%s(%0.1f) frameswritten %d downSampleFactor %d samplesPerFFT %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),dec_data.params.kin,m_downSampleFactor,m_samplesPerFFT);
Q_EMIT tciframeswritten (dec_data.params.kin);
// printf("%s(%0.1f) frameswritten done\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
m_bufferPos = 0;
}
} else {
// printf ("%s(%0.1f) writeAudioData2 maxs %d bytesPerFrame %ld Accepted %ld remaining %d Processed %ld Bufferpos %d kin %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),maxSize,bytesPerFrame,framesAccepted,remaining,numFramesProcessed,m_bufferPos,dec_data.params.kin);
store (&data[(framesAccepted - remaining) * bytesPerFrame],
numFramesProcessed, &dec_data.d2[dec_data.params.kin]);
m_bufferPos += numFramesProcessed;
dec_data.params.kin += numFramesProcessed;
if (m_bufferPos == static_cast<unsigned> (m_samplesPerFFT)) {
// printf("%s(%0.1f) frameswritten2 %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),dec_data.params.kin);
Q_EMIT tciframeswritten (dec_data.params.kin);
// printf("%s(%0.1f) frameswritten2 done\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
m_bufferPos = 0;
}
}
remaining -= numFramesProcessed;
}
return maxSize; // we drop any data past the end of the buffer on
// the floor until the next period starts
}
void TCITransceiver::rx2_enable (bool on)
{
// printf ("%s(%0.1f) TCI rx2_enable:%d->%d busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),rx2_,on,busy_rx2_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI rx2_enable:%d->%d busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),rx2_,on,busy_rx2_);
fclose (pFile);
#endif
if (busy_rx2_) return;
requested_rx2_ = on;
busy_rx2_ = true;
const QString cmd = CmdRxEnable + SmDP + "1" + SmCM + (requested_rx2_ ? "true" : "false") + SmTZ;
sendTextMessage(cmd);
mysleep1(1000);
busy_rx2_ = false;
}
void TCITransceiver::rig_split ()
{
// printf ("%s(%0.1f) TCI rig_split:%d->%d busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),split_,requested_split_,busy_split_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI rig_split:%d->%d busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),split_,requested_split_,busy_split_);
fclose (pFile);
#endif
if (busy_split_) return;
busy_split_ = true;
const QString cmd = CmdSplitEnable + SmDP + rx_ + SmCM + (requested_split_ ? "true" : "false") + SmTZ;
sendTextMessage(cmd);
mysleep2(500);
busy_split_ = false;
}
void TCITransceiver::rig_power (bool on)
{
TRACE_CAT ("TCITransceiver", on << state ());
// printf ("%s(%0.1f) TCI rig_power:%d _power_:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,_power_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI rig_power:%d _power_:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,_power_);
fclose (pFile);
#endif
if (on != _power_) {
if (on) {
const QString cmd = CmdStart + SmTZ;
sendTextMessage(cmd);
} else {
const QString cmd = CmdStop + SmTZ;
sendTextMessage(cmd);
}
}
}
void TCITransceiver::stream_audio (bool on)
{
TRACE_CAT ("TCITransceiver", on << state ());
// printf ("%s(%0.1f) TCI stream_audio:%d stream_audio_:%d requested_stream_audio_:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,stream_audio_,requested_stream_audio_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI stream_audio:%d stream_audio_:%d requested_stream_audio_:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,stream_audio_,requested_stream_audio_);
fclose (pFile);
#endif
if (on != stream_audio_ && tci_Ready) {
requested_stream_audio_ = on;
if (on) {
const QString cmd = CmdAudioStart + SmDP + rx_ + SmTZ;
sendTextMessage(cmd);
} else {
const QString cmd = CmdAudioStop + SmDP + rx_ + SmTZ;
sendTextMessage(cmd);
}
}
}
void TCITransceiver::do_audio (bool on)
{
TRACE_CAT ("TCITransceiver", on << state ());
// printf ("%s(%0.1f) TCI do_audio:%d audio_:%d state:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,audio_,state().audio());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_audio:%d audio_:%d state:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,audio_,state().audio());
fclose (pFile);
#endif
if (on) {
dec_data.params.kin = 0;
m_bufferPos = 0;
}
audio_ = on;
}
void TCITransceiver::do_period (double period)
{
TRACE_CAT ("TCITransceiver", period << state ());
// printf ("%s(%0.1f) TCI do_period:%0.1f m_period_:%0.1f state:%0.1f\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),period,m_period,state().period());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_period:%0.1f m_period_:%0.1f state:%0.1f\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),period,m_period,state().period());
fclose (pFile);
#endif
m_period = period;
}
void TCITransceiver::do_txvolume (qreal volume)
{
TRACE_CAT ("TCITransceiver", volume << state ());
QString drive = QString::number(round(100 - volume * 2.2222222));
// printf ("%s(%0.1f) TCI do_txvolume:%0.1f state:%0.1f drive:%s drive_:%s drive_busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),volume,state().volume(),drive.toStdString().c_str(),drive_.toStdString().c_str(),busy_drive_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_txvolume:%0.1f state:%0.1f drive:%s drive_:%s drive_busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),volume,state().volume(),drive.toStdString().c_str(),drive_.toStdString().c_str(),busy_drive_);
fclose (pFile);
#endif
if (busy_drive_ || !tci_Ready || requested_drive_ == drive || drive_ == drive){
if (busy_drive_) busy_drive_ = false;
return;
} else busy_drive_ = true;
requested_drive_ = drive;
if (ESDR3) {
const QString cmd = CmdDrive + SmDP + rx_ + SmCM + drive + SmTZ;
sendTextMessage(cmd);
} else {
const QString cmd = CmdDrive + SmDP + drive + SmTZ;
sendTextMessage(cmd);
}
}
void TCITransceiver::do_blocksize (qint32 blocksize)
{
TRACE_CAT ("TCITransceiver", blocksize << state ());
// printf ("%s(%0.1f) TCI do_blocksize:%d m_samplesPerFFT:%d state:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),blocksize,m_samplesPerFFT,state().blocksize());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_blocksize:%d m_samplesPerFFT:%d state:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),blocksize,m_samplesPerFFT,state().blocksize());
fclose (pFile);
#endif
m_samplesPerFFT = blocksize;
}
void TCITransceiver::do_ptt (bool on)
{
TRACE_CAT ("TCITransceiver", on << state ());
// printf ("%s(%0.1f) TCI do_ptt:%d PTT_:%d requested_PTT_:%d busy_PTT_:%d state:%d use_for_ptt:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,PTT_,requested_PTT_,busy_PTT_,state().ptt(),use_for_ptt_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_ptt:%d PTT_:%d requested_PTT_:%d busy_PTT_:%d state:%d use_for_ptt:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,PTT_,requested_PTT_,busy_PTT_,state().ptt(),use_for_ptt_);
fclose (pFile);
#endif
if (use_for_ptt_)
{
if (on != PTT_) {
if (!inConnected && !error_.isEmpty()) throw error {error_};
// if (!inConnected){ PTT_ = on; update_PTT(on); return; }
else if (busy_PTT_ || !tci_Ready || !_power_) return;
else busy_PTT_ = true;
requested_PTT_ = on;
if (ESDR3) {
const QString cmd = CmdTrx + SmDP + rx_ + SmCM + (on ? "true" : "false") + SmCM + "tci"+ SmTZ;
sendTextMessage(cmd);
} else {
const QString cmd = CmdTrx + SmDP + rx_ + SmCM + (on ? "true" : "false") + SmTZ;
sendTextMessage(cmd);
}
mysleep3(1000);
busy_PTT_ = false;
if (requested_PTT_ == PTT_) {
update_PTT(PTT_);
if (PTT_ && do_snr_) update_level (-54);
else { power_ = 0; if (do_pwr_) update_power (0);}
} else {
// printf ("%s(%0.1f) TCI failed set ptt %d->%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),PTT_,requested_PTT_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI failed set ptt %d->%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),PTT_,requested_PTT_);
fclose (pFile);
#endif
error_ = tr ("TCI failed to set ptt");
// tci_Ready = false;
// throw error {tr ("TCI failed to set ptt")};
}
} else update_PTT(on);
}
else
{
TRACE_CAT ("TCITransceiver", "TCI should use PTT via CAT");
throw error {tr ("TCI should use PTT via CAT")};
}
}
void TCITransceiver::do_frequency (Frequency f, MODE m, bool no_ignore)
{
TRACE_CAT ("TCITransceiver", f << state ());
auto f_string = frequency_to_string (f);
// printf ("%s(%0.1f) TCI do_frequency:%s current_frequency:%s mode:%s current_mode:%s no_ignore:%d busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),f_string.toStdString().c_str(),rx_frequency_.toStdString().c_str(),map_mode(m).toStdString().c_str(),requested_mode_.toStdString().c_str(),no_ignore,busy_rx_frequency_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_frequency:%s current_frequency:%s mode:%s current_mode:%s no_ignore:%d busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),f_string.toStdString().c_str(),rx_frequency_.toStdString().c_str(),map_mode(m).toStdString().c_str(),requested_mode_.toStdString().c_str(),no_ignore,busy_rx_frequency_);
fclose (pFile);
#endif
if (tci_Ready && busy_rx_frequency_ && no_ignore) {
// printf ("%s(%0.1f) TCI do_frequency critical no_ignore set vfo will be missed\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_frequency critical no_ignore set vfo will be missed\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
fclose (pFile);
#endif
}
if (busy_rx_frequency_) return;
else {
requested_rx_frequency_ = f_string;
requested_mode_ = map_mode (m);
}
if (tci_Ready && _power_) {
if (rx_frequency_ != requested_rx_frequency_) {
busy_rx_frequency_ = true;
band_change = abs(rx_frequency_.toInt()-requested_rx_frequency_.toInt()) > 1000000;
const QString cmd = CmdVFO + SmDP + rx_ + SmCM + "0" + SmCM + requested_rx_frequency_ + SmTZ;
sendTextMessage(cmd);
mysleep1(1000);
// if (band_change) mysleep1(500);
if (requested_rx_frequency_ == rx_frequency_) update_rx_frequency (f);
else {
// printf ("%s(%0.1f) TCI failed set rxfreq:%s->%s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),rx_frequency_.toStdString().c_str(),requested_rx_frequency_.toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI failed set rxfreq:%s->%s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),rx_frequency_.toStdString().c_str(),requested_rx_frequency_.toStdString().c_str());
fclose (pFile);
#endif
error_ = tr ("TCI failed set rxfreq");
// tci_Ready = false;
// throw error {tr ("TCI failed set rxfreq")};
}
busy_rx_frequency_ = false;
}
if (!requested_mode_.isEmpty() && requested_mode_ != mode_) {
busy_mode_ = true;
sendTextMessage(mode_to_command(requested_mode_));
mysleep1(1000);
if (requested_mode_.isEmpty() || requested_mode_ == mode_) update_mode (m);
else {
// printf ("%s(%0.1f) TCI failed set mode %s->%s",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),mode_.toStdString().c_str(),requested_mode_.toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI failed set mode %s->%s",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),mode_.toStdString().c_str(),requested_mode_.toStdString().c_str());
fclose (pFile);
#endif
error_ = tr ("TCI failed set mode");
// tci_Ready = false;
// throw error {tr ("TCI failed set mode")};
}
busy_mode_ = false;
}
if (band_change) {
band_change = false;
tci_done2();
}
} else {
update_rx_frequency (f);
update_mode (m);
}
}
void TCITransceiver::do_tx_frequency (Frequency tx, MODE mode, bool no_ignore)
{
TRACE_CAT ("TCITransceiver", tx << state ());
auto f_string = frequency_to_string (tx);
// printf ("%s(%0.1f) TCI do_tx_frequency:%s current_frequency:%s mode:%s no_ignore:%d busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),f_string.toStdString().c_str(),other_frequency_.toStdString().c_str(),map_mode(mode).toStdString().c_str(),no_ignore,busy_other_frequency_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_tx_frequency:%s current_frequency:%s mode:%s no_ignore:%d busy:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),f_string.toStdString().c_str(),other_frequency_.toStdString().c_str(),map_mode(mode).toStdString().c_str(),no_ignore,busy_other_frequency_);
fclose (pFile);
#endif
if (tci_Ready && busy_other_frequency_ && no_ignore) {
// printf ("%s(%0.1f) TCI do_txfrequency critical no_ignore set tx vfo will be missed\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_txfrequency critical no_ignore set tx vfo will be missed\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
fclose (pFile);
#endif
}
if (busy_other_frequency_) return;
requested_other_frequency_ = f_string;
requested_mode_ = map_mode (mode);
if (tx)
{
requested_split_ = true;
if (tci_Ready && _power_) {
if (band_change) mysleep2(500);
if (requested_split_ != split_) rig_split();
if (requested_split_ == split_) update_split (split_);
else {
// printf ("%s(%0.1f) TCI failed set split:%d->%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),split_,requested_split_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI failed set split:%d->%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),split_,requested_split_);
fclose (pFile);
#endif
error_ = tr ("TCI failed set split");
// tci_Ready = false;
// throw error {tr ("TCI failed set split")};
}
if (other_frequency_ != requested_other_frequency_) {
busy_other_frequency_ = true;
const QString cmd = CmdVFO + SmDP + rx_ + SmCM + "1" + SmCM + requested_other_frequency_ + SmTZ;
sendTextMessage(cmd);
mysleep2(1000);
if (requested_other_frequency_ == other_frequency_) update_other_frequency (tx);
else {
// printf ("%s(%0.1f) TCI failed set txfreq:%s->%s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),other_frequency_.toStdString().c_str(),requested_other_frequency_.toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI failed set txfreq:%s->%s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),other_frequency_.toStdString().c_str(),requested_other_frequency_.toStdString().c_str());
fclose (pFile);
#endif
error_ = tr ("TCI failed set txfreq");
// tci_Ready = false;
// throw error {tr ("TCI failed set txfreq")};
}
busy_other_frequency_ = false;
}
} else {
update_split (requested_split_);
update_other_frequency (tx);
}
}
else {
requested_split_ = false;
if (tci_Ready && _power_) {
requested_other_frequency_ = "";
if (requested_split_ != split_) rig_split();
update_other_frequency (tx);
if (requested_split_ == split_) update_split (split_);
else {
// printf ("%s(%0.1f) TCI failed set split:%d->%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),split_,requested_split_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI failed set split:%d->%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),split_,requested_split_);
fclose (pFile);
#endif
error_ = tr ("TCI failed set split");
// tci_Ready = false;
// throw error {tr ("TCI failed set split")};
}
} else {
update_other_frequency (tx);
update_split (requested_split_);
}
}
}
void TCITransceiver::do_mode (MODE m)
{
TRACE_CAT ("TCITransceiver", m << state ());
auto m_string = map_mode (m);
// printf ("%s(%0.1f) TCI do_mode:%s->%s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),mode_.toStdString().c_str(),m_string.toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_mode:%s->%s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),mode_.toStdString().c_str(),m_string.toStdString().c_str());
fclose (pFile);
#endif
if (requested_mode_ != m_string) requested_mode_ = m_string;
if (mode_ != m_string) {
sendTextMessage(mode_to_command(m_string));
mysleep1(1000);
if (requested_mode_ == mode_) update_mode (m);
else {
// printf ("%s(%0.1f) TCI failed set mode %s->%s",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),mode_.toStdString().c_str(),requested_mode_.toStdString().c_str());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI failed set mode %s->%s",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),mode_.toStdString().c_str(),requested_mode_.toStdString().c_str());
fclose (pFile);
#endif
error_ = tr ("TCI failed set mode");
// tci_Ready = false;
// throw error {tr ("TCI failed set mode")};
}
}
}
void TCITransceiver::do_poll ()
{
if (!inConnected) {
// printf("%s(%0.1f) TCI do_poll |%s| split:%d ptt:%d rx_busy:%d tx_busy:%d level:%d power:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),error_.toStdString().c_str(),state ().split (),state (). ptt (),busy_rx_frequency_,busy_other_frequency_,level_,power_);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI do_poll |%s| split:%d ptt:%d rx_busy:%d tx_busy:%d level:%d power:%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),error_.toStdString().c_str(),state ().split (),state (). ptt (),busy_rx_frequency_,busy_other_frequency_,level_,power_);
fclose (pFile);
#endif
}
if (!inConnected && !error_.isEmpty()) throw error {error_};
else if (!tci_Ready) throw error {tr ("TCI could not be opened")};
update_rx_frequency (string_to_frequency (rx_frequency_));
update_split(split_);
if (state ().split ()) update_other_frequency (string_to_frequency (other_frequency_));
update_mode (get_mode());
if (do_pwr_ && PTT_) update_power (power_ * 100);
if (do_snr_ && !PTT_) {
update_level (level_);
if(!ESDR3) {
const QString cmd = CmdSmeter + SmDP + rx_ + SmCM + "0" + SmTZ;
sendTextMessage(cmd);
}
}
}
auto TCITransceiver::get_mode (bool requested) -> MODE
{
MODE m {UNK};
if (requested) {
if ("am" == requested_mode_)
{
m = AM;
}
else if ("cw" == requested_mode_)
{
m = CW;
}
else if ("wfm" == requested_mode_)
{
m = FM;
}
else if ("nfm" == requested_mode_)
{
m = DIG_FM;
}
else if ("lsb" == requested_mode_)
{
m = LSB;
}
else if ("usb" == requested_mode_)
{
m = USB;
}
else if ("digl" == requested_mode_)
{
m = DIG_L;
}
else if ("digu" == requested_mode_)
{
m = DIG_U;
}
else
{
m = USB;
}
} else {
if ("am" == mode_)
{
m = AM;
}
else if ("cw" == mode_)
{
m = CW;
}
else if ("wfm" == mode_)
{
m = FM;
}
else if ("nfm" == mode_)
{
m = DIG_FM;
}
else if ("lsb" == mode_)
{
m = LSB;
}
else if ("usb" == mode_)
{
m = USB;
}
else if ("digl" == mode_)
{
m = DIG_L;
}
else if ("digu" == mode_)
{
m = DIG_U;
}
else
{
m = USB;
}
}
return m;
}
QString TCITransceiver::mode_to_command (QString m_string) const
{
// if (ESDR3) {
// const QString cmd = CmdMode + SmDP + rx_ + SmCM + m_string.toUpper() + SmTZ;
// return cmd;
// } else {
const QString cmd = CmdMode + SmDP + rx_ + SmCM + m_string + SmTZ;
return cmd;
// }
}
QString TCITransceiver::frequency_to_string (Frequency f) const
{
// number is localized and in kHz, avoid floating point translation
// errors by adding a small number (0.1Hz)
auto f_string = QString {"%L2"}.arg (f);
// printf ("frequency_to_string1 %s\n",f_string.toStdString().c_str());
f_string = f_string.simplified().remove(' ');
// printf ("frequency_to_string2 %s\n",f_string.toStdString().c_str());
f_string = f_string.replace(",","");
f_string = f_string.replace(".","");
f_string = f_string.replace("'","");
// printf ("frequency_to_string3 %s\n",f_string.toStdString().c_str());
return f_string;
}
auto TCITransceiver::string_to_frequency (QString s) const -> Frequency
{
// temporary hack because Commander is returning invalid UTF-8 bytes
s.replace (QChar {QChar::ReplacementCharacter}, locale_.groupSeparator ());
bool ok;
auto f = QLocale::c ().toDouble (s, &ok); // temporary fix
if (!ok)
{
throw error {tr ("TCI sent an unrecognized frequency") + " |" + s + "|"};
}
return f;
}
void TCITransceiver::mysleep1 (int ms)
{
// tci_timer1->setSingleShot(true);
// printf("%s(%0.1f) TCI sleep1 start %d %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),ms,tci_timer1_->isActive());
tci_timer1_->start(ms);
tci_loop1_->exec();
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI sleep1 %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),tci_timer1_->isActive());
fclose (pFile);
#endif
// printf("%s(%0.1f) TCI sleep1 end %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),tci_timer1_->isActive());
if (tci_timer1_->isActive() && tci_Ready) tci_timer1_->stop();
}
void TCITransceiver::mysleep2 (int ms)
{
// tci_timer2->setSingleShot(true);
// printf("%s(%0.1f) TCI sleep2 start %d %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),ms,tci_timer2_->isActive());
tci_timer2_->start(ms);
tci_loop2_->exec();
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI sleep2 %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),tci_timer2_->isActive());
fclose (pFile);
#endif
// printf("%s(%0.1f) TCI sleep2 end %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),tci_timer2_->isActive());
if (tci_timer2_->isActive()) tci_timer2_->stop();
}
void TCITransceiver::mysleep3 (int ms)
{
// tci_timer3->setSingleShot(true);
// printf("%s(%0.1f) TCI sleep3 start %d %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),ms,tci_timer3_->isActive());
tci_timer3_->start(ms);
tci_loop3_->exec();
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI sleep3 %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),tci_timer3_->isActive());
fclose (pFile);
#endif
// printf("%s(%0.1f) TCI sleep3 end %d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),tci_timer3_->isActive());
if (tci_timer3_->isActive()) tci_timer3_->stop();
}
// Modulator part
void TCITransceiver::do_modulator_start (unsigned symbolsLength, double framesPerSymbol,
double frequency, double toneSpacing, bool synchronize, double dBSNR, double TRperiod)
{
// QThread::currentThread()->setPriority(QThread::HighPriority);
// Q_ASSERT (stream);
// Time according to this computer which becomes our base time
qint64 ms0 = m_jtdxtime->currentMSecsSinceEpoch2() % 86400000;
// qDebug() << "ModStart" << QDateTime::currentDateTimeUtc().toString("hh:mm:ss.sss");
unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time
if (m_state != Idle) {
// stop ();
throw error {tr ("TCI modulator not Idle")};
}
m_quickClose = false;
m_symbolsLength = symbolsLength;
m_isym0 = std::numeric_limits<unsigned>::max (); // big number
m_frequency0 = 0.;
m_phi = 0.;
m_addNoise = dBSNR < 0.;
m_nsps = framesPerSymbol;
m_trfrequency = frequency;
m_amp = std::numeric_limits<qint16>::max ();
m_toneSpacing = toneSpacing;
m_TRperiod=TRperiod;
unsigned delay_ms=1000;
if(m_nsps==1920) delay_ms=500; //FT8
else if(m_nsps==576) {
delay_ms=500; //FT4
}
// noise generator parameters
if (m_addNoise) {
m_snr = qPow (10.0, 0.05 * (dBSNR - 6.0));
m_fac = 3000.0;
if (m_snr > 1.0) m_fac = 3000.0 / m_snr;
}
// round up to an exact portion of a second that allows for startup delays
//m_ic = (mstr / delay_ms) * audioSampleRate * delay_ms / 1000;
auto mstr2 = mstr - delay_ms;
if (mstr <= delay_ms) {
m_ic = 0;
} else {
m_ic = mstr2 * (audioSampleRate / 1000);
}
m_silentFrames = 0;
// calculate number of silent frames to send
if (m_ic == 0 && synchronize && !m_tuning) {
m_silentFrames = audioSampleRate / (1000 / delay_ms) - (mstr * (audioSampleRate / 1000));
}
m_state = (synchronize && m_silentFrames) ?
Synchronizing : Active;
// printf ("%s(%0.1f) TCI modulator startdelay_ms=%d ASR=%d mstr=%d mstr2=%d m_ic=%d s_Frames=%lld State=%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),delay_ms,audioSampleRate,mstr,mstr2,m_ic,m_silentFrames,m_state);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI modulator startdelay_ms=%d ASR=%d mstr=%d mstr2=%d m_ic=%d s_Frames=%lld State=%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),delay_ms,audioSampleRate,mstr,mstr2,m_ic,m_silentFrames,m_state);
fclose (pFile);
#endif
Q_EMIT tci_mod_active(m_state != Idle);
}
void TCITransceiver::do_tune (bool newState)
{
// printf("%s(%0.1f) TCI modulator tune %d ->%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),m_tuning,newState);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI modulator tune %d ->%d\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),m_tuning,newState);
fclose (pFile);
#endif
m_tuning = newState;
if (!m_tuning) do_modulator_stop (true);
}
void TCITransceiver::do_modulator_stop (bool quick)
{
m_quickClose = quick;
if(m_state != Idle) {
m_state = Idle;
Q_EMIT tci_mod_active(m_state != Idle);
}
tx_audio_ = false;
}
quint16 TCITransceiver::readAudioData (float * data, qint32 maxSize)
{
double toneFrequency=1500.0;
if(m_nsps==6) {
toneFrequency=1000.0;
m_trfrequency=1000.0;
m_frequency0=1000.0;
}
if(maxSize==0) return 0;
qint64 numFrames (maxSize/bytesPerFrame);
float * samples (reinterpret_cast<float *> (data));
float * end (samples + numFrames * bytesPerFrame);
// printf("%s(%0.1f) readAudioData %d %p %p\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),maxSize,samples,end);
qint64 framesGenerated (0);
switch (m_state)
{
case Synchronizing:
{
if (m_silentFrames) { // send silence up to first second
framesGenerated = qMin (m_silentFrames, numFrames);
for ( ; samples != end; samples = load (0, samples)) { // silence
}
m_silentFrames -= framesGenerated;
return framesGenerated * bytesPerFrame;
}
m_state = Active;
Q_EMIT tci_mod_active(m_state != Idle);
m_cwLevel = false;
m_ramp = 0; // prepare for CW wave shaping
}
// fall through
case Active:
{
unsigned int isym=0;
qint16 sample=0;
if(!m_tuning) isym=m_ic/(4.0*m_nsps); // Actual fsample=48000
bool slowCwId=((isym >= m_symbolsLength) && (icw[0] > 0));
m_nspd=2560; // 22.5 WPM
if(m_TRperiod > 16.0 && slowCwId) { // Transmit CW ID?
m_dphi = m_twoPi*m_trfrequency/audioSampleRate;
unsigned ic0 = m_symbolsLength * 4 * m_nsps;
unsigned j(0);
while (samples != end) {
j = (m_ic - ic0)/m_nspd + 1; // symbol of this sample
bool level {bool (icw[j])};
m_phi += m_dphi;
if (m_phi > m_twoPi) m_phi -= m_twoPi;
sample=0;
float amp=32767.0;
float x=0.0;
if(m_ramp!=0) {
x=qSin(float(m_phi));
if(SOFT_KEYING) {
amp=qAbs(qint32(m_ramp));
if(amp>32767.0) amp=32767.0;
}
sample=round(amp*x);
}
if (int (j) <= icw[0] && j < NUM_CW_SYMBOLS) { // stopu condition
samples = load (postProcessSample (sample), samples);
++framesGenerated;
++m_ic;
} else {
m_state = Idle;
// printf("%s(%0.1f) TCI modulator Idle1 %lld frames generated\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),framesGenerated);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI modulator Idle1 %lld frames generated\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),framesGenerated);
fclose (pFile);
#endif
Q_EMIT tci_mod_active(m_state != Idle);
return framesGenerated * bytesPerFrame;
}
// adjust ramp
if ((m_ramp != 0 && m_ramp != std::numeric_limits<qint16>::min ()) || level != m_cwLevel) {
// either ramp has terminated at max/min or direction has changed
m_ramp += RAMP_INCREMENT; // ramp
}
m_cwLevel = level;
}
return framesGenerated * bytesPerFrame;
} //End of code for CW ID
double const baud (12000.0 / m_nsps);
// fade out parameters (no fade out for tuning)
unsigned int i0,i1;
if(m_tuning) {
i1 = i0 = 9999 * m_nsps;
} else {
i0=(m_symbolsLength - 0.017) * 4.0 * m_nsps;
i1= m_symbolsLength * 4.0 * m_nsps;
}
sample=0;
for (unsigned i = 0; i < numFrames && m_ic <= i1; ++i) {
// printf("algus %d %lld %d %d",i,numFrames,m_ic,i1);
if(m_TRperiod > 16.0 || m_tuning) {
isym=0;
if(!m_tuning) isym=m_ic / (4.0 * m_nsps); //Actual fsample=48000
if (isym != m_isym0 || m_trfrequency != m_frequency0) {
if(itone[0]>=100) {
m_toneFrequency0=itone[0];
} else {
if(m_toneSpacing==0.0) {
m_toneFrequency0=m_trfrequency + itone[isym]*baud;
} else {
m_toneFrequency0=m_trfrequency + itone[isym]*m_toneSpacing;
}
}
// qDebug() << "B" << m_ic << numFrames << isym << itone[isym] << toneFrequency0 << m_nsps;
m_dphi = m_twoPi * m_toneFrequency0 / audioSampleRate;
m_isym0 = isym;
m_frequency0 = m_trfrequency; //???
}
int j=m_ic/480;
if(m_fSpread>0.0 and j!=m_j0) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
float x1=QRandomGenerator::global ()->generateDouble ();
float x2=QRandomGenerator::global ()->generateDouble ();
#else
float x1=(float)qrand()/RAND_MAX;
float x2=(float)qrand()/RAND_MAX;
#endif
toneFrequency = m_toneFrequency0 + 0.5*m_fSpread*(x1+x2-1.0);
m_dphi = m_twoPi * toneFrequency / audioSampleRate;
m_j0=j;
}
m_phi += m_dphi;
if (m_phi > m_twoPi) m_phi -= m_twoPi;
//ramp for first tone
if (m_ic==0) m_amp = m_amp * 0.008144735;
if (m_ic > 0 and m_ic < 191) m_amp = m_amp / 0.975;
//ramp for last tone
if (m_ic > i0) m_amp = 0.99 * m_amp;
if (m_ic > i1) m_amp = 0.0;
sample=qRound(m_amp*qSin(m_phi));
}
//transmit from a precomputed FT8 wave[] array:
if(!m_tuning and (m_toneSpacing < 0.0)) { m_amp=32767.0; sample=qRound(m_amp*foxcom_.wave[m_ic]); }
samples = load (postProcessSample (sample), samples);
++framesGenerated; ++m_ic;
}
// printf("sample saved %lld %d\n",framesGenerated,m_ic);
if (m_amp == 0.0) { // TODO G4WJS: compare double with zero might not be wise
if (icw[0] == 0) {
// no CW ID to send
m_state = Idle;
// printf("%s(%0.1f) TCI modulator Idle2 %lld frames generated\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),framesGenerated);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI modulator Idle2 %lld frames generated\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),framesGenerated);
fclose (pFile);
#endif
Q_EMIT tci_mod_active(m_state != Idle);
return framesGenerated * bytesPerFrame;
}
m_phi = 0.0;
}
m_frequency0 = m_trfrequency;
// done for this chunk - continue on next call
if (samples != end && framesGenerated) {
// printf("%s(%0.1f) TCI modulator Idle3 %lld frames generated\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),framesGenerated);
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) TCI modulator Idle3 %lld frames generated\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),framesGenerated);
fclose (pFile);
#endif
}
while (samples != end) { // pad block with silence
samples = load (0, samples);
++framesGenerated;
}
return framesGenerated * bytesPerFrame;
}
// fall through
case Idle:
break;
}
Q_ASSERT (Idle == m_state);
return 0;
}
qint16 TCITransceiver::postProcessSample (qint16 sample) const
{
if (m_addNoise) { // Test frame, we'll add noise
qint32 s = m_fac * (gran () + sample * m_snr / 32768.0);
if (s > std::numeric_limits<qint16>::max ()) {
s = std::numeric_limits<qint16>::max ();
}
if (s < std::numeric_limits<qint16>::min ()) {
s = std::numeric_limits<qint16>::min ();
}
sample = s;
}
return sample;
}