jtdx/TCITransceiver.cpp
2022-02-27 20:14:04 +02:00

2018 lines
88 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
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;
HPSDR = 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;
requested_rx2_ = false;
started_rx2_ = false;
split_ = false;
requested_split_ = false;
started_split_ = false;
PTT_ = false;
requested_PTT_ = false;
mode_ = "";
requested_mode_ = "";
started_mode_ = "";
requested_rx_frequency_ = "";
rx_frequency_ = "";
requested_other_frequency_ = "";
other_frequency_ = "";
requested_drive_ = "";
drive_ = "";
level_ = -54;
power_ = 0;
swr_ = 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 (210);
if (HPSDR) {
busy_split_ = true;
const QString cmd = CmdSplitEnable + SmDP + rx_ + SmTZ;
sendTextMessage(cmd);
mysleep2(500);
busy_split_ = false;
}
if (error_.isEmpty()) {
tci_Ready = true;
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);}
if (!requested_drive_.isEmpty() && requested_drive_ != drive_) {
busy_drive_ = true;
if (ESDR3) {
const QString cmd = CmdDrive + SmDP + rx_ + SmCM + requested_drive_ + SmTZ;
sendTextMessage(cmd);
} else {
const QString cmd = CmdDrive + SmDP + requested_drive_ + SmTZ;
sendTextMessage(cmd);
}
}
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 (!commander_) return;
#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_other_frequency_ = "";
if (started_split_ != split_) {requested_split_ = started_split_; rig_split();}
if (started_mode_ != mode_) sendTextMessage(mode_to_command(started_mode_));
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());
// printf("band_change:%d busy_other_frequency_:%d timer1_remaining:%d timer2_remaining:%d",band_change,busy_other_frequency_,tci_timer1_->remainingTime(),tci_timer2_->remainingTime());
#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());
fprintf (pFile,"band_change:%d busy_other_frequency_:%d timer1_remaining:%d timer2_remaining:%d",band_change,busy_other_frequency_,tci_timer1_->remainingTime(),tci_timer2_->remainingTime());
#endif
if(args.at(0)==rx_ && args.at(1) == "0") {
if (args.at(2).left(1) != "-") rx_frequency_ = args.at(2);
if (!tci_Ready && requested_rx_frequency_.isEmpty()) {requested_rx_frequency_ = rx_frequency_; }
if (busy_rx_frequency_ && !band_change) {
// printf (" cmdvfo0 done1");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile," cmdvfo0 done1");
#endif
tci_done1();
} else if (!tci_timer2_->isActive() && split_) {
// printf (" cmdvfo0 timer2 start 210");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile," cmdvfo0 timer2 start 210");
#endif
tci_timer2_->start(210);
}
}
else if (args.at(0)==rx_ && args.at(1) == "1") {
if (args.at(2).left(1) != "-") other_frequency_ = args.at(2);
// if (!tci_Ready && requested_other_frequency_.isEmpty()) requested_other_frequency_ = other_frequency_;
if (band_change && tci_timer1_->isActive()) {
// printf (" cmdvfo1 done1");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile," cmdvfo1 done1");
#endif
band_change = false;
tci_timer2_->start(210);
tci_done1();
} else if (busy_other_frequency_) {
// printf (" cmdvfo1 done2");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile," cmdvfo1 done2");
#endif
tci_done2();
} else if (tci_timer2_->isActive()) {
// printf (" cmdvfo1 timer2 reset 210");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile," cmdvfo1 timer2 reset 210");
#endif
tci_timer2_->start(210);
} else if (other_frequency_ != requested_other_frequency_ && tci_Ready && split_ && !tci_timer2_->isActive()) {
// printf (" cmdvfo1 timer2 start 210");
#if JTDX_DEBUG_TO_FILE
fprintf (pFile," cmdvfo1 timer2 start 210");
#endif
tci_timer2_->start(210);
}
}
// printf("->%d\n",tci_timer2_->remainingTime());
#if JTDX_DEBUG_TO_FILE
fprintf(pFile,"->%d\n",tci_timer2_->remainingTime());
fclose (pFile);
#endif
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 || HPSDR) {
if (args.at(1) == "0" ) mode_ = args.at(2).toLower(); else mode_ = args.at(1).toLower();
} else mode_ = args.at(1);
if (started_mode_.isEmpty()) started_mode_ = mode_;
if (busy_mode_) tci_done1();
else if (!requested_mode_.isEmpty() && 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 (!tci_Ready) {started_split_ = split_;}
else if (busy_split_) tci_done2();
else if (requested_split_ != split_ && !tci_timer2_->isActive()) {
tci_timer2_->start(210);
rig_split();
}
}
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 && !HPSDR) || args.at(0)==rx_) {
if (ESDR3 || HPSDR) drive_ = args.at(1); else drive_ = args.at(0);
if (requested_drive_.isEmpty()) requested_drive_ = drive_;
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);
swr_ = 0; if (do_pwr_) update_swr (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;
if (tci_Ready) { //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;
if (tci_Ready) { //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);
swr_ = 0; if (do_pwr_) update_swr (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;
else if (args.at(0)=="Thetis") HPSDR = 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) CmdDevice : %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 received type=%d last_type=%d %d samplerate %d stream_size %d frame_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,data.size());
#if JTDX_DEBUG_TO_FILE
FILE * pFile = fopen (debug_file_.c_str(),"a");
fprintf (pFile,"%s(%0.1f) binary received type=%d last_type=%d %d samplerate %d stream_size %d frame_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,data.size());
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()){
mtx_.lock(); 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);/* m_tx1[tx_fifo].fill('\0x00');*/}
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) {
quint16 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
tx_fifo2 = tx_fifo; mtx_.unlock();
if (!inConnected || commander_->sendBinaryMessage(m_tx1[tx_fifo2]) != m_tx1[tx_fifo2].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
}
}// else printf ("Unused binary message received type=%d receiver=%d\n",pStream->type,pStream->receiver);
}
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/2) { //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;
if (tci_timer2_->isActive()) mysleep2(0);
busy_split_ = true;
const QString cmd = CmdSplitEnable + SmDP + rx_ + SmCM + (requested_split_ ? "true" : "false") + SmTZ;
sendTextMessage(cmd);
mysleep2(500);
busy_split_ = false;
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");
}
}
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 rx_=%s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,stream_audio_,requested_stream_audio_,rx_.toStdString().c_str());
#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 rx_=%s\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),on,stream_audio_,requested_stream_audio_,rx_.toStdString().c_str());
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 tci_Ready:%d 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(),tci_Ready,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 tci_Ready:%d 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(),tci_Ready,volume,state().volume(),drive.toStdString().c_str(),drive_.toStdString().c_str(),busy_drive_);
fclose (pFile);
#endif
requested_drive_ = drive;
if (busy_drive_ || !tci_Ready || drive_ == drive) {
if (busy_drive_) busy_drive_ = false;
} else {
busy_drive_ = true;
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); swr_ = 0; if (do_pwr_) update_swr (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(2000);
// 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;
} else update_rx_frequency (string_to_frequency (rx_frequency_));
if (!requested_mode_.isEmpty() && requested_mode_ != mode_ && !busy_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) {
// tci_timer2_->start(210);
// band_change = false;
// }
} 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 timer:%d remaining:%d band_change:%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_,tci_timer2_->isActive(),tci_timer2_->remainingTime(),band_change);
#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 timer:%d remaining:%d band_change:%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_,tci_timer2_->isActive(),tci_timer2_->remainingTime(),band_change);
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 && !tci_timer2_->isActive()) {if (!HPSDR) mysleep2(210); else mysleep2(2000);}
else if (tci_timer2_->isActive()) mysleep2(0);
if (requested_split_ != split_) rig_split();
else update_split (split_);
if (other_frequency_ != requested_other_frequency_) {
busy_other_frequency_ = true;
// printf ("%s(%0.1f) TCI VFO1 command sent\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 VFO1 command sent\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset());
fclose (pFile);
#endif
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_other_frequency (string_to_frequency (other_frequency_));
} else {
update_split (requested_split_);
update_other_frequency (tx);
}
}
else {
requested_split_ = false;
requested_other_frequency_ = "";
if (tci_Ready && _power_) {
if (band_change) {mysleep2(2000); if (!HPSDR) mysleep2(200);}
if (tci_timer2_->isActive()) mysleep2(0);
if (requested_split_ != split_) rig_split();
else update_split (split_);
update_other_frequency (tx);
} else {
update_split (requested_split_);
update_other_frequency (tx);
}
}
}
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 (!requested_mode_.isEmpty() && mode_ != requested_mode_ && !busy_mode_) {
busy_mode_ = true;
sendTextMessage(mode_to_command(requested_mode_));
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")};
}
busy_mode_ = false;
}
}
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()) {tci_Ready = false; 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 ()) {
if (other_frequency_ == requested_other_frequency_) update_other_frequency (string_to_frequency (other_frequency_));
else if (!busy_rx_frequency_) do_tx_frequency(string_to_frequency (requested_other_frequency_),get_mode(true),false);
}
update_mode (get_mode());
if (do_pwr_ && PTT_) {update_power (power_ * 100); update_swr (swr_*10);}
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 {
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;
}
}
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);
auto f_string = QString {}.setNum(f);
// f_string = f_string.simplified().remove(' ');
// f_string = f_string.replace(",","");
// 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());
if (ms) 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());
if (ms) 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());
if (ms) 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 synchronize=%d m_tuning=%d 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,synchronize,m_tuning,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 synchronize=%d m_tuning=%d 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,synchronize,m_tuning,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 %f %f %lld %lld %d %p %p\n",m_jtdxtime->currentDateTimeUtc2().toString("hh:mm:ss.zzz").toStdString().c_str(),m_jtdxtime->GetOffset(),m_nsps,m_TRperiod,numFrames,m_silentFrames,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:
while (samples != end) samples = load (0, samples);
}
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;
}