1
0
mirror of https://github.com/JvanKatwijk/qt-dab.git synced 2025-10-06 16:22:41 +02:00
Files
SDR-DAB_Qt-DAB/sources/main/radio.cpp

4834 lines
152 KiB
C++
Raw Normal View History

2024-01-27 20:16:14 +01:00
#
/*
2025-03-05 16:34:15 +01:00
* Copyright (C) 2015 .. 2025
2024-01-27 20:16:14 +01:00
* 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>
#include <QToolTip>
2025-09-12 18:33:52 +02:00
#include <QKeyEvent>
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"
#include "db-element.h"
2024-02-25 14:18:27 +01:00
#include "distances.h"
2024-03-04 14:45:33 +01:00
#include "position-handler.h"
#include "settings-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
2025-07-27 11:35:19 +02:00
#include "dab-tables.h"
2024-01-27 20:16:14 +01:00
#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
#include <QScreen>
2025-02-12 14:08:44 +01:00
#include <QDomElement>
2025-08-06 14:14:21 +02:00
#include "basic-print.h"
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);
}
2025-07-14 17:25:42 +02:00
bool getCpuTimes (size_t &idle_time, size_t &total_time) {
2024-01-27 20:16:14 +01:00
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
2025-07-14 17:25:42 +02:00
std::vector<size_t> getCpuTimes() {
2024-01-27 20:16:14 +01:00
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;
}
2025-07-14 17:25:42 +02:00
bool getCpuTimes (size_t &idle_time, size_t &total_time) {
const std::vector <size_t> cpu_times = getCpuTimes();
2024-01-27 20:16:14 +01:00
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-11-10 12:45:48 +01:00
#define WHITE "#ffffff"
#define BLACK "#000000"
#define GREEN "#8ff0a4"
#define BLUE "#00ffff"
#define RED "#ff007f"
#define YELLOW "#f9f06b"
2024-04-03 18:44:52 +02:00
static inline
2025-07-14 17:25:42 +02:00
QString idsToString (int mainId, int subId) {
return "(" + QString::number (mainId) + "-"
2024-10-17 15:44:28 +02:00
+ QString::number (subId) + ")";
2024-04-03 18:44:52 +02:00
}
2024-03-13 19:45:53 +01:00
static inline
QStringList splitter (const QString &s) {
2025-03-06 13:20:13 +01:00
#if QT_VERSION > QT_VERSION_CHECK (5, 15, 2)
2024-03-13 19:45:53 +01:00
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,
2025-07-17 20:49:55 +02:00
const QString &tiiFile,
2024-01-27 20:16:14 +01:00
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),
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),
2025-08-31 20:55:36 +02:00
theErrorLogger (Si),
theDeviceChoser (&theErrorLogger, Si),
2024-06-01 11:12:04 +02:00
theDXDisplay (this, Si),
2024-10-14 15:35:13 +02:00
theLogger (Si),
2025-03-05 16:34:15 +01:00
theSCANHandler (this, Si,
freqExtension),
2025-07-17 20:49:55 +02:00
theTIIProcessor (tiiFile),
2025-09-01 19:04:36 +02:00
myTimeTable (this, Si),
epgVertaler (&theErrorLogger) {
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 -> the_aboutLabel = nullptr;
running. store (false);
2025-07-20 19:25:14 +02:00
stereoSetting = false;
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 =
value_i (dabSettings_p, DAB_GENERAL, "dabMode", 1);
2024-01-27 20:16:14 +01:00
globals. threshold =
value_i (dabSettings_p, DAB_GENERAL, "threshold", 3);
2024-01-27 20:16:14 +01:00
globals. diff_length =
value_i (dabSettings_p, DAB_GENERAL, "diff_length", DIFF_LENGTH);
2024-01-27 20:16:14 +01:00
globals. tii_delay =
2024-12-11 19:06:03 +01:00
value_i (dabSettings_p, DAB_GENERAL, "tii_delay", 3);
2024-01-27 20:16:14 +01:00
if (globals. tii_delay < 2)
globals. tii_delay = 2;
globals. tii_depth =
value_i (dabSettings_p, DAB_GENERAL, "tii_depth", 4);
2024-01-27 20:16:14 +01:00
globals. echo_depth =
value_i (dabSettings_p, DAB_GENERAL, "echo_depth", 1);
2024-01-27 20:16:14 +01:00
#ifdef _SEND_DATAGRAM_
ipAddress = value_s (dabSettings_p, "DATAGRAM",
"ipAddress", "127.0.0.1");
port = value_i (dabSettings_p, "DATAGRAM",
"port" 8888);
2024-01-27 20:16:14 +01:00
#endif
// set on top or not? checked at start up
if (value_i (dabSettings_p, DAB_GENERAL, "onTop", 0) == 1)
2024-01-27 20:16:14 +01:00
setWindowFlags (windowFlags () | Qt::WindowStaysOnTopHint);
2025-03-05 16:34:15 +01:00
//
// signal strength icons
2024-01-27 20:16:14 +01:00
for (int i = 0; i < 4; i ++) {
QPixmap p;
QString labelName =
QString (":res/radio-pictures/signal%1.png"). arg (i, 1, 10, QChar ('0'));
2024-01-27 20:16:14 +01:00
p. load (labelName, "png");
strengthLabels. push_back (p);
}
2025-03-20 18:23:52 +01:00
2024-01-27 20:16:14 +01:00
// The settings are done, now creation of the GUI parts
setupUi (this);
2025-03-05 16:34:15 +01:00
// and init the up and down button, the select for details button ans
// the button to show the directory with files
2024-01-27 20:16:14 +01:00
{ QPixmap p;
if (p. load (":res/radio-pictures/up-arrow.png", "png"))
2025-03-05 16:34:15 +01:00
prevChannelButton -> setPixmap (p. scaled (30, 30,
Qt::KeepAspectRatio));
if (p. load (":res/radio-pictures/down-arrow.png", "png"))
2025-03-05 16:34:15 +01:00
nextChannelButton -> setPixmap (p. scaled (30, 30,
Qt::KeepAspectRatio));
if (p. load (":res/radio-pictures/details24.png", "png"))
2025-03-05 16:34:15 +01:00
serviceButton -> setPixmap (p. scaled (30, 30,
Qt::KeepAspectRatio));
2025-09-01 19:04:36 +02:00
else
theErrorLogger. add ("main", "Loading details button failed");
if (p. load (":res/radio-pictures/folder_button.png", "png"))
2024-10-14 15:35:13 +02:00
folder_shower -> setPixmap (p. scaled (30, 30, Qt::KeepAspectRatio));
2024-01-27 20:16:14 +01:00
}
//
2025-03-20 18:23:52 +01:00
connect (folder_shower, &clickablelabel::clicked,
this, &RadioInterface::handle_folderButton);
dxMode = value_i (dabSettings_p, CONFIG_HANDLER, S_DX_MODE, 0) != 0;
2025-05-03 20:00:55 +02:00
tiiButton -> setText (dxMode ? "tii local" : "dx display");
connect (tiiButton, &QPushButton::clicked,
2025-03-20 18:23:52 +01:00
this, &RadioInterface::handle_tiiButton);
2024-10-14 15:35:13 +02:00
2024-03-13 19:45:53 +01:00
// put the widgets in the right place and create the workers
2025-07-11 12:48:10 +02:00
setPositionAndSize (dabSettings_p, this, S_MAIN_WIDGET);
2024-11-22 20:21:44 +01:00
2025-05-27 18:50:45 +02:00
configHandler_p. reset (new configHandler (this, dabSettings_p));
2025-07-11 12:48:10 +02:00
theEnsembleHandler. reset (new ensembleHandler (this, dabSettings_p,
2025-05-27 18:50:45 +02:00
presetFile));
2024-02-16 15:46:54 +01:00
// we have the configuration handler and the ensemble handler,
// connect some signals directly
2025-07-25 21:02:40 +02:00
configHandler_p -> set_activeServices (0);
2024-02-16 15:46:54 +01:00
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 ());
2025-05-27 18:50:45 +02:00
connect (configHandler_p. data (), &configHandler::frameClosed,
this, &RadioInterface::handle_configFrame_closed);
2025-05-27 18:50:45 +02:00
connect (configHandler_p. data (), &configHandler::handle_fontSelect,
2025-07-11 12:48:10 +02:00
theEnsembleHandler. data (),
&ensembleHandler::handleFontSelect);
2025-05-27 18:50:45 +02:00
connect (configHandler_p. data (),
&configHandler::handle_fontSizeSelect,
2025-07-11 12:48:10 +02:00
theEnsembleHandler. data (),
&ensembleHandler::handleFontSizeSelect);
2025-05-27 18:50:45 +02:00
connect (configHandler_p. data (),
&configHandler::handle_fontColorSelect,
2025-07-11 12:48:10 +02:00
theEnsembleHandler. data (),
&ensembleHandler::handleFontColorSelect);
2025-05-27 18:50:45 +02:00
connect (configHandler_p. data (), &configHandler::set_serviceOrder,
2025-07-11 12:48:10 +02:00
theEnsembleHandler. data (),
&ensembleHandler::setServiceOrder);
2024-06-01 11:12:04 +02:00
connect (&theNewDisplay, &displayWidget::frameClosed,
this, &RadioInterface::handle_newDisplayFrame_closed);
2025-04-04 16:17:00 +02:00
2024-01-27 20:16:14 +01:00
#ifdef HAVE_RTLSDR_V3
2025-09-09 17:42:31 +02:00
SystemVersion = QString ("9.4") + " with RTLSDR-V3";
2024-01-27 20:16:14 +01:00
#elif HAVE_RTLSDR_V4
2025-09-09 17:42:31 +02:00
SystemVersion = QString ("9.4") + " with RTLSDR-V4";
2024-01-27 20:16:14 +01:00
#else
2025-09-09 17:42:31 +02:00
SystemVersion = QString ("9.4");
2024-01-27 20:16:14 +01:00
#endif
2024-11-20 16:33:31 +01:00
#if QT_VERSION > QT_VERSION_CHECK (6, 0, 0)
2025-04-04 16:17:00 +02:00
version = "Qt6-DAB-6." + SystemVersion ;
2024-11-20 16:33:31 +01:00
#else
version = "Qt5-DAB-6." + SystemVersion;
#endif
setWindowTitle (version);
2024-01-27 20:16:14 +01:00
2025-07-11 12:48:10 +02:00
ensembleWidget -> setWidget (theEnsembleHandler. data ());
connect (theEnsembleHandler. data (), &ensembleHandler::selectService,
this, &RadioInterface::localSelect);
2025-07-11 12:48:10 +02:00
connect (theEnsembleHandler. data (),
&ensembleHandler::start_background_task,
2025-03-19 12:32:08 +01:00
this, &RadioInterface::handle_backgroundTask);
2024-01-27 20:16:14 +01:00
2025-05-27 18:50:45 +02:00
techWindow_p. reset (new techData (this, dabSettings_p, &theTechData));
2025-05-27 18:50:45 +02:00
connect (techWindow_p. data (), &techData::frameClosed,
this, &RadioInterface::handle_techFrame_closed);
2024-02-25 14:18:27 +01:00
if (value_i (dabSettings_p, DAB_GENERAL, NEW_DISPLAY_VISIBLE, 0) != 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
2025-07-21 15:03:49 +02:00
peakLeftDamped = 0;
peakRightDamped = 0;
audioTeller = 0; // counting audio frames
pauzeSlideTeller = 0; // counting pause slides
labelStyle = value_s (dabSettings_p, DAB_GENERAL, LABEL_COLOR,
LABEL_STYLE);
2024-03-04 14:45:33 +01:00
QFont font = serviceLabel -> font ();
font. setPointSize (16);
font. setBold (true);
serviceLabel -> setStyleSheet (labelStyle);
serviceLabel -> setFont (font);
2025-03-02 20:15:42 +01:00
serviceLabel -> setToolTip ("<font color=\"black\">the label displays the selected service. If a logo can be found, it will be displayed, otherwise the shortname is displayed");
2024-11-20 16:33:31 +01:00
motLabel -> setStyleSheet ("QLabel {color : red}");
motLabel -> setToolTip ("<font color=\"black\">the label colors green when MOT data, for the currently selected service, can be decoded");
2024-03-04 14:45:33 +01:00
programTypeLabel -> setStyleSheet (labelStyle);
2024-03-13 19:45:53 +01:00
font = ensembleId -> font ();
2024-10-17 15:44:28 +02:00
font. setPointSize (14);
ensembleId -> setFont (font);
channel. cleanChannel ();
2024-02-16 15:46:54 +01:00
localPos. latitude =
value_f (dabSettings_p, MAP_HANDLING, HOME_LATITUDE, 0.0);
2024-02-16 15:46:54 +01:00
localPos. longitude =
value_f (dabSettings_p, MAP_HANDLING, HOME_LONGITUDE, 0.0);
2024-01-27 20:16:14 +01:00
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
2024-10-09 17:57:23 +02:00
volumeSlider -> hide ();
2024-01-27 20:16:14 +01:00
// Where do we leave the audio out?
2024-02-16 15:46:54 +01:00
configHandler_p -> show_streamSelector (false);
int latency = value_i (dabSettings_p, SOUND_HANDLING, "latency", 5);
2024-04-03 18:44:52 +02:00
soundOut_p = nullptr;
2024-10-09 17:57:23 +02:00
//
// If we do not have a TCP streamer, we go for one of the
// Portaudio and the Qt_audio alternatives.
// Default - and if Qt_Audio fails, we go for Portaudio
#ifndef TCP_STREAMER
2024-03-13 19:45:53 +01:00
QStringList streams;
QString temp;
QString s = value_s (dabSettings_p, SOUND_HANDLING, SOUND_HANDLER,
S_PORT_AUDIO);
2024-10-09 17:57:23 +02:00
if (s != S_PORT_AUDIO) { // try Qt_Audio
try {
2024-11-22 20:21:44 +01:00
soundOut_p = new Qt_Audio (this, dabSettings_p);
streams = ((Qt_Audio *)soundOut_p) -> streams ();
temp =
value_s (dabSettings_p, SOUND_HANDLING,
2024-11-22 20:21:44 +01:00
AUDIO_STREAM_NAME, "default");
volumeSlider -> show ();
2025-05-08 12:55:36 +02:00
audioVolume =
value_i (dabSettings_p, SOUND_HANDLING, QT_AUDIO_VOLUME, 50);
2025-05-08 12:55:36 +02:00
volumeSlider -> setValue (audioVolume);
((Qt_Audio *)soundOut_p) -> setVolume (audioVolume);
connect (volumeSlider, &QSlider::valueChanged,
this, &RadioInterface::setVolume);
} catch (...) {
soundOut_p = nullptr;
}
}
2024-10-09 17:57:23 +02:00
//
// we end up here if selection was PORT_AUDIO or using Qt_Audio failed
// as it does on U20
if (soundOut_p == nullptr) {
2024-11-20 16:33:31 +01:00
soundOut_p = new audioSink (latency);
2024-03-13 19:45:53 +01:00
streams = ((audioSink *)soundOut_p) -> streams ();
temp =
value_s (dabSettings_p, SOUND_HANDLING,
AUDIO_STREAM_NAME, "default");
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);
2024-11-20 16:33:31 +01:00
if (k >= 0) {
QString str = configHandler_p -> currentStream ();
soundOut_p -> selectDevice (k, str);
}
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-11-22 20:21:44 +01:00
if (!soundOut_p -> hasMissed ())
techWindow_p -> hideMissed ();
2024-10-09 17:57:23 +02:00
#else
soundOut_p = new tcpStreamer (20040);
techWindow_p -> hide ();
2024-01-27 20:16:14 +01:00
#endif
2024-10-09 17:57:23 +02:00
//
2025-01-31 15:06:31 +01:00
// some MOT, text and other data is stored in the Qt-DAB-files directory
QString tempPath = theFilenameFinder. basicPath ();
path_for_files =
value_s (dabSettings_p, DAB_GENERAL,
S_FILE_PATH, tempPath);
if (path_for_files != "")
path_for_files = checkDir (path_for_files);
2024-10-09 17:57:23 +02:00
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);
2025-09-12 18:33:52 +02:00
stressTimer. setSingleShot (true);
connect (&stressTimer, &QTimer::timeout,
this, &RadioInterface::handle_nextServiceButton);
2025-07-11 12:48:10 +02:00
myTimeTable. hide ();
2024-01-27 20:16:14 +01:00
2025-07-11 12:48:10 +02:00
connect (&theScanlistHandler, &scanListHandler::handleScanListSelect,
this, &RadioInterface::handleScanListSelect);
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
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);
2025-05-03 20:00:55 +02:00
connect (tiiButton, &smallPushButton::rightClicked,
this, &RadioInterface::color_tiiButton);
2024-04-14 12:47:14 +02:00
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
//
//
2025-07-11 12:48:10 +02:00
connect (techWindow_p. data (), &techData::handleTimeTable,
2024-04-14 12:47:14 +02:00
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
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
2025-01-13 19:13:10 +01:00
if (theTIIProcessor. has_tiiFile ())
configHandler_p -> enable_loadLib ();
2025-01-13 19:13:10 +01:00
else
httpButton -> setEnabled (false);
2024-01-27 20:16:14 +01:00
channel. etiActive = false;
2025-02-23 11:54:05 +01:00
QPixmap epgP;
epgP. load (":res/epgLabel.png", "png");
epgLabel -> setPixmap (epgP. scaled (30, 30,
2025-02-23 11:54:05 +01:00
Qt::KeepAspectRatio));
2025-07-25 21:02:40 +02:00
epgLabel -> setToolTip ("this icon is visible when the EPG processor is active, it will always run in the background");
2025-02-23 11:54:05 +01:00
epgLabel -> hide ();
2024-01-27 20:16:14 +01:00
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
h =
value_s (dabSettings_p, DAB_GENERAL,
SELECTED_DEVICE, "no device");
2024-02-16 15:46:54 +01:00
bool b = configHandler_p -> findDevice (h);
if (b) {
2025-05-29 12:51:05 +02:00
inputDevice_p. reset (createDevice (h, &theLogger));
2024-01-27 20:16:14 +01:00
}
//
2024-11-20 16:33:31 +01:00
peakLeftDamped = -100;
peakRightDamped = -100;
2024-11-20 16:33:31 +01:00
leftAudio -> setFillBrush (QColor ("white"));
rightAudio -> setFillBrush (QColor ("white"));
2024-12-11 19:06:03 +01:00
leftAudio -> setBorderWidth (0);
rightAudio -> setBorderWidth (0);
leftAudio -> setValue (-30);
rightAudio -> setValue (-30);
leftAudio -> setAlarmBrush (Qt::red);
rightAudio -> setAlarmBrush (Qt::red);
leftAudio -> setAlarmEnabled (true);
rightAudio -> setAlarmEnabled(true);
2024-11-20 16:33:31 +01:00
2025-09-08 13:38:08 +02:00
journalineKey = -1;
2024-01-27 20:16:14 +01:00
// do we show controls?
2024-02-25 14:18:27 +01:00
bool visible =
value_i (dabSettings_p, DAB_GENERAL,
CONFIG_WIDGET_VISIBLE, 0) != 0;
2024-02-25 14:18:27 +01:00
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
if (value_i (dabSettings_p, DAB_GENERAL, SNR_WIDGET_VISIBLE, 0) != 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 ();
if (value_i (dabSettings_p, DAB_GENERAL, TECHDATA_VISIBLE, 0) != 0)
2024-01-27 20:16:14 +01:00
techWindow_p -> show ();
2024-01-29 15:47:49 +01:00
dynamicLabel -> setTextInteractionFlags(Qt::TextSelectableByMouse);
2025-03-02 20:15:42 +01:00
dynamicLabel -> setToolTip ("<font color=\"black\">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 = "";
2024-01-27 20:16:14 +01:00
// if a device was selected, we just start, otherwise
// we wait until one is selected
2025-07-25 16:18:31 +02:00
// nrServicesLabel -> display (QString::number (0));
2024-02-25 14:18:27 +01:00
connectGUI ();
2024-11-10 12:45:48 +01:00
//
this -> cpuSupport = 0;
#ifdef __ARCH_X86__
__builtin_cpu_init ();
int has_avg2 =
__builtin_cpu_supports ("avx2") != 0 ? AVX_SUPPORT : 0;
int has_sse4
= __builtin_cpu_supports ("sse4.1") != 0 ? SSE_SUPPORT : 0;
cpuSupport = has_avg2 + has_sse4;
#endif
2024-11-10 12:45:48 +01:00
// Just check whether the ini file is used before
bool iniExists =
value_i (dabSettings_p, DAB_GENERAL, "EXISTS", 0) != 0;
if (!iniExists) {
store (dabSettings_p, DAB_GENERAL, "EXISTS", 1);
QMessageBox::warning (this, tr ("Warning"),
tr ("The ini file is new and no home location is known yet"));
}
2025-03-20 18:23:52 +01:00
2025-05-29 12:51:05 +02:00
if (!inputDevice_p .isNull ()) {
2025-01-05 13:11:25 +01:00
startDirect ();
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
store (dabSettings_p, DAB_GENERAL, CONFIG_WIDGET_VISIBLE, 1);
store (dabSettings_p, DAB_GENERAL, 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);
}
//
// 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) {
2025-05-29 12:51:05 +02:00
inputDevice_p. reset (createDevice (dev, &theLogger));
2024-01-27 20:16:14 +01:00
// Some buttons should not be touched before we have a device
2025-05-29 12:51:05 +02:00
if (inputDevice_p. isNull ()) {
2024-01-27 20:16:14 +01:00
return;
}
2025-01-05 13:11:25 +01:00
startDirect ();
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
2025-01-05 13:11:25 +01:00
void RadioInterface::startDirect () {
2024-04-15 14:03:12 +02:00
disconnect (channelSelector,
#if QT_VERSION >= QT_VERSION_CHECK (5, 15, 2)
2024-10-07 19:35:30 +02:00
qOverload<const QString &> (&QComboBox::textActivated),
#else
2024-04-15 14:03:12 +02:00
qOverload<const QString &> (&QComboBox::activated),
2024-10-07 19:35:30 +02:00
#endif
2024-04-14 12:47:14 +02:00
this, &RadioInterface::handle_channelSelector);
QString startingChannel =
value_s (dabSettings_p, DAB_GENERAL, CHANNEL_NAME, "5A");
int k = channelSelector -> findText (startingChannel);
if (k != -1)
channelSelector -> setCurrentIndex (k);
#ifdef __ARCH_X86__
if (cpuSupport & AVX_SUPPORT)
cpuLabel -> setText ("avx2");
else
if (cpuSupport & SSE_SUPPORT)
cpuLabel -> setText ("sse4.1");
else
cpuLabel -> setText ("scalar");
#else
cpuLabel -> setText ("");
#endif
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_RADIO_STARTS, inputDevice_p -> deviceName (),
channelSelector -> currentText ());
2025-05-29 12:51:05 +02:00
theOFDMHandler. reset (new ofdmHandler (this,
inputDevice_p. data (),
&globals, dabSettings_p,
2025-05-29 12:51:05 +02:00
&theLogger, this -> cpuSupport));
if (theOFDMHandler. isNull ()) {
QMessageBox::warning (this, tr ("Warning"),
tr ("Fatal error, call expert 11"));
abort ();
}
2025-09-06 19:12:13 +02:00
theOFDMHandler -> set_dcRemoval (configHandler_p -> get_dcRemoval ());
theNewDisplay. set_dcRemoval (configHandler_p -> get_dcRemoval ());
2024-01-27 20:16:14 +01:00
channel. cleanChannel ();
2025-05-29 12:51:05 +02:00
//
2025-07-11 12:48:10 +02:00
// Note: this is NOT "theEnsembleHandler. reset ()" !!!!
theEnsembleHandler -> reset ();
theEnsembleHandler -> setMode (!inputDevice_p -> isFileInput ());
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,
2024-10-07 19:35:30 +02:00
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 2)
qOverload<const QString &> (&QComboBox::textActivated),
#else
2024-04-15 14:03:12 +02:00
qOverload<const QString &> (&QComboBox::activated),
2024-10-07 19:35:30 +02:00
#endif
2024-04-14 12:47:14 +02:00
this, &RadioInterface::handle_channelSelector);
2024-02-25 14:18:27 +01:00
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
2024-12-21 13:46:43 +01:00
int auto_http = value_i (dabSettings_p, CONFIG_HANDLER,
2025-04-24 13:36:09 +02:00
AUTO_HTTP, 0);
2024-04-19 18:34:50 +02:00
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
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
}
///////////////////////////////////////////////////////////////////////////
//
2025-08-22 19:38:35 +02:00
static
bool seems_epg (const QString &name) {
return name. contains ("-EPG ", Qt::CaseInsensitive) ||
name. contains (" EPG ", Qt::CaseInsensitive) ||
name. contains ("Spored", Qt::CaseInsensitive) ||
name. contains ("NivaaEPG", Qt::CaseInsensitive) ||
name. contains ("SPI", Qt::CaseSensitive) ||
name. contains ("BBC Guide", Qt::CaseInsensitive) ||
name. contains ("BBC Guide", Qt::CaseInsensitive) ||
name. contains ("EPG_", Qt::CaseInsensitive) ||
name. contains ("EPG-", Qt::CaseInsensitive) ||
name. startsWith ("EPG ", Qt::CaseInsensitive);
}
//
2024-01-27 20:16:14 +01:00
// a slot, called by the fic/fib handlers
2025-07-14 17:25:42 +02:00
void RadioInterface::addToEnsemble (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;
2025-07-11 12:48:10 +02:00
if (theEnsembleHandler -> alreadyIn (ed))
2024-12-27 12:39:00 +01:00
return;
2025-08-22 19:38:35 +02:00
if (((SId & 0xFFFF0000) != 0) &&
(configHandler_p -> get_audioServices_only ())) {
if (!seems_epg (serviceName))
return;
}
2025-07-11 12:48:10 +02:00
bool added = theEnsembleHandler -> addToEnsemble (ed);
2024-01-27 20:16:14 +01:00
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 ()) {
2024-11-25 14:55:59 +01:00
if ((SId & 0XF0000) == 0) // only audio
2024-11-24 13:08:32 +01:00
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-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 ++) {
2025-07-20 19:25:14 +02:00
const uint8_t t = (v & 0xF000) >> 12;
2024-01-27 20:16:14 +01:00
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
2025-07-14 17:25:42 +02:00
void RadioInterface::ensembleName (int id, const QString &v) {
2024-01-27 20:16:14 +01:00
QString s;
if (!running. load())
return;
ensembleId -> setText (v + QString ("(") + hextoString (id) + QString (")"));
2025-07-14 17:25:42 +02:00
// transmitter_country -> setText (channel. countryName);
2024-01-27 20:16:14 +01:00
channel. ensembleName = v;
channel. Eid = id;
2025-05-03 11:10:32 +02:00
dynamicLabel -> setText ("");
2024-01-27 20:16:14 +01:00
//
// id we are scanning "to data", we reached the end
2024-11-14 16:16:03 +01:00
if (theSCANHandler. scan_to_data ()) {
2024-01-27 20:16:14 +01:00
stopScanning ();
2024-11-14 16:16:03 +01:00
}
2024-01-27 20:16:14 +01:00
else
2025-04-24 13:36:09 +02:00
if (theSCANHandler. active ()) {
if (theSCANHandler. scan_single () ||
theSCANHandler. scan_continuous ()) {
2025-04-26 15:05:14 +02:00
theSCANHandler.
addEnsemble (channelSelector -> currentText (), v);
2025-04-24 13:36:09 +02:00
channelTimer. stop ();
int switchStay =
configHandler_p -> switchStayValue ();
if (theSCANHandler. dumpInFile ()) {
2025-05-16 19:16:32 +02:00
inputDevice_p -> startDump ();
}
2025-04-24 13:36:09 +02:00
channelTimer. start (switchStay);
}
}
2025-02-15 17:53:47 +01:00
else
if (!theSCANHandler. active ()) {
2025-02-25 20:32:17 +01:00
read_pictureMappings (id);
2024-01-27 20:16:14 +01:00
// ... and is we are not scanning, clicking the ensembleName
// has effect
2024-04-14 12:47:14 +02:00
connect (ensembleId, &clickablelabel::clicked,
this, &RadioInterface::handle_contentButton);
2025-02-15 17:53:47 +01:00
}
2024-01-27 20:16:14 +01:00
}
//
///////////////////////////////////////////////////////////////////////////
void RadioInterface::handle_contentButton () {
2025-08-06 14:14:21 +02:00
basicPrint thePrinter;
QStringList s = thePrinter. print (theOFDMHandler -> contentPrint ());
2024-01-27 20:16:14 +01:00
if (contentTable_p != nullptr) {
contentTable_p -> hide ();
delete contentTable_p;
contentTable_p = nullptr;
return;
}
2025-05-01 20:23:57 +02:00
QString headLine = build_kop ();
2024-01-27 20:16:14 +01:00
contentTable_p = new contentTable (this, dabSettings_p,
channel. channelName,
2025-08-06 14:14:21 +02:00
thePrinter. 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);
2025-05-01 20:23:57 +02:00
for (auto &tr : channel. transmitters) {
QString transmitterLine = build_transmitterLine (tr);
2025-05-01 20:23:57 +02:00
contentTable_p -> addLine (transmitterLine);
2025-05-16 11:18:43 +02:00
}
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;
2025-02-14 19:33:17 +01:00
2024-01-27 20:16:14 +01:00
switch (getContentBaseType ((MOTContentType)contentType)) {
case MOTBaseTypeGeneralData:
break;
case MOTBaseTypeText:
2025-01-05 13:11:25 +01:00
saveMOTtext (result, contentType, objectName);
2024-01-27 20:16:14 +01:00
break;
2025-02-15 17:53:47 +01:00
case MOTBaseTypeImage:
2025-01-05 13:11:25 +01:00
showMOTlabel (result, contentType,
2024-01-27 20:16:14 +01:00
objectName, dirElement, backgroundFlag);
break;
case MOTBaseTypeAudio:
break;
case MOTBaseTypeVideo:
break;
case MOTBaseTypeTransport:
2025-01-05 13:11:25 +01:00
saveMOTObject (result, objectName);
2024-01-27 20:16:14 +01:00
break;
case MOTBaseTypeSystem:
break;
2025-03-05 16:34:15 +01:00
case MOTBaseTypeApplication: { // epg data
if ((path_for_files == "") || (theSCANHandler. active ()))
2024-01-27 20:16:14 +01:00
return;
if (objectName == QString (""))
objectName = "epg file";
2025-03-05 16:34:15 +01:00
std::vector<uint8_t> epgData (result. begin(), result. end());
QDomDocument epgDocument;
uint8_t docType = epgVertaler. process_epg (epgDocument,
2025-03-19 12:32:08 +01:00
epgData, channel.lto);
2025-03-05 16:34:15 +01:00
if (docType == noType) // should not happen
break;
2025-03-05 16:34:15 +01:00
if (docType == serviceInformationType) {
extractServiceInformation (epgDocument, channel. Eid, true);
return;
}
2025-03-05 16:34:15 +01:00
QString theName = extractName (objectName);
if (theName == "")
return;
QString temp = path_for_files +
2025-03-06 13:20:13 +01:00
QString::number (channel. Eid, 16). toUpper () + "/";
2025-03-05 16:34:15 +01:00
if (!QDir (temp). exists ())
QDir (). mkpath (temp);
theName = temp + theName;
QFile file (QDir::toNativeSeparators (theName));
if (file. open (QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream (&file);
stream << epgDocument. toString ();
file. close ();
2024-01-27 20:16:14 +01:00
}
2025-03-05 16:34:15 +01:00
}
return;
2024-01-27 20:16:14 +01:00
case MOTBaseTypeProprietary:
break;
}
}
//
// In the MOT name, we look for a sequence of 8 digits with
// some constraints, and then for a sequence of 4 characters
// that match an Sid in this ensemble
QString RadioInterface::extractName (const QString &motName) {
QString dateString;
QString sidString;
int eos = 0;
bool ok = false;
QString env;
QString realName;
int base = motName. lastIndexOf (QChar ('/'));
for (int i = 0; i <= base; i ++)
env. push_back (motName. at (i));
for (int i = base + 1; i < motName. size (); i ++)
realName . push_back (motName. at (i));
2025-03-05 16:34:15 +01:00
int dotat = realName. lastIndexOf (".");
if (dotat < 0)
return "";
for (int i = 0; i < 4; i ++) {
dateString = "";
for (int j = 0; j < 4; j ++)
dateString . push_back (realName. at (i + j));
int y = dateString. toInt (&ok);
if ((2000 <= y) && (y <= 2030)) {
for (int j = 4; j < 8; j ++)
dateString. push_back (realName. at (i + j));
eos = i + 8;
break;
}
}
if (eos == 0)
return "";
2025-03-05 16:34:15 +01:00
for (int i = eos; i < dotat - 3; i ++) {
sidString = "";
for (int j = i; j < i + 4; j ++)
sidString. push_back (realName. at (j));
uint32_t sid = sidString. toInt (&ok, 16);
if (ok) {
2025-07-11 12:48:10 +02:00
QString name = theEnsembleHandler -> extractName (sid);
if (name != "") {
2025-03-05 19:52:36 +01:00
return env + dateString + "_" + sidString. toUpper () + "_SI.xml";
}
}
}
return "";
}
2025-01-05 13:11:25 +01:00
void RadioInterface::saveMOTtext (QByteArray &result,
2024-01-27 20:16:14 +01:00
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");
2025-09-01 19:04:36 +02:00
if (x == nullptr) {
QString t = QString ("problem to open file ") + textName;
theErrorLogger. add ("main", t);
}
2024-01-27 20:16:14 +01:00
else {
(void)fwrite (result. data (), 1, result.length(), x);
fclose (x);
}
}
2025-01-05 13:11:25 +01:00
void RadioInterface::saveMOTObject (QByteArray &result,
QString &name) {
2024-01-27 20:16:14 +01:00
if (path_for_files == "")
return;
2025-02-17 12:26:30 +01:00
if (name == "") { // should not happen
2024-01-27 20:16:14 +01:00
static int counter = 0;
name = "motObject_" + QString::number (counter);
counter ++;
}
2025-01-05 13:11:25 +01:00
saveMOTtext (result, 5, name);
2024-01-27 20:16:14 +01:00
}
// MOT slide, to show
2025-01-05 13:11:25 +01:00
void RadioInterface::showMOTlabel (QByteArray &data,
2024-01-27 20:16:14 +01:00
int contentType,
const QString &pictureName,
int dirs,
bool backgroundFlag) {
const char *type;
2025-02-23 11:54:05 +01:00
if (!running. load () || (pictureName == QString ("")))
2024-01-27 20:16:14 +01:00
return;
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;
}
2025-02-23 11:54:05 +01:00
if (dirs || ((value_i (dabSettings_p, CONFIG_HANDLER,
SAVE_SLIDES_SETTING, 0) != 0) &&
(path_for_files != ""))) {
2025-02-15 17:53:47 +01:00
QString pict;
if (!dirs)
pict = path_for_files + pictureName;
2025-02-15 17:53:47 +01:00
else
2025-03-06 13:20:13 +01:00
pict = path_for_files + QString::number (channel. Eid, 16). toUpper () + "/" + pictureName;
2024-01-27 20:16:14 +01:00
QString temp = pict;
temp = temp. left (temp. lastIndexOf (QChar ('/')));
if (!QDir (temp). exists())
QDir (). mkpath (temp);
2025-02-15 17:53:47 +01:00
pict = QDir::toNativeSeparators (pict);
2024-01-27 20:16:14 +01:00
FILE *x = fopen (pict. toUtf8 (). data (), "w+b");
2025-09-01 19:04:36 +02:00
if (x == nullptr) {
QString t = QString ("Problem opening picture file (writing) ") +
pict;
theErrorLogger. add ("main", t);
}
2024-01-27 20:16:14 +01:00
else {
theLogger. log (logger::LOG_SLIDE_WRITTEN, pict);
2024-01-27 20:16:14 +01:00
(void)fwrite (data. data(), 1, data.length(), x);
fclose (x);
}
}
2025-02-15 17:53:47 +01:00
if (backgroundFlag || dirs)
2024-01-27 20:16:14 +01:00
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
}
/**
2024-10-09 17:57:23 +02:00
* If a "change in configuration" is detected, we have to
* restart the selected service - if any.s
* If the service is a secondary service, it might be the case
* that we have to start the main service
2024-01-27 20:16:14 +01:00
* how do we find that?
*
* Response to a signal, so we presume that the signaling body exists
* signal may be pending though
2025-03-19 12:32:08 +01:00
* we copy the tasklist and stop all services,
* then, using the data in the copy we (try to) start
* all services again (including the secondary services);
2024-01-27 20:16:14 +01:00
*/
2025-05-16 11:18:43 +02:00
2025-03-19 12:32:08 +01:00
void RadioInterface::changeinConfiguration () {
std::vector<dabService> taskCopy = channel. runningTasks;
if (theSCANHandler. active ()) {
stopScanning ();
2024-01-27 20:16:14 +01:00
return;
}
2025-03-19 12:32:08 +01:00
channelTimer. stop ();
stopMuting ();
setSoundLabel (false);
2024-01-27 20:16:14 +01:00
if (channel. etiActive)
2025-07-11 12:48:10 +02:00
theOFDMHandler -> resetEtiGenerator ();
myTimeTable. clear ();
myTimeTable. hide ();
2025-03-19 12:32:08 +01:00
// and stop the service
for (auto &serv :channel. runningTasks)
stopService (serv);
2025-03-20 18:23:52 +01:00
// fprintf (stderr, "All services are halted, now start rebuilding\n");
2025-03-19 12:32:08 +01:00
techWindow_p -> cleanUp ();
for (auto &serv : taskCopy) {
2025-07-11 12:48:10 +02:00
int index = theOFDMHandler -> getServiceComp (serv. serviceName);
2025-03-19 12:32:08 +01:00
if (index < 0)
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> remove (serv. serviceName);
2025-03-19 12:32:08 +01:00
// hier moet de ensemlelist nog worden aangepast
continue;
if (serv. runsBackground)
handle_backgroundTask (serv. serviceName);
else
startService (serv, index);
2024-01-27 20:16:14 +01:00
}
}
2025-03-19 12:32:08 +01:00
2024-01-27 20:16:14 +01:00
//
// 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;
2025-07-21 15:03:49 +02:00
audioTeller ++;
if (audioTeller > 10) {
audioTeller = 0;
2024-01-27 20:16:14 +01:00
if (!techWindow_p -> isHidden ())
2025-07-11 12:48:10 +02:00
techWindow_p -> showRate (rate, ps, sbr);
2024-12-11 19:06:03 +01:00
audiorateLabel -> setStyleSheet ("color:cyan");
2024-01-27 20:16:14 +01:00
audiorateLabel -> setText (QString::number (rate));
if (!ps)
psLabel -> setText (" ");
else {
2024-12-11 19:06:03 +01:00
psLabel -> setStyleSheet ("color:cyan");
2024-01-27 20:16:14 +01:00
psLabel -> setText ("ps");
}
if (!sbr)
sbrLabel -> setText (" ");
else {
2024-12-11 19:06:03 +01:00
sbrLabel -> setStyleSheet ("color:cyan");
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);
}
2025-01-05 13:11:25 +01:00
setPeakLevel (tmpBuffer);
2024-01-27 20:16:14 +01:00
}
}
2024-11-20 16:33:31 +01:00
2025-01-05 13:11:25 +01:00
void RadioInterface::setPeakLevel (const std::vector<float> &samples) {
2024-11-20 16:33:31 +01:00
float absPeakLeft = 0;
float absPeakRight = 0;
2024-11-25 14:55:59 +01:00
for (int i = 0; i < (int)(samples. size ()) / 2; i ++) {
2024-11-20 16:33:31 +01:00
const float absLeft = std::abs (samples [2 * i]);
const float absRight = std::abs (samples [2 * i + 1]);
if (absLeft > absPeakLeft)
absPeakLeft = absLeft;
if (absRight > absPeakRight)
absPeakRight = absRight;
}
float leftDb = (absPeakLeft > 0.0f ?
20.0f * std::log10 (absPeakLeft) : -40.0f);
float rightDb = (absPeakRight > 0.0f ?
20.0f * std::log10 (absPeakRight) : -40.0f);
showPeakLevel (leftDb, rightDb);
}
2024-01-27 20:16:14 +01:00
//
/////////////////////////////////////////////////////////////////////////////
//
/**
* \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);
2025-07-20 19:25:14 +02:00
storeWidgetPosition (dabSettings_p, this, S_MAIN_WIDGET);
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);
2025-07-20 19:25:14 +02:00
theSCANHandler. hide ();
myTimeTable. hide ();
if (scanTable_p != nullptr) {
scanTable_p -> clearTable ();
scanTable_p -> hide ();
delete scanTable_p;
}
2024-01-27 20:16:14 +01:00
hideButtons ();
2025-07-20 19:25:14 +02:00
// stop the timers
2024-01-27 20:16:14 +01:00
displayTimer. stop ();
channelTimer. stop ();
presetTimer. stop ();
epgTimer. stop ();
2025-07-20 19:25:14 +02:00
pauzeTimer. stop ();
muteTimer. stop ();
//
// hide the windows
theNewDisplay. hide ();
theDXDisplay. hide ();
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> hide ();
2025-05-27 18:50:45 +02:00
if (the_aboutLabel != nullptr) {
the_aboutLabel -> hide ();
delete the_aboutLabel;
}
2024-01-27 20:16:14 +01:00
if (contentTable_p != nullptr) {
contentTable_p -> clearTable ();
contentTable_p -> hide ();
delete contentTable_p;
}
2025-09-15 16:06:38 +02:00
configHandler_p. reset ();
techWindow_p. reset ();
2025-07-20 19:25:14 +02:00
theSNRViewer. hide ();
theScheduler. hide ();
theScanlistHandler. hide ();
//
#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
if (dlTextFile != nullptr)
fclose (dlTextFile);
#ifdef HAVE_PLUTO_RXTX
if (streamerOut_p != nullptr)
streamerOut_p -> stop ();
#endif
if (mapHandler != nullptr)
mapHandler -> stop ();
2024-01-27 20:16:14 +01:00
// just save a few checkbox settings that are not
2025-07-11 12:48:10 +02:00
stopFrameDumping ();
stopSourceDumping ();
stopAudioDumping ();
2025-07-21 15:03:49 +02:00
if (!theOFDMHandler. isNull ())
theOFDMHandler -> stop ();
if (soundOut_p != nullptr)
2025-07-20 19:25:14 +02:00
delete soundOut_p;
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_RADIO_STOPS);
2024-01-27 20:16:14 +01:00
usleep (1000); // pending signals
// everything should be halted by now
dabSettings_p -> sync ();
2025-05-29 12:51:05 +02:00
theOFDMHandler. reset ();
2025-07-20 19:25:14 +02:00
inputDevice_p. reset ();
2024-01-27 20:16:14 +01:00
// 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;
2025-07-14 17:25:42 +02:00
getCpuTimes (idle_time, total_time);
2024-01-27 20:16:14 +01:00
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
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-12-20 15:58:42 +01:00
if (!techWindow_p -> isHidden () && soundOut_p -> hasMissed ()) {
2024-11-22 20:21:44 +01:00
int totalSamples = 0;
int totalMissed = 0;
soundOut_p -> samplesMissed (totalSamples, totalMissed);
if (totalSamples != 0) {
float correct = (totalSamples - totalMissed) * 100 / totalSamples;
techWindow_p -> showMissed (correct);
2024-01-27 20:16:14 +01:00
}
}
}
//
// precondition: everything is quiet
2025-01-05 13:11:25 +01:00
deviceHandler *RadioInterface::createDevice (const QString &s,
logger *theLogger) {
deviceHandler *inputDevice = theDeviceChoser.
2025-08-31 20:55:36 +02:00
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 ();
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> setMode (channel. realChannel);
2024-04-14 12:47:14 +02:00
connect (inputDevice, &deviceHandler::frameClosed,
this, &RadioInterface::handle_deviceFrame_closed);
QString ss = s;
store (dabSettings_p, DAB_GENERAL, SELECTED_DEVICE, ss);
inputDevice -> setVisibility (true);
// if (value_i (dabSettings_p, DAB_GENERAL, DEVICE_WIDGET_VISIBLE, 1) == 0)
// inputDevice -> setVisibility (false);
2025-01-06 20:47:14 +01:00
theNewDisplay. setBitDepth (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");
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_NEWDEVICE, deviceName,
channelSelector -> currentText ());
2025-05-29 12:51:05 +02:00
inputDevice_p. reset (createDevice (deviceName, &theLogger));
if (inputDevice_p. isNull ()) {
inputDevice_p. reset (new deviceHandler ());
2024-01-27 20:16:14 +01:00
return; // nothing will happen
}
2024-11-25 14:55:59 +01:00
2025-01-05 13:11:25 +01:00
startDirect (); // 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);
2025-02-12 14:08:44 +01:00
QDate theDate (year, month, day);
channel. theDate = theDate;
2024-01-27 20:16:14 +01:00
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) {
2025-02-17 12:26:30 +01:00
return convertTime (t. year, t. month, t. day, t. hour, t. minute);
2024-01-27 20:16:14 +01:00
}
//
// called from the MP4 decoder
void RadioInterface::show_frameErrors (int s) {
if (!running. load ())
return;
if (!techWindow_p -> isHidden ())
2025-07-11 12:48:10 +02:00
techWindow_p -> showFrameErrors (s);
2024-01-27 20:16:14 +01:00
}
//
// called from the MP4 decoder
void RadioInterface::show_rsErrors (int s) {
if (!running. load ()) // should not happen
return;
if (!techWindow_p -> isHidden ())
2025-07-11 12:48:10 +02:00
techWindow_p -> showRsErrors (s);
2024-01-27 20:16:14 +01:00
}
//
// called from the NP4 decoder
2024-01-27 20:16:14 +01:00
void RadioInterface::show_aacErrors (int s) {
if (!running. load ())
return;
if (!techWindow_p -> isHidden ())
2025-07-11 12:48:10 +02:00
techWindow_p -> showAacErrors (s);
2024-01-27 20:16:14 +01:00
}
//
// called from the ficHandler
2024-11-20 16:33:31 +01:00
void RadioInterface::show_ficQuality (int val, int scaler) {
2024-01-27 20:16:14 +01:00
if (!running. load ())
return;
2024-11-20 16:33:31 +01:00
QPalette p = theNewDisplay. ficError_display -> palette();
if (val * scaler < 85)
p. setColor (QPalette::Highlight, Qt::red);
else
p. setColor (QPalette::Highlight, Qt::green);
2024-01-27 20:16:14 +01:00
2024-11-20 16:33:31 +01:00
theNewDisplay. ficError_display -> setPalette (p);
theNewDisplay. ficError_display -> setValue (val * scaler);
2024-01-27 20:16:14 +01:00
}
2024-11-22 20:21:44 +01:00
void RadioInterface::show_ficBER (float ber) {
if (!running. load ())
return;
if (!theNewDisplay. isHidden ())
2025-01-06 20:47:14 +01:00
theNewDisplay. showFICBER (ber);
2024-11-22 20:21:44 +01:00
}
2024-01-27 20:16:14 +01:00
//
// called from the PAD handler
void RadioInterface::show_mothandling (bool b) {
2024-11-20 16:33:31 +01:00
static bool old_mot = false;
if (!running. load () || (old_mot == b))
2024-01-27 20:16:14 +01:00
return;
2024-11-20 16:33:31 +01:00
if (b)
motLabel -> setStyleSheet (labelStyle);
else
motLabel -> setStyleSheet ("QLabel {color : red}");
old_mot = b;
2024-01-27 20:16:14 +01:00
}
// just switch a color, called from the dabprocessor
void RadioInterface::set_synced (bool b) {
2025-01-06 20:47:14 +01:00
theNewDisplay. setSyncLabel (b);
2024-01-27 20:16:14 +01:00
}
//
// called from the PAD handler
2024-11-25 14:55:59 +01:00
2025-08-14 22:00:06 +02:00
void RadioInterface::showLabel (const QString &s, int charset) {
2025-01-15 20:22:28 +01:00
(void)charset;
2024-01-27 20:16:14 +01:00
#ifdef HAVE_PLUTO_RXTX
if ((streamerOut_p != nullptr) && (s != ""))
streamerOut_p -> addRds (std::string (s. toUtf8 (). data ()));
#endif
2025-01-13 19:13:10 +01:00
2024-01-27 20:16:14 +01:00
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-11-20 16:33:31 +01:00
techWindow_p -> showStereo (b);
2024-01-27 20:16:14 +01:00
stereoSetting = b;
}
2024-02-25 14:18:27 +01:00
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 ();
store (dabSettings_p, DAB_GENERAL, 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);
scanListButton -> setEnabled (true);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::hideButtons () {
scanButton -> setEnabled (false);
channelSelector -> setEnabled (false);
nextChannelButton -> setEnabled (false);
prevChannelButton -> setEnabled (false);
scanListButton -> setEnabled (false);
2024-01-27 20:16:14 +01:00
}
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 ();
}
2025-07-11 12:48:10 +02:00
void RadioInterface::handleAudiodumpButton () {
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)
2025-07-11 12:48:10 +02:00
stopAudioDumping ();
2024-01-27 20:16:14 +01:00
else
2025-07-11 12:48:10 +02:00
startAudioDumping ();
2024-01-27 20:16:14 +01:00
}
2025-07-11 12:48:10 +02:00
void RadioInterface::stopAudioDumping () {
2024-07-28 12:47:27 +02:00
if (!audioDumping)
2024-01-27 20:16:14 +01:00
return;
2024-10-14 13:12:03 +02:00
theLogger. log (logger::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);
}
2025-07-11 12:48:10 +02:00
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;
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_AUDIODUMP_STARTS,
channelSelector -> currentText (),
channel. currentService. serviceName);
2024-01-27 20:16:14 +01:00
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
}
2025-01-05 13:11:25 +01:00
void RadioInterface::scheduledAudioDumping () {
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
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;
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
}
2025-07-11 12:48:10 +02:00
void RadioInterface::handleFramedumpButton () {
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)
2025-07-11 12:48:10 +02:00
stopFrameDumping ();
2024-01-27 20:16:14 +01:00
else
2025-07-11 12:48:10 +02:00
startFrameDumping ();
2024-01-27 20:16:14 +01:00
}
2025-07-11 12:48:10 +02:00
void RadioInterface::stopFrameDumping () {
2024-01-27 20:16:14 +01:00
if (channel. currentService. frameDumper == nullptr)
return;
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_FRAMEDUMP_STOPS);
2024-01-27 20:16:14 +01:00
fclose (channel. currentService. frameDumper);
2025-07-29 22:12:40 +02:00
techWindow_p -> framedumpButton_text ("save AAC/MP2", 10);
2024-01-27 20:16:14 +01:00
channel. currentService. frameDumper = nullptr;
}
2025-07-11 12:48:10 +02:00
void RadioInterface::startFrameDumping () {
2025-07-29 22:12:40 +02:00
if (!channel. currentService. isAudio)
return;
2024-01-27 20:16:14 +01:00
channel. currentService. frameDumper =
theFilenameFinder.
findFrameDump_fileName (channel. currentService. serviceName,
2025-07-29 22:12:40 +02:00
channel. currentService. ASCTy, true);
2024-01-27 20:16:14 +01:00
if (channel. currentService. frameDumper == nullptr)
return;
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_FRAMEDUMP_STARTS,
channel. channelName,
channel. currentService. serviceName);
QString mode = channel. currentService. ASCTy == DAB_PLUS ?
"recording aac" : "recording mp2";
2025-07-29 22:12:40 +02:00
techWindow_p -> framedumpButton_text (mode, 12);
2024-01-27 20:16:14 +01:00
}
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;
}
audiodata ad;
int index = theOFDMHandler -> getServiceComp (s);
if (index < 0)
return;
theOFDMHandler -> audioData (index, ad);
if (!ad. defined)
return;
2024-01-27 20:16:14 +01:00
channel. currentService. frameDumper =
theFilenameFinder. findFrameDump_fileName (s, ad. ASCTy, 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 ();
store (dabSettings_p, DAB_GENERAL, 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-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);
2025-09-18 20:13:06 +02:00
connect (this, &RadioInterface::call_scanButton,
this, &RadioInterface::handle_scanButton);
2024-01-27 20:16:14 +01:00
//
2025-07-29 22:12:40 +02:00
//// and for the techWindow
// connect (techWindow_p. data (), &techData::handleAudioDumping,
// this, &RadioInterface::handleAudiodumpButton);
// connect (techWindow_p. data (), &techData::handleFrameDumping,
// this, &RadioInterface::handleFramedumpButton);
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 ();
store (dabSettings_p, CONFIG_HANDLER, 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",
2025-05-03 11:10:32 +02:00
tr("Quitting Qt-DAB\nAre you sure?\n"),
2024-01-27 20:16:14 +01:00
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);
2025-09-12 18:33:52 +02:00
if (obj == this -> theEnsembleHandler -> viewport ()) {
if (event -> type () == QEvent::MouseButtonPress) {
QMouseEvent *ev = static_cast<QMouseEvent *>(event);
if (ev -> buttons () & Qt::RightButton) {
QTableWidgetItem *x =
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> itemAt (ev -> pos ());
2025-09-12 18:33:52 +02:00
if (x != nullptr)
theEnsembleHandler -> handleRightMouseClick (x -> text ());
return true;
}
else {
return QWidget::eventFilter (obj, event);
}
}
}
else
if (event -> type () == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent -> key () == Qt::Key_Return) {
theEnsembleHandler -> selectCurrentItem ();
return true;
2024-01-27 20:16:14 +01:00
}
2025-09-19 19:52:42 +02:00
else // handling function keys
if (handle_keyEvent (keyEvent -> key ()))
return true;
2024-01-27 20:16:14 +01:00
}
// 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();
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> addFavoriteFromScanList (service);
2024-01-27 20:16:14 +01:00
}
}
2025-09-12 18:33:52 +02:00
// else
// if (event -> type () == QEvent::MouseButtonPress) {
// QPixmap originalPixmap;
// QScreen *screen = QGuiApplication::primaryScreen();
// originalPixmap = screen -> grabWindow(this -> winId());
// QString format = "png";
// QString fileName = path_for_files + "main-widget";
//#ifdef __MINGW32__
// fileName = fileName + ".png";
// originalPixmap. save (fileName);
//#else
// originalPixmap. save (fileName, format.toLatin1 (). data ());
//#endif
// }
2024-01-27 20:16:14 +01:00
return QWidget::eventFilter (obj, event);
}
2025-01-05 13:11:25 +01:00
QPixmap RadioInterface::fetchAnnouncement (int id) {
2024-01-27 20:16:14 +01:00
QPixmap p;
QString pictureName = QString (":res/radio-pictures/announcement%1.png").
arg (id, 2, 10, QChar ('0'));
2024-01-27 20:16:14 +01:00
if (!p.load (pictureName, "png"))
p. load (":res/radio-pictures/announcement-d.png", "png");
2024-01-27 20:16:14 +01:00
return p;
}
2025-03-29 10:48:38 +01:00
void RadioInterface::announcement (int SId, int flags) {
2024-01-27 20:16:14 +01:00
if (!running. load ())
return;
2025-04-02 18:30:53 +02:00
if (channel. currentService. SId == (uint32_t)SId) {
2025-03-19 12:32:08 +01:00
if (flags != 0)
announcement_start (SId, flags);
else
announcement_stop ();
2024-01-27 20:16:14 +01:00
}
}
2025-03-19 12:32:08 +01:00
static inline
int bits (uint s) {
uint32_t startBit = 01;
for (int i = 0; i < 15; i ++) {
if ((s & startBit) != 0)
return i;
startBit <<= 1;
}
return 0;
}
// do not mess with the order
void RadioInterface::announcement_start (uint16_t SId, uint16_t flags) {
(void)SId;
serviceLabel -> setStyleSheet ("QLabel {color : red}");
int pictureId = bits (flags);
QPixmap p = fetchAnnouncement (pictureId);
displaySlide (p);
channel. announcing = true;
}
void RadioInterface::announcement_stop () {
serviceLabel -> setStyleSheet (labelStyle);
channel. announcing = false;
show_pauzeSlide ();
2024-01-27 20:16:14 +01:00
}
//
// selection, either direct, from presets, from scanlist or schedule
////////////////////////////////////////////////////////////////////////
//
// Selecting from the list of services,
// record the <channel:servicePair>
void RadioInterface::localSelect (const QString &service,
const QString &theChannel) {
localSelect_SS (service, theChannel);
}
// selecting from the preset list and handling delayed services
2024-01-27 20:16:14 +01:00
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
2025-07-11 12:48:10 +02:00
void RadioInterface::handleScanListSelect (const QString &s) {
if (!inputDevice_p -> isFileInput ()) {
QStringList list = splitter (s);
if (list. length () != 2)
return;
localSelect_SS (list. at (1), list. at (0));
}
2024-01-27 20:16:14 +01:00
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;
2024-11-14 16:16:03 +01:00
presetTimer. stop ();
2024-01-27 20:16:14 +01:00
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
}
//
// The function localSelect is called from different
// places, making it complex
void RadioInterface::localSelect_SS (const QString &service,
const QString &theChannel) {
2024-01-27 20:16:14 +01:00
QString serviceName = service;
2025-03-19 12:32:08 +01:00
// timers are stopped in the "stopService" function
2024-01-27 20:16:14 +01:00
stopService (channel. currentService);
for (int i = service. size (); i < 16; i ++)
serviceName. push_back (' ');
if (!inputDevice_p -> isFileInput ()) {
QString theService = service;
QString channelName = theChannel;
store (dabSettings_p, "channelPresets", channelName, theService);
}
2025-03-19 12:32:08 +01:00
2024-01-27 20:16:14 +01:00
if (theChannel == channel. channelName) {
2025-07-11 12:48:10 +02:00
channel. currentService. isValid = false;
2024-01-27 20:16:14 +01:00
dabService s;
2025-07-11 12:48:10 +02:00
int index = theOFDMHandler -> getServiceComp (service);
2025-03-19 12:32:08 +01:00
if (index < 0) {
dynamicLabel -> setText ("cannot run " + s. serviceName + " yet");
2024-01-27 20:16:14 +01:00
return;
}
s. serviceName = service;
2025-03-19 12:32:08 +01:00
startService (s, index);
2024-01-27 20:16:14 +01:00
}
2025-03-19 12:32:08 +01:00
else { // selecting a service in a different channel
stopChannel ();
int k = channelSelector -> findText (theChannel);
if (k != -1) {
2025-01-05 13:11:25 +01:00
newChannelIndex (k);
}
else {
QMessageBox::warning (this, tr ("Warning"),
tr ("Incorrect service specification\n"));
return;
}
startChannel (theChannel, serviceName);
2024-01-27 20:16:14 +01:00
}
}
2024-01-27 20:16:14 +01:00
///////////////////////////////////////////////////////////////////////////
//void RadioInterface::stopService (dabService s) {
void RadioInterface::stopService (dabService &s) {
2025-07-11 12:48:10 +02:00
if (!s. isValid)
2024-02-16 15:46:54 +01:00
return;
2024-01-27 20:16:14 +01:00
presetTimer. stop ();
channelTimer. stop ();
2025-01-05 13:11:25 +01:00
stopMuting ();
setSoundLabel (false);
2024-01-27 20:16:14 +01:00
channel. audioActive = false;
2025-05-29 12:51:05 +02:00
2025-03-19 12:32:08 +01:00
announcement_stop ();
2025-07-11 12:48:10 +02:00
if (s. isAudio) {
2025-03-19 12:32:08 +01:00
soundOut_p -> suspend ();
2025-09-08 13:38:08 +02:00
stopAudioDumping ();
stopFrameDumping ();
myTimeTable. clear ();
2024-01-27 20:16:14 +01:00
// and clean up the technical widget
2025-09-08 13:38:08 +02:00
techWindow_p -> cleanUp ();
2025-03-19 12:32:08 +01:00
// and stop the service and erase it from the task list
2025-09-08 13:38:08 +02:00
theOFDMHandler -> stopService (s. serviceName,
s. subChId, FORE_GROUND);
for (int i = 0; i < (int)channel. runningTasks. size (); i ++) {
if (channel. runningTasks [i]. serviceName == s. serviceName)
if (channel. runningTasks [i]. runsBackground == false) {
channel. runningTasks. erase
2025-03-19 12:32:08 +01:00
(channel. runningTasks. begin () + i);
2025-09-08 13:38:08 +02:00
}
2025-03-19 12:32:08 +01:00
}
2024-01-27 20:16:14 +01:00
// stop "secondary services" - if any - as well
2025-03-19 12:32:08 +01:00
// Note: they are not recorded on the tasklist
2025-09-08 13:38:08 +02:00
int nrComps =
theOFDMHandler -> getNrComps (s. SId);
for (int i = 1; i < nrComps; i ++) {
int index =
theOFDMHandler -> getServiceComp (s. SId, i);
if ((index < 0) ||
(theOFDMHandler -> serviceType (index) != PACKET_SERVICE))
2025-03-19 12:32:08 +01:00
continue;
packetdata pd;
theOFDMHandler -> packetData (index, pd);
if (pd. defined) {
2025-09-08 13:38:08 +02:00
theOFDMHandler -> stopService (pd. serviceName,
pd. subchId, BACK_GROUND);
2024-01-27 20:16:14 +01:00
}
}
}
2025-07-11 12:48:10 +02:00
s. isValid = false;
2024-01-27 20:16:14 +01:00
show_pauzeSlide ();
cleanScreen ();
}
//
2025-03-05 16:34:15 +01:00
// whether or not the epgService is triggered automatically or manually,
// it will run in the background
2025-02-23 11:54:05 +01:00
void RadioInterface::start_epgService (packetdata &pd) {
theOFDMHandler -> setDataChannel (pd, &theDataBuffer, BACK_GROUND);
dabService s;
s. channel = pd. channel;
s. serviceName = pd. serviceName;
s. SId = pd. SId;
s. subChId = pd. subchId;
s. fd = nullptr;
2025-03-19 12:32:08 +01:00
s. runsBackground = true;
channel. runningTasks. push_back (s);
2025-02-23 11:54:05 +01:00
epgLabel -> show ();
}
2024-01-27 20:16:14 +01:00
//
2025-03-19 12:32:08 +01:00
void RadioInterface::startService (dabService &s, int index) {
2024-01-27 20:16:14 +01:00
QString serviceName = s. serviceName;
2025-07-11 12:48:10 +02:00
s. SId = theOFDMHandler -> getSId (index);
2025-03-19 12:32:08 +01:00
// if the service is already running, ignore the call
2025-05-16 11:18:43 +02:00
for (auto &serv : channel. runningTasks) {
2025-03-19 12:32:08 +01:00
if (serv. serviceName == serviceName) {
2025-02-23 11:54:05 +01:00
return;
}
}
2025-03-19 12:32:08 +01:00
presetTimer. stop ();
channel. currentService = s;
2025-07-11 12:48:10 +02:00
channel. currentService. isValid = false;
2024-01-27 20:16:14 +01:00
channel. currentService. frameDumper = nullptr;
// mark the selected service in the service list
// and display the servicename on the serviceLabel
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> reportStart (serviceName);
2025-03-19 12:32:08 +01:00
if (theOFDMHandler -> serviceType (index) == AUDIO_SERVICE) {
audiodata ad;
theOFDMHandler -> audioData (index, ad);
ad. channel = channel. channelName;
if (ad. defined) {
2025-07-11 12:48:10 +02:00
channel. currentService. isValid = true;
channel. currentService. isAudio = true;
2025-07-29 22:12:40 +02:00
channel. currentService. ASCTy = ad. ASCTy;
2025-03-19 12:32:08 +01:00
channel. currentService. subChId = ad. subchId;
2025-07-11 12:48:10 +02:00
techWindow_p -> showTimetableButton (true);
2025-03-19 12:32:08 +01:00
startAudioservice (ad);
// serviceLabel -> setText (serviceName + "(" + ad. shortName + ")");
serviceLabel -> setText (serviceName);
QPixmap p;
bool hasIcon = false;
if (get_serviceLogo (p, channel. currentService. SId)) {
hasIcon = true;
iconLabel ->
setPixmap (p. scaled (55, 55, Qt::KeepAspectRatio));
}
else
iconLabel -> setText (ad. shortName);
2025-07-11 12:48:10 +02:00
if (myTimeTable. isVisible ()) {
myTimeTable. setUp (channel. theDate, channel. Eid,
2025-03-19 12:32:08 +01:00
channel. currentService. SId,
serviceName);
if (hasIcon)
2025-07-11 12:48:10 +02:00
myTimeTable. addLogo (p);
2025-03-19 12:32:08 +01:00
}
techWindow_p -> isDABPlus (ad. ASCTy == DAB_PLUS);
2025-03-19 12:32:08 +01:00
}
2024-01-27 20:16:14 +01:00
}
2025-03-19 12:32:08 +01:00
else
if (theOFDMHandler -> serviceType (index) == PACKET_SERVICE) {
2024-01-27 20:16:14 +01:00
packetdata pd;
2025-03-19 12:32:08 +01:00
theOFDMHandler -> packetData (index, pd);
pd. channel = channel. channelName;
if (!pd. defined) {
2024-03-27 16:24:49 +01:00
QMessageBox::warning (this, tr ("Warning"),
tr ("insufficient data for this program\n"));
QString s = "";
store (dabSettings_p, DAB_GENERAL, PRESET_NAME, s);
2025-03-19 12:32:08 +01:00
return;;
}
if (pd. appType == 7) {
start_epgService (pd);
return;
2024-03-27 16:24:49 +01:00
}
2025-03-19 12:32:08 +01:00
serviceLabel -> setText (pd. serviceName);
2025-07-11 12:48:10 +02:00
channel. currentService. isValid = true;
channel. currentService. isAudio = false;
2025-03-19 12:32:08 +01:00
channel. currentService. subChId = pd. subchId;
startPacketservice (pd);
2024-01-27 20:16:14 +01:00
}
}
//
void RadioInterface::startAudioservice (audiodata &ad) {
2025-01-06 20:47:14 +01:00
(void)theOFDMHandler -> setAudioChannel (ad, &theAudioBuffer,
2024-01-27 20:16:14 +01:00
nullptr, FORE_GROUND);
2025-07-11 12:48:10 +02:00
uint16_t flags = theOFDMHandler -> getAnnouncing (ad. SId);
2025-03-19 12:32:08 +01:00
if (flags != 0)
announcement_start (ad. SId, flags);
else
announcement_stop ();
dabService s;
s. channel = ad. channel;
s. serviceName = ad. serviceName;
s. SId = ad. SId;
s. subChId = ad. subchId;
s. fd = nullptr;
s. runsBackground = false;
channel. runningTasks. push_back (s);
2024-03-25 14:35:22 +01:00
//
// check the other components for this service (if any)
2025-03-19 12:32:08 +01:00
if (theOFDMHandler -> isPrimary (ad. serviceName)) {
int nrComps =
2025-07-11 12:48:10 +02:00
theOFDMHandler -> getNrComps (ad. SId);
2025-03-19 12:32:08 +01:00
for (int i = 1; i < nrComps; i ++) {
int index =
2025-07-11 12:48:10 +02:00
theOFDMHandler -> getServiceComp (ad. SId, i);
2025-03-19 12:32:08 +01:00
if ((index < 0) ||
(theOFDMHandler -> serviceType (index) != PACKET_SERVICE))
continue;
packetdata pd;
theOFDMHandler -> packetData (index, pd);
if (pd. defined) {
theOFDMHandler -> setDataChannel (pd, &theDataBuffer,
BACK_GROUND);
}
2024-01-27 20:16:14 +01:00
}
}
// activate sound
2025-03-05 16:34:15 +01:00
soundOut_p -> resume ();
2024-01-27 20:16:14 +01:00
channel. audioActive = true;
2025-01-05 13:11:25 +01:00
setSoundLabel (true);
2024-02-06 15:37:07 +01:00
programTypeLabel -> setText (getProgramType (ad. programType));
2024-12-11 19:06:03 +01:00
rateLabel -> setStyleSheet ("color:magenta");
2024-02-06 15:37:07 +01:00
rateLabel -> setText (QString::number (ad. bitRate) + "kbit");
2024-01-27 20:16:14 +01:00
// show service related data
2025-07-11 12:48:10 +02:00
techWindow_p -> showServiceData (&ad);
2024-01-27 20:16:14 +01:00
}
2025-03-19 12:32:08 +01:00
void RadioInterface::startPacketservice (packetdata &pd) {
if ((pd. DSCTy == 0) || (pd. bitRate == 0)) {
2024-01-27 20:16:14 +01:00
QMessageBox::warning (this, tr ("sdr"),
tr ("still insufficient data for this service\n"));
return;
}
2025-03-19 12:32:08 +01:00
if (!theOFDMHandler -> setDataChannel (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;
}
switch (pd. DSCTy) {
default:
2025-08-14 22:00:06 +02:00
showLabel (QString ("unimplemented Data"), 1);
2024-01-27 20:16:14 +01:00
break;
case 5:
2025-08-14 22:00:06 +02:00
showLabel (QString ("Transp. Channel partially implemented"), 1);
2024-01-27 20:16:14 +01:00
break;
case 60:
2025-08-14 22:00:06 +02:00
showLabel (QString (" processing MOT data"), 1);
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);
2025-08-14 22:00:06 +02:00
showLabel (text, 1);
2024-01-27 20:16:14 +01:00
#else
2025-08-14 22:00:06 +02:00
showLabel ("Embedded IP not supported ", 1);
2024-01-27 20:16:14 +01:00
#endif
}
break;
case 44:
2025-08-14 22:00:06 +02:00
showLabel (QString ("Journaline"), 1);
2024-01-27 20:16:14 +01:00
break;
}
}
// This function is only used in the Gui to clear
// the details of a selected service
void RadioInterface::cleanScreen () {
serviceLabel -> setText ("");
2025-03-01 13:23:23 +01:00
iconLabel -> setPixmap (QPixmap ());
2024-01-27 20:16:14 +01:00
dynamicLabel -> setText ("");
stereoLabel -> setText ("");
programTypeLabel -> setText ("");
psLabel -> setText ("");
sbrLabel -> setText ("");
audiorateLabel -> setText ("");
rateLabel -> setText ("");
stereoSetting = false;
setStereo (false);
2025-05-03 11:10:32 +02:00
techWindow_p -> cleanUp ();
2025-03-05 16:34:15 +01:00
motLabel -> setStyleSheet ("QLabel {color : red}");
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 () {
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> selectPrevService ();
2024-01-27 20:16:14 +01:00
}
void RadioInterface::handle_nextServiceButton () {
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> selectNextService ();
2025-09-12 18:33:52 +02:00
// stressTimer. setSingleShot (true);
// stressTimer. start (1000);
2024-01-27 20:16:14 +01:00
}
//
// The user(s)
///////////////////////////////////////////////////////////////////////////
// setPresetService () is called after a time out to
// actually start the service that we were waiting for
void RadioInterface::setPresetService () {
if (!running. load ())
return;
2024-11-14 16:16:03 +01:00
if (theSCANHandler. active ())
return;
2024-03-04 14:45:33 +01:00
presetTimer. stop ();
2024-01-27 20:16:14 +01:00
2024-02-16 15:46:54 +01:00
if (nextService. channel != channel. channelName)
2024-01-27 20:16:14 +01:00
return;
2025-01-21 09:31:28 +01:00
2024-01-27 20:16:14 +01:00
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;
2025-07-11 12:48:10 +02:00
int index = theOFDMHandler -> getServiceComp (presetName);
2025-03-19 12:32:08 +01:00
if (index < 0) {
2024-01-27 20:16:14 +01:00
dynamicLabel -> setText (QString ("not all data for ") +
2025-03-19 12:32:08 +01:00
s. serviceName + " on board");
2024-01-27 20:16:14 +01:00
return;
}
2025-03-19 12:32:08 +01:00
startService (s, index);
2024-01-27 20:16:14 +01:00
}
//
// Channel basics
///////////////////////////////////////////////////////////////////////////
// Precondition: no channel should be active
//
// start channel gets as second parameter a servicename (or
// an empty string. If it is a serviceName, then the
// function will initiate a start of the service of that name,
// otherwise it will start the service found associated to the
// channel (if any)
void RadioInterface::startChannel (const QString &theChannel,
QString firstService) {
2024-01-27 20:16:14 +01:00
int tunedFrequency =
2024-06-01 11:12:04 +02:00
theSCANHandler. Frequency (theChannel);
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> reset ();
2024-09-04 12:14:53 +02:00
theNewDisplay. showFrequency (theChannel, tunedFrequency);
presetTimer. stop (); // should not run
2025-06-16 19:02:39 +02:00
inputDevice_p -> restartReader (tunedFrequency,
SAMPLERATE / 10);
channel. cleanChannel ();
2024-01-27 20:16:14 +01:00
channel. channelName = theChannel;
channel. tunedFrequency = tunedFrequency;
2024-09-04 09:46:23 +02:00
channel. countryName = "";
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_NEW_CHANNEL, theChannel, channel. snr);
2024-11-02 09:05:53 +01:00
channel. realChannel = !inputDevice_p -> isFileInput ();
if (channel. realChannel) {
store (dabSettings_p, DAB_GENERAL, CHANNEL_NAME, theChannel);
}
2024-11-02 09:05:53 +01:00
// The ".sdr" and ".uff" files - when built by us - carry
// the channel frequency in their data
2024-07-27 15:30:56 +02:00
if (inputDevice_p -> isFileInput ()) {
channelSelector -> setEnabled (false);
2025-02-05 12:52:51 +01:00
int freq = inputDevice_p -> getVFOFrequency ();
2024-07-27 15:30:56 +02:00
QString realChannel = theSCANHandler. getChannel (freq);
if (realChannel != "") {
int k = channelSelector -> findText (realChannel);
2025-02-05 12:52:51 +01:00
channelSelector -> setCurrentIndex (k);
2024-07-27 15:30:56 +02:00
channel. channelName = realChannel;
channel. tunedFrequency = freq;
2025-03-19 12:32:08 +01:00
theNewDisplay. showFrequency (realChannel, freq);
2024-07-27 15:30:56 +02:00
}
else {
channel. channelName = "";
channel. tunedFrequency = -1;
}
}
2024-01-27 20:16:14 +01:00
distanceLabel -> setText ("");
2025-03-19 12:32:08 +01:00
theDXDisplay. cleanUp ();
2025-04-02 18:30:53 +02:00
theDXDisplay. setChannel (channel. channelName, channel. ensembleName);
2025-03-19 12:32:08 +01:00
theNewDisplay. cleanTII ();
theNewDisplay. showTransmitters (channel. transmitters);
2024-01-27 20:16:14 +01:00
if (mapHandler != nullptr)
2024-02-25 14:18:27 +01:00
mapHandler -> putData (MAP_FRAME, position {-1, -1});
2024-11-14 16:16:03 +01:00
if (theSCANHandler. active ()) {
theOFDMHandler -> start ();
return;
}
2024-11-01 13:46:39 +01:00
//
2024-11-14 16:16:03 +01:00
// If we are scanning, we do not do delayed service start
int switchDelay =
configHandler_p -> switchDelayValue ();
// if no preset is started, we look in the tables what the servicename
// was the last time the channel was active
if (!inputDevice_p -> isFileInput () &&
!theSCANHandler. active ()) {
if (firstService == "") // no preset specified
firstService =
value_s (dabSettings_p, "channelPresets", theChannel, "");
2024-11-02 09:05:53 +01:00
// at this point we do not know whether or not a preset is
// set, so if this mode is "on" and there is a service name
// associated with the channel, we set the preset handling on
// but only if ....
if (firstService != "") {
2024-11-14 16:16:03 +01:00
presetTimer. stop (); // should not run here
nextService. channel = theChannel;
nextService. serviceName = firstService;
nextService. SId = 0;
presetTimer. setSingleShot (true);
2025-01-21 09:31:28 +01:00
presetTimer. setInterval (switchDelay);
presetTimer. start (switchDelay);
}
2024-11-01 13:46:39 +01:00
}
2024-06-01 11:12:04 +02:00
if (!theSCANHandler. active ())
2024-02-16 15:46:54 +01:00
epgTimer. start (switchDelay);
2024-11-02 09:05:53 +01:00
//
// all set, go for it
theOFDMHandler -> start ();
2024-01-27 20:16:14 +01:00
}
//
// apart from stopping the reader, a lot of administration
// is to be done.
void RadioInterface::stopChannel () {
2024-02-16 15:46:54 +01:00
epgTimer. stop (); // if running
2025-02-23 11:54:05 +01:00
epgLabel -> hide ();
2024-02-16 15:46:54 +01:00
presetTimer. stop (); // if running
channelTimer. stop (); // if running
2025-07-11 12:48:10 +02:00
if (myTimeTable. isVisible ()) {
myTimeTable. clear ();
myTimeTable. hide ();
2025-03-19 10:08:05 +01:00
}
2025-03-19 12:32:08 +01:00
2025-05-16 19:16:32 +02:00
inputDevice_p -> stopReader ();
inputDevice_p -> stopDump ();
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 ("");
2025-07-11 12:48:10 +02:00
stopSourceDumping ();
2025-05-29 12:51:05 +02:00
if (channel. etiActive)
stop_etiHandler (); //
theLogger. log (logger::LOG_CHANNEL_STOPS, channel. channelName);
2024-12-11 19:06:03 +01:00
transmitter_country -> setText ("");
theNewDisplay. setSilent ();
2024-01-27 20:16:14 +01:00
//
2025-03-20 18:23:52 +01:00
for (auto &serv : channel. runningTasks) {
2025-03-19 12:32:08 +01:00
if (!serv. runsBackground)
2025-09-08 13:38:08 +02:00
theOFDMHandler -> stopService (serv. serviceName,
serv. subChId, FORE_GROUND);
2025-03-19 12:32:08 +01:00
else
2025-09-08 13:38:08 +02:00
theOFDMHandler -> stopService (serv. serviceName,
serv. subChId, BACK_GROUND);
2025-03-19 12:32:08 +01:00
if (serv. fd != nullptr)
fclose (serv. fd);
2024-01-27 20:16:14 +01:00
}
2025-03-19 12:32:08 +01:00
channel. runningTasks. resize (0);
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
2025-07-24 14:59:25 +02:00
theOFDMHandler -> stopFicDump (); // just in case ...
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 ();
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;
2024-10-14 13:12:03 +02:00
// LOG select channel
2024-01-27 20:16:14 +01:00
presetTimer. stop ();
stopScanning ();
stopChannel ();
startChannel (channel);
}
void RadioInterface::handle_nextChannelButton () {
int nrChannels = channelSelector -> count ();
int newChannel = channelSelector -> currentIndex () + 1;
2025-01-05 13:11:25 +01:00
setChannelButton (newChannel % nrChannels);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::handle_prevChannelButton () {
int nrChannels = channelSelector -> count ();
if (channelSelector -> currentIndex () == 0)
2025-01-05 13:11:25 +01:00
setChannelButton (nrChannels - 1);
2024-01-27 20:16:14 +01:00
else
2025-01-05 13:11:25 +01:00
setChannelButton (channelSelector -> currentIndex () - 1);
2024-01-27 20:16:14 +01:00
}
2025-01-05 13:11:25 +01:00
void RadioInterface::setChannelButton (int currentChannel) {
2024-01-27 20:16:14 +01:00
if (!running. load ())
return;
presetTimer. stop ();
stopScanning ();
stopChannel ();
2025-01-05 13:11:25 +01:00
newChannelIndex (currentChannel);
2024-01-27 20:16:14 +01:00
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 () {
if (inputDevice_p -> isFileInput ()) {
QMessageBox::warning (this, tr ("Warning"),
tr ("Scanning not useful with file input"));
return;
}
stopChannel ();
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> setShowMode (SHOW_ENSEMBLE);
2024-02-01 11:39:22 +01:00
presetButton -> setText ("not in use");
presetButton -> setEnabled (false);
// scanning and showing the techWindows does not make much sense
techWindow_p -> hide (); // until shown otherwise
store (dabSettings_p, DAB_GENERAL, TECHDATA_VISIBLE, false);
2024-01-27 20:16:14 +01:00
presetTimer. stop ();
channelTimer. stop ();
epgTimer. stop ();
2025-07-11 12:48:10 +02:00
connect (theOFDMHandler. data (), &ofdmHandler::noSignalFound,
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 ())
2025-01-05 13:11:25 +01:00
startScan_to_data ();
2024-01-27 20:16:14 +01:00
else
2024-06-01 11:12:04 +02:00
if (theSCANHandler. scan_single ())
2025-01-05 13:11:25 +01:00
startScan_single ();
2024-01-27 20:16:14 +01:00
else
2025-01-05 13:11:25 +01:00
startScan_continuous ();
2024-01-27 20:16:14 +01:00
}
2025-01-05 13:11:25 +01:00
void RadioInterface::startScan_to_data () {
2024-01-27 20:16:14 +01:00
// 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);
2024-10-14 13:12:03 +02:00
// LOG scanning starts
2025-01-05 13:11:25 +01:00
newChannelIndex (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);
2025-07-11 12:48:10 +02:00
theOFDMHandler -> setScanMode (true);
2024-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
}
2025-01-05 13:11:25 +01:00
void RadioInterface::startScan_single () {
2025-08-06 14:14:21 +02:00
basicPrint thePrinter;
2025-07-11 12:48:10 +02:00
theScanlistHandler. clearScanList ();
2025-08-06 14:14:21 +02:00
2024-01-27 20:16:14 +01:00
if (scanTable_p == nullptr)
scanTable_p = new contentTable (this, dabSettings_p, "scan",
2025-08-06 14:14:21 +02:00
thePrinter. scanWidth ());
2024-01-27 20:16:14 +01:00
else // should not happen
scanTable_p -> clearTable ();
QString topLine = QString ("ensemble") + ";" +
"channelName" + ";" +
"frequency (KHz)" + ";" +
"Eid" + ";" +
"time" + ";" +
"SNR" + ";" +
2025-05-01 20:23:57 +02:00
"nr services" + ";" ;
2024-12-30 14:51:14 +01:00
2024-03-04 14:45:33 +01:00
scanTable_p -> addLine (topLine);
2024-01-27 20:16:14 +01:00
scanTable_p -> addLine ("\n");
2025-07-11 12:48:10 +02:00
theOFDMHandler -> setScanMode (true);
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);
if (k != -1)
2025-01-05 13:11:25 +01:00
newChannelIndex (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-01-27 20:16:14 +01:00
startChannel (channelSelector -> currentText ());
}
2025-01-05 13:11:25 +01:00
void RadioInterface::startScan_continuous () {
2025-08-06 14:14:21 +02:00
basicPrint thePrinter;
2024-01-27 20:16:14 +01:00
if (scanTable_p == nullptr)
scanTable_p = new contentTable (this, dabSettings_p, "scan",
2025-08-06 14:14:21 +02:00
thePrinter.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" + ";" +
2024-12-30 14:51:14 +01:00
"nr services" + ";" +
"transmitterName;" +
"distance;" +
"azimuth;" +
"height";
2024-01-27 20:16:14 +01:00
scanTable_p -> addLine (topLine);
scanTable_p -> addLine ("\n");
2025-07-11 12:48:10 +02:00
theOFDMHandler -> setScanMode (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);
2025-01-05 13:11:25 +01:00
newChannelIndex (k);
2024-01-27 20:16:14 +01:00
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 ());
2025-02-25 20:32:17 +01:00
// fprintf (stderr, "de scan start met %s\n",
// channelSelector -> currentText (). toLatin1 (). data ());
2024-01-27 20:16:14 +01:00
}
//
2025-01-05 13:11:25 +01:00
// stopScanning is called
2024-01-27 20:16:14 +01:00
// 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
if (!theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
return;
2024-12-30 14:51:14 +01:00
// fprintf (stderr, "De scan wordt gestopt\n");
2025-07-11 12:48:10 +02:00
disconnect (theOFDMHandler. data (), &ofdmHandler::noSignalFound,
2024-11-14 16:16:03 +01:00
this, &RadioInterface::no_signal_found);
2024-02-01 11:39:22 +01:00
presetButton -> setText ("favorites");
presetButton -> setEnabled (true);
2024-10-14 13:12:03 +02: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 ())
2025-01-05 13:11:25 +01:00
stopScan_to_data ();
2024-01-27 20:16:14 +01:00
else
2024-06-01 11:12:04 +02:00
if (theSCANHandler. scan_single ())
2025-01-05 13:11:25 +01:00
stopScan_single ();
2024-01-27 20:16:14 +01:00
else
2025-01-05 13:11:25 +01:00
stopScan_continuous ();
2024-06-01 11:12:04 +02:00
theSCANHandler. setStop ();
2024-01-27 20:16:14 +01:00
// presetButton -> setEnabled (true);
}
2025-01-05 13:11:25 +01:00
void RadioInterface::stopScan_to_data () {
2025-07-11 12:48:10 +02:00
theOFDMHandler -> setScanMode (false);
2024-01-27 20:16:14 +01:00
channelTimer. stop ();
}
2025-01-05 13:11:25 +01:00
void RadioInterface::stopScan_single () {
2025-07-11 12:48:10 +02:00
theOFDMHandler -> setScanMode (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;
2024-10-17 15:44:28 +02:00
QMessageBox::StandardButton reply =
QMessageBox::question (this,
"upload content to fmlist.org?", "",
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
2024-03-13 19:45:53 +01:00
the_uploader. loadUp ("Scan",
0,
"result table",
scanTable_p -> upload ());
}
2024-10-17 15:44:28 +02:00
} 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;
2024-01-27 20:16:14 +01:00
}
2025-01-05 13:11:25 +01:00
void RadioInterface::stopScan_continuous () {
2025-07-11 12:48:10 +02:00
theOFDMHandler -> setScanMode (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;
2024-01-27 20:16:14 +01:00
}
// 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 () {
2025-08-15 18:51:36 +02:00
// fprintf (stderr, "Channel timeout\n");
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-11-14 16:16:03 +01:00
if (theSCANHandler. scan_to_data ()) {
2025-01-05 13:11:25 +01:00
nextFor_scan_to_data ();
2024-11-14 16:16:03 +01:00
}
2024-01-27 20:16:14 +01:00
else
2024-11-14 16:16:03 +01:00
if (theSCANHandler. scan_single ()) {
2025-04-30 14:24:37 +02:00
if (channel. transmitters. size () > 0) {
QStringList ss;
2025-05-16 11:18:43 +02:00
for (auto &tr : channel. transmitters)
ss << tr. transmitterName;
2025-04-30 14:24:37 +02:00
theSCANHandler.
addTransmitters (ss, channel. channelName);
}
2025-01-05 13:11:25 +01:00
nextFor_scan_single ();
2024-11-14 16:16:03 +01:00
}
else {
2025-01-05 13:11:25 +01:00
nextFor_scan_continuous ();
2024-11-14 16:16:03 +01:00
}
2024-01-27 20:16:14 +01:00
}
2025-01-05 13:11:25 +01:00
void RadioInterface::nextFor_scan_to_data () {
2024-01-27 20:16:14 +01:00
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);
2025-01-05 13:11:25 +01:00
newChannelIndex (cc);
2024-01-27 20:16:14 +01:00
//
// 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 ());
}
2025-01-05 13:11:25 +01:00
void RadioInterface::nextFor_scan_single () {
2025-04-30 14:24:37 +02:00
if (channel. nrServices > 0)
2024-01-27 20:16:14 +01:00
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);
2025-01-05 13:11:25 +01:00
newChannelIndex (cc);
2024-01-27 20:16:14 +01:00
} 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 ());
}
2025-01-05 13:11:25 +01:00
void RadioInterface::nextFor_scan_continuous () {
2024-01-27 20:16:14 +01:00
if (channel. nrServices > 0)
show_for_continuous ();
stopChannel ();
2024-06-01 11:12:04 +02:00
QString cs = theSCANHandler. getNextChannel ();
2024-12-30 14:51:14 +01:00
// fprintf (stderr, "Going for channel %s\n", cs. toLatin1 (). data ());
2024-01-27 20:16:14 +01:00
int cc = channelSelector -> findText (cs);
2025-01-05 13:11:25 +01:00
newChannelIndex (cc);
2024-01-27 20:16:14 +01:00
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 ());
}
////////////////////////////////////////////////////////////////////////////
2025-01-05 13:11:25 +01:00
QString RadioInterface::buildHeadLine () {
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;
2024-12-02 14:46:38 +01:00
QString theAzimuth;
2024-04-07 14:58:26 +02:00
QString theHeight;
2024-01-27 20:16:14 +01:00
2024-04-08 11:08:56 +02:00
if (channel. mainId != -1)
2025-07-14 17:25:42 +02:00
tii = idsToString (channel. mainId,
2024-12-30 14:51:14 +01:00
channel. subId);
2024-04-08 11:08:56 +02:00
else
2024-12-30 14:51:14 +01:00
tii = "???";
if (channel. transmitterName != "")
2024-12-30 14:51:14 +01:00
theName = channel. transmitterName;
2024-04-08 11:08:56 +02:00
else
2024-12-30 14:51:14 +01:00
theName = " ";
if (channel. distance > 0) {
2024-04-07 14:58:26 +02:00
theDistance = QString::number (channel. distance, 'f', 1) + " km ";
2024-12-02 14:46:38 +01:00
theAzimuth = QString::number (channel. azimuth, 'f', 1)
2024-10-17 15:44:28 +02:00
+ QString::fromLatin1 (" \xb0 ");
2024-12-31 19:44:38 +01:00
theHeight = " (" + QString::number (channel. height, 'f', 1) + "m)";
2024-04-07 14:58:26 +02:00
}
else {
2024-12-31 19:44:38 +01:00
theName = "unknown";
2024-04-07 14:58:26 +02:00
theDistance = "unknown";
2024-12-02 14:46:38 +01:00
theAzimuth = "";
2024-12-31 19:44:38 +01:00
theHeight = "";
2024-04-07 14:58:26 +02:00
}
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) + ";" +
2024-12-30 14:51:14 +01:00
tii + ";" +
2024-04-07 14:58:26 +02:00
utcTime + ";" +
SNR + ";" +
QString::number (channel. nrServices) +";" +
theName + ";" +
2024-12-30 14:51:14 +01:00
theDistance + ";" +
theAzimuth + ";" + theHeight;
2024-04-07 14:58:26 +02:00
return headLine;
}
2024-04-03 18:44:52 +02:00
2025-05-01 20:23:57 +02:00
QString RadioInterface::build_kop () {
QString SNR = "SNR " + QString::number (channel. snr);
QString theName;
QString utcTime = convertTime (UTC. year, UTC.month,
UTC. day, UTC. hour,
UTC. minute);
2025-05-06 16:26:16 +02:00
int freeSpace = theOFDMHandler -> freeSpace ();
2025-05-01 20:23:57 +02:00
QString headLine = channel. ensembleName + ";" +
channel. channelName + ";" +
QString::number (channel. tunedFrequency) + ";" +
hextoString (channel. Eid) + ";" +
utcTime + ";" +
SNR + ";" +
2025-05-06 16:26:16 +02:00
QString::number (channel. nrServices) +";" +
QString::number (freeSpace) + ", " +
QString::number ((int) (freeSpace / 864.0 * 100)) + "%" + ";";
2025-05-01 20:23:57 +02:00
return headLine;
}
QString RadioInterface::build_transmitterLine (const transmitter &c) {
2025-05-01 20:23:57 +02:00
QString res = "";
res += ";";
2025-07-14 17:25:42 +02:00
res += idsToString (c. mainId, c. subId) + ";";
2025-05-01 20:23:57 +02:00
res += c. transmitterName + ";";
res += QString::number (c. distance, 'f', 1) + "km;";
res += QString::number (c. azimuth, 'f', 1) +
QString::fromLatin1 (" \xb0 ") + ";";
res += QString::number (c. altitude, 'f', 1) + "m;";
res += QString::number (c. height, 'f', 1) + "m;\n";
return res;
}
2024-04-07 14:58:26 +02:00
void RadioInterface::show_for_single_scan () {
2025-05-01 20:23:57 +02:00
QString headLine = build_kop ();
2024-01-27 20:16:14 +01:00
scanTable_p -> addLine (headLine);
2024-12-31 19:44:38 +01:00
scanTable_p -> addLine ("\n");
2025-05-01 20:23:57 +02:00
for (const auto &tr : channel. transmitters) {
QString transmitterLine = build_transmitterLine (tr);
2025-05-01 20:23:57 +02:00
scanTable_p -> addLine (transmitterLine);
}
2025-08-06 14:14:21 +02:00
basicPrint thePrinter;
QStringList s = thePrinter. print (theOFDMHandler -> contentPrint ());
2024-01-27 20:16:14 +01:00
for (const auto &l : s)
scanTable_p -> addLine (l);
scanTable_p -> addLine ("\n;\n;\n");
scanTable_p -> show ();
}
void RadioInterface::show_for_continuous () {
2025-01-05 13:11:25 +01:00
QString headLine = buildHeadLine ();
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 (const transmitter &tr) {
QString tii;
QString theName;
QString theDistance;
QString theCorner;
QString theHeight;
tii = idsToString (tr. mainId, tr. subId) + ";" ;
if (tr. transmitterName != "")
theName = tr. transmitterName;
else
2024-12-30 14:51:14 +01:00
theName = "";
if (tr. distance > 0) {
theDistance = QString::number (tr. distance, 'f', 1) + " km ";
theCorner = QString::number (tr. azimuth, 'f', 1)
2024-10-17 15:44:28 +02:00
+ QString::fromLatin1 (" \xb0 ");
theHeight = " (" + QString::number (tr. height, 'f', 1) + "m)";
}
else {
2024-12-31 19:44:38 +01:00
theName = "unknown";
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 () {
2025-05-27 18:50:45 +02:00
// do not activate mute timer if volume == 0
// but Volume is only defined with Qt_Audio
if ((soundOut_p -> is_QtAudio () && audioVolume == 0) &&
!muteTimer. isActive ())
2025-05-08 12:55:36 +02:00
return;
2024-01-27 20:16:14 +01:00
if (muteTimer. isActive ()) {
2025-01-05 13:11:25 +01:00
stopMuting ();
2024-01-27 20:16:14 +01:00
return;
}
if (!channel. audioActive)
return;
2025-01-05 13:11:25 +01:00
setSoundLabel (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);
}
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)
2025-01-05 13:11:25 +01:00
setSoundLabel (true);
2024-01-27 20:16:14 +01:00
}
}
2025-01-05 13:11:25 +01:00
void RadioInterface::stopMuting () {
2024-01-27 20:16:14 +01:00
if (!muteTimer. isActive ())
return;
2025-01-05 13:11:25 +01:00
setSoundLabel (true);
2024-01-27 20:16:14 +01:00
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
2025-01-05 13:11:25 +01:00
// newChannelIndex is called whenever we are sure that
2024-02-27 15:03:33 +01:00
// 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
2025-01-05 13:11:25 +01:00
void RadioInterface::newChannelIndex (int index) {
2024-01-27 20:16:14 +01:00
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 () {
QString scanButton_color =
value_s (dabSettings_p, COLOR_SETTINGS, SCAN_BUTTON + "_color",
2024-11-10 12:45:48 +01:00
GREEN);
2024-01-27 20:16:14 +01:00
QString scanButton_font =
value_s (dabSettings_p, COLOR_SETTINGS, SCAN_BUTTON + "_font",
2024-11-10 12:45:48 +01:00
BLACK);
2024-01-27 20:16:14 +01:00
QString spectrumButton_color =
value_s (dabSettings_p, COLOR_SETTINGS, SPECTRUM_BUTTON + "_color",
2024-11-10 12:45:48 +01:00
BLUE);
2024-01-27 20:16:14 +01:00
QString spectrumButton_font =
value_s (dabSettings_p, COLOR_SETTINGS, SPECTRUM_BUTTON + "_font",
2024-11-10 12:45:48 +01:00
BLACK);
2024-01-27 20:16:14 +01:00
QString scanListButton_color =
value_s (dabSettings_p, COLOR_SETTINGS, SCANLIST_BUTTON + "_color",
2024-11-10 12:45:48 +01:00
GREEN);
2024-01-27 20:16:14 +01:00
QString scanListButton_font =
value_s (dabSettings_p, COLOR_SETTINGS, SCANLIST_BUTTON + "_font",
2024-11-10 12:45:48 +01:00
BLACK);
2024-01-27 20:16:14 +01:00
QString presetButton_color =
value_s (dabSettings_p, COLOR_SETTINGS, PRESET_BUTTON + "_color",
2024-11-10 12:45:48 +01:00
GREEN);
2024-01-27 20:16:14 +01:00
QString presetButton_font =
value_s (dabSettings_p, COLOR_SETTINGS, PRESET_BUTTON + "_font",
2024-11-10 12:45:48 +01:00
BLACK);
2024-01-27 20:16:14 +01:00
QString prevServiceButton_color =
value_s (dabSettings_p, COLOR_SETTINGS,
2024-11-10 12:45:48 +01:00
PREVSERVICE_BUTTON + "_color", YELLOW);
2024-01-27 20:16:14 +01:00
QString prevServiceButton_font =
value_s (dabSettings_p, COLOR_SETTINGS,
2024-11-10 12:45:48 +01:00
PREVSERVICE_BUTTON + "_font", BLACK);
2024-01-27 20:16:14 +01:00
QString nextServiceButton_color =
value_s (dabSettings_p, COLOR_SETTINGS,
2024-11-10 12:45:48 +01:00
NEXTSERVICE_BUTTON + "_color", YELLOW);
2024-01-27 20:16:14 +01:00
QString nextServiceButton_font =
value_s (dabSettings_p, COLOR_SETTINGS,
2024-11-10 12:45:48 +01:00
NEXTSERVICE_BUTTON + "_font", BLACK);
2024-01-27 20:16:14 +01:00
QString configButton_color =
value_s (dabSettings_p, COLOR_SETTINGS, CONFIG_BUTTON + "_color",
2024-11-10 12:45:48 +01:00
YELLOW);
2024-01-27 20:16:14 +01:00
QString configButton_font =
value_s (dabSettings_p, COLOR_SETTINGS, CONFIG_BUTTON + "_font",
2024-11-10 12:45:48 +01:00
BLACK);
2024-01-27 20:16:14 +01:00
QString httpButton_color =
value_s (dabSettings_p, COLOR_SETTINGS, HTTP_BUTTON + "_color",
2024-11-10 12:45:48 +01:00
YELLOW);
2024-01-27 20:16:14 +01:00
QString httpButton_font =
value_s (dabSettings_p, COLOR_SETTINGS, HTTP_BUTTON + "_font",
2024-11-10 12:45:48 +01:00
BLACK);
2024-01-27 20:16:14 +01:00
2024-12-11 19:06:03 +01:00
QString tiiButton_color =
value_s (dabSettings_p, COLOR_SETTINGS, TII_BUTTON + "_color",
YELLOW);
QString tiiButton_font =
value_s (dabSettings_p, COLOR_SETTINGS, TII_BUTTON + "_font",
BLACK);
2024-01-27 20:16:14 +01:00
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));
2024-12-11 19:06:03 +01:00
tiiButton ->
setStyleSheet (temp. arg (tiiButton_color,
tiiButton_font));
2024-01-27 20:16:14 +01:00
prevServiceButton ->
setStyleSheet (temp. arg (prevServiceButton_color,
prevServiceButton_font));
nextServiceButton ->
setStyleSheet (temp. arg (nextServiceButton_color,
nextServiceButton_font));
}
void RadioInterface::color_scanButton () {
2025-01-05 13:11:25 +01:00
setButtonColors (scanButton, SCAN_BUTTON);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::color_spectrumButton () {
2025-01-05 13:11:25 +01:00
setButtonColors (spectrumButton, SPECTRUM_BUTTON);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::color_scanListButton () {
2025-01-05 13:11:25 +01:00
setButtonColors (scanListButton, SCANLIST_BUTTON);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::color_presetButton () {
2025-01-05 13:11:25 +01:00
setButtonColors (presetButton, PRESET_BUTTON);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::color_prevServiceButton () {
2025-01-05 13:11:25 +01:00
setButtonColors (prevServiceButton, PREVSERVICE_BUTTON);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::color_nextServiceButton () {
2025-01-05 13:11:25 +01:00
setButtonColors (nextServiceButton, NEXTSERVICE_BUTTON);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::color_configButton () {
2025-01-05 13:11:25 +01:00
setButtonColors (configButton, CONFIG_BUTTON);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::color_httpButton () {
2025-01-05 13:11:25 +01:00
setButtonColors (httpButton, HTTP_BUTTON);
2024-01-27 20:16:14 +01:00
}
2024-12-11 19:06:03 +01:00
void RadioInterface::color_tiiButton () {
2025-05-03 20:00:55 +02:00
setButtonColors (tiiButton, TII_BUTTON);
2024-12-11 19:06:03 +01:00
}
2025-01-05 13:11:25 +01:00
void RadioInterface::setButtonColors (QPushButton *b,
2024-01-27 20:16:14 +01:00
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";
QString baseColor_name = baseColor. name ();
QString textColor_name = textColor. name ();
store (dabSettings_p, COLOR_SETTINGS, buttonColor, baseColor_name);
store (dabSettings_p, COLOR_SETTINGS, buttonFont, textColor_name);
2024-01-27 20:16:14 +01:00
}
///////////////////////////////////////////////////////////////////////////
// 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
2025-07-11 12:48:10 +02:00
QStringList selectables = theEnsembleHandler -> getSelectables ();
2024-01-27 20:16:14 +01:00
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") {
2025-01-05 13:11:25 +01:00
scheduledAudioDumping ();
2024-01-27 20:16:14 +01:00
return;
}
if (s == "dlText") {
2025-01-05 13:11:25 +01:00
scheduledDLTextDumping ();
2024-01-27 20:16:14 +01:00
return;
}
if (s == "ficDump") {
2025-01-05 13:11:25 +01:00
scheduledFICDumping ();
2024-01-27 20:16:14 +01:00
return;
}
presetTimer. stop ();
stopScanning ();
scheduleSelect (s);
}
2025-01-05 13:11:25 +01:00
void RadioInterface::scheduledFICDumping () {
2025-07-24 14:59:25 +02:00
if (theOFDMHandler -> ficDumping_on ()) {
theOFDMHandler -> stopFicDump ();
2024-01-27 20:16:14 +01:00
return;
}
2025-07-24 14:59:25 +02:00
QString ficDumpFileName =
theFilenameFinder. find_ficDump_file (channel. channelName);
if (ficDumpFileName == "")
return;
theOFDMHandler -> startFicDump (ficDumpFileName);
2024-01-27 20:16:14 +01:00
}
//------------------------------------------------------------------------
//
// 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-06-01 11:12:04 +02:00
if (theSCANHandler. active ())
2024-01-27 20:16:14 +01:00
return;
2025-02-28 20:59:29 +01:00
if (value_i (dabSettings_p, CONFIG_HANDLER, "epgFlag", 0) != 1)
return;
2025-07-11 12:48:10 +02:00
QStringList epgList = theEnsembleHandler -> getEpgServices ();
2025-05-16 11:18:43 +02:00
for (auto &serv : epgList) {
2025-07-11 12:48:10 +02:00
int index = theOFDMHandler -> getServiceComp (serv);
2025-03-19 12:32:08 +01:00
if (index < 0)
continue;
if (theOFDMHandler -> serviceType (index) != PACKET_SERVICE)
continue;
2024-01-27 20:16:14 +01:00
packetdata pd;
2025-03-19 12:32:08 +01:00
theOFDMHandler -> packetData (index, pd);
2024-01-27 20:16:14 +01:00
if ((!pd. defined) ||
(pd. DSCTy == 0) || (pd. bitRate == 0))
continue;
if (pd. DSCTy == 60) {
2024-10-14 13:12:03 +02:00
// LOG hidden service starts
2025-02-25 20:32:17 +01:00
// fprintf (stderr, "Starting hidden service %s\n",
// serv. toUtf8 (). data ());
2025-02-23 11:54:05 +01:00
start_epgService (pd);
2024-01-27 20:16:14 +01:00
}
}
}
void RadioInterface::handle_timeTable () {
2025-07-11 12:48:10 +02:00
if (myTimeTable. isVisible ()) {
myTimeTable. clear ();
myTimeTable. hide ();
2024-01-27 20:16:14 +01:00
return;
}
2025-07-11 12:48:10 +02:00
if (!channel. currentService. isValid ||
!channel. currentService. isAudio)
2024-01-27 20:16:14 +01:00
return;
2025-07-11 12:48:10 +02:00
myTimeTable. setUp (channel. theDate, channel. Eid,
2025-02-28 20:59:29 +01:00
channel. currentService. SId,
2025-03-19 12:32:08 +01:00
channel. currentService. serviceName);
2025-02-28 20:59:29 +01:00
QPixmap p;
2025-03-19 12:32:08 +01:00
if (get_serviceLogo (p, channel. currentService. SId)) // this may be
2025-07-11 12:48:10 +02:00
myTimeTable. addLogo (p);
2024-01-27 20:16:14 +01:00
}
//----------------------------------------------------------------------
//
2025-01-05 13:11:25 +01:00
void RadioInterface::scheduledDLTextDumping () {
2024-01-27 20:16:14 +01:00
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 ();
store (dabSettings_p, DAB_GENERAL, CONFIG_WIDGET_VISIBLE, 0);
2024-01-27 20:16:14 +01:00
}
else {
2024-02-16 15:46:54 +01:00
configHandler_p -> show ();
store (dabSettings_p, DAB_GENERAL, CONFIG_WIDGET_VISIBLE, 1);
2024-01-27 20:16:14 +01:00
}
}
void RadioInterface::handle_devicewidgetButton () {
2025-05-29 12:51:05 +02:00
if (inputDevice_p. isNull ())
2024-01-27 20:16:14 +01:00
return;
int currentVisibility = inputDevice_p -> getVisibility ();
inputDevice_p -> setVisibility (!currentVisibility);
store (dabSettings_p, DAB_GENERAL, DEVICE_WIDGET_VISIBLE,
!currentVisibility);
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_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 ();
store (dabSettings_p, DAB_GENERAL, 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 =
value_f (dabSettings_p, MAP_HANDLING, HOME_LATITUDE, 0);
2024-02-16 15:46:54 +01:00
localPos. longitude =
value_f (dabSettings_p, MAP_HANDLING, HOME_LONGITUDE, 0);
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-06-01 11:12:04 +02:00
theTIIProcessor. reload ();
2025-01-13 19:13:10 +01:00
//dbLoader theLoader (dabSettings_p);
//
// if (theLoader. load_db ()) {
// QMessageBox::information (this, tr ("success"),
// tr ("Loading and installing database complete\n"));
// theTIIProcessor. reload ();
// }
// else {
// QMessageBox::information (this, tr ("fail"),
// tr ("Loading database failed\n"));
// }
2024-01-27 20:16:14 +01:00
}
2025-07-11 12:48:10 +02:00
void RadioInterface::stopSourceDumping () {
2024-07-29 20:19:31 +02:00
if (!sourceDumping)
return;
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_SOURCEDUMP_STOPS);
2025-07-11 12:48:10 +02:00
theOFDMHandler -> stopDumping();
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
}
2025-07-11 12:48:10 +02:00
void RadioInterface::startSourceDumping () {
QString deviceName = inputDevice_p -> deviceName ();
int bitDepth = inputDevice_p -> bitDepth ();
2024-01-27 20:16:14 +01:00
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;
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_SOURCEDUMP_STARTS,
deviceName, channelName);
2024-02-16 15:46:54 +01:00
configHandler_p -> mark_dumpButton (true);
2025-07-11 12:48:10 +02:00
theOFDMHandler -> startDumping (rawDumpName,
2025-08-19 15:10:33 +02:00
channel. tunedFrequency,
bitDepth,
inputDevice_p -> deviceName ());
2024-07-27 15:30:56 +02:00
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)
2025-07-11 12:48:10 +02:00
stopSourceDumping ();
2024-01-27 20:16:14 +01:00
else
2025-07-11 12:48:10 +02:00
startSourceDumping ();
2024-01-27 20:16:14 +01:00
}
void RadioInterface::handle_LoggerButton (int s) {
(void)s;
2024-02-16 15:46:54 +01:00
if (configHandler_p -> logger_active ()) {
2024-10-14 13:12:03 +02:00
theLogger. logging_starts ();
store (dabSettings_p, DAB_GENERAL, LOG_MODE, 1);
2024-01-27 20:16:14 +01:00
}
2024-10-14 13:12:03 +02:00
else {
theLogger. logging_stops ();
store (dabSettings_p, DAB_GENERAL, LOG_MODE, 0);
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
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) {
2025-05-29 12:51:05 +02:00
theOFDMHandler -> handleDecoderSelector (decoder);
2024-01-27 20:16:14 +01:00
}
void RadioInterface:: set_streamSelector (int k) {
if (!running. load ())
return;
QString str = configHandler_p -> currentStream ();
2024-11-20 16:33:31 +01:00
((audioSink *)(soundOut_p)) -> selectDevice (k, str);
store (dabSettings_p, SOUND_HANDLING, AUDIO_STREAM_NAME, str);
2024-01-27 20:16:14 +01:00
}
//
//////////////////////////////////////////////////////////////////////////
//
// Some, by far not all, ensembles are transmitted with a
// specification of the number of services carried
2024-01-27 20:16:14 +01:00
void RadioInterface::nrServices (int n) {
channel. serviceCount = n;
}
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 =
value_s (dabSettings_p, MAP_HANDLING, BROWSER_ADDRESS,
"http://localhost");
2024-04-19 18:34:50 +02:00
QString mapPort =
value_s (dabSettings_p, MAP_HANDLING, MAP_PORT_SETTING,
"8080");
2024-04-19 18:34:50 +02:00
mapHandler = new httpHandler (this,
mapPort,
browserAddress,
localPos,
"",
configHandler_p -> localBrowserSelector_active (), dabSettings_p);
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 =
value_s (dabSettings_p, MAP_HANDLING, BROWSER_ADDRESS,
"http://localhost");
2024-01-27 20:16:14 +01:00
QString mapPort =
value_s (dabSettings_p, MAP_HANDLING, MAP_PORT_SETTING,
"8080");
2024-01-27 20:16:14 +01:00
mapHandler = new httpHandler (this,
mapPort,
browserAddress,
2024-02-16 15:46:54 +01:00
localPos,
2024-12-11 19:06:03 +01:00
QString (""),
2024-04-16 15:18:29 +02:00
configHandler_p -> localBrowserSelector_active (), dabSettings_p);
2024-01-27 20:16:14 +01:00
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");
}
2024-10-18 19:36:29 +02:00
void RadioInterface::displaySlide (const QPixmap &p, const QString &t) {
int w = 320;
2024-12-11 19:06:03 +01:00
int h = 3 * w / 4;
2025-03-19 12:32:08 +01:00
if (channel. announcing)
return;
2024-03-13 19:45:53 +01:00
pauzeTimer. stop ();
2024-01-27 20:16:14 +01:00
pictureLabel -> setAlignment(Qt::AlignCenter);
2024-12-11 19:06:03 +01:00
if ((p. width () != 320) || (p. height () != 200))
pictureLabel ->
setPixmap (p. scaled (w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation));
else
pictureLabel -> setPixmap (p);
2024-10-18 19:36:29 +02:00
pictureLabel -> setToolTip (t);
2024-01-27 20:16:14 +01:00
pictureLabel -> show ();
}
void RadioInterface::show_pauzeSlide () {
QPixmap p;
QString slideName = ":res/radio-pictures/pauze-slide-%1.png";
2024-03-13 19:45:53 +01:00
pauzeTimer. stop ();
2024-10-21 09:42:45 +02:00
// int nr = rand () % 11;
2025-07-21 15:03:49 +02:00
slideName = slideName. arg (pauzeSlideTeller);
2024-10-18 19:36:29 +02:00
if (p. load (slideName, "png")) {
QString tooltipText;
2025-07-21 15:03:49 +02:00
switch (pauzeSlideTeller) {
2024-10-18 19:36:29 +02:00
case 2:
2024-10-21 09:42:45 +02:00
tooltipText = "homebrew 60-ies";
2024-10-18 19:36:29 +02:00
break;
case 3:
2024-10-21 09:42:45 +02:00
tooltipText = "homebrew 70-ies";
2024-10-18 19:36:29 +02:00
break;
case 4:
2024-10-21 09:42:45 +02:00
tooltipText = "Flee market in the 60-ies";
2024-10-18 19:36:29 +02:00
break;
case 5:
tooltipText = "The DEC PDP-11/60";
break;
case 6:
2024-10-21 09:42:45 +02:00
tooltipText = "the DEC PDP-1 mainframe";
2024-10-18 19:36:29 +02:00
break;
case 7:
2024-10-21 09:42:45 +02:00
tooltipText = "the DEC PDP-10 mainframe";
2024-10-18 19:36:29 +02:00
break;
case 8:
2024-10-21 09:42:45 +02:00
tooltipText = "the unforgettable DEC PDP-8";
2024-10-18 19:36:29 +02:00
break;
case 9:
2024-10-21 09:42:45 +02:00
tooltipText = "The DEC VAX 11/780";
2024-10-18 19:36:29 +02:00
break;
default:
tooltipText = "";
}
displaySlide (p, tooltipText);
}
2024-08-15 13:16:44 +02:00
pauzeTimer. start (1 * 30 * 1000);
2025-07-21 15:03:49 +02:00
pauzeSlideTeller = (pauzeSlideTeller + 1) % 11;
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 () {
if (channel. etiActive)
stop_etiHandler ();
else
start_etiHandler ();
}
void RadioInterface::stop_etiHandler () {
if (!channel. etiActive)
return;
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_ETI_STOPS);
2025-07-11 12:48:10 +02:00
theOFDMHandler -> stopEtiGenerator ();
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;
2024-10-14 13:12:03 +02:00
theLogger. log (logger::LOG_ETI_STARTS,
inputDevice_p -> deviceName (),
channel. channelName);
2025-07-11 12:48:10 +02:00
channel. etiActive = theOFDMHandler -> startEtiGenerator (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 (setting) {
2024-11-14 16:16:03 +01:00
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);
2025-08-14 22:00:06 +02:00
scanButton -> setEnabled (true);
2024-01-27 20:16:14 +01:00
scanButton -> setText ("eti");
2025-08-14 22:00:06 +02:00
// if (!inputDevice_p -> isFileInput ())// restore the button' visibility
2024-01-27 20:16:14 +01:00
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) {
2025-06-16 19:02:39 +02:00
std::vector<Complex> inBuffer (SAMPLERATE / 1000);
2024-01-27 20:16:14 +01:00
(void)amount;
2025-06-16 19:02:39 +02:00
if (theSpectrumBuffer. GetRingBufferReadAvailable () < SAMPLERATE / 1000)
2024-01-27 20:16:14 +01:00
return;
2025-06-16 19:02:39 +02:00
theSpectrumBuffer. getDataFromBuffer (inBuffer. data (), SAMPLERATE / 1000);
2024-06-01 11:12:04 +02:00
theSpectrumBuffer. FlushRingBuffer ();
if (!theNewDisplay. isHidden () &&
2025-01-06 20:47:14 +01:00
(theNewDisplay. getTab () == SHOW_SPECTRUM))
theNewDisplay. showSpectrum (inBuffer, channel. tunedFrequency);
2024-01-27 20:16:14 +01:00
}
2024-12-02 14:46:38 +01:00
void RadioInterface::handle_tiiThreshold (int v) {
store (dabSettings_p, CONFIG_HANDLER, TII_THRESHOLD, v);
2025-07-11 12:48:10 +02:00
theOFDMHandler -> setTIIThreshold (v);
2024-12-02 14:46:38 +01:00
}
2024-01-27 20:16:14 +01:00
void RadioInterface::show_tii_spectrum () {
2025-06-16 19:02:39 +02:00
std::vector<Complex> inBuffer (SAMPLERATE / 1000);
2024-01-27 20:16:14 +01:00
2025-06-16 19:02:39 +02:00
if (theTIIBuffer. GetRingBufferReadAvailable () < SAMPLERATE / 1000)
2024-01-27 20:16:14 +01:00
return;
2025-06-16 19:02:39 +02:00
theTIIBuffer. getDataFromBuffer (inBuffer. data (), SAMPLERATE / 1000);
2024-06-01 11:12:04 +02:00
theTIIBuffer. FlushRingBuffer ();
if (!theNewDisplay. isHidden () &&
2025-05-16 11:18:43 +02:00
(theNewDisplay. getTab () == SHOW_TII)) {
if (channel. subId != 0)
theNewDisplay. showTII (inBuffer,
channel. tunedFrequency, channel. subId);
else
theNewDisplay. showTII (inBuffer,
channel. tunedFrequency, -1);
}
2024-01-27 20:16:14 +01:00
}
void RadioInterface::showCorrelation (int s, int g, QVector<int> maxVals) {
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 ()) {
2025-01-06 20:47:14 +01:00
if (theNewDisplay. getTab () == SHOW_CORRELATION)
theNewDisplay. showCorrelation (inBuffer,
2024-12-11 19:06:03 +01:00
maxVals,
g,
channel. transmitters);
2024-01-27 20:16:14 +01:00
}
}
2024-04-03 18:44:52 +02:00
2024-12-11 19:06:03 +01:00
void RadioInterface::show_null (int amount, int startIndex) {
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 ())
2025-01-06 20:47:14 +01:00
if (theNewDisplay. getTab () == SHOW_NULL)
theNewDisplay. showNULL (inBuffer, amount, startIndex);
2024-01-27 20:16:14 +01:00
}
2024-12-02 14:46:38 +01:00
void RadioInterface::removeFromList (uint8_t mainId, uint8_t subId) {
for (uint16_t i = 0; i < channel. transmitters. size (); i ++)
if ((mainId == channel. transmitters [i]. mainId) &&
(subId == channel. transmitters [i]. subId)) {
2024-12-02 14:46:38 +01:00
channel. transmitters. erase
(channel. transmitters. begin () + i);
2024-12-02 14:46:38 +01:00
break;
}
}
2025-07-14 17:25:42 +02:00
//
transmitter *RadioInterface::inList (uint8_t mainId, uint8_t subId) {
2024-12-02 14:46:38 +01:00
for (auto &tr: channel. transmitters)
if ((tr. mainId == mainId) &&
(tr. subId == subId))
return &tr;
2024-12-02 14:46:38 +01:00
return nullptr;
}
2024-12-11 19:06:03 +01:00
void RadioInterface::show_tiiData (QVector<tiiData> r, int ind) {
2024-12-02 14:46:38 +01:00
2025-01-15 20:22:28 +01:00
(void)ind;
2024-12-02 14:46:38 +01:00
if (r. size () == 0)
return;
2024-01-27 20:16:14 +01:00
2024-10-09 17:57:23 +02:00
if (!dxMode) {
2024-10-15 16:10:55 +02:00
if (!theDXDisplay. isHidden ())
theDXDisplay. hide ();
2024-10-09 17:57:23 +02:00
}
2024-12-02 19:27:09 +01:00
// first step: are we going to process the data or not?
2024-12-02 14:46:38 +01:00
if (!running. load ()) // shouldn't be
return;
if ((localPos. latitude == 0) || (localPos. longitude == 0))
return;
if (!theTIIProcessor. has_tiiFile ())
2024-01-27 20:16:14 +01:00
return;
2025-07-14 17:25:42 +02:00
if (channel. Eid == 0)
2024-04-03 18:44:52 +02:00
return;
2024-12-02 14:46:38 +01:00
// probably yes, get the country code
2025-07-14 17:25:42 +02:00
if ((channel. countryName == "") && (channel. hasEcc)) {
2025-07-11 12:48:10 +02:00
QString country = find_ITU_code (channel. eccByte,
2024-01-27 20:16:14 +01:00
(channel. Eid >> 12) &0xF);
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-12-11 19:06:03 +01:00
// The data in the vector is sorted on signal strength
2024-12-02 19:27:09 +01:00
2024-12-02 14:46:38 +01:00
// first step
// see whether or not the data is already in the list
// if it is already
for (uint16_t i = 0; i < r. size (); i ++) {
2024-12-02 19:27:09 +01:00
if ((r [i]. mainId == 0) ||
2024-12-11 19:06:03 +01:00
(r [i]. mainId == 255))
2024-12-02 14:46:38 +01:00
continue;
2024-12-02 19:27:09 +01:00
//
2024-12-11 19:06:03 +01:00
// It the new TII data make sense and there is already
// an item in the transmitterList, then just check whether
2025-01-31 15:06:31 +01:00
// or not that item as recognized
transmitter *to = inList (r [i]. mainId, r [i]. subId);
2024-12-11 19:06:03 +01:00
if (to != nullptr) {
if (to -> transmitterName == "not in database") {
removeFromList (to -> mainId, to -> subId);
}
else {
to -> strength = r [i]. strength;
2025-01-15 20:22:28 +01:00
// need_to_print = false;
2024-12-11 19:06:03 +01:00
continue;
}
}
dbElement * tr =
2025-07-14 17:25:42 +02:00
channel. realChannel ?
theTIIProcessor. getTransmitter (channel. channelName,
channel. Eid,
r [i]. mainId, r [i]. subId):
theTIIProcessor. getTransmitter (channel. Eid,
r [i]. mainId, r [i]. subId);
transmitter theTransmitter (tr);
//
if (!tr -> valid) { // nothing found
2025-04-04 16:17:00 +02:00
if (!configHandler_p -> get_allTIISelector ())
continue;
theTransmitter. valid = false;
2025-04-01 19:25:23 +02:00
theTransmitter. ensemble = channel. ensembleName;
2024-12-02 14:46:38 +01:00
theTransmitter. mainId = r [i]. mainId;
theTransmitter. subId = r [i]. subId;
theTransmitter. pattern = r [i]. pattern;
theTransmitter. phase = r [i]. phase;
theTransmitter. norm = r [i]. norm;
2024-12-02 14:46:38 +01:00
theTransmitter. transmitterName = "not in database";
2025-01-11 14:46:55 +01:00
theTransmitter. distance = -1;
2024-12-11 19:06:03 +01:00
theTransmitter. strength = r [i]. strength;
theTransmitter. isStrongest = false;
// transmitterDesc t = {false, false, theTransmitter};
// channel. transmitters. push_back (t);
channel. transmitters. push_back (theTransmitter);
2024-12-02 14:46:38 +01:00
}
else {
// first copy the db data, theTransmitter is properly initalized
// with the db Calues, now the dynamics
theTransmitter. valid = true;
2024-11-29 20:31:44 +01:00
position thePosition;
2024-12-02 14:46:38 +01:00
thePosition. latitude = theTransmitter. latitude;
thePosition. longitude = theTransmitter. longitude;
2024-11-29 20:31:44 +01:00
theTransmitter. distance = distance (thePosition, localPos);
2024-12-02 14:46:38 +01:00
theTransmitter. azimuth = corner (thePosition, localPos);
2024-12-11 19:06:03 +01:00
theTransmitter. strength = r [i]. strength;
2024-12-18 20:45:47 +01:00
theTransmitter. phase = r [i]. phase;
theTransmitter. norm = r [i]. norm;
2025-01-05 13:11:25 +01:00
theTransmitter. collision = r [i]. collision;
theTransmitter. pattern = r [i]. pattern;
theTransmitter. isStrongest = false;
channel. transmitters. push_back (theTransmitter);
// transmitterDesc t = {true, false, theTransmitter};
// channel. transmitters. push_back (t);
2024-11-29 20:31:44 +01:00
}
2024-12-02 14:46:38 +01:00
if (dxMode)
2024-11-29 20:31:44 +01:00
addtoLogFile (&theTransmitter);
2025-01-15 20:22:28 +01:00
// need_to_print = true;
2024-01-27 20:16:14 +01:00
}
2024-12-11 19:06:03 +01:00
//
2024-12-02 14:46:38 +01:00
int bestIndex = -1;
float Strength = -100;
2024-12-02 14:46:38 +01:00
// Now the list is updated, see whether or not the strongest is ...
2025-03-20 18:23:52 +01:00
int teller = 0;
for (auto &transm : channel. transmitters) {
if (transm. valid &&
(transm. strength > Strength)) {
2025-03-20 18:23:52 +01:00
bestIndex = teller;
Strength = transm. strength;
}
2025-03-20 18:23:52 +01:00
transm. isStrongest = false;
teller ++;
2024-12-11 19:06:03 +01:00
}
2024-12-02 19:27:09 +01:00
2024-12-11 19:06:03 +01:00
if (bestIndex >= 0) {
channel. transmitters [bestIndex]. isStrongest = true;
2024-04-03 18:44:52 +02:00
}
2024-11-29 20:31:44 +01:00
//
2024-12-02 14:46:38 +01:00
// for content maps etc we need to have the data of the strongest
// signal
if (bestIndex >= 0) {
transmitter *ce = &channel. transmitters [bestIndex];
2024-12-02 14:46:38 +01:00
channel. mainId = ce -> mainId;
channel. subId = ce -> subId;
channel. transmitterName = ce -> transmitterName;
channel. height = ce -> height;
channel. distance = ce -> distance;
channel. azimuth = ce -> azimuth;
2024-12-02 14:46:38 +01:00
}
// if the list has somehow changed, rewrite it
if (dxMode) {
theDXDisplay. cleanUp ();
theDXDisplay. show ();
2025-04-02 18:30:53 +02:00
theDXDisplay. setChannel (channel. channelName,
channel. ensembleName);
2025-03-20 18:23:52 +01:00
int teller = 0;
for (auto &theTr : channel. transmitters) {
2025-04-05 12:59:05 +02:00
if (!configHandler_p -> get_allTIISelector ()) {
if (theTr. distance < 0) {
2025-04-04 16:17:00 +02:00
continue;
2025-04-05 12:59:05 +02:00
}
}
if (bestIndex == teller) {
QString labelText = createTIILabel (theTr);
distanceLabel -> setText (labelText);
}
theDXDisplay. addRow (theTr,
2025-03-20 18:23:52 +01:00
bestIndex == teller);
teller ++;
2024-12-11 19:06:03 +01:00
}
2024-12-02 14:46:38 +01:00
}
else { // just show on the main widget the strongest
for (auto &theTr: channel. transmitters) {
if (theTr. distance < 0)
2025-04-09 19:42:03 +02:00
continue;
2024-12-02 14:46:38 +01:00
if (theTr. isStrongest) {
QString labelText = createTIILabel (theTr);
2024-10-29 19:54:10 +01:00
distanceLabel -> setText (labelText);
2024-12-02 19:27:09 +01:00
break;
2024-12-01 14:36:25 +01:00
}
2024-10-29 19:54:10 +01:00
}
2024-10-17 15:44:28 +02:00
}
2024-12-02 14:46:38 +01:00
//
if (mapHandler == nullptr)
return;
2024-12-02 14:46:38 +01:00
//
2024-10-17 15:44:28 +02:00
for (auto &theTr : channel. transmitters) {
if (theTr. transmitterName == "not in database")
2024-04-03 18:44:52 +02:00
continue;
2024-01-27 20:16:14 +01:00
2025-04-24 13:36:09 +02:00
uint8_t key = configHandler_p -> showAll_Selector_active () ?
SHOW_ALL: SHOW_SINGLE;
2024-04-03 18:44:52 +02:00
QDateTime theTime =
2025-04-24 13:36:09 +02:00
configHandler_p -> utcSelector_active () ?
QDateTime::currentDateTimeUtc () :
QDateTime::currentDateTime ();
2025-02-16 10:37:57 +01:00
2024-10-17 15:44:28 +02:00
mapHandler -> putData (key,
theTr,
theTime. toString (Qt::TextDate));
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 ())
2025-01-06 20:47:14 +01:00
theNewDisplay. showCorrector (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 ())
2025-01-06 20:47:14 +01:00
theNewDisplay. showStdDev (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 ())
2025-01-06 20:47:14 +01:00
theNewDisplay. showSNR (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;
2025-01-06 20:47:14 +01:00
theNewDisplay. showQuality (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 ())
2025-07-11 12:48:10 +02:00
techWindow_p -> showRsCorrections (c, ec);
2024-01-27 20:16:14 +01:00
}
//
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 ()) {
2025-01-06 20:47:14 +01:00
theNewDisplay. showClock_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 () &&
2025-01-06 20:47:14 +01:00
(theNewDisplay. getTab () == SHOW_CHANNEL))
theNewDisplay. showChannel (v);
2024-01-27 20:16:14 +01:00
}
2024-12-11 19:06:03 +01:00
2024-01-27 20:16:14 +01:00
bool RadioInterface::channelOn () {
2024-06-01 11:12:04 +02:00
return (!theNewDisplay. isHidden () &&
2025-01-06 20:47:14 +01:00
(theNewDisplay. getTab () == SHOW_CHANNEL));
2024-01-27 20:16:14 +01:00
}
bool RadioInterface::devScopeOn () {
2024-06-01 11:12:04 +02:00
return !theNewDisplay. isHidden () &&
2025-01-06 20:47:14 +01:00
(theNewDisplay. getTab () == SHOW_STDDEV);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::handle_iqSelector () {
2025-05-29 12:51:05 +02:00
theOFDMHandler -> handleIQSelector ();
2024-01-27 20:16:14 +01:00
}
void RadioInterface::showPeakLevel (float iPeakLeft, float iPeakRight) {
2024-11-20 16:33:31 +01:00
auto peak_avr = [](float iPeak, float & ioPeakAvr) -> void {
ioPeakAvr = (iPeak > ioPeakAvr ? iPeak : ioPeakAvr - 0.5f /*decay*/);
};
2024-11-20 16:33:31 +01:00
peak_avr (iPeakLeft, peakLeftDamped);
peak_avr (iPeakRight, peakRightDamped);
2024-11-20 16:33:31 +01:00
leftAudio -> setValue (peakLeftDamped);
rightAudio -> setValue (peakRightDamped);
2024-01-27 20:16:14 +01:00
}
void RadioInterface::handle_presetButton () {
2025-07-11 12:48:10 +02:00
int mode = theEnsembleHandler -> getShowMode ();
2024-01-27 20:16:14 +01:00
if (inputDevice_p -> isFileInput ()) {
mode = SHOW_ENSEMBLE;
presetButton -> setText ("favorites");
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> setShowMode (mode);
2024-01-27 20:16:14 +01:00
return;
}
2024-03-13 19:45:53 +01:00
mode = mode == SHOW_ENSEMBLE ? SHOW_PRESETS : SHOW_ENSEMBLE;
2025-07-11 12:48:10 +02:00
theEnsembleHandler -> setShowMode (mode);
2024-04-19 18:34:50 +02:00
presetButton -> setText (mode == SHOW_ENSEMBLE ? "favorites" : "ensemble");
2024-01-27 20:16:14 +01:00
}
2025-01-05 13:11:25 +01:00
void RadioInterface::setSoundLabel (bool f) {
2024-01-27 20:16:14 +01:00
QPixmap p;
if (f)
p. load (":res/radio-pictures/volume_on.png", "png");
2024-01-27 20:16:14 +01:00
else
p. load (":res/radio-pictures/volume_off.png", "png");
2024-01-27 20:16:14 +01:00
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
2025-03-19 12:32:08 +01:00
void RadioInterface::handle_backgroundTask (const QString &service) {
2024-01-27 20:16:14 +01:00
audiodata ad;
2025-07-11 12:48:10 +02:00
int index = theOFDMHandler -> getServiceComp (service);
2025-03-19 12:32:08 +01:00
if (index < 0)
return;
if (theOFDMHandler -> serviceType (index) != AUDIO_SERVICE)
return;
theOFDMHandler -> audioData (index, ad);
if (!ad. defined)
2024-01-27 20:16:14 +01:00
return;
2025-03-20 18:23:52 +01:00
int teller = 0;
for (auto &task: channel. runningTasks) {
if (task. serviceName == service) {
2025-09-08 13:38:08 +02:00
theOFDMHandler -> stopService (service, ad. subchId, BACK_GROUND);
2025-03-20 18:23:52 +01:00
if (task. fd != nullptr)
fclose (task. fd);
2025-03-19 12:32:08 +01:00
channel. runningTasks. erase
2025-03-20 18:23:52 +01:00
(channel. runningTasks. begin () + teller);
2024-01-27 20:16:14 +01:00
return;
}
2025-03-20 18:23:52 +01:00
teller ++;
2024-01-27 20:16:14 +01:00
}
uint8_t audioType = ad. ASCTy;
FILE *f = theFilenameFinder. findFrameDump_fileName (service,
audioType, true);
2024-01-27 20:16:14 +01:00
if (f == nullptr)
return;
2024-06-01 11:12:04 +02:00
(void)theOFDMHandler ->
2025-01-06 20:47:14 +01:00
setAudioChannel (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. subChId = ad. subchId;
s. ASCTy = ad. ASCTy;
2024-01-27 20:16:14 +01:00
s. fd = f;
2025-03-19 12:32:08 +01:00
s. runsBackground = true;
channel. runningTasks. push_back (s);
2024-01-27 20:16:14 +01:00
}
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 ();
store (dabSettings_p, COLOR_SETTINGS, 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
void RadioInterface::show_dcOffset (float dcOffset) {
2025-01-06 20:47:14 +01:00
theNewDisplay. showDCOffset (dcOffset);
2024-02-25 14:18:27 +01:00
}
void RadioInterface::handle_techFrame_closed () {
store (dabSettings_p, DAB_GENERAL, TECHDATA_VISIBLE, 0);
2024-02-25 14:18:27 +01:00
}
void RadioInterface::handle_configFrame_closed () {
store (dabSettings_p, DAB_GENERAL, CONFIG_WIDGET_VISIBLE, 0);
2024-02-25 14:18:27 +01:00
}
void RadioInterface::handle_deviceFrame_closed () {
2024-11-12 20:24:17 +01:00
store (dabSettings_p, DAB_GENERAL, DEVICE_WIDGET_VISIBLE, 0);
2024-02-25 14:18:27 +01:00
}
void RadioInterface::handle_newDisplayFrame_closed () {
store (dabSettings_p, DAB_GENERAL, NEW_DISPLAY_VISIBLE, 0);
2024-02-25 14:18:27 +01:00
}
void RadioInterface::setVolume (int n) {
2025-05-08 12:55:36 +02:00
audioVolume = n;
if (n == 0)
2025-01-05 13:11:25 +01:00
setSoundLabel (false);
2025-05-08 12:55:36 +02:00
else {
if (muteTimer. isActive ()) {
muteTimer. stop ();
disconnect (&muteTimer, &QTimer::timeout,
this, &RadioInterface::muteButton_timeOut);
stillMuting -> hide ();
}
if (channel. audioActive)
setSoundLabel (true);
((Qt_Audio *)soundOut_p) -> setVolume (n);
2025-07-20 19:25:14 +02:00
store (dabSettings_p, SOUND_HANDLING, QT_AUDIO_VOLUME, audioVolume);
2025-05-08 12:55:36 +02:00
}
}
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 ();
2025-01-15 20:22:28 +01:00
store (dabSettings_p, CONFIG_HANDLER, S_CORRELATION_ORDER, b ? 1 : 0);
2025-05-29 12:51:05 +02:00
theOFDMHandler -> setCorrelationOrder (b);
2024-04-03 18:44:52 +02:00
}
2024-04-16 15:18:29 +02:00
void RadioInterface::channelSignal (const QString &channel) {
stopChannel ();
2025-04-24 13:36:09 +02:00
channelSelector -> setEnabled (false);
int k = channelSelector -> findText (channel);
if (k != -1)
channelSelector -> setCurrentIndex (k);
channelSelector -> setEnabled (true);
2024-04-16 15:18:29 +02:00
startChannel (channel);
}
2024-09-14 14:57:15 +02:00
void RadioInterface::show_changeLabel (const QStringList notInOld,
const QStringList notInNew) {
theLogger. log (logger::LOG_CONFIG_CHANGE);
2024-09-14 14:57:15 +02:00
if (notInOld. size () > 0) {
fprintf (stderr, "New service:\n");
2025-05-16 11:18:43 +02:00
for (auto &s: notInOld)
2024-09-14 14:57:15 +02:00
fprintf (stderr, "\t%s\n", s. toUtf8 (). data ());
}
if (notInNew. size () > 0) {
fprintf (stderr, "removed service:\n");
2025-05-16 11:18:43 +02:00
for (auto &s: notInNew)
2024-09-14 14:57:15 +02:00
fprintf (stderr, "\t%s\n", s. toUtf8 (). data ());
}
}
2024-10-14 15:35:13 +02:00
void RadioInterface::handle_folderButton () {
QString tempPath = theFilenameFinder. basicPath ();
#ifdef __MINGW32__
2024-10-14 17:52:41 +02:00
LPCWSTR temp = (const wchar_t *)tempPath. utf16 ();
2024-10-17 15:44:28 +02:00
ShellExecute (nullptr, L"open", temp,
nullptr, nullptr, SW_SHOWDEFAULT);
2024-10-14 15:35:13 +02:00
#else
std::string x = "xdg-open " + tempPath. toStdString ();
2024-10-17 15:44:28 +02:00
(void)system (x. c_str ());
2024-10-14 15:35:13 +02:00
#endif
}
2025-04-02 18:30:53 +02:00
const char *directionTable [] = {
"N", "NE", "E", "SE", "S", "SW", "W", "NW", "N"};
QString fromAzimuth_toDirection (float azimuth) {
int direction = (azimuth) / 22.5;
return directionTable [(direction + 1) / 2];
}
QString RadioInterface::createTIILabel (const transmitter &theTransmitter) {
uint8_t mainId = theTransmitter. mainId;
uint8_t subId = theTransmitter. subId;
const QString & theTransmitterName
= theTransmitter. transmitterName;
float theDistance = theTransmitter. distance;
float theAzimuth = theTransmitter. azimuth;
2025-04-02 18:30:53 +02:00
QString direction = fromAzimuth_toDirection (theAzimuth);
// int theAltitude = theTransmitter. altitude;
// int theHeight = theTransmitter. height;
// float thePower = theTransmitter. power;
2024-11-29 20:31:44 +01:00
QString labelText = "(" + QString::number (mainId) + ","
+ QString::number (subId) + ") ";
labelText += theTransmitterName;
2025-05-03 11:10:32 +02:00
labelText += QString (" ")
+ "(" + direction + ") "
2024-11-29 20:31:44 +01:00
+ QString::number (theDistance, 'f', 1) + " km "
+ QString::number (theAzimuth, 'f', 1)
2025-05-03 20:00:55 +02:00
+ QString::fromLatin1 (" \xb0 ");
// + "altitude " + QString::number (theAltitude) + "m "
// + "transmitter height " + QString::number (theHeight) + "m "
// + "transmitter power " + QString::number (thePower, 'f', 1) + "kW";
2024-11-29 20:31:44 +01:00
return labelText;
}
void RadioInterface::addtoLogFile (const transmitter &theTransmitter) {
2024-11-29 20:31:44 +01:00
FILE *theFile = nullptr;
bool exists = false;
if ((theTransmitter. mainId == 0) ||
(theTransmitter. mainId == 255))
2024-12-01 14:36:25 +01:00
return;
QString fileName = path_for_files + "tii-files.csv";
2024-12-02 14:46:38 +01:00
theFile = fopen (fileName. toLatin1 (). data (), "r");
if (theFile != nullptr) {
2024-11-29 20:31:44 +01:00
exists = true;
fclose (theFile);
}
theFile = fopen (fileName. toLatin1 (). data (), "a");
if (theFile == nullptr)
return;
if (!exists)
2024-11-30 14:58:29 +01:00
fprintf (theFile, "date; channel; ensemble; transmitter; coords; mainId; subId;distance (km);azimuth;Power;altitude;height;direction\n\n");
2024-11-29 20:31:44 +01:00
2024-12-01 14:36:25 +01:00
QDateTime theTime;
QString tod = theTime. currentDateTime (). toString ();
// QString symb = QString::fromLatin1 (" \xb0 ");
QString symb = "";
2024-11-29 20:31:44 +01:00
fprintf (theFile, "%s;\"%s\";\"%s\";\"%s\"; \"(%f, %f)\";\"%d\";\"%d\";\"%.1f km\";\"%.1f %s\" ;\"%.1f kW\";\"%d m\";\"%d m\";\"%s\"\n",
2024-12-01 14:36:25 +01:00
tod. toLatin1 (). data (), // the time
theTransmitter. channel. toLatin1 (). data (),
theTransmitter. ensemble. toLatin1 (). data (), +
theTransmitter. transmitterName. toLatin1 (). data (),
theTransmitter. latitude,
theTransmitter. longitude,
theTransmitter. mainId,
theTransmitter. subId,
theTransmitter. distance,
theTransmitter. azimuth, symb. toLatin1 (). data (),
theTransmitter. power,
(int)(theTransmitter. altitude),
(int)(theTransmitter. height),
theTransmitter. direction. toLatin1 (). data ());
2024-11-29 20:31:44 +01:00
fclose (theFile);
}
2024-12-11 19:06:03 +01:00
void RadioInterface::handle_tiiButton () {
dxMode = !dxMode;
store (dabSettings_p, CONFIG_HANDLER, S_DX_MODE, dxMode ? 1 : 0);
theDXDisplay. cleanUp ();
2024-12-11 19:06:03 +01:00
if (!dxMode) {
theDXDisplay. hide ();
2025-05-03 20:00:55 +02:00
tiiButton -> setText ("dx display");
2024-12-11 19:06:03 +01:00
}
if (dxMode) {
distanceLabel -> setText ("");
theDXDisplay. show ();
2025-05-03 20:00:55 +02:00
tiiButton -> setText ("tii local");
2024-12-11 19:06:03 +01:00
}
2025-01-06 20:47:14 +01:00
theOFDMHandler -> setDXMode (dxMode);
2024-12-11 19:06:03 +01:00
}
2025-01-02 09:41:23 +01:00
void RadioInterface::handle_tiiCollisions (int b) {
2025-07-11 12:48:10 +02:00
theOFDMHandler -> setTIICollisions (b);
2024-12-30 14:51:14 +01:00
}
void RadioInterface::handle_tiiFilter (bool b) {
2025-07-11 12:48:10 +02:00
theOFDMHandler -> setTIIFilter (b);
2024-12-30 14:51:14 +01:00
}
2025-01-06 20:47:14 +01:00
void RadioInterface::process_tiiSelector (bool b) {
2025-07-11 12:48:10 +02:00
theOFDMHandler -> selectTII (b ? 1 : 0);
2025-01-06 20:47:14 +01:00
}
2024-12-30 14:51:14 +01:00
2025-01-10 14:24:41 +01:00
void RadioInterface::deviceListChanged () {
#ifndef TCP_STREAMER
QStringList streams = ((Qt_Audio *)soundOut_p) -> streams ();
configHandler_p -> fill_streamTable (streams);
configHandler_p -> show_streamSelector (true);
#endif
}
2025-02-16 10:37:57 +01:00
//
/////////////////////////////////////////////////////////////////////////
//
2025-03-05 16:34:15 +01:00
// Handling epg/spi
/////////////////////////////////////////////////////////////////////////
2025-02-15 17:53:47 +01:00
void RadioInterface::extractServiceInformation (const QDomDocument &doc,
uint32_t Eid, bool fresh) {
2025-02-15 17:53:47 +01:00
QDomElement root = doc. firstChildElement ("serviceInformation");
2025-02-15 19:30:50 +01:00
for (QDomElement theElement = root. firstChildElement ("");
!theElement. isNull ();
theElement = theElement. nextSiblingElement ("")) {
2025-02-25 20:32:17 +01:00
if (theElement. tagName () == "ensemble") {
2025-02-28 20:59:29 +01:00
bool ok = false;
2025-03-09 10:46:43 +01:00
QString Ident = theElement. attribute ("Eid");
2025-03-01 13:23:23 +01:00
uint32_t ensemble = Ident. toInt (&ok, 16);
2025-03-20 18:23:52 +01:00
// fprintf (stderr, "Comparing %X and %X\n",
// Eid, ensemble);
2025-02-28 20:59:29 +01:00
if (Eid != ensemble)
2025-02-25 20:32:17 +01:00
continue;
if (process_ensemble (theElement, Eid) && fresh)
saveServiceInfo (doc, Eid);
2025-02-25 20:32:17 +01:00
}
2025-02-15 19:30:50 +01:00
else
if (theElement. tagName () == "service")
2025-07-20 19:25:14 +02:00
processService (theElement);
2025-02-14 19:33:17 +01:00
}
}
void RadioInterface::saveServiceInfo (const QDomDocument &doc,
uint32_t Eid) {
QString fileName = path_for_files;
if (!fileName. endsWith ("/"))
fileName = fileName + "/";
2025-03-06 13:20:13 +01:00
fileName += QString::number (Eid, 16). toUpper () + "/list.xml";
QFile file (QDir::toNativeSeparators (fileName));
if (file. open (QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream (&file);
stream << doc. toString ();
file. close ();
}
}
2025-02-25 20:32:17 +01:00
bool RadioInterface::process_ensemble (const QDomElement &node,
2025-02-14 19:33:17 +01:00
uint32_t Eid) {
int picturesSeen = 0;
2025-02-14 19:33:17 +01:00
QString Ident = node. attribute ("Eid");
2025-03-06 13:20:13 +01:00
bool ok = false;
uint32_t attrib = Ident. toInt (&ok, 16);
if (!ok || (Eid != attrib))
2025-02-25 20:32:17 +01:00
return false;
2025-02-14 19:33:17 +01:00
QDomElement nameNode =
node. firstChildElement ("mediumName");
2025-02-25 20:32:17 +01:00
QString ensembleName = nameNode. text ();
2025-02-14 19:33:17 +01:00
for (QDomElement service = node. firstChildElement ("service");
!service. isNull ();
service = service. nextSiblingElement ("service")) {
2025-07-20 19:25:14 +02:00
picturesSeen += processService (service);
2025-02-15 19:30:50 +01:00
}
return picturesSeen > 0;
2025-02-25 20:32:17 +01:00
}
2025-05-29 12:51:05 +02:00
bool containsPicture (mmDescriptor &set, multimediaElement &m) {
2025-02-25 20:32:17 +01:00
for (auto &mm : set. elements) {
if ((mm. url == m. url) && (mm. width == m. width))
return true;
}
return false;
2025-02-15 19:30:50 +01:00
}
2025-07-20 19:25:14 +02:00
int RadioInterface::processService (const QDomElement &service) {
2025-02-25 20:32:17 +01:00
mmDescriptor pictures;
uint32_t serviceId =
2025-02-14 19:33:17 +01:00
xmlHandler. serviceSid (service);
2025-02-25 20:32:17 +01:00
pictures. serviceId = serviceId;
QDomElement mediaDescription =
service. firstChildElement ("mediaDescription");
while (!mediaDescription. isNull ()) {
QDomElement multimedia =
mediaDescription. firstChildElement ("multimedia");
multimediaElement mE = xmlHandler. extract_multimedia (multimedia);
if (mE. valid) {
pictures. elements. push_back (mE);
2025-02-15 17:53:47 +01:00
}
2025-02-25 20:32:17 +01:00
2025-03-05 16:34:15 +01:00
mediaDescription = mediaDescription.
nextSiblingElement ("mediaDescription");
2025-02-25 20:32:17 +01:00
}
for (auto &pictureElement: channel. servicePictures) {
uint32_t serviceId = pictureElement. serviceId;
if (pictures. serviceId != serviceId)
continue;
for (auto &me : pictures. elements) {
if (!containsPicture (pictureElement, me)) {
2025-02-25 20:32:17 +01:00
pictureElement. elements. push_back (me);
break;
}
}
2025-02-15 17:53:47 +01:00
}
2025-02-25 20:32:17 +01:00
channel. servicePictures. push_back (pictures);
return pictures. elements. size ();
2025-02-15 17:53:47 +01:00
}
2025-02-16 10:37:57 +01:00
//
2025-02-25 20:32:17 +01:00
static
int mcmp (const void *a, const void *b) {
multimediaElement *aa = (multimediaElement *)a;
multimediaElement *bb = (multimediaElement *)b;
if (aa -> width < bb -> width)
return 1;
if (aa -> width > bb -> width)
return -1;
return 0;
}
//
// we want the largest pictures, so we sort the list
2025-03-19 12:32:08 +01:00
bool RadioInterface::get_serviceLogo (QPixmap &p, uint32_t SId) {
2025-02-15 17:53:47 +01:00
bool res = false;
for (auto &ss : channel. servicePictures) {
2025-03-20 18:23:52 +01:00
// fprintf (stderr, "comparing %X with %X\n",
// ss. serviceId, SId);
2025-03-19 12:32:08 +01:00
if (ss. serviceId != SId)
2025-02-25 20:32:17 +01:00
continue;
QVector<multimediaElement> options;
for (auto &ff: ss. elements)
options. push_back (ff);
qsort (options. data (), options. size (),
sizeof (multimediaElement), &mcmp);
for (auto &ff: options) {
2025-03-06 13:20:13 +01:00
QString pict = path_for_files + QString::number (channel. Eid, 16). toUpper ()+ "/" + ff. url;
2025-02-15 17:53:47 +01:00
FILE *tt = fopen (pict. toLatin1 (). data (), "r + b");
if (tt == nullptr)
2025-02-25 20:32:17 +01:00
continue;
2025-02-15 17:53:47 +01:00
fclose (tt);
bool res = p. load (pict, "png");
return res;
}
}
return res;
}
2025-02-16 10:37:57 +01:00
//
2025-02-25 20:32:17 +01:00
void RadioInterface::read_pictureMappings (uint32_t Eid) {
QString fileName = path_for_files;
if (!fileName. endsWith ("/"))
fileName += "/";
2025-03-06 13:20:13 +01:00
fileName += QString::number (Eid, 16). toUpper () + "/list.xml";
2025-02-25 20:32:17 +01:00
QDomDocument pictureMappings;
2025-02-15 17:53:47 +01:00
QFile f (fileName);
2025-02-25 20:32:17 +01:00
if (!f. open (QIODevice::ReadOnly))
return;
pictureMappings. setContent (&f);
extractServiceInformation (pictureMappings, Eid, false);
}
2025-03-05 16:34:15 +01:00
//
2025-03-19 12:32:08 +01:00
void RadioInterface::lto_ecc (int lto, int ecc) {
2025-07-11 12:48:10 +02:00
channel. eccByte = ecc;
channel. hasEcc = true;
2025-05-29 12:51:05 +02:00
channel. lto = lto;
2025-03-19 10:08:05 +01:00
}
2025-03-19 12:32:08 +01:00
void RadioInterface::setFreqList () {
2025-05-29 12:51:05 +02:00
std::vector<int> freqList =
theOFDMHandler -> getFrequency (channel.
2025-03-19 12:32:08 +01:00
currentService. serviceName);
if (freqList. size () == 0)
2025-03-19 12:32:08 +01:00
return;
channel. currentService. fmFrequencies = freqList;
techWindow_p -> updateFM (freqList);
2025-03-19 12:32:08 +01:00
}
2025-09-05 19:54:10 +02:00
void RadioInterface::handle_dcRemoval (bool b) {
theOFDMHandler -> set_dcRemoval (b);
2025-09-06 19:12:13 +02:00
theNewDisplay. set_dcRemoval (b);
2025-09-05 19:54:10 +02:00
}
2025-09-10 18:05:28 +02:00
//
// Experimental code for handling DL2 data
2025-09-09 17:42:31 +02:00
static QString previousComposer;
static uint8_t old_IT = 0;
void RadioInterface::show_dl2 (uint8_t ct, uint8_t IT,
2025-06-09 15:04:46 +02:00
const QString &s) {
2025-09-09 17:42:31 +02:00
static QString title = "";
static QString composer = "";
static QString stationName = "";
static QString programNow = "";
2025-09-10 18:05:28 +02:00
if (IT != old_IT) {
title = "";
composer = "";
stationName = "";
programNow = "";
}
old_IT = IT;
2025-09-09 17:42:31 +02:00
if (!configHandler_p -> get_saveTitles ())
return;
QString fileName = theFilenameFinder. basicPath ();
if (!fileName. endsWith ("/"))
fileName += "/";
fileName += "DL2_titles.csv";
QDateTime theTime = QDateTime::currentDateTime ();
QString currentService = channel. currentService. serviceName;
2025-09-10 18:05:28 +02:00
QString ensemble = channel. ensembleName;
QString channelName = channel. channelName;
QString front = theTime. toString () + ";" +
channelName + ";" +
ensemble + ";" + currentService + ";";;
QString res;
2025-09-09 17:42:31 +02:00
switch (ct) {
case 1: // the title
title = s;
if (composer != "") {
2025-09-10 18:05:28 +02:00
res = front + title + ";" + composer + ";";
2025-09-09 17:42:31 +02:00
title = "";
composer = "";
}
break;
case 4: // the artist
case 8: // the composer
case 9: // the band
if (previousComposer == "")
previousComposer = s;
else
if (previousComposer. startsWith (s) ||
s. startsWith (previousComposer) ||
s == previousComposer)
break;
previousComposer = s;
composer = s;
if (title != "") {
2025-09-10 18:05:28 +02:00
res = front + title + ";" + composer + ";";
2025-09-09 17:42:31 +02:00
title = "";
composer = "";
}
break;
case 31: // stationname short
case 32: // stationname long
stationName = s;
if (programNow != "") {
2025-09-10 18:05:28 +02:00
res = front + stationName + ";" + programNow + ";";
2025-09-09 17:42:31 +02:00
stationName = "";
programNow = "";
}
break;
case 33: // program now
programNow = s;
if (stationName != "") {
2025-09-10 18:05:28 +02:00
res = front + stationName + ";" + programNow + ";";
2025-09-09 17:42:31 +02:00
stationName = "";
programNow = "";
}
break;
default:
break;
}
if (res != "") {
FILE *dlTextFile = fopen (fileName. toUtf8 (). data (), "a+");
if (dlTextFile != nullptr) {
fprintf (dlTextFile, "%s\n", res. toLatin1 (). data ());
fclose (dlTextFile);
}
}
2025-06-09 15:04:46 +02:00
}
2025-07-25 21:02:40 +02:00
void RadioInterface::nrActiveServices (int n) {
configHandler_p -> set_activeServices (n);
2025-07-24 14:59:25 +02:00
}
2025-07-27 11:35:19 +02:00
//
/////////////////////////////////////////////////////////////////////////////
//
// work in progress
void RadioInterface::handle_activeServices () {
QList<contentType> serviceData = theOFDMHandler -> contentPrint ();
bool serviceAvailable = false;
for (auto &ct : serviceData) {
if (theOFDMHandler -> serviceRuns (ct. SId, ct. subChId)) {
serviceAvailable = true;
2025-08-15 18:51:36 +02:00
// fprintf (stderr, "Service %s (%X, %d) runs\n",
// ct. serviceName. toLatin1 (). data (),
// ct. SId, ct. subChId);
}
}
(void)serviceAvailable;
}
2025-09-08 13:38:08 +02:00
//////////////////////////////////////////////////////////////////
// handling journaline //
void RadioInterface::startJournaline (int currentKey) {
if (!journalineHandler. isNull ())
return;
journalineHandler. reset (new journaline_dataHandler ());
journalineKey = currentKey;
}
void RadioInterface::stopJournaline (int currentKey) {
if (journalineHandler. isNull ())
return;
if (journalineKey != currentKey)
fprintf (stderr, "What is happenng here %d %d\n",
journalineKey, currentKey);
journalineHandler. reset ();
journalineKey = -1;
}
void RadioInterface::journalineData (QByteArray data,
int currentKey) {
if (journalineHandler. isNull ())
return;
if (currentKey != journalineKey)
return;
std::vector<uint8_t> theMscdata (data. size());
for (int i = 0; i < data. size (); i ++)
theMscdata [i] = data [i];
journalineHandler -> add_mscDatagroup (theMscdata);
}
2025-09-15 16:06:38 +02:00
void RadioInterface::focusInEvent (QFocusEvent *evt) {
}
2025-09-19 19:52:42 +02:00
//
// This function is called whenever a key is touched
// that is not the return key
bool RadioInterface::handle_keyEvent (int theKey) {
switch (theKey) {
case Qt::Key_F1:
theEnsembleHandler -> activateWindow ();
theEnsembleHandler -> setFocus ();
return true;
2025-09-15 16:06:38 +02:00
2025-09-19 19:52:42 +02:00
case Qt::Key_F2:
configHandler_p -> activateWindow ();
configHandler_p -> setFocus ();
return true;
case Qt::Key_F3:
techWindow_p -> activateWindow ();
techWindow_p -> setFocus ();
return true;
case Qt::Key_F4:
this -> activateWindow ();
this -> setFocus ();
return true;
case Qt::Key_F6:
if (theEnsembleHandler -> hasFocus ()) {
this -> activateWindow ();
this -> setFocus ();
return true;
}
else
if (this -> hasFocus ()) {
configHandler_p -> activateWindow ();
configHandler_p -> setFocus ();
return true;
}
else
if (configHandler_p -> hasFocus ()) {
techWindow_p -> activateWindow ();
techWindow_p -> setFocus ();
return true;
}
else
if (techWindow_p -> hasFocus ()) {
theEnsembleHandler -> activateWindow ();
theEnsembleHandler -> setFocus ();
return true;
}
else
return false;
default:
return false;
}
}