1
0
mirror of https://github.com/JvanKatwijk/qt-dab.git synced 2025-10-06 08:12:40 +02:00
Files
SDR-DAB_Qt-DAB/qt-dab-RC/radio.cpp

4009 lines
124 KiB
C++
Raw Normal View History

2024-01-27 20:16:14 +01:00
#
/*
* Copyright (C) 2015, 2023
* Jan van Katwijk (J.vanKatwijk@gmail.com)
* Lazy Chair Computing
*
* This file is part of the Qt-DAB
*
* Qt-DAB is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Qt-DAB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Qt-DAB; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <QCoreApplication>
#include <QSettings>
#include <QMessageBox>
#include <QDebug>
#include <QDateTime>
#include <QFile>
#include <QStringList>
#include <QMouseEvent>
#include <QDir>
2024-02-06 15:37:07 +01:00
#include <QColorDialog>
2024-01-27 20:16:14 +01:00
#include <fstream>
#include "dab-constants.h"
#include "mot-content-types.h"
#include <iostream>
#include <numeric>
#include <vector>
#include "radio.h"
2024-02-16 15:46:54 +01:00
#include "config-handler.h"
2024-01-27 20:16:14 +01:00
#include "ofdm-handler.h"
#include "schedule-selector.h"
#include "element-selector.h"
#include "dab-tables.h"
#include "dab-params.h"
#include "ITU_Region_1.h"
#include "coordinates.h"
#include "mapport.h"
#include "techdata.h"
#include "aboutdialog.h"
2024-02-25 14:18:27 +01:00
#include "db-loader.h"
#include "cacheElement.h"
#include "distances.h"
2024-03-04 14:45:33 +01:00
#include "position-handler.h"
2024-01-27 20:16:14 +01:00
#ifdef TCP_STREAMER
#include "tcp-streamer.h"
#else
2024-03-13 19:45:53 +01:00
#include "Qt-audio.h"
2024-01-27 20:16:14 +01:00
#include "audiosink.h"
#endif
#include "time-table.h"
#include "device-exceptions.h"
2024-02-25 14:18:27 +01:00
#include "settingNames.h"
2024-03-13 19:45:53 +01:00
#include "uploader.h"
2024-01-27 20:16:14 +01:00
2024-03-13 19:45:53 +01:00
#if defined (__MINGW32__) || defined (_WIN32)
2024-01-27 20:16:14 +01:00
#include <windows.h>
__int64 FileTimeToInt64 (FILETIME & ft) {
ULARGE_INTEGER foo;
foo.LowPart = ft.dwLowDateTime;
foo.HighPart = ft.dwHighDateTime;
return (foo.QuadPart);
}
bool get_cpu_times (size_t &idle_time, size_t &total_time) {
FILETIME IdleTime, KernelTime, UserTime;
size_t thisIdle, thisKernel, thisUser;
GetSystemTimes (&IdleTime, &KernelTime, &UserTime);
thisIdle = FileTimeToInt64 (IdleTime);
thisKernel = FileTimeToInt64 (KernelTime);
thisUser = FileTimeToInt64 (UserTime);
idle_time = (size_t) thisIdle;
total_time = (size_t)(thisKernel + thisUser);
return true;
}
#else
std::vector<size_t> get_cpu_times() {
std::ifstream proc_stat ("/proc/stat");
proc_stat. ignore (5, ' '); // Skip the 'cpu' prefix.
std::vector<size_t> times;
for (size_t time; proc_stat >> time; times. push_back (time));
return times;
}
bool get_cpu_times (size_t &idle_time, size_t &total_time) {
const std::vector <size_t> cpu_times = get_cpu_times();
if (cpu_times. size() < 4)
return false;
idle_time = cpu_times [3];
total_time = std::accumulate (cpu_times. begin(),
cpu_times. end(), (size_t)0);
return true;
}
2024-03-13 19:45:53 +01:00
#include <unistd.h>
#endif
2024-04-03 18:44:52 +02:00
static inline
QString ids_to_string (int mainId, int subId) {
return "(" + QString::number (mainId) + "-"
2024-04-03 18:44:52 +02:00
+ QString::number (subId) + ")";
}
2024-03-13 19:45:53 +01:00
static inline
QStringList splitter (const QString &s) {
#if QT_VERSION >= QT_VERSION_CHECK (5, 15, 2)
QStringList list = s.split (":", Qt::SkipEmptyParts);
#else
QStringList list = s.split (":", QString::SkipEmptyParts);
2024-01-27 20:16:14 +01:00
#endif
2024-03-13 19:45:53 +01:00
return list;
}
2024-01-27 20:16:14 +01:00
static const
2024-02-06 15:37:07 +01:00
char LABEL_STYLE [] = "color:lightgreen";
2024-01-27 20:16:14 +01:00
RadioInterface::RadioInterface (QSettings *Si,
const QString &scanListFile,
const QString &presetFile,
const QString &freqExtension,
const QString &schedule,
bool error_report,
int32_t dataPort,
int32_t clockPort,
int fmFrequency,
QWidget *parent):
QWidget (parent),
2024-06-01 11:12:04 +02:00
theSpectrumBuffer (16 * 32768),
theIQBuffer (2 * 1536),
theTIIBuffer (32768),
theNULLBuffer (32768),
theChannelBuffer (4096),
theSNRBuffer (512),
theResponseBuffer (32768),
theFrameBuffer (2 * 32768),
theDataBuffer (32768),
theAudioBuffer (8 * 32768),
2024-01-27 20:16:14 +01:00
stdDevBuffer (2 * 1536),
2024-06-01 11:12:04 +02:00
theNewDisplay (this, Si),
theSNRViewer (this, Si),
theDLCache (10),
theTIIProcessor (Si),
theFilenameFinder (Si),
2024-01-27 20:16:14 +01:00
theScheduler (this, schedule),
theTechData (16 * 32768),
2024-06-01 11:12:04 +02:00
theAudioConverter (this),
theScanlistHandler (this,
2024-01-27 20:16:14 +01:00
scanListFile),
2024-06-01 11:12:04 +02:00
theDeviceChoser (Si),
theDXDisplay (this, Si),
theSCANHandler (this, Si, freqExtension) {
2024-01-27 20:16:14 +01:00
int16_t k;
QString h;
dabSettings_p = Si;
this -> error_report = error_report;
this -> fmFrequency = fmFrequency;
this -> dlTextFile = nullptr;
this -> ficDumpPointer = nullptr;
this -> the_aboutLabel = nullptr;
running. store (false);
2024-06-01 11:12:04 +02:00
theOFDMHandler = nullptr;
2024-01-27 20:16:14 +01:00
stereoSetting = false;
maxDistance = -1;
contentTable_p = nullptr;
scanTable_p = nullptr;
mapHandler = nullptr;
2024-06-01 11:12:04 +02:00
theDXDisplay. hide ();
2024-01-27 20:16:14 +01:00
// "globals" is introduced to reduce the number of parameters
// for the ofdmHandler
2024-06-01 11:12:04 +02:00
globals. spectrumBuffer = &theSpectrumBuffer;
globals. iqBuffer = &theIQBuffer;
globals. responseBuffer = &theResponseBuffer;
globals. tiiBuffer = &theTIIBuffer;
globals. nullBuffer = &theNULLBuffer;
globals. channelBuffer = &theChannelBuffer;
globals. snrBuffer = &theSNRBuffer;
globals. frameBuffer = &theFrameBuffer;
2024-01-27 20:16:14 +01:00
globals. stdDevBuffer = &stdDevBuffer;
globals. dabMode =
2024-03-04 14:45:33 +01:00
dabSettings_p -> value ("dabMode", 1). toInt ();
2024-01-27 20:16:14 +01:00
globals. threshold =
dabSettings_p -> value ("threshold", 3). toInt();
globals. diff_length =
dabSettings_p -> value ("diff_length", DIFF_LENGTH). toInt();
globals. tii_delay =
dabSettings_p -> value ("tii_delay", 5). toInt();
if (globals. tii_delay < 2)
globals. tii_delay = 2;
globals. tii_depth =
dabSettings_p -> value ("tii_depth", 4). toInt();
globals. echo_depth =
dabSettings_p -> value ("echo_depth", 1). toInt();
#ifdef _SEND_DATAGRAM_
ipAddress = dabSettings_p -> value ("ipAddress", "127.0.0.1"). toString();
port = dabSettings_p -> value ("port", 8888). toInt();
#endif
// set on top or not? checked at start up
2024-02-25 14:18:27 +01:00
if (int_configValue ("onTop", 0) == 1)
2024-01-27 20:16:14 +01:00
setWindowFlags (windowFlags () | Qt::WindowStaysOnTopHint);
for (int i = 0; i < 4; i ++) {
QPixmap p;
QString labelName =
QString (":res/signal%1.png"). arg (i, 1, 10, QChar ('0'));
p. load (labelName, "png");
strengthLabels. push_back (p);
}
// The settings are done, now creation of the GUI parts
setupUi (this);
// and init the up and down button
{ QPixmap p;
if (p. load (":res/up-arrow.png", "png"))
prevChannelButton -> setPixmap (p. scaled (30, 30, Qt::KeepAspectRatio));
if (p. load (":res/down-arrow.png", "png"))
nextChannelButton -> setPixmap (p. scaled (30, 30, Qt::KeepAspectRatio));
if (p. load (":res/details24.png", "png"))
serviceButton -> setPixmap (p. scaled (30, 30, Qt::KeepAspectRatio));
else
2024-01-29 15:47:49 +01:00
fprintf (stderr, "Loading details button failed\n");
2024-01-27 20:16:14 +01:00
}
2024-03-13 19:45:53 +01:00
// put the widgets in the right place and create the workers
2024-04-15 14:03:12 +02:00
set_position_and_size (dabSettings_p, this, S_MAIN_WIDGET);
2024-02-16 15:46:54 +01:00
configHandler_p = new configHandler (this, dabSettings_p);
2024-01-27 20:16:14 +01:00
the_ensembleHandler = new ensembleHandler (this, dabSettings_p,
presetFile);
2024-02-16 15:46:54 +01:00
// we have the configuration handler and the ensemble handler,
// connect some signals directly
configHandler_p -> set_connections ();
2024-06-01 11:12:04 +02:00
configHandler_p -> setDeviceList (theDeviceChoser.
2024-03-30 19:39:33 +01:00
getDeviceList ());
connect (configHandler_p, &configHandler::frameClosed,
this, &RadioInterface::handle_configFrame_closed);
connect (configHandler_p, &configHandler::handle_fontSelect,
the_ensembleHandler, &ensembleHandler::handle_fontSelect);
connect (configHandler_p, &configHandler::handle_fontSizeSelect,
the_ensembleHandler, &ensembleHandler::handle_fontSizeSelect);
connect (configHandler_p, &configHandler::handle_fontColorSelect,
the_ensembleHandler,& ensembleHandler::handle_fontColorSelect);
connect (configHandler_p, &configHandler::set_serviceOrder,
the_ensembleHandler, &ensembleHandler::set_serviceOrder);
2024-06-01 11:12:04 +02:00
connect (&theNewDisplay, &displayWidget::frameClosed,
this, &RadioInterface::handle_newDisplayFrame_closed);
2024-01-27 20:16:14 +01:00
#ifdef HAVE_RTLSDR_V3
2024-03-04 14:45:33 +01:00
SystemVersion = QString ("X") + " with RTLSDR-V3";
2024-01-27 20:16:14 +01:00
#elif HAVE_RTLSDR_V4
2024-03-04 14:45:33 +01:00
SystemVersion = QString ("X") + " with RTLSDR-V4";
2024-01-27 20:16:14 +01:00
#else
2024-03-04 14:45:33 +01:00
SystemVersion = QString ("X");
2024-01-27 20:16:14 +01:00
#endif
setWindowTitle ("Qt-DAB-6." +SystemVersion);
ensembleWidget -> setWidget (the_ensembleHandler);
2024-03-04 14:45:33 +01:00
connect (the_ensembleHandler,
&ensembleHandler::selectService,
this, &RadioInterface::localSelect_SS);
2024-01-27 20:16:14 +01:00
connect (the_ensembleHandler,
&ensembleHandler::start_background_task,
this, &RadioInterface::start_background_task);
2024-01-27 20:16:14 +01:00
techWindow_p = new techData (this, dabSettings_p, &theTechData);
connect (techWindow_p, &techData::frameClosed,
this, &RadioInterface::handle_techFrame_closed);
2024-02-25 14:18:27 +01:00
if (dabSettings_p -> value (NEW_DISPLAY_VISIBLE, 0). toInt () != 0)
2024-06-01 11:12:04 +02:00
theNewDisplay. show ();
2024-01-27 20:16:14 +01:00
else
2024-06-01 11:12:04 +02:00
theNewDisplay. hide ();
2024-01-27 20:16:14 +01:00
2024-02-25 14:18:27 +01:00
labelStyle = dabSettings_p -> value (LABEL_COLOR,
2024-02-06 15:37:07 +01:00
LABEL_STYLE). toString ();
2024-03-04 14:45:33 +01:00
QFont font = serviceLabel -> font ();
font. setPointSize (16);
font. setBold (true);
serviceLabel -> setStyleSheet (labelStyle);
serviceLabel -> setFont (font);
programTypeLabel -> setStyleSheet (labelStyle);
2024-03-13 19:45:53 +01:00
font = ensembleId -> font ();
font. setPointSize (14);
ensembleId -> setFont (font);
2024-03-04 14:45:33 +01:00
2024-02-16 15:46:54 +01:00
nextService. valid = false;
2024-01-27 20:16:14 +01:00
channel. currentService. valid = false;
channel. serviceCount = -1;
channel. targetPos = position {0, 0};
2024-02-16 15:46:54 +01:00
localPos. latitude =
2024-02-25 14:18:27 +01:00
dabSettings_p -> value (HOME_LATITUDE, 0). toFloat ();
2024-02-16 15:46:54 +01:00
localPos. longitude =
2024-02-25 14:18:27 +01:00
dabSettings_p -> value (HOME_LONGITUDE, 0). toFloat ();
2024-01-27 20:16:14 +01:00
logFile = nullptr;
techWindow_p -> hide (); // until shown otherwise
stillMuting -> hide ();
2024-03-13 19:45:53 +01:00
2024-01-27 20:16:14 +01:00
#ifdef DATA_STREAMER
dataStreamer_p = new tcpServer (dataPort);
#else
(void)dataPort;
#endif
#ifdef CLOCK_STREAMER
clockStreamer_p = new tcpServer (clockPort);
#else
(void)clockPort;
#endif
// Where do we leave the audio out?
2024-02-16 15:46:54 +01:00
configHandler_p -> show_streamSelector (false);
2024-03-13 19:45:53 +01:00
int latency = dabSettings_p -> value ("latency", 5). toInt();
2024-04-03 18:44:52 +02:00
soundOut_p = nullptr;
2024-01-27 20:16:14 +01:00
#ifdef TCP_STREAMER
soundOut_p = new tcpStreamer (20040);
techWindow_p -> hide ();
#else
2024-03-13 19:45:53 +01:00
QStringList streams;
QString temp;
2024-04-15 14:03:12 +02:00
QString s = dabSettings_p -> value (S_SOUND_HANDLER, S_PORT_AUDIO).
2024-03-13 19:45:53 +01:00
toString ();
//
2024-04-15 14:03:12 +02:00
if (s != S_PORT_AUDIO) {
try {
soundOut_p = new Qt_Audio (dabSettings_p);
streams = ((Qt_Audio *)soundOut_p) -> streams ();
temp =
dabSettings_p -> value (QT_AUDIO_STREAM_NAME,
"default"). toString ();
volumeSlider -> show ();
int volume =
dabSettings_p -> value (QT_AUDIO_VOLUME, 50). toInt ();
volumeSlider -> setValue (volume);
((Qt_Audio *)soundOut_p) -> setVolume (volume);
connect (volumeSlider, &QSlider::valueChanged,
this, &RadioInterface::setVolume);
} catch (...) {
2024-08-27 12:40:14 +02:00
fprintf (stderr, "QT_AUDIO does not find streams\n");
soundOut_p = nullptr;
}
}
if (soundOut_p == nullptr) {
2024-03-13 19:45:53 +01:00
soundOut_p = new audioSink (latency);
streams = ((audioSink *)soundOut_p) -> streams ();
temp =
dabSettings_p -> value (AUDIO_STREAM_NAME,
2024-02-25 14:18:27 +01:00
"default"). toString ();
volumeSlider -> hide ();
2024-03-13 19:45:53 +01:00
}
if (streams. size () > 0) {
configHandler_p -> fill_streamTable (streams);
configHandler_p -> show_streamSelector (true);
k = configHandler_p -> init_streamTable (temp);
if (k >= 0)
2024-03-13 19:45:53 +01:00
soundOut_p -> selectDevice (k);
configHandler_p -> connect_streamTable ();
2024-01-27 20:16:14 +01:00
}
2024-03-25 14:35:22 +01:00
else {
2024-03-27 16:24:49 +01:00
delete soundOut_p;
soundOut_p = new audioPlayer ();
2024-03-25 14:35:22 +01:00
}
2024-01-27 20:16:14 +01:00
#endif
#ifndef __MINGW32__
path_for_pictures = checkDir (QDir::tempPath ());
#else
path_for_pictures = checkDir (QDir::homePath ());
#endif
path_for_pictures += "Qt-DAB-files/";
2024-04-15 14:03:12 +02:00
path_for_pictures = dabSettings_p -> value (S_PICTURES_PATH,
2024-01-27 20:16:14 +01:00
path_for_pictures). toString ();
path_for_pictures = checkDir (path_for_pictures);
if (path_for_files != "")
path_for_files = checkDir (path_for_files);
2024-04-15 14:03:12 +02:00
path_for_files = dabSettings_p -> value (S_FILE_PATH,
2024-03-04 14:45:33 +01:00
path_for_pictures). toString ();
2024-01-27 20:16:14 +01:00
//
#ifndef __MINGW32__
epgPath = checkDir (QDir::tempPath ());
#else
epgPath = checkDir (QDir::homePath ());
#endif
epgPath += "Qt-DAB-files/";
2024-04-15 14:03:12 +02:00
epgPath = dabSettings_p -> value (S_EPG_PATH,
epgPath). toString ();
2024-01-27 20:16:14 +01:00
epgPath = checkDir (epgPath);
connect (&epgProcessor, &epgDecoder::set_epgData,
this, &RadioInterface::set_epgData);
2024-01-27 20:16:14 +01:00
// timer for autostart epg service
epgTimer. setSingleShot (true);
2024-04-14 12:47:14 +02:00
connect (&epgTimer, &QTimer::timeout,
this, &RadioInterface::epgTimer_timeOut);
2024-03-13 19:45:53 +01:00
pauzeTimer. setSingleShot (true);
2024-04-14 12:47:14 +02:00
connect (&pauzeTimer, &QTimer::timeout,
this, &RadioInterface::show_pauzeSlide);
2024-01-27 20:16:14 +01:00
my_timeTable = new timeTableHandler (this);
my_timeTable -> hide ();
2024-06-01 11:12:04 +02:00
connect (&theScanlistHandler, &scanListHandler::handle_scanListSelect,
2024-04-14 12:47:14 +02:00
this, &RadioInterface::handle_scanListSelect);
2024-01-27 20:16:14 +01:00
// extract the channelnames and fill the combobox
2024-06-01 11:12:04 +02:00
QStringList res = theSCANHandler. getChannelNames ();
2024-01-27 20:16:14 +01:00
for (auto &s: res)
channelSelector -> addItem (s);
2024-06-01 11:12:04 +02:00
QPalette p = theNewDisplay. ficError_display -> palette();
2024-01-27 20:16:14 +01:00
p. setColor (QPalette::Highlight, Qt::red);
2024-06-01 11:12:04 +02:00
theNewDisplay. ficError_display -> setPalette (p);
2024-01-27 20:16:14 +01:00
p. setColor (QPalette::Highlight, Qt::green);
//
2024-07-28 12:47:27 +02:00
audioDumping = false;
2024-07-27 15:30:56 +02:00
sourceDumping = false;
2024-01-27 20:16:14 +01:00
ficBlocks = 0;
ficSuccess = 0;
total_ficError = 0;
total_fics = 0;
previous_idle_time = 0;
previous_total_time = 0;
// Connect the buttons for the color_settings
2024-04-14 12:47:14 +02:00
connect (scanButton, &smallPushButton::rightClicked,
this, &RadioInterface::color_scanButton);
connect (scanListButton, &newPushButton::rightClicked,
this, &RadioInterface::color_scanListButton);
connect (presetButton, &newPushButton::rightClicked,
this, &RadioInterface::color_presetButton);
connect (configButton, &smallPushButton::rightClicked,
this, &RadioInterface::color_configButton);
connect (httpButton, &smallPushButton::rightClicked,
this, &RadioInterface::color_httpButton);
connect (prevServiceButton, &smallPushButton::rightClicked,
this, &RadioInterface::color_prevServiceButton);
connect (nextServiceButton, &smallPushButton::rightClicked,
this, &RadioInterface::color_nextServiceButton);
connect (spectrumButton, &smallPushButton::rightClicked,
this, &RadioInterface::color_spectrumButton);
2024-01-27 20:16:14 +01:00
//
//
2024-04-14 12:47:14 +02:00
connect (techWindow_p, &techData::handle_timeTable,
this, &RadioInterface::handle_timeTable);
2024-06-01 11:12:04 +02:00
connect (&theNewDisplay, &displayWidget::mouseClick,
2024-04-14 12:47:14 +02:00
this, &RadioInterface::handle_iqSelector);
2024-01-27 20:16:14 +01:00
// display the version
version = "Qt-DAB-6." + SystemVersion;
2024-04-14 12:47:14 +02:00
connect (aboutLabel, &clickablelabel::clicked,
this, &RadioInterface::handle_aboutLabel);
2024-01-27 20:16:14 +01:00
2024-04-14 12:47:14 +02:00
connect (soundLabel, &clickablelabel::clicked,
this, &RadioInterface::handle_muteButton);
connect (snrLabel, &clickablelabel::clicked,
this, &RadioInterface::handle_snrLabel);
2024-01-27 20:16:14 +01:00
2024-06-01 11:12:04 +02:00
// if (theTIIProcessor. has_tiiFile ())
2024-02-25 14:18:27 +01:00
configHandler_p -> enable_loadLib ();
2024-04-14 18:35:47 +02:00
// else
// httpButton -> setEnabled (false);
2024-01-27 20:16:14 +01:00
channel. etiActive = false;
show_pauzeSlide ();
// and start the timer(s)
// The displaytimer is there to show the number of
// seconds running and handle - if available - the tii data
displayTimer. setInterval (1000);
2024-04-14 12:47:14 +02:00
connect (&displayTimer, &QTimer::timeout,
this, &RadioInterface::updateTimeDisplay);
2024-01-27 20:16:14 +01:00
displayTimer. start (1000);
numberofSeconds = 0;
// timer for scanning
channelTimer. setSingleShot (true);
channelTimer. setInterval (10000);
2024-04-14 12:47:14 +02:00
connect (&channelTimer, &QTimer::timeout,
this, &RadioInterface::channel_timeOut);
2024-01-27 20:16:14 +01:00
//
// presetTimer
presetTimer. setSingleShot (true);
2024-04-14 12:47:14 +02:00
connect (&presetTimer, &QTimer::timeout,
this, &RadioInterface::setPresetService);
2024-01-27 20:16:14 +01:00
//
// timer for muting
muteTimer. setSingleShot (true);
set_Colors ();
//
2024-04-14 18:35:47 +02:00
// do we have a known device from previous invocations?
2024-01-27 20:16:14 +01:00
inputDevice_p = nullptr;
h =
2024-02-25 14:18:27 +01:00
dabSettings_p -> value (SELECTED_DEVICE,
"no device"). toString();
2024-02-16 15:46:54 +01:00
bool b = configHandler_p -> findDevice (h);
if (b) {
inputDevice_p = create_device (h);
2024-01-27 20:16:14 +01:00
}
//
// do we show controls?
2024-02-25 14:18:27 +01:00
bool visible =
dabSettings_p -> value (CONFIG_WIDGET_VISIBLE,
0). toInt () != 0;
if (visible) {
2024-02-16 15:46:54 +01:00
configHandler_p -> show ();
2024-01-27 20:16:14 +01:00
}
2024-04-14 12:47:14 +02:00
connect (configButton, &QPushButton::clicked,
this, &RadioInterface::handle_configButton);
2024-01-27 20:16:14 +01:00
2024-02-25 14:18:27 +01:00
if (dabSettings_p -> value (SNR_WIDGET_VISIBLE, 0). toInt () != 0)
2024-06-01 11:12:04 +02:00
theSNRViewer. show ();
2024-01-27 20:16:14 +01:00
else
2024-06-01 11:12:04 +02:00
theSNRViewer. hide ();
2024-02-25 14:18:27 +01:00
if (dabSettings_p -> value (TECHDATA_VISIBLE, 0). toInt () == 1)
2024-01-27 20:16:14 +01:00
techWindow_p -> show ();
2024-01-29 15:47:49 +01:00
dynamicLabel -> setTextInteractionFlags(Qt::TextSelectableByMouse);
dynamicLabel -> setToolTip ("The text (or parts of it) of the dynamic label can be copied. Selecting the text with the mouse and clicking the right hand mouse button shows a small menu with which the text can be put into the clipboard");
2024-02-25 14:18:27 +01:00
//
// Until the opposite is known to be true:
nextService. channel = "";
nextService. serviceName = "";
nextService. valid = false;
2024-01-27 20:16:14 +01:00
// if a device was selected, we just start, otherwise
// we wait until one is selected
2024-02-25 14:18:27 +01:00
connectGUI ();
2024-01-27 20:16:14 +01:00
if (inputDevice_p != nullptr) {
2024-04-14 12:47:14 +02:00
doStart_direct ();
2024-02-25 14:18:27 +01:00
qApp -> installEventFilter (this);
return;
2024-01-27 20:16:14 +01:00
}
2024-02-25 14:18:27 +01:00
if (!visible) { // make it visible
dabSettings_p -> setValue (CONFIG_WIDGET_VISIBLE, 1);
dabSettings_p -> setValue (DEVICE_WIDGET_VISIBLE, 1);
2024-01-27 20:16:14 +01:00
}
2024-02-16 15:46:54 +01:00
configHandler_p -> show ();
configHandler_p -> connectDevices ();
2024-01-27 20:16:14 +01:00
qApp -> installEventFilter (this);
2024-02-25 14:18:27 +01:00
//
// and just wait to see what device is selected
2024-01-27 20:16:14 +01:00
}
//
// doStart (QString) is called when - on startup - NO device
// was registered to be used, and the user presses the
// selectDevice comboBox
void RadioInterface::doStart (const QString &dev) {
inputDevice_p = create_device (dev);
// Some buttons should not be touched before we have a device
if (inputDevice_p == nullptr) {
return;
}
2024-04-14 12:47:14 +02:00
doStart_direct ();
2024-01-27 20:16:14 +01:00
}
//
2024-02-25 14:18:27 +01:00
// we (re)start a device, if it happens to be a regular
// device, check for a preset name
2024-04-14 12:47:14 +02:00
void RadioInterface::doStart_direct () {
2024-04-15 14:03:12 +02:00
disconnect (channelSelector,
qOverload<const QString &> (&QComboBox::activated),
2024-04-14 12:47:14 +02:00
this, &RadioInterface::handle_channelSelector);
2024-02-25 14:18:27 +01:00
nextService = checkPresets ();
if (nextService. valid) {
2024-02-16 15:46:54 +01:00
int k = channelSelector -> findText (nextService. channel);
2024-01-27 20:16:14 +01:00
if (k != -1)
channelSelector -> setCurrentIndex (k);
}
else
channelSelector -> setCurrentIndex (0);
2024-06-01 11:12:04 +02:00
theOFDMHandler = new ofdmHandler (this,
2024-01-27 20:16:14 +01:00
inputDevice_p, &globals, dabSettings_p);
channel. cleanChannel ();
the_ensembleHandler -> reset ();
the_ensembleHandler -> setMode (!inputDevice_p -> isFileInput ());
2024-02-25 14:18:27 +01:00
if (dabSettings_p -> value (DEVICE_WIDGET_VISIBLE, 0). toInt () != 0)
2024-01-27 20:16:14 +01:00
inputDevice_p -> setVisibility (true);
2024-04-03 18:44:52 +02:00
2024-01-27 20:16:14 +01:00
// Just to be sure we disconnect here.
// It would have been helpful to have a function
// testing whether or not a connection exists, we need a kind
// of "reset"
2024-02-16 15:46:54 +01:00
configHandler_p -> disconnectDevices ();
configHandler_p -> reconnectDevices ();
2024-04-15 14:03:12 +02:00
connect (channelSelector,
qOverload<const QString &> (&QComboBox::activated),
2024-04-14 12:47:14 +02:00
this, &RadioInterface::handle_channelSelector);
2024-02-25 14:18:27 +01:00
if (configHandler_p -> tii_detector_active ())
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_tiiDetectorMode (true);
2024-02-25 14:18:27 +01:00
2024-02-16 15:46:54 +01:00
if (nextService. valid) {
int switchDelay = configHandler_p -> switchDelayValue ();
2024-01-27 20:16:14 +01:00
presetTimer. setSingleShot (true);
2024-02-16 15:46:54 +01:00
presetTimer. setInterval (switchDelay);
presetTimer. start (switchDelay);
2024-01-27 20:16:14 +01:00
// after the preset timer signals, the service will be started
2024-02-25 14:18:27 +01:00
}
2024-07-27 15:30:56 +02:00
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
2024-04-19 18:34:50 +02:00
int auto_http = dabSettings_p -> value ("auto_http", 0). toInt ();
if ((auto_http != 0) && (localPos. latitude != 0)) {
bool succ = autoStart_http ();
if (succ)
httpButton -> setText ("http-on");
}
2024-01-27 20:16:14 +01:00
running. store (true);
}
RadioInterface::~RadioInterface () {
fprintf (stderr, "radioInterface is deleted\n");
}
2024-02-25 14:18:27 +01:00
dabService RadioInterface::checkPresets () {
dabService res;
res. channel = "";
res. serviceName = "";
res. valid = false;
if (inputDevice_p -> isFileInput ())
return res;
QString preset = dabSettings_p -> value (PRESET_NAME, ""). toString ();
if (preset == "")
return res;
2024-03-13 19:45:53 +01:00
QStringList list = splitter (preset);
2024-02-25 14:18:27 +01:00
if (list. size () != 2)
return res;
res. channel = list. at (0);
res. serviceName = list. at (1);
res. valid = true;
return res;
}
2024-01-27 20:16:14 +01:00
//
2024-03-04 14:45:33 +01:00
// no_signal_found is called when scanning is on by the
// ofdm handler
void RadioInterface::no_signal_found () {
channel_timeOut ();
2024-01-27 20:16:14 +01:00
}
///////////////////////////////////////////////////////////////////////////
//
// a slot, called by the fic/fib handlers
void RadioInterface::add_to_ensemble (const QString &serviceName,
2024-03-27 16:24:49 +01:00
int32_t SId, int subChId) {
2024-01-27 20:16:14 +01:00
if (!running. load())
return;
serviceId ed;
ed. name = serviceName;
ed. SId = SId;
ed. subChId = subChId;
ed. channel = channel. channelName;
bool added = the_ensembleHandler -> add_to_ensemble (ed);
if (added) {
channel. nrServices ++;
2024-06-01 11:12:04 +02:00
if (theSCANHandler. active ())
theSCANHandler. addService (channel. channelName);
if (theSCANHandler. active () && !theSCANHandler. scan_to_data ()) {
theScanlistHandler. addElement (channel. channelName,
2024-01-27 20:16:14 +01:00
serviceName);
}
}
2024-02-25 14:18:27 +01:00
2024-01-27 20:16:14 +01:00
if ((channel. serviceCount == channel. nrServices)&&
2024-06-01 11:12:04 +02:00
!theSCANHandler. active ()) {
2024-03-04 14:45:33 +01:00
// presetTimer. stop ();
2024-01-27 20:16:14 +01:00
setPresetService ();
}
}
//
// The ensembleId is written as hexadecimal, however, the
// number display of Qt is only 7 segments ...
static
QString hextoString (int v) {
QString res;
for (int i = 0; i < 4; i ++) {
uint8_t t = (v & 0xF000) >> 12;
QChar c = t <= 9 ? (char)('0' + t) : (char) ('A' + t - 10);
res. append (c);
v <<= 4;
}
return res;
}
// a slot, called by the fib processor
void RadioInterface::name_of_ensemble (int id, const QString &v) {
QString s;
if (!running. load())
return;
ensembleId -> setText (v + QString ("(") + hextoString (id) + QString (")"));
2024-09-04 09:46:23 +02:00
transmitter_country -> setText (channel. countryName);
2024-01-27 20:16:14 +01:00
channel. ensembleName = v;
channel. Eid = id;
//
// id we are scanning "to data", we reached the end
2024-06-01 11:12:04 +02:00
if (theSCANHandler. scan_to_data ())
2024-01-27 20:16:14 +01:00
stopScanning ();
else
2024-06-01 11:12:04 +02:00
if (theSCANHandler. active () && theSCANHandler. scan_single ())
theSCANHandler. addEnsemble (channelSelector -> currentText (), v);
2024-01-27 20:16:14 +01:00
// ... and is we are not scanning, clicking the ensembleName
// has effect
2024-06-01 11:12:04 +02:00
if (!theSCANHandler. active ())
2024-04-14 12:47:14 +02:00
connect (ensembleId, &clickablelabel::clicked,
this, &RadioInterface::handle_contentButton);
2024-01-27 20:16:14 +01:00
}
//
///////////////////////////////////////////////////////////////////////////
void RadioInterface::handle_contentButton () {
2024-06-01 11:12:04 +02:00
QStringList s = theOFDMHandler -> basicPrint ();
2024-01-27 20:16:14 +01:00
if (contentTable_p != nullptr) {
contentTable_p -> hide ();
delete contentTable_p;
contentTable_p = nullptr;
return;
}
2024-04-07 14:58:26 +02:00
QString headLine = build_headLine ();
2024-01-27 20:16:14 +01:00
contentTable_p = new contentTable (this, dabSettings_p,
channel. channelName,
2024-06-01 11:12:04 +02:00
theOFDMHandler -> scanWidth ());
2024-04-14 12:47:14 +02:00
connect (contentTable_p, &contentTable::goService,
this, &RadioInterface::handle_contentSelector);
2024-01-27 20:16:14 +01:00
2024-04-07 14:58:26 +02:00
contentTable_p -> addLine (headLine);
2024-01-27 20:16:14 +01:00
// contentTable_p -> addLine ("\n");
2024-02-25 14:18:27 +01:00
for (auto &ss : s)
contentTable_p -> addLine (ss);
2024-01-27 20:16:14 +01:00
contentTable_p -> show ();
2024-03-04 14:45:33 +01:00
if (configHandler_p -> upload_selector_active ()) {
2024-03-13 19:45:53 +01:00
try {
uploader the_uploader;
QMessageBox::StandardButton reply =
2024-03-04 14:45:33 +01:00
QMessageBox::question (this,
2024-03-13 19:45:53 +01:00
"upload content to fmlist.org?", "",
2024-03-04 14:45:33 +01:00
QMessageBox::Yes | QMessageBox::No);
2024-03-13 19:45:53 +01:00
if (reply == QMessageBox::Yes)
the_uploader. loadUp (channel. ensembleName,
channel. Eid,
channel. channelName,
contentTable_p -> upload ());
} catch (...) {}
2024-03-04 14:45:33 +01:00
}
2024-01-27 20:16:14 +01:00
}
2024-07-16 19:52:55 +02:00
QString RadioInterface::checkDir (const QString &s) {
2024-01-27 20:16:14 +01:00
QString dir = s;
if (!dir. endsWith (QChar ('/')))
dir += QChar ('/');
if (QDir (dir). exists())
return dir;
QDir (). mkpath (dir);
return dir;
}
void RadioInterface::handle_motObject (QByteArray result,
QString objectName,
int contentType,
bool dirElement,
bool backgroundFlag) {
QString realName;
switch (getContentBaseType ((MOTContentType)contentType)) {
case MOTBaseTypeGeneralData:
break;
case MOTBaseTypeText:
save_MOTtext (result, contentType, objectName);
break;
case MOTBaseTypeImage:
show_MOTlabel (result, contentType,
objectName, dirElement, backgroundFlag);
break;
case MOTBaseTypeAudio:
break;
case MOTBaseTypeVideo:
break;
case MOTBaseTypeTransport:
save_MOTObject (result, objectName);
break;
case MOTBaseTypeSystem:
break;
case MOTBaseTypeApplication: // epg data
if (epgPath == "")
return;
if (objectName == QString (""))
objectName = "epg file";
objectName = epgPath + objectName;
2024-04-22 20:35:15 +02:00
{ QString temp = objectName;
2024-01-27 20:16:14 +01:00
temp = temp. left (temp. lastIndexOf (QChar ('/')));
if (!QDir (temp). exists ())
QDir (). mkpath (temp);
std::vector<uint8_t> epgData (result. begin(),
result. end());
// uint32_t ensembleId =
2024-06-01 11:12:04 +02:00
// theOFDMHandler -> get_ensembleId ();
2024-01-27 20:16:14 +01:00
uint32_t currentSId =
the_ensembleHandler -> extract_SId (objectName);
uint32_t julianDate =
2024-06-01 11:12:04 +02:00
theOFDMHandler -> julianDate ();
2024-01-27 20:16:14 +01:00
int subType =
getContentSubType ((MOTContentType)contentType);
epgProcessor. process_epg (epgData. data (),
epgData. size (), currentSId,
subType,
julianDate);
2024-02-16 15:46:54 +01:00
if (configHandler_p -> epg2_active ()) {
2024-01-27 20:16:14 +01:00
epgHandler. decode (epgData,
QDir::toNativeSeparators (objectName));
}
}
return;
case MOTBaseTypeProprietary:
break;
}
}
void RadioInterface::save_MOTtext (QByteArray &result,
int contentType,
const QString &name) {
(void)contentType;
if (path_for_files == "")
return;
QString textName = QDir::toNativeSeparators (path_for_files + name);
FILE *x = fopen (textName. toUtf8 (). data (), "w+b");
if (x == nullptr)
fprintf (stderr, "cannot write file %s\n",
textName. toUtf8 (). data ());
else {
fprintf (stderr, "going to write file %s\n",
textName. toUtf8(). data());
(void)fwrite (result. data (), 1, result.length(), x);
fclose (x);
}
}
void RadioInterface::save_MOTObject (QByteArray &result,
QString name) {
if (path_for_files == "")
return;
if (name == "") {
static int counter = 0;
name = "motObject_" + QString::number (counter);
counter ++;
}
save_MOTtext (result, 5, name);
}
// MOT slide, to show
void RadioInterface::show_MOTlabel (QByteArray &data,
int contentType,
const QString &pictureName,
int dirs,
bool backgroundFlag) {
const char *type;
if (!running. load() || (pictureName == QString ("")))
return;
(void)dirs;
switch (static_cast<MOTContentType>(contentType)) {
case MOTCTImageGIF:
type = "GIF";
break;
case MOTCTImageJFIF:
type = "JPG";
break;
case MOTCTImageBMP:
type = "BMP";
break;
case MOTCTImagePNG:
type = "PNG";
break;
default:
return;
}
2024-02-25 14:18:27 +01:00
if ((int_configValue ("saveSlides", 0) != 0) &&
2024-02-16 15:46:54 +01:00
(path_for_pictures != "")) {
2024-01-27 20:16:14 +01:00
QString pict = path_for_pictures + pictureName;
QString temp = pict;
temp = temp. left (temp. lastIndexOf (QChar ('/')));
if (!QDir (temp). exists())
QDir (). mkpath (temp);
pict = QDir::toNativeSeparators (pict);
FILE *x = fopen (pict. toUtf8 (). data (), "w+b");
if (x == nullptr)
fprintf (stderr, "cannot write file %s\n",
pict. toUtf8 (). data ());
else {
fprintf (stderr, "going to write file %s\n",
pict. toUtf8(). data());
(void)fwrite (data. data(), 1, data.length(), x);
fclose (x);
}
}
if (backgroundFlag)
return;
if (channel. currentService. valid &&
channel. currentService. announcement_going)
return;
QPixmap p;
if (p. loadFromData (data, type))
displaySlide (p);
}
//
// sendDatagram is triggered by the ip handler,
void RadioInterface::sendDatagram (int length) {
2024-04-22 20:35:15 +02:00
uint8_t *localBuffer = dynVec (uint8_t, length);
2024-01-27 20:16:14 +01:00
2024-06-01 11:12:04 +02:00
if (theDataBuffer. GetRingBufferReadAvailable() < length) {
2024-01-27 20:16:14 +01:00
fprintf (stderr, "Something went wrong\n");
return;
}
2024-06-01 11:12:04 +02:00
theDataBuffer. getDataFromBuffer (localBuffer, length);
2024-01-27 20:16:14 +01:00
#ifdef _SEND_DATAGRAM_
if (running. load ()) {
dataOut_socket. writeDatagram ((const char *)localBuffer, length,
QHostAddress (ipAddress),
port);
}
#endif
}
//
// tdcData is triggered by the backend.
void RadioInterface::handle_tdcdata (int frametype, int length) {
#ifdef DATA_STREAMER
2024-04-22 20:35:15 +02:00
uint8_t *localBuffer = dynVec (uint8_t, length + 8);
2024-01-27 20:16:14 +01:00
#endif
(void)frametype;
if (!running. load())
return;
2024-06-01 11:12:04 +02:00
if (theDataBuffer. GetRingBufferReadAvailable() < length) {
2024-01-27 20:16:14 +01:00
fprintf (stderr, "Something went wrong\n");
return;
}
#ifdef DATA_STREAMER
2024-03-27 16:24:49 +01:00
// fprintf (stderr, "%d\n", length);
2024-06-01 11:12:04 +02:00
theDataBuffer. getDataFromBuffer (&localBuffer [8], length);
2024-01-27 20:16:14 +01:00
localBuffer [0] = 0xFF;
localBuffer [1] = 0x00;
localBuffer [2] = 0xFF;
localBuffer [3] = 0x00;
localBuffer [4] = (length & 0xFF) >> 8;
localBuffer [5] = length & 0xFF;
localBuffer [6] = 0x00;
localBuffer [7] = frametype == 0 ? 0 : 0xFF;
if (running. load())
dataStreamer_p -> sendData (localBuffer, length + 8);
#endif
}
/**
* If a change is detected, we have to restart the selected
* service - if any. If the service is a secondary service,
* it might be the case that we have to start the main service
* how do we find that?
*
* Response to a signal, so we presume that the signaling body exists
* signal may be pending though
*/
2024-09-14 14:57:15 +02:00
void RadioInterface::changeinConfiguration (const QStringList &notInOld,
const QStringList &notInNew) {
2024-06-01 11:12:04 +02:00
if (!running. load () || theOFDMHandler == nullptr)
2024-01-27 20:16:14 +01:00
return;
2024-09-14 14:57:15 +02:00
2024-01-27 20:16:14 +01:00
dabService s;
if (channel. currentService. valid) {
s = channel. currentService;
s. serviceName = channel. currentService. serviceName;
s. SId = channel. currentService. SId;
s. SCIds = channel. currentService. SCIds;
s. channel = channel. channelName;
s. valid = true;
}
stopService (channel. currentService);
stopScanning ();
//
// we stop all secondary services as well, but we maintain theer
// description, file descriptors remain of course
//
if (channel. etiActive)
2024-06-01 11:12:04 +02:00
theOFDMHandler -> reset_etiGenerator ();
2024-01-27 20:16:14 +01:00
for (uint16_t i = 0; i < channel. backgroundServices. size (); i ++)
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop_service (channel. backgroundServices. at (i). subChId,
2024-01-27 20:16:14 +01:00
BACK_GROUND);
// we rebuild the services list from the fib and
// then we (try to) restart the service
2024-02-16 15:46:54 +01:00
int serviceOrder = configHandler_p -> get_serviceOrder ();
2024-01-27 20:16:14 +01:00
std::vector<serviceId> serviceList =
2024-06-01 11:12:04 +02:00
theOFDMHandler -> get_services (serviceOrder);
2024-01-27 20:16:14 +01:00
the_ensembleHandler -> reset ();
channel. nrServices = 0;
for (auto &serv: serviceList) {
serv . channel = channel. channelName;
if (the_ensembleHandler -> add_to_ensemble (serv))
channel. nrServices ++;
}
// Of course, the (sub)service may have disappeared
if (s. valid) {
2024-06-01 11:12:04 +02:00
QString ss = theOFDMHandler -> find_service (s. SId, s. SCIds);
2024-01-27 20:16:14 +01:00
if (ss != "") {
startService (s);
return;
}
//
2024-09-14 14:57:15 +02:00
show_changeLabel (notInOld, notInNew);
2024-01-27 20:16:14 +01:00
// The service is gone, it may be the subservice of another one
s. SCIds = 0;
s. serviceName =
2024-06-01 11:12:04 +02:00
theOFDMHandler -> find_service (s. SId, 0);
2024-01-27 20:16:14 +01:00
if (s. serviceName != "") {
startService (s);
}
}
//
// we also have to restart all background services,
for (uint16_t i = 0; i < channel. backgroundServices. size (); i ++) {
2024-06-01 11:12:04 +02:00
QString ss = theOFDMHandler -> find_service (s. SId, s. SCIds);
2024-01-27 20:16:14 +01:00
if (ss == "") { // it is gone, close the file if any
if (channel. backgroundServices. at (i). fd != nullptr)
fclose (channel. backgroundServices. at (i). fd);
channel. backgroundServices. erase
(channel. backgroundServices. begin () + i);
}
else { // (re)start the service
2024-03-27 16:24:49 +01:00
audiodata ad;
2024-06-01 11:12:04 +02:00
theOFDMHandler -> data_for_audioservice (ss, ad);
2024-03-27 16:24:49 +01:00
if (ad. defined) {
2024-01-27 20:16:14 +01:00
FILE *f = channel. backgroundServices. at (i). fd;
2024-06-01 11:12:04 +02:00
theOFDMHandler ->
set_audioChannel (ad, &theAudioBuffer, f, BACK_GROUND);
2024-01-27 20:16:14 +01:00
channel. backgroundServices. at (i). subChId = ad. subchId;
}
else {
packetdata pd;
2024-07-16 19:52:55 +02:00
theOFDMHandler -> data_for_packetservice (ss, pd, 0);
2024-06-01 11:12:04 +02:00
theOFDMHandler ->
set_dataChannel (pd, &theDataBuffer, BACK_GROUND);
2024-01-27 20:16:14 +01:00
channel. backgroundServices. at (i). subChId = pd. subchId;
}
}
}
}
//
// In order to not overload with an enormous amount of
// signals, we trigger this function at most 10 times a second
//
void RadioInterface::newAudio (int amount, int rate,
bool ps, bool sbr) {
if (!running. load ())
return;
static int teller = 0;
// if (!techWindow_p -> isHidden ()) {
teller ++;
if (teller > 10) {
teller = 0;
if (!techWindow_p -> isHidden ())
techWindow_p -> show_rate (rate, ps, sbr);
2024-02-06 15:37:07 +01:00
audiorateLabel -> setStyleSheet (labelStyle);
2024-01-27 20:16:14 +01:00
audiorateLabel -> setText (QString::number (rate));
if (!ps)
psLabel -> setText (" ");
else {
2024-02-06 15:37:07 +01:00
psLabel -> setStyleSheet (labelStyle);
2024-01-27 20:16:14 +01:00
psLabel -> setText ("ps");
}
if (!sbr)
sbrLabel -> setText (" ");
else {
2024-02-06 15:37:07 +01:00
sbrLabel -> setStyleSheet (labelStyle);
2024-01-27 20:16:14 +01:00
sbrLabel -> setText ("sbr");
}
}
std::complex<int16_t> vec [amount];
2024-06-01 11:12:04 +02:00
while (theAudioBuffer. GetRingBufferReadAvailable () > amount) {
theAudioBuffer. getDataFromBuffer (vec, amount);
2024-01-27 20:16:14 +01:00
#ifdef HAVE_PLUTO_RXTX
if (streamerOut_p != nullptr)
streamerOut_p -> audioOut (vec, amount, rate);
#endif
//
std::vector<float> tmpBuffer;
2024-06-01 11:12:04 +02:00
int size = theAudioConverter. convert (vec, amount, rate, tmpBuffer);
2024-01-27 20:16:14 +01:00
if (!muteTimer. isActive ())
soundOut_p -> audioOutput (tmpBuffer. data (), size);
if (!techWindow_p -> isHidden ()) {
theTechData. putDataIntoBuffer (vec, amount);
techWindow_p -> audioDataAvailable (amount, rate);
}
}
}
//
/////////////////////////////////////////////////////////////////////////////
//
/**
* \brief TerminateProcess
* Pretty critical, since there are many threads involved
* A clean termination is what is needed, regardless of the GUI
*/
void RadioInterface::TerminateProcess () {
running. store (false);
2024-06-01 11:12:04 +02:00
theSCANHandler. hide ();
2024-01-27 20:16:14 +01:00
stopScanning ();
2024-06-01 11:12:04 +02:00
while (theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
usleep (1000);
hideButtons ();
2024-06-01 11:12:04 +02:00
theDXDisplay. hide ();
2024-04-15 14:03:12 +02:00
store_widget_position (dabSettings_p, this, S_MAIN_WIDGET);
2024-06-01 11:12:04 +02:00
theNewDisplay. hide ();
2024-01-27 20:16:14 +01:00
//
#ifdef DATA_STREAMER
fprintf (stderr, "going to close the dataStreamer\n");
delete dataStreamer_p;
#endif
#ifdef CLOCK_STREAMER
fprintf (stderr, "going to close the clockstreamer\n");
delete clockStreamer_p;
#endif
displayTimer. stop ();
channelTimer. stop ();
presetTimer. stop ();
epgTimer. stop ();
soundOut_p -> stop ();
if (dlTextFile != nullptr)
fclose (dlTextFile);
#ifdef HAVE_PLUTO_RXTX
if (streamerOut_p != nullptr)
streamerOut_p -> stop ();
#endif
2024-06-01 11:12:04 +02:00
if (theOFDMHandler != nullptr)
theOFDMHandler -> stop ();
2024-01-27 20:16:14 +01:00
the_ensembleHandler -> hide ();
2024-02-25 14:18:27 +01:00
// delete the_ensembleHandler;
2024-02-16 15:46:54 +01:00
configHandler_p -> hide ();
2024-03-30 19:39:33 +01:00
delete configHandler_p;
2024-01-27 20:16:14 +01:00
techWindow_p -> hide ();
delete techWindow_p;
if (contentTable_p != nullptr) {
contentTable_p -> clearTable ();
contentTable_p -> hide ();
delete contentTable_p;
}
if (mapHandler != nullptr)
mapHandler -> stop ();
2024-01-27 20:16:14 +01:00
// just save a few checkbox settings that are not
if (scanTable_p != nullptr) {
scanTable_p -> clearTable ();
scanTable_p -> hide ();
delete scanTable_p;
}
2024-06-01 11:12:04 +02:00
theSCANHandler. hide ();
2024-01-27 20:16:14 +01:00
stopFramedumping ();
stop_sourcedumping ();
stopAudiodumping ();
theScheduler. hide ();
LOG ("terminating ", "");
usleep (1000); // pending signals
if (logFile != nullptr)
fclose (logFile);
logFile = nullptr;
// everything should be halted by now
dabSettings_p -> sync ();
2024-06-01 11:12:04 +02:00
theSNRViewer. hide ();
if (theOFDMHandler != nullptr)
delete theOFDMHandler;
2024-01-27 20:16:14 +01:00
if (inputDevice_p != nullptr)
delete inputDevice_p;
delete soundOut_p;
2024-06-01 11:12:04 +02:00
theScanlistHandler. hide ();
2024-01-27 20:16:14 +01:00
delete my_timeTable;
// close();
fprintf (stderr, ".. end the radio silences\n");
}
//
void RadioInterface::updateTimeDisplay() {
if (!running. load())
return;
numberofSeconds ++;
int16_t numberHours = numberofSeconds / 3600;
int16_t numberMinutes = (numberofSeconds / 60) % 60;
QString text = QString ("runtime ") +
QString::number (numberHours) + " hr, "
+ QString::number (numberMinutes) + " min";
runtimeDisplay -> setText (text);
if ((numberofSeconds % 2) == 0) {
2024-08-15 13:16:44 +02:00
size_t idle_time = 0, total_time;
2024-01-27 20:16:14 +01:00
get_cpu_times (idle_time, total_time);
const float idle_time_delta =
static_cast<float>(idle_time - previous_idle_time);
const float total_time_delta =
static_cast<float> (total_time - previous_total_time);
const float utilization = 100.0 * (1.0 - idle_time_delta / total_time_delta);
2024-02-16 15:46:54 +01:00
configHandler_p -> showLoad (utilization);
2024-01-27 20:16:14 +01:00
// cpuMonitor -> display (QString("%1").arg(utilization, 0, 'f', 2));
previous_idle_time = idle_time;
previous_total_time = total_time;
}
//
// The timer runs autonomously, so it might happen
// that it rings when there is no processor running
2024-06-01 11:12:04 +02:00
if (theOFDMHandler == nullptr)
2024-01-27 20:16:14 +01:00
return;
if (!techWindow_p -> isHidden ()) {
2024-01-27 20:16:14 +01:00
if (soundOut_p -> hasMissed ()) {
int xxx = ((audioSink *)soundOut_p) -> missed ();
techWindow_p -> showMissed (xxx);
}
}
}
//
// precondition: everything is quiet
deviceHandler *RadioInterface::create_device (const QString &s) {
2024-06-01 11:12:04 +02:00
deviceHandler *inputDevice = theDeviceChoser. createDevice (s, version);
2024-01-27 20:16:14 +01:00
if (inputDevice == nullptr)
return nullptr;
channel. realChannel = !inputDevice -> isFileInput ();
if (channel. realChannel)
showButtons ();
else
hideButtons ();
the_ensembleHandler -> setMode (channel. realChannel);
2024-04-14 12:47:14 +02:00
connect (inputDevice, &deviceHandler::frameClosed,
this, &RadioInterface::handle_deviceFrame_closed);
2024-02-25 14:18:27 +01:00
dabSettings_p -> setValue (SELECTED_DEVICE, s);
if (dabSettings_p -> value (DEVICE_WIDGET_VISIBLE, 1). toInt () != 0)
2024-01-27 20:16:14 +01:00
inputDevice -> setVisibility (true);
else
inputDevice -> setVisibility (false);
2024-06-01 11:12:04 +02:00
theNewDisplay. set_bitDepth (inputDevice -> bitDepth ());
2024-01-27 20:16:14 +01:00
return inputDevice;
}
//
// newDevice is called from the GUI when selecting a device
// with the selector
void RadioInterface::newDevice (const QString &deviceName) {
// Part I : stopping all activities
running. store (false);
stopScanning ();
stopChannel ();
fprintf (stderr, "disconnecting\n");
if (inputDevice_p != nullptr) {
delete inputDevice_p;
inputDevice_p = nullptr;
fprintf (stderr, "device is deleted\n");
}
LOG ("selecting ", deviceName);
inputDevice_p = create_device (deviceName);
2024-02-25 14:18:27 +01:00
fprintf (stderr, "na create_device met %s\n", deviceName. toLatin1 (). data ());
2024-01-27 20:16:14 +01:00
if (inputDevice_p == nullptr) {
inputDevice_p = new deviceHandler ();
return; // nothing will happen
}
2024-04-14 12:47:14 +02:00
doStart_direct (); // will set running
2024-01-27 20:16:14 +01:00
}
static
const char *monthTable [] = {
"jan", "feb", "mar", "apr", "may", "jun",
"jul", "aug", "sep", "oct", "nov", "dec"
};
//
// called from the fibDecoder
void RadioInterface::clockTime (int year, int month, int day,
int hours, int minutes,
int d2, int h2, int m2, int seconds){
this -> localTime. year = year;
this -> localTime. month = month;
this -> localTime. day = day;
this -> localTime. hour = hours;
this -> localTime. minute = minutes;
this -> localTime. second = seconds;
#ifdef CLOCK_STREAMER
uint8_t localBuffer [10];
localBuffer [0] = 0xFF;
localBuffer [1] = 0x00;
localBuffer [2] = 0xFF;
localBuffer [3] = 0x00;
localBuffer [4] = (year & 0xFF00) >> 8;
localBuffer [5] = year & 0xFF;
localBuffer [6] = month;
localBuffer [7] = day;
localBuffer [8] = minutes;
localBuffer [9] = seconds;
if (running. load())
clockStreamer_p -> sendData (localBuffer, 10);
#endif
this -> UTC. year = year;
this -> UTC. month = month;
this -> UTC. day = d2;
this -> UTC. hour = h2;
this -> UTC. minute = m2;
QString result;
2024-02-16 15:46:54 +01:00
if (configHandler_p -> utcSelector_active ())
2024-01-27 20:16:14 +01:00
result = convertTime (year, month, day, h2, m2);
else
result = convertTime (year, month, day,
hours, minutes);
localTimeDisplay -> setText (result);
}
QString RadioInterface::convertTime (int year, int month,
int day, int hours, int minutes) {
char dayString [3];
char hourString [3];
char minuteString [3];
sprintf (dayString, "%.2d", day);
sprintf (hourString, "%.2d", hours);
sprintf (minuteString, "%.2d", minutes);
QString result = QString::number (year) + "-" +
monthTable [month - 1] + "-" +
QString (dayString) + " " +
QString (hourString) + ":" +
QString (minuteString);
return result;
}
QString RadioInterface::convertTime (struct theTime &t) {
char dayString [3];
char hourString [3];
char minuteString [3];
sprintf (dayString, "%.2d", t. day);
sprintf (hourString, "%.2d", t. hour);
sprintf (minuteString, "%.2d", t. minute);
QString result = QString::number (t. year) + "-" +
monthTable [t. month - 1] + "-" +
QString (dayString) + " " +
QString (hourString) + ":" +
QString (minuteString);
return result;
}
//
// called from the MP4 decoder
void RadioInterface::show_frameErrors (int s) {
if (!running. load ())
return;
if (!techWindow_p -> isHidden ())
techWindow_p -> show_frameErrors (s);
}
//
// called from the MP4 decoder
void RadioInterface::show_rsErrors (int s) {
if (!running. load ()) // should not happen
return;
if (!techWindow_p -> isHidden ())
techWindow_p -> show_rsErrors (s);
}
//
// called from the aac decoder
void RadioInterface::show_aacErrors (int s) {
if (!running. load ())
return;
if (!techWindow_p -> isHidden ())
techWindow_p -> show_aacErrors (s);
}
//
// called from the ficHandler
void RadioInterface::show_ficSuccess (bool b) {
if (!running. load ())
return;
if (b)
ficSuccess ++;
if (++ficBlocks >= 100) {
2024-06-01 11:12:04 +02:00
QPalette p = theNewDisplay. ficError_display -> palette();
2024-01-27 20:16:14 +01:00
if (ficSuccess < 85)
p. setColor (QPalette::Highlight, Qt::red);
else
p. setColor (QPalette::Highlight, Qt::green);
2024-06-01 11:12:04 +02:00
theNewDisplay. ficError_display -> setPalette (p);
theNewDisplay. ficError_display -> setValue (ficSuccess);
2024-01-27 20:16:14 +01:00
total_ficError += 100 - ficSuccess;
total_fics += 100;
ficSuccess = 0;
ficBlocks = 0;
}
}
//
// called from the PAD handler
void RadioInterface::show_mothandling (bool b) {
if (!running. load () || !b)
return;
techWindow_p -> show_motHandling (b);
}
// just switch a color, called from the dabprocessor
void RadioInterface::set_synced (bool b) {
2024-06-01 11:12:04 +02:00
theNewDisplay. set_syncLabel (b);
2024-01-27 20:16:14 +01:00
}
//
// called from the PAD handler
void RadioInterface::show_label (const QString &s) {
#ifdef HAVE_PLUTO_RXTX
if ((streamerOut_p != nullptr) && (s != ""))
streamerOut_p -> addRds (std::string (s. toUtf8 (). data ()));
#endif
if (running. load()) {
2024-02-06 15:37:07 +01:00
dynamicLabel -> setStyleSheet (labelStyle);
2024-01-27 20:16:14 +01:00
dynamicLabel -> setText (s);
}
if ((s == "") || (dlTextFile == nullptr) ||
2024-06-01 11:12:04 +02:00
(theDLCache. addifNew (s)))
2024-01-27 20:16:14 +01:00
return;
QString currentChannel = channel. channelName;
QDateTime theDateTime = QDateTime::currentDateTime ();
fprintf (dlTextFile, "%s.%s %4d-%02d-%02d %02d:%02d:%02d %s\n",
currentChannel. toUtf8 (). data (),
channel. currentService. serviceName.
toUtf8 (). data (),
localTime. year,
localTime. month,
localTime. day,
localTime. hour,
localTime. minute,
localTime. second,
s. toUtf8 (). data ());
}
void RadioInterface::setStereo (bool b) {
2024-02-25 14:18:27 +01:00
if (!running. load () || (stereoSetting == b))
2024-01-27 20:16:14 +01:00
return;
2024-02-06 15:37:07 +01:00
if (b) {
stereoLabel -> setStyleSheet (labelStyle);
stereoLabel -> setText ("<i>stereo</i>");
}
else
stereoLabel -> setText (" ");
2024-01-27 20:16:14 +01:00
stereoSetting = b;
}
2024-02-25 14:18:27 +01:00
//static
//QString tiiNumber (int n) {
// if (n >= 10)
// return QString::number (n);
// return QString ("0") + QString::number (n);
//}
2024-01-27 20:16:14 +01:00
void RadioInterface::handle_detailButton () {
if (!running. load ())
return;
if (techWindow_p -> isHidden ())
techWindow_p -> show ();
else
techWindow_p -> hide ();
2024-02-25 14:18:27 +01:00
dabSettings_p -> setValue (TECHDATA_VISIBLE,
2024-02-16 15:46:54 +01:00
techWindow_p -> isHidden () ? 0 : 1);
2024-01-27 20:16:14 +01:00
}
//
// Whenever the input device is a file, some functions,
// e.g. selecting a channel, setting an alarm, are not
// meaningful
void RadioInterface::showButtons () {
scanButton -> setEnabled (true);;
channelSelector -> setEnabled (true);
nextChannelButton -> setEnabled (true);
prevChannelButton -> setEnabled (true);
}
void RadioInterface::hideButtons () {
scanButton -> setEnabled (false);
channelSelector -> setEnabled (false);
nextChannelButton -> setEnabled (false);
prevChannelButton -> setEnabled (false);
}
void RadioInterface::set_sync_lost () {
}
//
// dump handling
//
/////////////////////////////////////////////////////////////////////////
2024-02-16 15:46:54 +01:00
static inline
2024-01-27 20:16:14 +01:00
void setButtonFont (QPushButton *b, QString text, int size) {
QFont font = b -> font ();
font. setPointSize (size);
b -> setFont (font);
b -> setText (text);
b -> update ();
}
void RadioInterface::handle_audiodumpButton () {
2024-06-01 11:12:04 +02:00
if (!running. load () || theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
return;
2024-07-28 12:47:27 +02:00
if (audioDumping)
2024-01-27 20:16:14 +01:00
stopAudiodumping ();
else
startAudiodumping ();
}
void RadioInterface::stopAudiodumping () {
2024-07-28 12:47:27 +02:00
if (!audioDumping)
2024-01-27 20:16:14 +01:00
return;
LOG ("audiodump stops", "");
2024-06-01 11:12:04 +02:00
theAudioConverter. stop_audioDump ();
2024-07-28 12:47:27 +02:00
audioDumping = false;
2024-01-27 20:16:14 +01:00
techWindow_p -> audiodumpButton_text ("audio dump", 10);
}
void RadioInterface::startAudiodumping () {
2024-07-28 12:47:27 +02:00
if (audioDumping) // should not happen
return;
QString audioDumpName =
2024-06-01 11:12:04 +02:00
theFilenameFinder.
2024-01-27 20:16:14 +01:00
findAudioDump_fileName (channel. currentService. serviceName, true);
2024-07-28 12:47:27 +02:00
if (audioDumpName == "")
2024-01-27 20:16:14 +01:00
return;
LOG ("audiodump starts ", serviceLabel -> text ());
techWindow_p -> audiodumpButton_text ("writing", 12);
2024-07-28 12:47:27 +02:00
theAudioConverter. start_audioDump (audioDumpName);
audioDumping = true;
2024-01-27 20:16:14 +01:00
}
void RadioInterface::scheduled_audioDumping () {
2024-07-28 12:47:27 +02:00
if (audioDumping) {
2024-06-01 11:12:04 +02:00
theAudioConverter. stop_audioDump ();
2024-07-28 12:47:27 +02:00
audioDumping = false;
2024-01-27 20:16:14 +01:00
LOG ("scheduled audio dump stops ", serviceLabel -> text ());
techWindow_p -> audiodumpButton_text ("audio dump", 10);
return;
}
2024-07-28 12:47:27 +02:00
QString audioDumpName =
2024-06-01 11:12:04 +02:00
theFilenameFinder.
2024-01-27 20:16:14 +01:00
findAudioDump_fileName (serviceLabel -> text (), false);
2024-07-28 12:47:27 +02:00
if (audioDumpName == "")
2024-01-27 20:16:14 +01:00
return;
LOG ("scheduled audio dump starts ", serviceLabel -> text ());
techWindow_p -> audiodumpButton_text ("writing", 12);
2024-07-28 12:47:27 +02:00
theAudioConverter. start_audioDump (audioDumpName);
audioDumping = true;
2024-01-27 20:16:14 +01:00
}
void RadioInterface::handle_framedumpButton () {
2024-06-01 11:12:04 +02:00
if (!running. load () || theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
return;
if (channel. currentService. frameDumper != nullptr)
stopFramedumping ();
else
startFramedumping ();
}
void RadioInterface::stopFramedumping () {
if (channel. currentService. frameDumper == nullptr)
return;
fclose (channel. currentService. frameDumper);
techWindow_p -> framedumpButton_text ("frame dump", 10);
channel. currentService. frameDumper = nullptr;
}
void RadioInterface::startFramedumping () {
channel. currentService. frameDumper =
2024-06-01 11:12:04 +02:00
theFilenameFinder. findFrameDump_fileName (channel. currentService. serviceName,
2024-01-27 20:16:14 +01:00
true);
if (channel. currentService. frameDumper == nullptr)
return;
techWindow_p -> framedumpButton_text ("recording", 12);
}
void RadioInterface::scheduled_frameDumping (const QString &s) {
if (channel. currentService. frameDumper != nullptr) {
fclose (channel. currentService. frameDumper);
techWindow_p -> framedumpButton_text ("frame dump", 10);
channel. currentService. frameDumper = nullptr;
return;
}
channel. currentService. frameDumper =
2024-06-01 11:12:04 +02:00
theFilenameFinder. findFrameDump_fileName (s, false);
2024-01-27 20:16:14 +01:00
if (channel. currentService. frameDumper == nullptr)
return;
techWindow_p -> framedumpButton_text ("recording", 12);
}
//----------------------------------------------------------------------
// End of section on dumping
//----------------------------------------------------------------------
//
// called from the mp4 handler, using a signal
void RadioInterface::newFrame (int amount) {
2024-03-13 19:45:53 +01:00
uint8_t *buffer = (uint8_t *) alloca (amount * sizeof (uint8_t));
2024-01-27 20:16:14 +01:00
if (!running. load ())
return;
if (channel. currentService. frameDumper == nullptr)
2024-06-01 11:12:04 +02:00
theFrameBuffer. FlushRingBuffer ();
2024-01-27 20:16:14 +01:00
else
2024-06-01 11:12:04 +02:00
while (theFrameBuffer. GetRingBufferReadAvailable () >= amount) {
theFrameBuffer. getDataFromBuffer (buffer, amount);
2024-01-27 20:16:14 +01:00
if (channel. currentService. frameDumper != nullptr)
fwrite (buffer, amount, 1, channel. currentService. frameDumper);
}
}
void RadioInterface::handle_spectrumButton () {
if (!running. load ())
return;
2024-06-01 11:12:04 +02:00
if (theNewDisplay. isHidden ())
theNewDisplay. show ();
2024-01-27 20:16:14 +01:00
else
2024-06-01 11:12:04 +02:00
theNewDisplay. hide ();
2024-02-25 14:18:27 +01:00
dabSettings_p -> setValue (NEW_DISPLAY_VISIBLE,
2024-06-01 11:12:04 +02:00
theNewDisplay. isHidden () ? 0 : 1);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::handle_scanListButton () {
if (!running. load ())
return;
2024-09-04 12:14:53 +02:00
if (inputDevice_p -> isFileInput ())
return;
2024-06-01 11:12:04 +02:00
if (theScanlistHandler. isHidden ())
theScanlistHandler. show ();
2024-01-27 20:16:14 +01:00
else
2024-06-01 11:12:04 +02:00
theScanlistHandler. hide ();
2024-01-27 20:16:14 +01:00
}
//
// When changing (or setting) a device, we do not want anybody
// to have the buttons on the GUI touched, so
// we just disconnet them and (re)connect them as soon as
// a device is operational
void RadioInterface::connectGUI () {
// connections from the main widget
2024-04-14 12:47:14 +02:00
connect (prevServiceButton, &QPushButton::clicked,
this, &RadioInterface::handle_prevServiceButton);
connect (nextServiceButton, &QPushButton::clicked,
this, &RadioInterface::handle_nextServiceButton);
2024-01-27 20:16:14 +01:00
2024-02-16 15:46:54 +01:00
// channelButton handled elsewhere
2024-04-14 12:47:14 +02:00
connect (prevChannelButton, &clickablelabel::clicked,
this, &RadioInterface::handle_prevChannelButton);
connect (nextChannelButton, &clickablelabel::clicked,
this, &RadioInterface::handle_nextChannelButton);
2024-01-27 20:16:14 +01:00
2024-04-14 12:47:14 +02:00
connect (scanListButton, &QPushButton::clicked,
this, &RadioInterface::handle_scanListButton);
2024-01-27 20:16:14 +01:00
2024-04-14 12:47:14 +02:00
connect (presetButton, &QPushButton::clicked,
this, &RadioInterface::handle_presetButton);
connect (spectrumButton, &QPushButton::clicked,
this, &RadioInterface::handle_spectrumButton);
connect (serviceLabel, &clickablelabel::clicked,
this, &RadioInterface::handle_labelColor);
connect (serviceButton, &clickablelabel::clicked,
this, &RadioInterface::handle_detailButton);
//
connect (httpButton, &QPushButton::clicked,
this, &RadioInterface::handle_httpButton);
connect (scanButton, &QPushButton::clicked,
this, &RadioInterface::handle_scanButton);
2024-01-27 20:16:14 +01:00
//
// and for the techWindow
2024-04-14 12:47:14 +02:00
connect (techWindow_p, &techData::handle_audioDumping,
this, &RadioInterface::handle_audiodumpButton);
connect (techWindow_p, &techData::handle_frameDumping,
this, &RadioInterface::handle_framedumpButton);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::disconnectGUI () {
}
//
#include <QCloseEvent>
void RadioInterface::closeEvent (QCloseEvent *event) {
2024-02-16 15:46:54 +01:00
int x = configHandler_p -> closeDirect_active ();
2024-02-25 14:18:27 +01:00
dabSettings_p -> setValue (CLOSE_DIRECT_SETTING, x);
2024-01-27 20:16:14 +01:00
if (x != 0) {
TerminateProcess ();
event -> accept ();
return;
}
QMessageBox::StandardButton resultButton =
QMessageBox::question (this, "dabRadio",
tr("Are you sure?\n"),
QMessageBox::No | QMessageBox::Yes,
QMessageBox::Yes);
if (resultButton != QMessageBox::Yes) {
event -> ignore();
} else {
TerminateProcess ();
event -> accept();
}
}
bool RadioInterface::eventFilter (QObject *obj, QEvent *event) {
if (!running. load ())
return QWidget::eventFilter (obj, event);
2024-06-01 11:12:04 +02:00
if (theOFDMHandler == nullptr) {
2024-01-27 20:16:14 +01:00
fprintf (stderr, "expert error 5\n");
return true;
}
else
if ((obj == this -> the_ensembleHandler -> viewport ()) &&
(event -> type () == QEvent::MouseButtonPress)) {
QMouseEvent *ev = static_cast<QMouseEvent *>(event);
if (ev -> buttons () & Qt::RightButton) {
QTableWidgetItem *x =
the_ensembleHandler -> itemAt (ev -> pos ());
if (x != nullptr)
the_ensembleHandler -> handle_rightMouseClick (x -> text ());
}
else {
return QWidget::eventFilter (obj, event);
}
}
else
// An option is to click - right hand mouse button - on a
// service in the scanlist in order to add it to the
// list of favorites
2024-06-01 11:12:04 +02:00
if ((obj == this -> theScanlistHandler. viewport ()) &&
2024-01-27 20:16:14 +01:00
(event -> type () == QEvent::MouseButtonPress)) {
QMouseEvent *ev = static_cast<QMouseEvent *>(event);
if (ev -> buttons () & Qt::RightButton) {
QString service =
2024-06-01 11:12:04 +02:00
this -> theScanlistHandler. indexAt (ev -> pos()). data ().toString();
2024-01-27 20:16:14 +01:00
the_ensembleHandler -> add_favorite_from_scanList (service);
}
}
return QWidget::eventFilter (obj, event);
}
QPixmap RadioInterface::fetch_announcement (int id) {
QPixmap p;
QString pictureName = QString (":res/announcement%1.png"). arg (id, 2, 10, QChar ('0'));
if (!p.load (pictureName, "png"))
p. load (":res/announcement-d.png", "png");
return p;
}
void RadioInterface::start_announcement (const QString &name,
int subChId, int announcementId ) {
if (!running. load ())
return;
(void)subChId;
if (name == serviceLabel -> text ()) {
if (!channel. currentService. announcement_going) {
serviceLabel -> setStyleSheet ("QLabel {color : red}");
channel. currentService. announcement_going = true;
QPixmap p = fetch_announcement (announcementId);
displaySlide (p);
}
}
}
void RadioInterface::stop_announcement (const QString &name, int subChId) {
(void)subChId;
if (!running. load ())
return;
if (name == channel. currentService. serviceName) {
if (channel. currentService. announcement_going) {
2024-02-06 15:37:07 +01:00
serviceLabel -> setStyleSheet (labelStyle);
2024-01-27 20:16:14 +01:00
channel. currentService. announcement_going = false;
show_pauzeSlide ();
}
}
}
//
// selection, either direct, from presets, from scanlist or schedule
////////////////////////////////////////////////////////////////////////
//
// selecting from the preset list
void RadioInterface::handle_presetSelect (const QString &channel,
const QString &service) {
if (!inputDevice_p -> isFileInput ())
localSelect_SS (service, channel);
2024-01-27 20:16:14 +01:00
else
QMessageBox::warning (this, tr ("Warning"),
tr ("Selection not possible"));
}
//
// selecting from the scan list, which is essential
// the same as handling form the preset list
void RadioInterface::handle_scanListSelect (const QString &s) {
if (!inputDevice_p -> isFileInput ())
localSelect (s);
else
QMessageBox::warning (this, tr ("Warning"),
tr ("Selection not possible"));
}
//
// selecting from a content description
void RadioInterface::handle_contentSelector (const QString &s) {
localSelect_SS (s, channel. channelName);
2024-01-27 20:16:14 +01:00
}
//
// From a predefined schedule list, the service names most
// likely are less than 16 characters
//
void RadioInterface::scheduleSelect (const QString &s) {
2024-03-13 19:45:53 +01:00
QStringList list = splitter (s);
2024-01-27 20:16:14 +01:00
if (list. length () != 2)
return;
fprintf (stderr, "we found %s %s\n",
list. at (1). toLatin1 (). data (),
list. at (0). toLatin1 (). data ());
localSelect_SS (list. at (1), list. at (0));
2024-01-27 20:16:14 +01:00
}
//
void RadioInterface::localSelect (const QString &s) {
2024-03-13 19:45:53 +01:00
QStringList list = splitter (s);
2024-01-27 20:16:14 +01:00
if (list. length () != 2)
return;
localSelect_SS (list. at (1), list. at (0));
2024-01-27 20:16:14 +01:00
}
void RadioInterface::localSelect_SS (const QString &service,
const QString &theChannel) {
2024-01-27 20:16:14 +01:00
QString serviceName = service;
2024-06-01 11:12:04 +02:00
if (theOFDMHandler == nullptr) // should not happen
2024-01-27 20:16:14 +01:00
return;
2024-03-04 14:45:33 +01:00
channelTimer. stop ();
2024-03-13 19:45:53 +01:00
presetTimer. stop ();
2024-01-27 20:16:14 +01:00
stopService (channel. currentService);
for (int i = service. size (); i < 16; i ++)
serviceName. push_back (' ');
if (theChannel == channel. channelName) {
channel. currentService. valid = false;
dabService s;
2024-06-01 11:12:04 +02:00
theOFDMHandler -> get_parameters (serviceName, &s. SId, &s. SCIds);
2024-01-27 20:16:14 +01:00
if (s. SId == 0) {
dynamicLabel -> setText ("cannot run " +
s. serviceName + " yet");
return;
}
s. serviceName = serviceName;
startService (s);
return;
}
//
// The hard part is stopping the current service,
// quitting the current channel,
// selecting a new channel, and waiting a while
stopChannel ();
// and start the new channel first
int k = channelSelector -> findText (theChannel);
if (k != -1) {
new_channelIndex (k);
}
else {
QMessageBox::warning (this, tr ("Warning"),
tr ("Incorrect preset\n"));
return;
}
//
// prepare the service, start the new channel and wait
2024-02-16 15:46:54 +01:00
nextService. valid = true;
nextService. channel = theChannel;
nextService. serviceName = serviceName;
nextService. SId = 0;
2024-03-25 14:35:22 +01:00
nextService. SCIds = 0;
2024-01-27 20:16:14 +01:00
presetTimer. setSingleShot (true);
2024-02-16 15:46:54 +01:00
int switchDelay =
configHandler_p -> switchDelayValue ();
presetTimer. setInterval (switchDelay);
presetTimer. start (switchDelay);
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
}
//
///////////////////////////////////////////////////////////////////////////
void RadioInterface::stopService (dabService &s) {
2024-02-16 15:46:54 +01:00
if (!s. valid)
return;
2024-01-27 20:16:14 +01:00
presetTimer. stop ();
channelTimer. stop ();
stop_muting ();
set_soundLabel (false);
channel. audioActive = false;
2024-06-01 11:12:04 +02:00
if (theOFDMHandler == nullptr) {
2024-01-27 20:16:14 +01:00
fprintf (stderr, "Expert error 22\n");
return;
}
// stop "dumpers"
if (channel. currentService. frameDumper != nullptr) {
stopFramedumping ();
channel. currentService. frameDumper = nullptr;
}
2024-07-28 12:47:27 +02:00
if (audioDumping) {
2024-01-27 20:16:14 +01:00
stopAudiodumping ();
}
// and clean up the technical widget
techWindow_p -> cleanUp ();
// stop "secondary services" - if any - as well
if (s. valid) {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop_service (s. subChId, FORE_GROUND);
2024-01-27 20:16:14 +01:00
if (s. is_audio) {
2024-03-13 19:45:53 +01:00
soundOut_p -> suspend ();
2024-01-27 20:16:14 +01:00
for (int i = 0; i < 5; i ++) {
packetdata pd;
2024-06-01 11:12:04 +02:00
theOFDMHandler -> data_for_packetservice (s. serviceName,
2024-07-16 19:52:55 +02:00
pd, i);
2024-01-27 20:16:14 +01:00
if (pd. defined) {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop_service (pd. subchId, FORE_GROUND);
2024-01-27 20:16:14 +01:00
break;
}
}
}
s. valid = false;
}
show_pauzeSlide ();
cleanScreen ();
}
//
//
void RadioInterface::startService (dabService &s) {
QString serviceName = s. serviceName;
channel. currentService = s;
channel. currentService. frameDumper = nullptr;
channel. currentService. valid = false;
LOG ("start service ", serviceName. toUtf8 (). data ());
LOG ("service has SNR ", QString::number (channel. snr));
//
// mark the selected service in the service list
//
// and display the servicename on the serviceLabel
serviceLabel -> setText (serviceName);
dynamicLabel -> setText ("");
the_ensembleHandler -> reportStart (serviceName);
audiodata ad;
2024-06-01 11:12:04 +02:00
theOFDMHandler -> data_for_audioservice (serviceName, ad);
2024-01-27 20:16:14 +01:00
if (ad. defined) {
channel. currentService. valid = true;
channel. currentService. is_audio = true;
channel. currentService. subChId = ad. subchId;
2024-06-01 11:12:04 +02:00
if (theOFDMHandler -> has_timeTable (ad. SId))
2024-01-27 20:16:14 +01:00
techWindow_p -> show_timetableButton (true);
startAudioservice (ad);
2024-08-18 09:28:40 +02:00
techWindow_p -> is_DAB_plus (ad. ASCTy == 077);
2024-02-25 14:18:27 +01:00
// Only presets for real input devices
if (!inputDevice_p -> isFileInput ()) {
2024-01-27 20:16:14 +01:00
QString s = channel. channelName + ":" + serviceName;
2024-02-25 14:18:27 +01:00
dabSettings_p -> setValue (PRESET_NAME, s);
2024-01-27 20:16:14 +01:00
}
#ifdef HAVE_PLUTO_RXTX
if (streamerOut_p != nullptr)
streamerOut_p -> addRds (std::string (serviceName. toUtf8 (). data ()));
#endif
}
2024-03-27 16:24:49 +01:00
else {
2024-01-27 20:16:14 +01:00
packetdata pd;
2024-07-16 19:52:55 +02:00
theOFDMHandler -> data_for_packetservice (serviceName, pd, 0);
2024-03-27 16:24:49 +01:00
if (pd. defined) {
channel. currentService. valid = true;
channel. currentService. is_audio = false;
channel. currentService. subChId = pd. subchId;
startPacketservice (serviceName);
}
else {
QMessageBox::warning (this, tr ("Warning"),
tr ("insufficient data for this program\n"));
dabSettings_p -> setValue (PRESET_NAME, "");
}
2024-01-27 20:16:14 +01:00
}
}
//
void RadioInterface::startAudioservice (audiodata &ad) {
2024-03-04 14:45:33 +01:00
// channel. currentService. valid = true;
2024-06-01 11:12:04 +02:00
(void)theOFDMHandler -> set_audioChannel (ad, &theAudioBuffer,
2024-01-27 20:16:14 +01:00
nullptr, FORE_GROUND);
2024-03-25 14:35:22 +01:00
//
// check the other components for this service (if any)
int nrComps =
2024-06-01 11:12:04 +02:00
theOFDMHandler -> get_nrComps (channel. currentService. SId);
2024-03-25 14:35:22 +01:00
for (int i = 1; i < nrComps; i ++) {
2024-01-27 20:16:14 +01:00
packetdata pd;
2024-07-16 19:52:55 +02:00
theOFDMHandler -> data_for_packetservice (ad. serviceName, pd, i);
2024-01-27 20:16:14 +01:00
if (pd. defined) {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_dataChannel (pd, &theDataBuffer, FORE_GROUND);
2024-01-27 20:16:14 +01:00
fprintf (stderr, "adding %s (%d) as subservice\n",
pd. serviceName. toUtf8 (). data (),
pd. subchId);
break;
}
}
// activate sound
2024-03-13 19:45:53 +01:00
soundOut_p -> resume ();
2024-01-27 20:16:14 +01:00
channel. audioActive = true;
set_soundLabel (true);
2024-02-06 15:37:07 +01:00
programTypeLabel -> setText (getProgramType (ad. programType));
rateLabel -> setStyleSheet (labelStyle);
rateLabel -> setText (QString::number (ad. bitRate) + "kbit");
2024-01-27 20:16:14 +01:00
// show service related data
techWindow_p -> show_serviceData (&ad);
}
void RadioInterface::startPacketservice (const QString &s) {
packetdata pd;
2024-07-16 19:52:55 +02:00
theOFDMHandler -> data_for_packetservice (s, pd, 0);
2024-01-27 20:16:14 +01:00
if ((!pd. defined) ||
(pd. DSCTy == 0) || (pd. bitRate == 0)) {
QMessageBox::warning (this, tr ("sdr"),
tr ("still insufficient data for this service\n"));
return;
}
2024-06-01 11:12:04 +02:00
if (!theOFDMHandler -> set_dataChannel (pd,
&theDataBuffer, FORE_GROUND)) {
2024-01-27 20:16:14 +01:00
QMessageBox::warning (this, tr ("sdr"),
tr ("could not start this service\n"));
return;
}
2024-03-27 16:24:49 +01:00
int nrComps =
2024-06-01 11:12:04 +02:00
theOFDMHandler -> get_nrComps (channel. currentService. SId);
2024-03-27 16:24:49 +01:00
if (nrComps > 1)
fprintf (stderr, "%s has %d components\b",
channel. currentService. serviceName. toLatin1 (). data (), nrComps);
for (int i = 1; i < nrComps; i ++) {
packetdata lpd;
2024-07-16 19:52:55 +02:00
theOFDMHandler -> data_for_packetservice (pd. serviceName, lpd, i);
2024-03-27 16:24:49 +01:00
if (lpd. defined) {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_dataChannel (lpd, &theDataBuffer, FORE_GROUND);
2024-03-27 16:24:49 +01:00
fprintf (stderr, "adding %s (%d) as subservice\n",
lpd. serviceName. toUtf8 (). data (),
lpd. subchId);
break;
}
}
2024-01-27 20:16:14 +01:00
switch (pd. DSCTy) {
default:
show_label (QString ("unimplemented Data"));
break;
case 5:
fprintf (stderr, "selected apptype %d\n", pd. appType);
show_label (QString ("Transp. Channel partially implemented"));
2024-01-27 20:16:14 +01:00
break;
case 60:
show_label (QString ("MOT"));
2024-01-27 20:16:14 +01:00
break;
case 59: {
#ifdef _SEND_DATAGRAM_
QString text = QString ("Embedded IP: UDP data to ");
text. append (ipAddress);
text. append (" ");
QString n = QString::number (port);
text. append (n);
show_label (text);
#else
show_label ("Embedded IP not supported ");
#endif
}
break;
case 44:
show_label (QString ("Journaline"));
break;
}
}
// This function is only used in the Gui to clear
// the details of a selected service
void RadioInterface::cleanScreen () {
serviceLabel -> setText ("");
dynamicLabel -> setText ("");
techWindow_p -> cleanUp ();
stereoLabel -> setText ("");
programTypeLabel -> setText ("");
psLabel -> setText ("");
sbrLabel -> setText ("");
audiorateLabel -> setText ("");
rateLabel -> setText ("");
stereoLabel -> setText ("");
stereoSetting = false;
techWindow_p -> cleanUp ();
setStereo (false);
2024-02-16 15:46:54 +01:00
distanceLabel -> setText ("");
transmitter_country -> setText ("");
2024-06-01 11:12:04 +02:00
theNewDisplay. ficError_display -> setValue (0);
2024-01-27 20:16:14 +01:00
}
////////////////////////////////////////////////////////////////////////////
//
void RadioInterface::handle_prevServiceButton () {
the_ensembleHandler -> selectPrevService ();
}
void RadioInterface::handle_nextServiceButton () {
the_ensembleHandler -> selectNextService ();
}
//
// The user(s)
///////////////////////////////////////////////////////////////////////////
// setPresetService () is called after a time out to
// actually start the service that we were waiting for
// Assumption is that the channel is set, and the servicename
// is to be found in "nextService"
void RadioInterface::setPresetService () {
if (!running. load ())
return;
stopScanning ();
2024-03-04 14:45:33 +01:00
presetTimer. stop ();
2024-02-16 15:46:54 +01:00
if (!nextService. valid)
2024-01-27 20:16:14 +01:00
return;
2024-02-16 15:46:54 +01:00
if (nextService. channel != channel. channelName)
2024-01-27 20:16:14 +01:00
return;
if (channel. Eid == 0) {
dynamicLabel -> setText ("ensemblename not yet found\n");
return;
}
2024-02-16 15:46:54 +01:00
QString presetName = nextService. serviceName;
2024-01-27 20:16:14 +01:00
for (int i = presetName. length (); i < 16; i ++)
presetName. push_back (' ');
2024-02-16 15:46:54 +01:00
dabService s = nextService;
2024-06-01 11:12:04 +02:00
theOFDMHandler -> get_parameters (presetName, &s. SId, &s. SCIds);
2024-01-27 20:16:14 +01:00
if (s. SId == 0) {
dynamicLabel -> setText (QString ("not all data for ") +
s. serviceName +
" on board");
return;
}
2024-02-16 15:46:54 +01:00
nextService. valid = false;
2024-01-27 20:16:14 +01:00
startService (s);
}
//
// Channel basics
///////////////////////////////////////////////////////////////////////////
// Precondition: no channel should be active
//
void RadioInterface::startChannel (const QString &theChannel) {
int tunedFrequency =
2024-06-01 11:12:04 +02:00
theSCANHandler. Frequency (theChannel);
2024-01-27 20:16:14 +01:00
LOG ("channel starts ", theChannel);
2024-09-04 12:14:53 +02:00
theNewDisplay. showFrequency (theChannel, tunedFrequency);
2024-01-27 20:16:14 +01:00
inputDevice_p -> restartReader (tunedFrequency);
channel. cleanChannel ();
channel. channelName = theChannel;
channel. tunedFrequency = tunedFrequency;
2024-09-04 09:46:23 +02:00
channel. countryName = "";
2024-07-27 15:30:56 +02:00
if (inputDevice_p -> isFileInput ()) {
channelSelector -> setEnabled (false);
int freq = inputDevice_p -> getVFOFrequency ();
QString realChannel = theSCANHandler. getChannel (freq);
if (realChannel != "") {
int k = channelSelector -> findText (realChannel);
channelSelector -> setCurrentIndex (k);
channel. channelName = realChannel;
channel. tunedFrequency = freq;
2024-09-04 12:14:53 +02:00
theNewDisplay. showFrequency (realChannel,
channel. tunedFrequency);
2024-07-27 15:30:56 +02:00
}
else {
channel. channelName = "";
channel. tunedFrequency = -1;
}
}
2024-01-27 20:16:14 +01:00
channel. realChannel = !inputDevice_p -> isFileInput ();
2024-03-04 14:45:33 +01:00
if (channel. realChannel)
dabSettings_p -> setValue (CHANNEL_NAME, theChannel);
2024-01-27 20:16:14 +01:00
distanceLabel -> setText ("");
2024-06-01 11:12:04 +02:00
theDXDisplay. cleanUp ();
theNewDisplay. show_transmitters (channel. transmitters);
2024-02-16 15:46:54 +01:00
bool localTransmitters =
configHandler_p -> localTransmitterSelector_active ();
if (localTransmitters && (mapHandler != nullptr))
2024-02-25 14:18:27 +01:00
mapHandler -> putData (MAP_RESET, channel. targetPos);
2024-01-27 20:16:14 +01:00
else
if (mapHandler != nullptr)
2024-02-25 14:18:27 +01:00
mapHandler -> putData (MAP_FRAME, position {-1, -1});
2024-03-04 14:45:33 +01:00
the_ensembleHandler -> reset ();
2024-06-01 11:12:04 +02:00
theOFDMHandler -> start ();
2024-02-16 15:46:54 +01:00
int switchDelay = configHandler_p -> switchDelayValue ();
2024-06-01 11:12:04 +02:00
if (!theSCANHandler. active ())
2024-02-16 15:46:54 +01:00
epgTimer. start (switchDelay);
2024-01-27 20:16:14 +01:00
}
//
// apart from stopping the reader, a lot of administration
// is to be done.
void RadioInterface::stopChannel () {
if (inputDevice_p == nullptr) // should not happen
return;
2024-02-16 15:46:54 +01:00
epgTimer. stop (); // if running
presetTimer. stop (); // if running
channelTimer. stop (); // if running
inputDevice_p -> stopReader ();
2024-04-14 12:47:14 +02:00
disconnect (ensembleId, &clickablelabel::clicked,
this, &RadioInterface::handle_contentButton);
2024-02-16 15:46:54 +01:00
ensembleId -> setText ("");
stop_sourcedumping ();
2024-03-04 14:45:33 +01:00
stop_etiHandler (); // if any
2024-01-27 20:16:14 +01:00
LOG ("channel stops ", channel. channelName);
2024-08-27 12:40:14 +02:00
transmitter_country -> setText ("");
2024-01-27 20:16:14 +01:00
//
// first, stop services in fore and background
if (channel. currentService. valid)
stopService (channel. currentService);
2024-03-13 19:45:53 +01:00
soundOut_p -> suspend ();
2024-01-27 20:16:14 +01:00
2024-02-25 14:18:27 +01:00
for (auto s : channel. backgroundServices) {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop_service (s. subChId, BACK_GROUND);
2024-01-27 20:16:14 +01:00
if (s. fd != nullptr)
fclose (s. fd);
}
channel. backgroundServices. clear ();
2024-02-16 15:46:54 +01:00
2024-01-27 20:16:14 +01:00
if (contentTable_p != nullptr) {
contentTable_p -> hide ();
delete contentTable_p;
contentTable_p = nullptr;
}
// note framedumping - if any - was already stopped
// ficDumping - if on - is stopped here
if (ficDumpPointer != nullptr) {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop_ficDump ();
2024-01-27 20:16:14 +01:00
ficDumpPointer = nullptr;
}
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop ();
theDXDisplay. cleanUp ();
2024-01-27 20:16:14 +01:00
usleep (1000);
techWindow_p -> cleanUp ();
show_pauzeSlide ();
channel. cleanChannel ();
2024-02-16 15:46:54 +01:00
bool localTransmitters =
configHandler_p -> localTransmitterSelector_active ();
if (localTransmitters && (mapHandler != nullptr))
2024-02-25 14:18:27 +01:00
mapHandler -> putData (MAP_RESET, channel. targetPos);
2024-01-27 20:16:14 +01:00
QCoreApplication::processEvents ();
//
// no processing left at this time
usleep (1000); // may be handling pending signals?
// all stopped, now look at the GUI elements
// the visual elements related to service and channel
set_synced (false);
cleanScreen ();
}
//
// next- and previous channel buttons
/////////////////////////////////////////////////////////////////////////
void RadioInterface::handle_channelSelector (const QString &channel) {
if (!running. load ())
return;
LOG ("select channel ", channel. toUtf8 (). data ());
presetTimer. stop ();
stopScanning ();
stopChannel ();
startChannel (channel);
}
void RadioInterface::handle_nextChannelButton () {
int nrChannels = channelSelector -> count ();
int newChannel = channelSelector -> currentIndex () + 1;
set_channelButton (newChannel % nrChannels);
}
void RadioInterface::handle_prevChannelButton () {
int nrChannels = channelSelector -> count ();
if (channelSelector -> currentIndex () == 0)
set_channelButton (nrChannels - 1);
else
set_channelButton (channelSelector -> currentIndex () - 1);
}
void RadioInterface::set_channelButton (int currentChannel) {
if (!running. load ())
return;
presetTimer. stop ();
2024-06-01 11:12:04 +02:00
if (theOFDMHandler == nullptr) {
2024-01-27 20:16:14 +01:00
fprintf (stderr, "Expert error 23\n");
abort ();
}
stopScanning ();
stopChannel ();
new_channelIndex (currentChannel);
startChannel (channelSelector -> currentText ());
}
//
// scanning
// The scan function covers three scan strategies. In order to make things
// manageable, we implement the streams in different functions and procedures
void RadioInterface::handle_scanButton () {
if (!running. load ())
return;
2024-06-01 11:12:04 +02:00
if (theSCANHandler. isVisible ())
theSCANHandler. hide ();
2024-01-27 20:16:14 +01:00
else
2024-06-01 11:12:04 +02:00
theSCANHandler. show ();
2024-01-27 20:16:14 +01:00
}
void RadioInterface::startScanning () {
2024-02-01 11:39:22 +01:00
the_ensembleHandler -> set_showMode (SHOW_ENSEMBLE);
presetButton -> setText ("not in use");
presetButton -> setEnabled (false);
2024-01-27 20:16:14 +01:00
stopChannel ();
presetTimer. stop ();
channelTimer. stop ();
if (inputDevice_p -> isFileInput ())
QMessageBox::warning (this, tr ("Warning"),
tr ("Scanning not useful with file input"));
epgTimer. stop ();
2024-06-01 11:12:04 +02:00
connect (theOFDMHandler, &ofdmHandler::no_signal_found,
2024-04-14 12:47:14 +02:00
this, &RadioInterface::no_signal_found);
2024-01-27 20:16:14 +01:00
2024-06-01 11:12:04 +02:00
if (theSCANHandler. scan_to_data ())
2024-01-27 20:16:14 +01:00
start_scan_to_data ();
else
2024-06-01 11:12:04 +02:00
if (theSCANHandler. scan_single ())
2024-01-27 20:16:14 +01:00
start_scan_single ();
else
start_scan_continuous ();
}
void RadioInterface::start_scan_to_data () {
// when running scan to data, we look at all channels, whether
// on the skiplist or not
2024-06-01 11:12:04 +02:00
QString cs = theSCANHandler. getNextChannel (channelSelector -> currentText ());
2024-01-27 20:16:14 +01:00
int cc = channelSelector -> findText (cs);
LOG ("scanning starts with ", cs);
new_channelIndex (cc);
2024-06-01 11:12:04 +02:00
// theSCANHandler. addText (" scanning channel " +
2024-01-27 20:16:14 +01:00
// channelSelector -> currentText ());
int switchDelay =
2024-02-16 15:46:54 +01:00
configHandler_p -> switchDelayValue ();
channelTimer. start (switchDelay);
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_scanMode (true);
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
}
void RadioInterface::start_scan_single () {
2024-02-16 15:46:54 +01:00
if (configHandler_p -> clearScan_Selector_active ())
2024-06-01 11:12:04 +02:00
theScanlistHandler. clear_scanList ();
2024-01-27 20:16:14 +01:00
if (scanTable_p == nullptr)
scanTable_p = new contentTable (this, dabSettings_p, "scan",
2024-06-01 11:12:04 +02:00
theOFDMHandler -> scanWidth ());
2024-01-27 20:16:14 +01:00
else // should not happen
scanTable_p -> clearTable ();
QString topLine = QString ("ensemble") + ";" +
"channelName" + ";" +
"frequency (KHz)" + ";" +
"Eid" + ";" +
"tii" + ";" +
"time" + ";" +
"SNR" + ";" +
"nr services" + ";";
2024-03-04 14:45:33 +01:00
scanTable_p -> addLine (topLine);
2024-01-27 20:16:14 +01:00
scanTable_p -> addLine ("\n");
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_scanMode (true);
QString fs = theSCANHandler. getFirstChannel ();
2024-01-27 20:16:14 +01:00
int k = channelSelector -> findText (fs);
if (k != -1)
new_channelIndex (k);
2024-06-01 11:12:04 +02:00
theSCANHandler. addText (" scanning channel " +
2024-03-04 14:45:33 +01:00
channelSelector -> currentText ());
2024-01-27 20:16:14 +01:00
int switchDelay =
2024-02-16 15:46:54 +01:00
configHandler_p -> switchDelayValue ();
channelTimer. start (switchDelay);
2024-03-04 14:45:33 +01:00
fprintf (stderr, "en starten maar\n");
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
}
void RadioInterface::start_scan_continuous () {
if (scanTable_p == nullptr)
scanTable_p = new contentTable (this, dabSettings_p, "scan",
2024-06-01 11:12:04 +02:00
theOFDMHandler -> scanWidth ());
2024-01-27 20:16:14 +01:00
else // should not happen
scanTable_p -> clearTable ();
QString topLine = QString ("ensemble") + ";" +
"channelName" + ";" +
"frequency (KHz)" + ";" +
"Eid" + ";" +
"tii" + ";" +
"time" + ";" +
"SNR" + ";" +
"nr services" + ";";
scanTable_p -> addLine (topLine);
scanTable_p -> addLine ("\n");
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_scanMode (true);
2024-01-27 20:16:14 +01:00
// To avoid reaction of the system on setting a different value:
2024-06-01 11:12:04 +02:00
QString fs = theSCANHandler. getFirstChannel ();
2024-01-27 20:16:14 +01:00
int k = channelSelector -> findText (fs);
new_channelIndex (k);
int switchDelay =
2024-02-16 15:46:54 +01:00
configHandler_p -> switchDelayValue ();
channelTimer. start (2 * switchDelay);
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
}
//
// stop_scanning is called
// 1. when the scanbutton is touched during scanning
// 2. on user selection of a service or a channel select
// 3. on device selection
// 4. on handling a reset
void RadioInterface::stopScanning () {
2024-06-01 11:12:04 +02:00
disconnect (theOFDMHandler, &ofdmHandler::no_signal_found,
2024-04-14 12:47:14 +02:00
this, &RadioInterface::no_signal_found);
2024-06-01 11:12:04 +02:00
if (!theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
return;
2024-02-01 11:39:22 +01:00
presetButton -> setText ("favorites");
presetButton -> setEnabled (true);
2024-01-27 20:16:14 +01:00
LOG ("scanning stops ", "");
2024-03-04 14:45:33 +01:00
channelTimer. stop ();
2024-06-01 11:12:04 +02:00
if (theSCANHandler. scan_to_data ())
2024-01-27 20:16:14 +01:00
stop_scan_to_data ();
else
2024-06-01 11:12:04 +02:00
if (theSCANHandler. scan_single ())
2024-01-27 20:16:14 +01:00
stop_scan_single ();
else
stop_scan_continuous ();
2024-06-01 11:12:04 +02:00
theSCANHandler. setStop ();
2024-01-27 20:16:14 +01:00
// presetButton -> setEnabled (true);
}
void RadioInterface::stop_scan_to_data () {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_scanMode (false);
2024-01-27 20:16:14 +01:00
channelTimer. stop ();
}
void RadioInterface::stop_scan_single () {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_scanMode (false);
2024-01-27 20:16:14 +01:00
channelTimer. stop ();
if (scanTable_p == nullptr)
return; // should not happen
2024-03-04 14:45:33 +01:00
if (configHandler_p -> upload_selector_active ()) {
2024-03-13 19:45:53 +01:00
try {
uploader the_uploader;
QMessageBox::StandardButton reply =
2024-03-04 14:45:33 +01:00
QMessageBox::question (this,
2024-03-13 19:45:53 +01:00
"upload content to fmlist.org?", "",
2024-03-04 14:45:33 +01:00
QMessageBox::Yes | QMessageBox::No);
2024-03-13 19:45:53 +01:00
if (reply == QMessageBox::Yes) {
the_uploader. loadUp ("Scan",
0,
"result table",
scanTable_p -> upload ());
}
} catch (...) {}
2024-03-04 14:45:33 +01:00
}
2024-06-01 11:12:04 +02:00
FILE *scanDumper_p = theSCANHandler. askFileName ();
2024-01-27 20:16:14 +01:00
if (scanDumper_p != nullptr) {
scanTable_p -> dump (scanDumper_p);
fclose (scanDumper_p);
scanDumper_p = nullptr;
}
delete scanTable_p;
scanTable_p = nullptr;
}
void RadioInterface::stop_scan_continuous () {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_scanMode (false);
2024-01-27 20:16:14 +01:00
channelTimer. stop ();
if (scanTable_p == nullptr)
return; // should not happen
2024-06-01 11:12:04 +02:00
FILE *scanDumper_p = theSCANHandler. askFileName ();
2024-01-27 20:16:14 +01:00
if (scanDumper_p != nullptr) {
scanTable_p -> dump (scanDumper_p);
fclose (scanDumper_p);
scanDumper_p = nullptr;
}
delete scanTable_p;
scanTable_p = nullptr;
}
// If the ofdm processor has waited - without success -
// for a period of N frames to get a start of a synchronization,
// it sends a signal to the GUI handler
// If "scanning" is "on" we hop to the next frequency on
// the list.
// Also called as a result of time out on channelTimer
2024-03-04 14:45:33 +01:00
void RadioInterface::channel_timeOut () {
2024-01-27 20:16:14 +01:00
channelTimer. stop ();
2024-06-01 11:12:04 +02:00
if (!theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
return;
2024-06-01 11:12:04 +02:00
if (theSCANHandler. scan_to_data ())
2024-01-27 20:16:14 +01:00
next_for_scan_to_data ();
else
2024-06-01 11:12:04 +02:00
if (theSCANHandler. scan_single ())
2024-01-27 20:16:14 +01:00
next_for_scan_single ();
else
next_for_scan_continuous ();
}
void RadioInterface::next_for_scan_to_data () {
if (channel. nrServices > 0) {
stopScanning ();
return;
}
stopChannel ();
2024-06-01 11:12:04 +02:00
QString ns = theSCANHandler. getNextChannel ();
2024-01-27 20:16:14 +01:00
int cc = channelSelector -> findText (ns);
new_channelIndex (cc);
//
// and restart for the next run
2024-06-01 11:12:04 +02:00
theSCANHandler. addText ("scanning channel " +
2024-03-04 14:45:33 +01:00
channelSelector -> currentText ());
2024-01-27 20:16:14 +01:00
int switchDelay =
2024-02-16 15:46:54 +01:00
configHandler_p -> switchDelayValue ();
channelTimer. start (switchDelay);
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
}
void RadioInterface::next_for_scan_single () {
if (channel. nrServices > 0)
show_for_single_scan ();
stopChannel ();
try {
2024-06-01 11:12:04 +02:00
QString cs = theSCANHandler. getNextChannel ();
2024-01-27 20:16:14 +01:00
int cc = channelSelector -> findText (cs);
new_channelIndex (cc);
} catch (...) {
stopScanning ();
return;
}
2024-06-01 11:12:04 +02:00
theSCANHandler. addText ("scanning channel " +
2024-03-04 14:45:33 +01:00
channelSelector -> currentText ());
2024-01-27 20:16:14 +01:00
int switchDelay =
2024-02-16 15:46:54 +01:00
configHandler_p -> switchDelayValue ();
channelTimer. start (switchDelay);
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
}
void RadioInterface::next_for_scan_continuous () {
if (channel. nrServices > 0)
show_for_continuous ();
stopChannel ();
2024-06-01 11:12:04 +02:00
QString cs = theSCANHandler. getNextChannel ();
2024-01-27 20:16:14 +01:00
int cc = channelSelector -> findText (cs);
new_channelIndex (cc);
int switchDelay =
2024-02-16 15:46:54 +01:00
configHandler_p -> switchDelayValue ();
channelTimer. start (2 * switchDelay);
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
}
////////////////////////////////////////////////////////////////////////////
2024-04-07 14:58:26 +02:00
QString RadioInterface::build_headLine () {
2024-01-27 20:16:14 +01:00
QString SNR = "SNR " + QString::number (channel. snr);
2024-04-07 14:58:26 +02:00
QString tii;
QString theName;
QString theDistance;
QString theCorner;
QString theHeight;
2024-01-27 20:16:14 +01:00
2024-06-01 11:12:04 +02:00
if (theOFDMHandler == nullptr) { // cannot happen
2024-01-27 20:16:14 +01:00
fprintf (stderr, "Expert error 26\n");
2024-04-07 14:58:26 +02:00
return "";
2024-01-27 20:16:14 +01:00
}
2024-04-08 11:08:56 +02:00
if (channel. mainId != -1)
2024-04-07 14:58:26 +02:00
tii = ids_to_string (channel. mainId,
channel. subId) + ";" ;
2024-04-08 11:08:56 +02:00
else
tii = "?,?;";
if (channel. transmitterName != "")
2024-04-07 14:58:26 +02:00
theName = channel. transmitterName + ";";
2024-04-08 11:08:56 +02:00
else
theName = ";";
if (channel. distance > 0) {
2024-04-07 14:58:26 +02:00
theDistance = QString::number (channel. distance, 'f', 1) + " km ";
theCorner = QString::number (channel. corner, 'f', 1)
+ QString::fromLatin1 (" \xb0 ");
theHeight = " (" + QString::number (channel. height, 'f', 1) + "m)" + "\n";
}
else {
theDistance = "unknown";
theCorner = "";
theHeight = "\n";
}
2024-01-27 20:16:14 +01:00
QString utcTime = convertTime (UTC. year, UTC.month,
UTC. day, UTC. hour,
UTC. minute);
QString headLine = channel. ensembleName + ";" +
2024-04-07 14:58:26 +02:00
channel. channelName + ";" +
2024-01-27 20:16:14 +01:00
QString::number (channel. tunedFrequency) + ";" +
2024-04-07 14:58:26 +02:00
hextoString (channel. Eid) + ";" +
tii +
utcTime + ";" +
SNR + ";" +
QString::number (channel. nrServices) +";" +
theName + theDistance + theCorner + theHeight;
return headLine;
}
2024-04-03 18:44:52 +02:00
2024-04-07 14:58:26 +02:00
void RadioInterface::show_for_single_scan () {
QString headLine = build_headLine ();
2024-06-01 11:12:04 +02:00
QStringList s = theOFDMHandler -> basicPrint ();
2024-01-27 20:16:14 +01:00
scanTable_p -> addLine (headLine);
scanTable_p -> addLine ("\n;\n");
for (const auto &l : s)
scanTable_p -> addLine (l);
scanTable_p -> addLine ("\n;\n;\n");
scanTable_p -> show ();
}
void RadioInterface::show_for_continuous () {
QString headLine = build_headLine ();
2024-01-27 20:16:14 +01:00
scanTable_p -> addLine (headLine);
for (auto &tr: channel. transmitters) {
if (!tr. isStrongest) {
QString line = build_cont_addLine (tr);
if (line == "")
continue;
scanTable_p -> addLine (line);
}
}
scanTable_p -> show ();
}
QString RadioInterface::build_cont_addLine (transmitterDesc &tr) {
QString tii;
QString theName;
QString theDistance;
QString theCorner;
QString theHeight;
tii = ids_to_string (tr. theTransmitter. mainId,
tr. theTransmitter. subId) + ";" ;
if (tr. theTransmitter. transmitterName != "")
theName = tr. theTransmitter. transmitterName + ";";
else
theName = ";";
if (tr. distance > 0) {
theDistance = QString::number (tr. distance, 'f', 1) + " km ";
theCorner = QString::number (tr. corner, 'f', 1)
+ QString::fromLatin1 (" \xb0 ");
theHeight = " (" + QString::number (tr. theTransmitter. height, 'f', 1) + "m)" + "\n";
}
else {
theDistance = "unknown";
theCorner = "?";
theHeight = "?";
}
return QString (";") +
";" +
";" +
";" +
tii +
";" +
";" +
";" +
theName + theDistance + theCorner + theHeight;
2024-01-27 20:16:14 +01:00
}
/////////////////////////////////////////////////////////////////////
//
// Handling the Mute button
void RadioInterface::handle_muteButton () {
if (muteTimer. isActive ()) {
stop_muting ();
return;
}
if (!channel. audioActive)
return;
set_soundLabel (false);
2024-04-14 12:47:14 +02:00
connect (&muteTimer, &QTimer::timeout,
this, &RadioInterface::muteButton_timeOut);
2024-02-16 15:46:54 +01:00
muteDelay = configHandler_p -> muteValue ();
2024-02-27 15:03:33 +01:00
muteDelay *= 60; // seconds
2024-01-27 20:16:14 +01:00
muteTimer. start (1000);
stillMuting -> show ();
stillMuting -> display (muteDelay);
}
void RadioInterface::muteButton_timeOut () {
muteDelay --;
if (muteDelay > 0) {
stillMuting -> display (muteDelay);
muteTimer. start (1000);
return;
}
else {
2024-04-14 12:47:14 +02:00
disconnect (&muteTimer, &QTimer::timeout,
this, &RadioInterface::muteButton_timeOut);
2024-01-27 20:16:14 +01:00
stillMuting -> hide ();
if (channel. audioActive)
2024-01-27 20:16:14 +01:00
set_soundLabel (true);
}
}
void RadioInterface::stop_muting () {
if (!muteTimer. isActive ())
return;
set_soundLabel (true);
muteTimer. stop ();
2024-04-14 12:47:14 +02:00
disconnect (&muteTimer, &QTimer::timeout,
this, &RadioInterface::muteButton_timeOut);
2024-01-27 20:16:14 +01:00
stillMuting -> hide ();
}
//
// End of handling mute button
2024-02-27 15:03:33 +01:00
// new_channelIndex is called whenever we are sure that
// the channel selector is "connected", and we programamtically
// change the setting, which obviously would lead to a signal
// that we do not wwant right now
2024-01-27 20:16:14 +01:00
void RadioInterface::new_channelIndex (int index) {
if (channelSelector -> currentIndex () == index)
return;
2024-03-04 14:45:33 +01:00
channelSelector -> setEnabled (false);
channelSelector -> setCurrentIndex (index);
channelSelector -> setEnabled (true);
2024-01-27 20:16:14 +01:00
}
//
/////////////////////////////////////////////////////////////////////////
// merely as a gadget, for each button the color can be set
// Lots of code, about 400 lines, just for a gadget
//
void RadioInterface::set_Colors () {
2024-02-25 14:18:27 +01:00
dabSettings_p -> beginGroup (COLOR_SETTINGS);
2024-01-27 20:16:14 +01:00
QString scanButton_color =
dabSettings_p -> value (SCAN_BUTTON + "_color",
"white"). toString ();
QString scanButton_font =
dabSettings_p -> value (SCAN_BUTTON + "_font",
"black"). toString ();
QString spectrumButton_color =
dabSettings_p -> value (SPECTRUM_BUTTON + "_color",
"white"). toString ();
QString spectrumButton_font =
dabSettings_p -> value (SPECTRUM_BUTTON + "_font",
"black"). toString ();
QString scanListButton_color =
dabSettings_p -> value (SCANLIST_BUTTON + "_color",
"white"). toString ();
QString scanListButton_font =
dabSettings_p -> value (SCANLIST_BUTTON + "_font",
"black"). toString ();
QString presetButton_color =
dabSettings_p -> value (PRESET_BUTTON + "_color",
"white"). toString ();
QString presetButton_font =
dabSettings_p -> value (PRESET_BUTTON + "_font",
"black"). toString ();
QString prevServiceButton_color =
dabSettings_p -> value (PREVSERVICE_BUTTON + "_color",
"blaCK"). toString ();
QString prevServiceButton_font =
dabSettings_p -> value (PREVSERVICE_BUTTON + "_font",
"white"). toString ();
QString nextServiceButton_color =
dabSettings_p -> value (NEXTSERVICE_BUTTON + "_color",
"black"). toString ();
QString nextServiceButton_font =
dabSettings_p -> value (NEXTSERVICE_BUTTON + "_font",
"white"). toString ();
QString configButton_color =
dabSettings_p -> value (CONFIG_BUTTON + "_color",
"black"). toString ();
QString configButton_font =
dabSettings_p -> value (CONFIG_BUTTON + "_font",
"white"). toString ();
QString httpButton_color =
dabSettings_p -> value (HTTP_BUTTON + "_color",
"black"). toString ();
QString httpButton_font =
dabSettings_p -> value (HTTP_BUTTON + "_font",
"white"). toString ();
dabSettings_p -> endGroup ();
QString temp = "QPushButton {background-color: %1; color: %2}";
spectrumButton ->
setStyleSheet (temp. arg (spectrumButton_color,
spectrumButton_font));
scanListButton ->
setStyleSheet (temp. arg (scanListButton_color,
scanListButton_font));
presetButton ->
setStyleSheet (temp. arg (presetButton_color,
presetButton_font));
scanButton ->
setStyleSheet (temp. arg (scanButton_color,
scanButton_font));
configButton ->
setStyleSheet (temp. arg (configButton_color,
configButton_font));
httpButton ->
setStyleSheet (temp. arg (httpButton_color,
httpButton_font));
prevServiceButton ->
setStyleSheet (temp. arg (prevServiceButton_color,
prevServiceButton_font));
nextServiceButton ->
setStyleSheet (temp. arg (nextServiceButton_color,
nextServiceButton_font));
}
void RadioInterface::color_scanButton () {
set_buttonColors (scanButton, SCAN_BUTTON);
}
void RadioInterface::color_spectrumButton () {
set_buttonColors (spectrumButton, SPECTRUM_BUTTON);
}
void RadioInterface::color_scanListButton () {
set_buttonColors (scanListButton, SCANLIST_BUTTON);
}
void RadioInterface::color_presetButton () {
set_buttonColors (presetButton, PRESET_BUTTON);
}
void RadioInterface::color_prevServiceButton () {
set_buttonColors (prevServiceButton, PREVSERVICE_BUTTON);
}
void RadioInterface::color_nextServiceButton () {
set_buttonColors (nextServiceButton, NEXTSERVICE_BUTTON);
}
void RadioInterface::color_configButton () {
set_buttonColors (configButton, CONFIG_BUTTON);
}
void RadioInterface::color_httpButton () {
set_buttonColors (httpButton, HTTP_BUTTON);
}
void RadioInterface::set_buttonColors (QPushButton *b,
const QString &buttonName) {
2024-04-22 20:35:15 +02:00
QColor baseColor, textColor;
2024-02-06 15:37:07 +01:00
2024-04-22 20:35:15 +02:00
QColor color = QColorDialog::getColor (baseColor, nullptr, "baseColor");
2024-02-06 15:37:07 +01:00
if (!color. isValid ())
2024-01-27 20:16:14 +01:00
return;
2024-02-06 15:37:07 +01:00
baseColor = color;
color = QColorDialog::getColor (textColor, nullptr, "textColor");
if (!color. isValid ())
2024-01-27 20:16:14 +01:00
return;
2024-02-06 15:37:07 +01:00
textColor = color;
2024-01-27 20:16:14 +01:00
QString temp = "QPushButton {background-color: %1; color: %2}";
2024-02-06 15:37:07 +01:00
b -> setStyleSheet (temp. arg (baseColor. name (),
textColor. name ()));
2024-01-27 20:16:14 +01:00
QString buttonColor = buttonName + "_color";
QString buttonFont = buttonName + "_font";
2024-02-25 14:18:27 +01:00
dabSettings_p -> beginGroup (COLOR_SETTINGS);
2024-02-06 15:37:07 +01:00
dabSettings_p -> setValue (buttonColor, baseColor. name ());
dabSettings_p -> setValue (buttonFont, textColor. name ());
2024-01-27 20:16:14 +01:00
dabSettings_p -> endGroup ();
}
///////////////////////////////////////////////////////////////////////////
// Handling schedule
2024-04-19 18:34:50 +02:00
static
2024-06-01 11:12:04 +02:00
const char *scheduleList[] = {"nothing", "exit",
"framedump", "dltext", "ficDump"};
2024-04-19 18:34:50 +02:00
2024-01-27 20:16:14 +01:00
void RadioInterface::handle_scheduleButton () {
QStringList candidates;
scheduleSelector theSelector;
QString scheduleService;
2024-04-19 18:34:50 +02:00
for (int i = 0; i < 5; i ++) {
theSelector. addtoList (QString (scheduleList [i]));
candidates += QString (scheduleList [i]);
}
2024-01-27 20:16:14 +01:00
QStringList selectables = the_ensembleHandler -> getSelectables ();
for (auto &candidate: selectables) {
if (!candidates. contains (candidate)) {
theSelector.
addtoList (candidate);
candidates += candidate;
}
}
int selected = theSelector. QDialog::exec ();
scheduleService = candidates. at (selected);
{ elementSelector theElementSelector (scheduleService);
int targetTime = theElementSelector. QDialog::exec ();
int delayDays = (targetTime & 0XF0000) >> 16;
targetTime = targetTime & 0xFFFF;
theScheduler. addRow (scheduleService,
delayDays,
targetTime / 60,
targetTime % 60);
}
theScheduler. show ();
}
void RadioInterface::scheduler_timeOut (const QString &s) {
if (!running. load ())
return;
if (s == "nothing")
return;
if (s == "exit") {
2024-02-16 15:46:54 +01:00
configHandler_p -> set_closeDirect (true);
2024-01-27 20:16:14 +01:00
QWidget::close ();
return;
}
if (s == "framedump") {
scheduled_frameDumping (channel.currentService. serviceName);
return;
}
if (s == "audiodump") {
scheduled_audioDumping ();
return;
}
if (s == "dlText") {
scheduled_dlTextDumping ();
return;
}
if (s == "ficDump") {
scheduled_ficDumping ();
return;
}
presetTimer. stop ();
stopScanning ();
scheduleSelect (s);
}
void RadioInterface::scheduled_ficDumping () {
if (ficDumpPointer == nullptr) {
ficDumpPointer =
2024-06-01 11:12:04 +02:00
theFilenameFinder. find_ficDump_file (channel. channelName);
2024-01-27 20:16:14 +01:00
if (ficDumpPointer == nullptr)
return;
2024-06-01 11:12:04 +02:00
theOFDMHandler -> start_ficDump (ficDumpPointer);
2024-01-27 20:16:14 +01:00
return;
}
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop_ficDump ();
2024-01-27 20:16:14 +01:00
ficDumpPointer = nullptr;
}
//------------------------------------------------------------------------
//
// if configured, the interpreation of the EPG data starts automatically,
// the servicenames of an SPI/EPG service may differ from one country
// to another
void RadioInterface::epgTimer_timeOut () {
epgTimer. stop ();
2024-02-25 14:18:27 +01:00
if (int_configValue ("epgFlag", 0) != 1)
2024-01-27 20:16:14 +01:00
return;
2024-06-01 11:12:04 +02:00
if (theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
return;
QStringList epgList = the_ensembleHandler -> get_epgServices ();
for (auto serv : epgList) {
packetdata pd;
2024-07-16 19:52:55 +02:00
theOFDMHandler -> data_for_packetservice (serv, pd, 0);
2024-01-27 20:16:14 +01:00
if ((!pd. defined) ||
(pd. DSCTy == 0) || (pd. bitRate == 0))
continue;
if (pd. DSCTy == 60) {
LOG ("hidden service started ", serv);
fprintf (stderr, "Starting hidden service %s\n",
serv. toUtf8 (). data ());
2024-06-01 11:12:04 +02:00
theOFDMHandler -> set_dataChannel (pd, &theDataBuffer, BACK_GROUND);
2024-01-27 20:16:14 +01:00
dabService s;
s. channel = pd. channel;
s. serviceName = pd. serviceName;
s. SId = pd. SId;
2024-03-25 14:35:22 +01:00
s. SCIds = pd. SCIds;
2024-01-27 20:16:14 +01:00
s. subChId = pd. subchId;
s. fd = nullptr;
channel. backgroundServices. push_back (s);
}
}
}
void RadioInterface::set_epgData (int SId, int theTime,
const QString &theText,
const QString &theDescr) {
2024-06-01 11:12:04 +02:00
if (theOFDMHandler != nullptr)
theOFDMHandler -> set_epgData (SId, theTime,
2024-01-27 20:16:14 +01:00
theText, theDescr);
}
void RadioInterface::handle_timeTable () {
int epgWidth;
if (!my_timeTable -> isHidden ()) {
my_timeTable -> hide ();
return;
}
if (!channel. currentService. valid ||
!channel. currentService. is_audio)
return;
my_timeTable -> clear ();
epgWidth = dabSettings_p -> value ("epgWidth", 70). toInt ();
if (epgWidth < 50)
epgWidth = 50;
std::vector<epgElement> res =
2024-06-01 11:12:04 +02:00
theOFDMHandler -> find_epgData (channel. currentService. SId);
2024-01-27 20:16:14 +01:00
for (const auto& element: res)
my_timeTable -> addElement (element. theTime,
epgWidth,
element. theText,
element. theDescr);
my_timeTable -> show ();
}
//----------------------------------------------------------------------
//
void RadioInterface::scheduled_dlTextDumping () {
if (dlTextFile != nullptr) {
fclose (dlTextFile);
dlTextFile = nullptr;
2024-02-16 15:46:54 +01:00
configHandler_p -> mark_dlTextButton (false);
2024-01-27 20:16:14 +01:00
return;
}
2024-06-01 11:12:04 +02:00
QString fileName = theFilenameFinder. finddlText_fileName (false);
2024-01-27 20:16:14 +01:00
dlTextFile = fopen (fileName. toUtf8 (). data (), "w+");
if (dlTextFile == nullptr)
return;
2024-02-16 15:46:54 +01:00
configHandler_p -> mark_dlTextButton (true);
2024-01-27 20:16:14 +01:00
}
//
//---------------------------------------------------------------------
//
void RadioInterface::handle_configButton () {
2024-02-16 15:46:54 +01:00
if (!configHandler_p -> isHidden ()) {
configHandler_p -> hide ();
2024-03-13 19:45:53 +01:00
dabSettings_p -> setValue (CONFIG_WIDGET_VISIBLE, 0);
2024-01-27 20:16:14 +01:00
}
else {
2024-02-16 15:46:54 +01:00
configHandler_p -> show ();
2024-03-13 19:45:53 +01:00
dabSettings_p -> setValue (CONFIG_WIDGET_VISIBLE, 1);
2024-01-27 20:16:14 +01:00
}
}
void RadioInterface::handle_devicewidgetButton () {
if (inputDevice_p == nullptr)
return;
fprintf (stderr, "setting visibility to %d\n",
!inputDevice_p -> getVisibility ());
2024-01-27 20:16:14 +01:00
inputDevice_p -> setVisibility (!inputDevice_p -> getVisibility ());
2024-02-25 14:18:27 +01:00
dabSettings_p -> setValue (DEVICE_WIDGET_VISIBLE,
2024-01-27 20:16:14 +01:00
inputDevice_p -> getVisibility () ? 1 : 0);
}
2024-02-16 15:46:54 +01:00
//
// called from the configHandler
2024-01-27 20:16:14 +01:00
void RadioInterface::handle_dlTextButton () {
if (dlTextFile != nullptr) {
fclose (dlTextFile);
dlTextFile = nullptr;
2024-02-16 15:46:54 +01:00
configHandler_p -> mark_dlTextButton (false);
2024-01-27 20:16:14 +01:00
return;
}
2024-06-01 11:12:04 +02:00
QString fileName =theFilenameFinder. finddlText_fileName (true);
2024-01-27 20:16:14 +01:00
dlTextFile = fopen (fileName. toUtf8 (). data (), "w+");
if (dlTextFile == nullptr)
return;
2024-02-16 15:46:54 +01:00
configHandler_p -> mark_dlTextButton (true);
2024-01-27 20:16:14 +01:00
}
2024-02-16 15:46:54 +01:00
//
// called from the config handler
2024-01-27 20:16:14 +01:00
void RadioInterface::handle_resetButton () {
if (!running. load())
return;
QString channelName = channel. channelName;
stopScanning ();
stopChannel ();
startChannel (channelName);
}
2024-02-16 15:46:54 +01:00
//
// called from the config handler
2024-01-27 20:16:14 +01:00
void RadioInterface::handle_snrButton () {
if (!running. load ())
return;
2024-06-01 11:12:04 +02:00
if (theSNRViewer. isHidden ())
theSNRViewer. show ();
2024-01-27 20:16:14 +01:00
else
2024-06-01 11:12:04 +02:00
theSNRViewer. hide ();
2024-02-25 14:18:27 +01:00
dabSettings_p -> setValue (SNR_WIDGET_VISIBLE,
2024-06-01 11:12:04 +02:00
theSNRViewer. isHidden () ? 0 : 1);
2024-01-27 20:16:14 +01:00
}
2024-02-16 15:46:54 +01:00
//
// called from the configHandler
2024-01-27 20:16:14 +01:00
void RadioInterface::handle_set_coordinatesButton () {
coordinates theCoordinator (dabSettings_p);
(void)theCoordinator. QDialog::exec();
2024-02-16 15:46:54 +01:00
localPos. latitude =
2024-02-25 14:18:27 +01:00
dabSettings_p -> value (HOME_LATITUDE, 0). toFloat ();
2024-02-16 15:46:54 +01:00
localPos. longitude =
2024-02-25 14:18:27 +01:00
dabSettings_p -> value (HOME_LONGITUDE, 0). toFloat ();
2024-01-27 20:16:14 +01:00
}
2024-02-16 15:46:54 +01:00
//
// called from the configHandler
2024-01-27 20:16:14 +01:00
void RadioInterface::handle_loadTable () {
2024-02-25 14:18:27 +01:00
dbLoader theLoader (dabSettings_p);
if (theLoader. load_db ()) {
2024-01-27 20:16:14 +01:00
QMessageBox::information (this, tr ("success"),
tr ("Loading and installing database complete\n"));
2024-06-01 11:12:04 +02:00
theTIIProcessor. reload ();
2024-01-27 20:16:14 +01:00
}
else {
QMessageBox::information (this, tr ("fail"),
tr ("Loading database failed\n"));
}
}
void RadioInterface::stop_sourcedumping () {
2024-07-29 20:19:31 +02:00
if (!sourceDumping)
return;
2024-01-27 20:16:14 +01:00
LOG ("source dump stops ", "");
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop_dumping();
2024-07-27 15:30:56 +02:00
sourceDumping = false;
2024-02-16 15:46:54 +01:00
configHandler_p -> mark_dumpButton (false);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::start_sourcedumping () {
QString deviceName = inputDevice_p -> deviceName ();
QString channelName = channel. channelName;
2024-06-01 11:12:04 +02:00
if (theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
return;
2024-07-27 15:30:56 +02:00
QString rawDumpName =
2024-06-01 11:12:04 +02:00
theFilenameFinder. findRawDump_fileName (deviceName, channelName);
2024-07-27 15:30:56 +02:00
if (rawDumpName == "")
2024-01-27 20:16:14 +01:00
return;
LOG ("source dump starts ", channelName);
2024-02-16 15:46:54 +01:00
configHandler_p -> mark_dumpButton (true);
2024-07-27 15:30:56 +02:00
theOFDMHandler -> start_dumping (rawDumpName, channel. tunedFrequency);
sourceDumping = true;
2024-01-27 20:16:14 +01:00
}
void RadioInterface::handle_sourcedumpButton () {
2024-06-01 11:12:04 +02:00
if (!running. load () || theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
return;
2024-07-27 15:30:56 +02:00
if (sourceDumping)
2024-01-27 20:16:14 +01:00
stop_sourcedumping ();
else
start_sourcedumping ();
}
void RadioInterface::handle_LoggerButton (int s) {
(void)s;
2024-02-16 15:46:54 +01:00
if (configHandler_p -> logger_active ()) {
2024-01-27 20:16:14 +01:00
if (logFile != nullptr) {
fprintf (stderr, "should not happen (logfile)\n");
return;
}
2024-06-01 11:12:04 +02:00
logFile = theFilenameFinder. findLogFileName ();
2024-01-27 20:16:14 +01:00
if (logFile != nullptr)
LOG ("Log started with ", inputDevice_p -> deviceName ());
}
else
if (logFile != nullptr) {
fclose (logFile);
logFile = nullptr;
}
}
2024-02-16 15:46:54 +01:00
void RadioInterface::set_tii_detectorMode (bool isChecked) {
2024-06-01 11:12:04 +02:00
if (theOFDMHandler != nullptr)
theOFDMHandler -> set_tiiDetectorMode (isChecked);
2024-01-27 20:16:14 +01:00
}
2024-02-25 14:18:27 +01:00
void RadioInterface::handle_dcRemovalSelector (bool b) {
2024-06-01 11:12:04 +02:00
if (theOFDMHandler != nullptr)
theOFDMHandler -> set_dcRemoval (b);
theNewDisplay. set_dcRemoval (b);
2024-01-27 20:16:14 +01:00
}
2024-02-16 15:46:54 +01:00
void RadioInterface::set_transmitters_local (bool isChecked) {
2024-01-27 20:16:14 +01:00
maxDistance = -1;
channel. targetPos = position {0, 0};
2024-02-16 15:46:54 +01:00
if ((isChecked) && (mapHandler != nullptr))
2024-02-25 14:18:27 +01:00
mapHandler -> putData (MAP_RESET, channel. targetPos);
2024-01-27 20:16:14 +01:00
}
2024-02-16 15:46:54 +01:00
void RadioInterface::selectDecoder (int decoder) {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> handle_decoderSelector (decoder);
2024-01-27 20:16:14 +01:00
}
void RadioInterface:: set_streamSelector (int k) {
if (!running. load ())
return;
((audioSink *)(soundOut_p)) -> selectDevice (k);
2024-02-25 14:18:27 +01:00
dabSettings_p -> setValue (AUDIO_STREAM_NAME,
2024-02-16 15:46:54 +01:00
configHandler_p -> currentStream ());
2024-01-27 20:16:14 +01:00
}
//
//////////////////////////////////////////////////////////////////////////
void RadioInterface::nrServices (int n) {
channel. serviceCount = n;
}
void RadioInterface::LOG (const QString &a1, const QString &a2) {
QString theTime;
if (logFile == nullptr)
return;
2024-02-16 15:46:54 +01:00
if (configHandler_p -> utcSelector_active ())
2024-01-27 20:16:14 +01:00
theTime = convertTime (UTC. year, UTC. month, UTC. day,
UTC. hour, UTC. minute);
else
theTime = QDateTime::currentDateTime (). toString ();
fprintf (logFile, "at %s: %s %s\n",
theTime. toUtf8 (). data (),
a1. toUtf8 (). data (), a2. toUtf8 (). data ());
}
2024-04-19 18:34:50 +02:00
bool RadioInterface::autoStart_http () {
if (localPos. latitude == 0)
return false;
if (mapHandler != nullptr)
return false;
QString browserAddress =
dabSettings_p -> value (BROWSER_ADDRESS,
"http://localhost"). toString ();
QString mapPort =
dabSettings_p -> value (MAP_PORT_SETTING,
8080). toString ();
mapHandler = new httpHandler (this,
mapPort,
browserAddress,
localPos,
"",
configHandler_p -> localBrowserSelector_active (), dabSettings_p);
maxDistance = -1;
return mapHandler != nullptr;
}
2024-01-27 20:16:14 +01:00
// ensure that we only get a handler if we have a start location
void RadioInterface::handle_httpButton () {
2024-02-16 15:46:54 +01:00
if (localPos. latitude == 0) {
2024-01-27 20:16:14 +01:00
QMessageBox::information (this, tr ("Warning"),
tr ("Function not available, no coordinates were found"));
return;
}
if (mapHandler == nullptr) {
QString browserAddress =
2024-02-25 14:18:27 +01:00
dabSettings_p -> value (BROWSER_ADDRESS,
2024-02-16 15:46:54 +01:00
"http://localhost"). toString ();
2024-01-27 20:16:14 +01:00
QString mapPort =
2024-02-25 14:18:27 +01:00
dabSettings_p -> value (MAP_PORT_SETTING,
8080). toString ();
2024-01-27 20:16:14 +01:00
QString mapFile;
2024-02-25 14:18:27 +01:00
if (configHandler_p -> transmitterNames_active ())
2024-06-01 11:12:04 +02:00
mapFile = theFilenameFinder. findMaps_fileName ();
2024-02-25 14:18:27 +01:00
else
mapFile = "";
2024-02-16 15:46:54 +01:00
2024-01-27 20:16:14 +01:00
mapHandler = new httpHandler (this,
mapPort,
browserAddress,
2024-02-16 15:46:54 +01:00
localPos,
2024-01-27 20:16:14 +01:00
mapFile,
2024-04-16 15:18:29 +02:00
configHandler_p -> localBrowserSelector_active (), dabSettings_p);
2024-01-27 20:16:14 +01:00
maxDistance = -1;
if (mapHandler != nullptr)
httpButton -> setText ("http-on");
}
else {
locker. lock ();
delete mapHandler;
mapHandler = nullptr;
locker. unlock ();
httpButton -> setText ("http");
}
}
void RadioInterface::http_terminate () {
locker. lock ();
if (mapHandler != nullptr) {
delete mapHandler;
mapHandler = nullptr;
}
locker. unlock ();
httpButton -> setText ("http");
}
void RadioInterface::displaySlide (const QPixmap &p) {
int w = 360;
int h = 2 * w / 3;
2024-03-13 19:45:53 +01:00
pauzeTimer. stop ();
2024-01-27 20:16:14 +01:00
pictureLabel -> setAlignment(Qt::AlignCenter);
pictureLabel ->
setPixmap (p. scaled (w, h, Qt::KeepAspectRatio));
pictureLabel -> show ();
}
void RadioInterface::show_pauzeSlide () {
QPixmap p;
2024-03-04 14:45:33 +01:00
QString slideName = ":res/pauze-slide-%1.png";
2024-03-13 19:45:53 +01:00
pauzeTimer. stop ();
2024-08-15 13:16:44 +02:00
int nr = rand () % 11;
slideName = slideName. arg (nr);
2024-03-04 14:45:33 +01:00
if (p. load (slideName, "png"))
2024-01-27 20:16:14 +01:00
displaySlide (p);
2024-08-15 13:16:44 +02:00
pauzeTimer. start (1 * 30 * 1000);
2024-01-27 20:16:14 +01:00
}
//////////////////////////////////////////////////////////////////////////
// Experimental: handling eti
// writing an eti file and scanning seems incompatible to me, so
// that is why I use the button, originally named "scanButton"
// for eti when eti is prepared.
// Preparing eti is with a checkbox on the configuration widget
//
/////////////////////////////////////////////////////////////////////////
void RadioInterface::handle_etiHandler () {
2024-06-01 11:12:04 +02:00
if (theOFDMHandler == nullptr) // should not happen
2024-01-27 20:16:14 +01:00
return;
if (channel. etiActive)
stop_etiHandler ();
else
start_etiHandler ();
}
void RadioInterface::stop_etiHandler () {
if (!channel. etiActive)
return;
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop_etiGenerator ();
2024-01-27 20:16:14 +01:00
channel. etiActive = false;
scanButton -> setText ("eti");
}
void RadioInterface::start_etiHandler () {
if (channel. etiActive)
return;
2024-06-01 11:12:04 +02:00
QString etiFile = theFilenameFinder.
2024-01-27 20:16:14 +01:00
find_eti_fileName (channel. ensembleName, channel. channelName);
if (etiFile == QString (""))
return;
LOG ("etiHandler started", etiFile);
2024-06-01 11:12:04 +02:00
channel. etiActive = theOFDMHandler -> start_etiGenerator (etiFile);
2024-01-27 20:16:14 +01:00
if (channel. etiActive)
scanButton -> setText ("eti runs");
}
void RadioInterface::handle_eti_activeSelector (int k) {
2024-02-16 15:46:54 +01:00
bool setting = configHandler_p -> eti_active ();
2024-01-27 20:16:14 +01:00
(void)k;
if (inputDevice_p == nullptr)
return;
if (setting) {
stopScanning ();
2024-04-14 12:47:14 +02:00
disconnect (scanButton, &QPushButton::clicked,
this, &RadioInterface::handle_scanButton);
connect (scanButton, &QPushButton::clicked,
this, &RadioInterface::handle_etiHandler);
2024-01-27 20:16:14 +01:00
scanButton -> setText ("eti");
if (!inputDevice_p -> isFileInput ())// restore the button' visibility
scanButton -> show ();
return;
}
// otherwise, disconnect the eti handling and reconnect scan
// be careful, an ETI session may be going on
stop_etiHandler (); // just in case
2024-04-14 12:47:14 +02:00
disconnect (scanButton, &QPushButton::clicked,
this, &RadioInterface::handle_etiHandler);
connect (scanButton, &QPushButton::clicked,
this, &RadioInterface::handle_scanButton);
2024-01-27 20:16:14 +01:00
scanButton -> setText ("scan");
if (inputDevice_p -> isFileInput ()) // hide the button now
scanButton -> hide ();
}
//
// access functions to the display widget
void RadioInterface::show_spectrum (int amount) {
std::vector<Complex> inBuffer (2048);
(void)amount;
2024-06-01 11:12:04 +02:00
if (theSpectrumBuffer. GetRingBufferReadAvailable () < 2048)
2024-01-27 20:16:14 +01:00
return;
2024-06-01 11:12:04 +02:00
theSpectrumBuffer. getDataFromBuffer (inBuffer. data (), 2048);
theSpectrumBuffer. FlushRingBuffer ();
if (!theNewDisplay. isHidden () &&
(theNewDisplay. get_tab () == SHOW_SPECTRUM))
theNewDisplay. show_spectrum (inBuffer, channel. tunedFrequency);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::show_tii_spectrum () {
std::vector<Complex> inBuffer (2048);
2024-06-01 11:12:04 +02:00
if (theTIIBuffer. GetRingBufferReadAvailable () < 2048)
2024-01-27 20:16:14 +01:00
return;
2024-06-01 11:12:04 +02:00
theTIIBuffer. getDataFromBuffer (inBuffer. data (), 2048);
theTIIBuffer. FlushRingBuffer ();
if (!theNewDisplay. isHidden () &&
(theNewDisplay. get_tab () == SHOW_TII))
theNewDisplay. show_tii (inBuffer, channel. tunedFrequency);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::show_correlation (int s, int g, QVector<int> r) {
2024-03-13 19:45:53 +01:00
std::vector<float> inBuffer (s);
2024-01-27 20:16:14 +01:00
(void)g;
2024-06-01 11:12:04 +02:00
theResponseBuffer. getDataFromBuffer (inBuffer. data (), s);
theResponseBuffer. FlushRingBuffer ();
if (!theNewDisplay. isHidden ()) {
if (theNewDisplay. get_tab () == SHOW_CORRELATION)
theNewDisplay. show_correlation (inBuffer, g, r, channel. distance);
2024-01-27 20:16:14 +01:00
}
}
2024-04-03 18:44:52 +02:00
2024-01-27 20:16:14 +01:00
void RadioInterface::show_null (int amount) {
2024-03-13 19:45:53 +01:00
Complex *inBuffer = (Complex *)(alloca (amount * sizeof (Complex)));
2024-06-01 11:12:04 +02:00
theNULLBuffer. getDataFromBuffer (inBuffer, amount);
if (!theNewDisplay. isHidden ())
if (theNewDisplay. get_tab () == SHOW_NULL)
theNewDisplay. show_null (inBuffer, amount);
2024-01-27 20:16:14 +01:00
}
2024-04-03 18:44:52 +02:00
void RadioInterface::show_tii (int tiiValue, int index) {
2024-01-27 20:16:14 +01:00
QString country = "";
2024-04-03 18:44:52 +02:00
int mainId = tiiValue >> 8;
cacheElement theTransmitter;
bool listChanged = false;
2024-01-27 20:16:14 +01:00
2024-04-03 18:44:52 +02:00
bool dxMode = configHandler_p -> get_dxSelector ();
if (!dxMode)
channel. transmitters. resize (0);
2024-01-27 20:16:14 +01:00
if (!running. load () ||(mainId == 0xFF)) // shouldn't be
return;
2024-06-01 11:12:04 +02:00
if (theOFDMHandler -> get_ecc () == 0)
2024-04-03 18:44:52 +02:00
return;
2024-01-27 20:16:14 +01:00
2024-04-03 18:44:52 +02:00
if (!channel. has_ecc) {
2024-06-01 11:12:04 +02:00
channel. ecc_byte = theOFDMHandler -> get_ecc ();
2024-01-27 20:16:14 +01:00
country = find_ITU_code (channel. ecc_byte,
(channel. Eid >> 12) &0xF);
channel. has_ecc = true;
2024-08-27 12:40:14 +02:00
channel. countryName = country;
2024-01-27 20:16:14 +01:00
channel. transmitterName = "";
transmitter_country -> setText (country);
}
2024-07-27 15:30:56 +02:00
2024-08-27 12:40:14 +02:00
// if (country != channel. countryName) {
// transmitter_country -> setText (country);
// channel. countryName = country;
// }
2024-02-25 14:18:27 +01:00
if ((localPos. latitude == 0) || (localPos. longitude == 0))
return;
2024-06-01 11:12:04 +02:00
if (!theTIIProcessor. has_tiiFile ())
2024-01-27 20:16:14 +01:00
return;
2024-04-19 18:34:50 +02:00
// OK, here we really start
2024-04-03 18:44:52 +02:00
bool inList = false;
for (uint16_t i = 0; i < channel. transmitters. size (); i ++) {
2024-04-03 18:44:52 +02:00
if (channel. transmitters. at (i). tiiValue == tiiValue) {
inList = true;
theTransmitter = channel. transmitters [i]. theTransmitter;
break;
2024-04-03 18:44:52 +02:00
}
}
2024-01-27 20:16:14 +01:00
2024-04-03 18:44:52 +02:00
if (!inList) {
cacheElement * tr =
2024-06-01 11:12:04 +02:00
theTIIProcessor. get_transmitter (channel. realChannel?
2024-02-25 14:18:27 +01:00
channel. channelName :
"any",
channel. Eid,
2024-04-03 18:44:52 +02:00
tiiValue >> 8, tiiValue & 0xFF);
if (tr == nullptr) {
QString labelText =
QString ("%1 %2 detected but not identified\n").
arg (uint8_t (tiiValue >> 8))
.arg (uint8_t ( tiiValue & 0xFF));
distanceLabel -> setText (labelText);
return;
}
2024-04-03 18:44:52 +02:00
if (tr == nullptr)
return;
if ((tr -> mainId == 0) || (tr -> subId == 0))
return;
2024-02-25 14:18:27 +01:00
theTransmitter = *tr;
transmitterDesc t = {tiiValue, false, theTransmitter, 0, 0};
channel. transmitters. push_back (t);
//
// we know the list changed, and we retransmit it later on
listChanged = true;
2024-01-27 20:16:14 +01:00
}
//
// Check which one is "strongest",
2024-04-03 18:44:52 +02:00
if (index == 0) {
int currentMax = -1;
for (uint16_t i = 0; i < channel. transmitters. size (); i ++) {
if (channel.transmitters. at (i). isStrongest)
currentMax = i;
2024-04-03 18:44:52 +02:00
channel. transmitters. at (i). isStrongest = false;
}
for (uint16_t i = 0; i < channel. transmitters. size (); i ++) {
if (channel. transmitters. at (i). tiiValue == tiiValue) {
channel. transmitters. at (i). isStrongest = true;
if (i != currentMax)
listChanged = true;
}
}
2024-04-03 18:44:52 +02:00
}
// display the transmitters on the scope widget
2024-06-01 11:12:04 +02:00
if (!(theNewDisplay. isHidden () &&
(theNewDisplay. get_tab () == SHOW_TII)))
theNewDisplay. show_transmitters (channel. transmitters);
2024-04-03 18:44:52 +02:00
//
// and recompute distances etc etc
if (!dxMode) {
QFont f ("Arial", 9);
distanceLabel -> setFont (f);
}
else {
2024-04-15 14:03:12 +02:00
if (listChanged) // adapt the list and display
2024-06-01 11:12:04 +02:00
theDXDisplay. cleanUp ();
theDXDisplay. show ();
theDXDisplay. setChannel (channel. channelName);
2024-04-03 18:44:52 +02:00
}
if (!listChanged && dxMode)
return;
//
// The list was changed, so we rewrite the dxDisplay and
// the map
2024-04-03 18:44:52 +02:00
QString labelText;
for (auto &theTr : channel. transmitters) {
position thePosition;
thePosition. latitude = theTr. theTransmitter. latitude;
thePosition. longitude = theTr. theTransmitter. longitude;
if (theTr. isStrongest) {
channel. targetPos. latitude = thePosition. latitude;
channel. targetPos. longitude = thePosition. longitude;
channel. transmitterName =
theTr. theTransmitter. transmitterName;
channel. mainId = theTr. tiiValue >> 8;
channel. subId = theTr. tiiValue & 0xFF;
}
QString theName = theTr. theTransmitter. transmitterName;
float power = theTr. theTransmitter. power;
float height = theTr. theTransmitter. height;
2024-01-27 20:16:14 +01:00
// if positions are known, we can compute distance and corner
theTr. distance = distance (thePosition, localPos);
theTr. corner = corner (thePosition, localPos);
2024-04-03 18:44:52 +02:00
if (theTr. isStrongest) {
channel. distance = theTr. distance;
channel. corner = theTr. corner;
2024-04-03 18:44:52 +02:00
channel. height = height;
}
2024-04-04 15:13:56 +02:00
int tiiValue_local = theTr. tiiValue;
labelText = "(" + QString::number (tiiValue_local >> 8) + ","
2024-04-03 18:44:52 +02:00
+ QString::number (tiiValue_local & 0xFF) + ") "
2024-04-04 15:13:56 +02:00
+ theName + " ";
QString text2 = " "
+ QString::number (theTr. distance, 'f', 1) + " km "
+ QString::number (theTr. corner, 'f', 1)
2024-04-03 18:44:52 +02:00
+ QString::fromLatin1 (" \xb0 ")
2024-04-15 14:03:12 +02:00
+ " (" + QString::number (height, 'f', 1) + "m)"
+ " " + QString::number (power, 'f', 1) + "kW";
2024-04-04 15:13:56 +02:00
if (dxMode)
2024-06-01 11:12:04 +02:00
theDXDisplay. addRow (labelText, text2, theTr. isStrongest);
2024-04-04 15:13:56 +02:00
else
distanceLabel -> setText (labelText + text2);
2024-04-03 18:44:52 +02:00
2024-01-27 20:16:14 +01:00
// see if we have a map
2024-04-03 18:44:52 +02:00
if (mapHandler == nullptr)
continue;
2024-01-27 20:16:14 +01:00
2024-04-03 18:44:52 +02:00
uint8_t key = MAP_NORM_TRANS; // default value
bool localTransmitters =
2024-02-16 15:46:54 +01:00
configHandler_p -> localTransmitterSelector_active ();
if ((!localTransmitters) && (theTr. distance > maxDistance)) {
maxDistance = theTr. distance;
2024-04-03 18:44:52 +02:00
key = MAP_MAX_TRANS;
}
2024-01-27 20:16:14 +01:00
//
2024-04-03 18:44:52 +02:00
QDateTime theTime =
2024-02-16 15:46:54 +01:00
configHandler_p -> utcSelector_active () ?
2024-04-03 18:44:52 +02:00
QDateTime::currentDateTimeUtc () :
QDateTime::currentDateTime ();
if (listChanged)
2024-06-15 13:12:16 +02:00
mapHandler -> putData (key,
thePosition,
theTr. theTransmitter. transmitterName,
channel. channelName,
theTime. toString (Qt::TextDate),
theTr. tiiValue,
channel. snr,
theTr. distance,
theTr. corner, power, height);
2024-04-03 18:44:52 +02:00
}
2024-01-27 20:16:14 +01:00
}
void RadioInterface::showIQ (int amount) {
std::vector<Complex> Values (amount);
2024-06-01 11:12:04 +02:00
theIQBuffer. getDataFromBuffer (Values. data (), amount);
theIQBuffer. FlushRingBuffer ();
if (!theNewDisplay. isHidden ())
theNewDisplay. showIQ (Values);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::show_Corrector (int h, float l) {
2024-06-01 11:12:04 +02:00
if (!theNewDisplay. isHidden ())
theNewDisplay. show_corrector (h, l);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::show_stdDev (int amount) {
std::vector<float>Values (amount);
stdDevBuffer. getDataFromBuffer (Values. data (), amount);
2024-06-01 11:12:04 +02:00
if (!theNewDisplay. isHidden ())
theNewDisplay. show_stdDev (Values);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::show_snr (float snr) {
QPixmap p;
2024-06-01 11:12:04 +02:00
if (!theNewDisplay. isHidden ())
theNewDisplay. show_snr (snr);
2024-01-27 20:16:14 +01:00
channel. snr = snr;
if (snr < 5)
p = strengthLabels. at (0);
else
if (snr < 8)
p = strengthLabels. at (1);
else
if (snr < 12)
p = strengthLabels. at (2);
else
p = strengthLabels. at (3);
this -> snrLabel -> setAlignment(Qt::AlignRight);
this -> snrLabel -> setPixmap (p. scaled (30, 30, Qt::KeepAspectRatio));
2024-06-01 11:12:04 +02:00
if (theSNRViewer. isHidden ()) {
theSNRBuffer. FlushRingBuffer ();
2024-01-27 20:16:14 +01:00
return;
}
2024-06-01 11:12:04 +02:00
int amount = theSNRBuffer. GetRingBufferReadAvailable ();
2024-01-27 20:16:14 +01:00
if (amount <= 0)
return;
2024-03-13 19:45:53 +01:00
float *ss = (float *) alloca (amount * sizeof (float));
2024-06-01 11:12:04 +02:00
theSNRBuffer. getDataFromBuffer (ss, amount);
2024-01-27 20:16:14 +01:00
for (int i = 0; i < amount; i ++) {
2024-06-01 11:12:04 +02:00
theSNRViewer. add_snr (ss [i]);
2024-01-27 20:16:14 +01:00
}
2024-06-01 11:12:04 +02:00
theSNRViewer. show_snr ();
2024-01-27 20:16:14 +01:00
}
void RadioInterface::show_quality (float q,
float sco, float freqOffset) {
2024-06-01 11:12:04 +02:00
if (!running. load () || theNewDisplay. isHidden ())
2024-01-27 20:16:14 +01:00
return;
2024-06-01 11:12:04 +02:00
theNewDisplay. show_quality (q, sco, freqOffset);
2024-01-27 20:16:14 +01:00
}
//
// called from the MP4 decoder
void RadioInterface::show_rsCorrections (int c, int ec) {
if (!running)
return;
if (!techWindow_p -> isHidden ())
techWindow_p -> show_rsCorrections (c, ec);
}
//
2024-04-19 18:34:50 +02:00
// called from the ofdm handler
2024-01-27 20:16:14 +01:00
void RadioInterface::show_clock_error (int d) {
if (!running. load ())
return;
2024-06-01 11:12:04 +02:00
if (!theNewDisplay. isHidden ()) {
theNewDisplay. show_clock_err (d);
2024-01-27 20:16:14 +01:00
}
}
void RadioInterface::show_channel (int n) {
std::vector<Complex> v (n);
2024-06-01 11:12:04 +02:00
theChannelBuffer. getDataFromBuffer (v. data (), n);
theChannelBuffer. FlushRingBuffer ();
if (!theNewDisplay. isHidden () &&
(theNewDisplay. get_tab () == SHOW_CHANNEL))
theNewDisplay. show_channel (v);
2024-01-27 20:16:14 +01:00
}
bool RadioInterface::channelOn () {
2024-06-01 11:12:04 +02:00
return (!theNewDisplay. isHidden () &&
(theNewDisplay. get_tab () == SHOW_CHANNEL));
2024-01-27 20:16:14 +01:00
}
bool RadioInterface::devScopeOn () {
2024-06-01 11:12:04 +02:00
return !theNewDisplay. isHidden () &&
(theNewDisplay. get_tab () == SHOW_STDDEV);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::handle_iqSelector () {
2024-06-01 11:12:04 +02:00
if (theOFDMHandler != nullptr)
theOFDMHandler -> handle_iqSelector ();
2024-01-27 20:16:14 +01:00
}
void RadioInterface::showPeakLevel (float iPeakLeft, float iPeakRight) {
techWindow_p -> showPeakLevel (iPeakLeft, iPeakRight);
}
void RadioInterface::handle_presetButton () {
int mode = the_ensembleHandler -> get_showMode ();
if (inputDevice_p -> isFileInput ()) {
mode = SHOW_ENSEMBLE;
presetButton -> setText ("favorites");
the_ensembleHandler -> set_showMode (mode);
return;
}
2024-03-13 19:45:53 +01:00
mode = mode == SHOW_ENSEMBLE ? SHOW_PRESETS : SHOW_ENSEMBLE;
2024-01-27 20:16:14 +01:00
the_ensembleHandler -> set_showMode (mode);
2024-04-19 18:34:50 +02:00
presetButton -> setText (mode == SHOW_ENSEMBLE ? "favorites" : "ensemble");
2024-01-27 20:16:14 +01:00
}
void RadioInterface::set_soundLabel (bool f) {
QPixmap p;
if (f)
p. load (":res/volume_on.png", "png");
else
p. load (":res/volume_off.png", "png");
soundLabel -> setAlignment(Qt::AlignRight);
soundLabel ->
setPixmap (p. scaled (30, 30, Qt::KeepAspectRatio));
}
void RadioInterface::handle_aboutLabel () {
if (the_aboutLabel == nullptr) {
the_aboutLabel = new AboutDialog (nullptr);
the_aboutLabel -> show ();
return;
}
delete the_aboutLabel;
the_aboutLabel = nullptr;
}
//
// Starting a background task is by clicking with the right mouse button
// on the servicename, swrvice is known to be in current ensemble
void RadioInterface::start_background_task (const QString &service) {
audiodata ad;
2024-06-01 11:12:04 +02:00
theOFDMHandler -> data_for_audioservice (service, ad);
2024-01-27 20:16:14 +01:00
if ((!ad. defined) || (ad. ASCTy != 077))
return;
for (uint16_t i = 0;
i < channel. backgroundServices. size (); i ++) {
if (channel. backgroundServices. at (i). serviceName ==
service) {
2024-06-01 11:12:04 +02:00
theOFDMHandler -> stop_service (ad. subchId, BACK_GROUND);
2024-01-27 20:16:14 +01:00
if (channel. backgroundServices. at (i). fd != nullptr)
fclose (channel. backgroundServices. at (i). fd);
channel. backgroundServices. erase
(channel. backgroundServices. begin () + i);
return;
}
}
2024-06-01 11:12:04 +02:00
FILE *f = theFilenameFinder. findFrameDump_fileName (service, true);
2024-01-27 20:16:14 +01:00
if (f == nullptr)
return;
fprintf (stderr, "starting a background job %s\n",
ad. serviceName. toLatin1 (). data ());
2024-06-01 11:12:04 +02:00
(void)theOFDMHandler ->
set_audioChannel (ad, &theAudioBuffer, f, BACK_GROUND);
2024-01-27 20:16:14 +01:00
dabService s;
s. channel = ad. channel;
s. serviceName = ad. serviceName;
s. SId = ad. SId;
s. SCIds = ad. SCIds;
s. subChId = ad. subchId;
s. fd = f;
channel. backgroundServices. push_back (s);
}
2024-02-06 15:37:07 +01:00
void RadioInterface::handle_labelColor () {
QColor labelColor;
QColor color = QColorDialog::getColor (labelColor,
nullptr, "labelColor");
if (!color. isValid ())
return;
labelStyle = "color:" + color. name ();
2024-02-25 14:18:27 +01:00
dabSettings_p -> setValue (LABEL_COLOR, labelStyle);
2024-03-04 14:45:33 +01:00
QFont font = serviceLabel -> font ();
font. setPointSize (16);
font. setBold (true);
serviceLabel -> setStyleSheet (labelStyle);
serviceLabel -> setFont (font);
programTypeLabel -> setStyleSheet (labelStyle);
2024-02-13 10:22:47 +01:00
}
2024-02-25 14:18:27 +01:00
int RadioInterface::int_configValue (const QString &key, int d) {
int val;
val = dabSettings_p -> value (key, d). toInt ();
return val;
}
void RadioInterface::show_dcOffset (float dcOffset) {
2024-06-01 11:12:04 +02:00
theNewDisplay. show_dcOffset (dcOffset);
2024-02-25 14:18:27 +01:00
}
void RadioInterface::handle_techFrame_closed () {
dabSettings_p -> setValue (TECHDATA_VISIBLE, 0);
}
void RadioInterface::handle_configFrame_closed () {
dabSettings_p -> setValue (CONFIG_WIDGET_VISIBLE, 0);
}
void RadioInterface::handle_deviceFrame_closed () {
dabSettings_p -> setValue (DEVICE_WIDGET_VISIBLE, 0);
}
void RadioInterface::handle_newDisplayFrame_closed () {
dabSettings_p -> setValue (NEW_DISPLAY_VISIBLE, 0);
}
void RadioInterface::setVolume (int n) {
if (n == 0)
set_soundLabel (false);
else
if (channel. audioActive)
set_soundLabel (true);
((Qt_Audio *)soundOut_p) -> setVolume (n);
}
void RadioInterface::handle_snrLabel () {
if (running. load()) {
dynamicLabel -> setStyleSheet (labelStyle);
QString SNR = "SNR " + QString::number (channel. snr);
dynamicLabel -> setText (SNR);
}
}
2024-04-03 18:44:52 +02:00
void RadioInterface::handle_correlationSelector (int d) {
(void)d;
bool b = configHandler_p -> get_correlationSelector ();
2024-04-15 14:03:12 +02:00
dabSettings_p -> setValue (S_CORRELATION_ORDER, b ? 1 : 0);
2024-06-01 11:12:04 +02:00
if (theOFDMHandler != nullptr)
theOFDMHandler -> set_correlationOrder (b);
2024-04-03 18:44:52 +02:00
}
void RadioInterface::handle_dxSelector (int d) {
(void)d;
bool b = configHandler_p -> get_dxSelector ();
2024-04-15 14:03:12 +02:00
dabSettings_p -> setValue (S_DX_MODE, b ? 1 : 0);
2024-04-04 15:13:56 +02:00
if (!b)
2024-06-01 11:12:04 +02:00
theDXDisplay. hide ();
if (theOFDMHandler != nullptr)
theOFDMHandler -> set_dxMode (b);
2024-04-03 18:44:52 +02:00
if (b)
distanceLabel -> setText ("");
}
2024-04-16 15:18:29 +02:00
void RadioInterface::channelSignal (const QString &channel) {
stopChannel ();
startChannel (channel);
}
2024-09-14 14:57:15 +02:00
void RadioInterface::show_changeLabel (const QStringList notInOld,
const QStringList notInNew) {
fprintf (stderr, "A change in configuration occurred\n");
if (notInOld. size () > 0) {
fprintf (stderr, "New service:\n");
for (auto s: notInOld)
fprintf (stderr, "\t%s\n", s. toUtf8 (). data ());
}
if (notInNew. size () > 0) {
fprintf (stderr, "removed service:\n");
for (auto s: notInNew)
fprintf (stderr, "\t%s\n", s. toUtf8 (). data ());
}
}