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>
2025-03-02 16:10:05 +01:00
# 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"
2025-08-05 18:30:03 +02:00
# 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"
2024-11-09 10:53:40 +01:00
# 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
2025-01-27 19:41:03 +01:00
# include <QScreen>
2025-02-12 14:08:44 +01:00
# include <QDomElement>
2025-01-27 19:41:03 +01:00
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 ) {
2024-04-10 19:49:55 +02:00
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 =
2024-11-09 10:53:40 +01:00
value_i ( dabSettings_p , DAB_GENERAL , " dabMode " , 1 ) ;
2024-01-27 20:16:14 +01:00
globals . threshold =
2024-11-09 10:53:40 +01:00
value_i ( dabSettings_p , DAB_GENERAL , " threshold " , 3 ) ;
2024-01-27 20:16:14 +01:00
globals . diff_length =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
value_i ( dabSettings_p , DAB_GENERAL , " tii_depth " , 4 ) ;
2024-01-27 20:16:14 +01:00
globals . echo_depth =
2024-11-09 10:53:40 +01:00
value_i ( dabSettings_p , DAB_GENERAL , " echo_depth " , 1 ) ;
2024-01-27 20:16:14 +01:00
# ifdef _SEND_DATAGRAM_
2024-11-09 10:53:40 +01:00
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
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 ;
2024-11-09 10:53:40 +01:00
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 ) ) ;
2024-11-09 10:53:40 +01:00
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 ) ) ;
2024-11-09 10:53:40 +01:00
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 " ) ;
2024-11-09 10:53:40 +01:00
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-02 16:10:05 +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 ,
2024-04-10 19:49:55 +02:00
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 ,
2024-04-10 19:49:55 +02:00
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 ,
2024-11-09 10:53:40 +01:00
this , & RadioInterface : : localSelect ) ;
2025-07-11 12:48:10 +02:00
connect ( theEnsembleHandler . data ( ) ,
2024-04-10 19:49:55 +02:00
& 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 ) ) ;
2024-04-10 19:49:55 +02:00
2025-05-27 18:50:45 +02:00
connect ( techWindow_p . data ( ) , & techData : : frameClosed ,
2024-04-10 19:49:55 +02:00
this , & RadioInterface : : handle_techFrame_closed ) ;
2024-02-25 14:18:27 +01:00
2024-11-09 10:53:40 +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
2024-11-09 10:53:40 +01:00
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} " ) ;
2025-03-02 16:10:05 +01:00
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 ) ;
2025-03-02 16:10:05 +01:00
channel . cleanChannel ( ) ;
2024-02-16 15:46:54 +01:00
localPos . latitude =
2024-11-09 10:53:40 +01:00
value_f ( dabSettings_p , MAP_HANDLING , HOME_LATITUDE , 0.0 ) ;
2024-02-16 15:46:54 +01:00
localPos . longitude =
2024-11-09 10:53:40 +01:00
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 ) ;
2024-11-09 10:53:40 +01:00
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 ;
2024-11-09 10:53:40 +01:00
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
2024-03-24 14:07:49 +01:00
try {
2024-11-22 20:21:44 +01:00
soundOut_p = new Qt_Audio ( this , dabSettings_p ) ;
2024-03-24 14:07:49 +01:00
streams = ( ( Qt_Audio * ) soundOut_p ) - > streams ( ) ;
temp =
2024-11-09 10:53:40 +01:00
value_s ( dabSettings_p , SOUND_HANDLING ,
2024-11-22 20:21:44 +01:00
AUDIO_STREAM_NAME , " default " ) ;
2024-03-24 14:07:49 +01:00
volumeSlider - > show ( ) ;
2025-05-08 12:55:36 +02:00
audioVolume =
2024-11-09 10:53:40 +01:00
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 ) ;
2024-04-10 19:49:55 +02:00
connect ( volumeSlider , & QSlider : : valueChanged ,
this , & RadioInterface : : setVolume ) ;
2024-03-24 14:07:49 +01:00
} 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
2024-03-24 14:07:49 +01:00
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 =
2025-03-02 16:10:05 +01:00
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 ) ;
}
2024-03-24 14:07:49 +01:00
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
2025-03-02 16:10:05 +01:00
QString tempPath = theFilenameFinder . basicPath ( ) ;
2024-11-09 10:53:40 +01:00
path_for_files =
value_s ( dabSettings_p , DAB_GENERAL ,
S_FILE_PATH , tempPath ) ;
2025-03-02 16:10:05 +01:00
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 ( ) )
2025-06-02 19:54:05 +02:00
configHandler_p - > enable_loadLib ( ) ;
2025-01-13 19:13:10 +01:00
else
2025-06-02 19:54:05 +02:00
httpButton - > setEnabled ( false ) ;
2024-01-27 20:16:14 +01:00
channel . etiActive = false ;
2025-02-23 11:54:05 +01:00
QPixmap epgP ;
2025-03-02 16:10:05 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 ;
2025-03-02 16:10:05 +01:00
peakRightDamped = - 100 ;
2024-11-20 16:33:31 +01:00
2025-03-02 16:10:05 +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 ) ;
2025-03-02 16:10:05 +01:00
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 =
2024-11-09 10:53:40 +01:00
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
2024-11-09 10:53:40 +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 ( ) ;
2024-11-09 10:53:40 +01:00
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
//
2025-01-29 19:39:38 +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
2024-11-09 10:53:40 +01:00
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 ,
2025-01-29 19:39:38 +01:00
# 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 ) ;
2024-11-09 10:53:40 +01:00
QString startingChannel =
value_s ( dabSettings_p , DAB_GENERAL , CHANNEL_NAME , " 5A " ) ;
int k = channelSelector - > findText ( startingChannel ) ;
if ( k ! = - 1 )
channelSelector - > setCurrentIndex ( k ) ;
2025-01-29 19:39:38 +01:00
# 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 ( ) ,
2025-01-29 19:39:38 +01:00
& 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 ( ) ;
2025-05-16 14:26:34 +02:00
if ( theSCANHandler . dumpInFile ( ) ) {
2025-05-16 19:16:32 +02:00
inputDevice_p - > startDump ( ) ;
2025-05-16 14:26:34 +02:00
}
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 ) {
2025-08-06 12:32:05 +02:00
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
2025-03-02 16:10:05 +01:00
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-02 16:10:05 +01:00
2025-03-05 16:34:15 +01:00
if ( docType = = serviceInformationType ) {
extractServiceInformation ( epgDocument , channel . Eid , true ) ;
return ;
}
2025-03-02 16:10:05 +01:00
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 ;
}
}
2025-03-02 16:10:05 +01:00
//
// 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 ( " . " ) ;
2025-03-02 16:10:05 +01:00
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 + + ) {
2025-03-02 16:10:05 +01:00
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 ) ;
2025-03-02 16:10:05 +01:00
if ( name ! = " " ) {
2025-03-05 19:52:36 +01:00
return env + dateString + " _ " + sidString . toUpper ( ) + " _SI.xml " ;
2025-03-02 16:10:05 +01:00
}
}
}
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 ,
2025-06-02 19:54:05 +02:00
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 ,
2024-11-09 10:53:40 +01:00
SAVE_SLIDES_SETTING , 0 ) ! = 0 ) & &
2025-03-02 16:10:05 +01:00
( path_for_files ! = " " ) ) ) {
2025-02-15 17:53:47 +01:00
QString pict ;
if ( ! dirs )
2025-03-02 16:10:05 +01:00
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 {
2024-11-09 10:53:40 +01:00
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
2024-04-10 19:49:55 +02:00
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 ,
2024-11-09 10:53:40 +01:00
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 ) ;
2024-11-09 10:53:40 +01:00
QString ss = s ;
store ( dabSettings_p , DAB_GENERAL , SELECTED_DEVICE , ss ) ;
2025-06-02 19:54:05 +02:00
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
}
//
2024-11-09 10:53:40 +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 ( ) ;
2024-11-09 10:53:40 +01:00
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 ) ;
2024-11-09 10:53:40 +01:00
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 ) ;
2024-11-09 10:53:40 +01:00
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 =
2025-06-02 19:54:05 +02:00
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 ) ;
2025-07-30 12:11:48 +02:00
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 ;
}
2025-07-30 12:11:48 +02:00
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 =
2025-07-30 12:11:48 +02:00
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 ( ) ;
2024-11-09 10:53:40 +01:00
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 ( ) ;
2024-11-09 10:53:40 +01:00
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 \n Are 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
2025-10-02 18:53:42 +02:00
if ( QApplication : : keyboardModifiers ( ) .
testFlag ( Qt : : ControlModifier ) ) {
return handle_keyEvent ( keyEvent - > key ( ) ) ;
}
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 ;
2024-11-09 10:53:40 +01:00
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 " ) )
2024-11-09 10:53:40 +01:00
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
////////////////////////////////////////////////////////////////////////
//
2024-11-09 10:53:40 +01:00
// 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 ( ) )
2024-04-10 19:49:55 +02:00
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 ) {
2024-11-09 10:53:40 +01:00
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 ) {
2024-04-10 19:49:55 +02:00
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 ( ) ) ;
2024-04-10 19:49:55 +02:00
localSelect_SS ( list . at ( 1 ) , list . at ( 0 ) ) ;
2024-01-27 20:16:14 +01:00
}
//
2024-11-09 10:53:40 +01:00
// The function localSelect is called from different
// places, making it complex
2024-04-10 19:49:55 +02:00
void RadioInterface : : localSelect_SS ( const QString & service ,
const QString & theChannel ) {
2024-01-27 20:16:14 +01:00
QString serviceName = service ;
2025-03-03 20:52:13 +01:00
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 ( ' ' ) ;
2024-12-29 16:22:08 +01:00
if ( ! inputDevice_p - > isFileInput ( ) ) {
2024-11-09 10:53:40 +01:00
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 ;
}
2024-11-09 10:53:40 +01:00
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
2024-11-09 10:53:40 +01:00
stopChannel ( ) ;
int k = channelSelector - > findText ( theChannel ) ;
if ( k ! = - 1 ) {
2025-01-05 13:11:25 +01:00
newChannelIndex ( k ) ;
2024-11-09 10:53:40 +01:00
}
else {
QMessageBox : : warning ( this , tr ( " Warning " ) ,
tr ( " Incorrect service specification \n " ) ) ;
return ;
}
startChannel ( theChannel , serviceName ) ;
2024-01-27 20:16:14 +01:00
}
}
2024-11-09 10:53:40 +01:00
2024-01-27 20:16:14 +01:00
///////////////////////////////////////////////////////////////////////////
2025-06-02 19:54:05 +02: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
}
2025-07-30 12:11:48 +02: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 " ) ) ;
2024-11-09 10:53:40 +01:00
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
2024-11-09 10:53:40 +01:00
//
// 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 ) ;
2024-11-09 10:53:40 +01:00
presetTimer . stop ( ) ; // should not run
2025-06-16 19:02:39 +02:00
inputDevice_p - > restartReader ( tunedFrequency ,
SAMPLERATE / 10 ) ;
2024-11-09 10:53:40 +01:00
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 ( ) ;
2024-11-09 10:53:40 +01:00
if ( channel . realChannel ) {
2025-06-13 20:34:42 +02:00
store ( dabSettings_p , DAB_GENERAL , CHANNEL_NAME , theChannel ) ;
2024-11-09 10:53:40 +01:00
}
2025-01-04 16:03:58 +01:00
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-11-09 10:53:40 +01:00
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
2024-11-09 10:53:40 +01:00
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 ( ) ) {
2024-12-29 16:22:08 +01:00
if ( firstService = = " " ) // no preset specified
2024-11-09 10:53:40 +01:00
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
2024-12-29 16:22:08 +01:00
// associated with the channel, we set the preset handling on
2024-11-09 10:53:40 +01:00
// but only if ....
if ( firstService ! = " " ) {
2024-11-14 16:16:03 +01:00
presetTimer . stop ( ) ; // should not run here
2024-11-09 10:53:40 +01:00
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-09 10:53:40 +01:00
}
2024-11-01 13:46:39 +01:00
}
2024-12-29 16:22:08 +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 ( ) ; //
2024-11-09 10:53:40 +01:00
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 ( ) {
2025-06-02 19:54:05 +02:00
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 " ) ;
2025-06-02 19:54:05 +02:00
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 ( ) ;
2024-04-10 19:49:55 +02:00
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 ;
}
2025-05-05 16:17:06 +02:00
// 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 ;
}
2025-05-05 16:17:06 +02:00
// 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 )
2025-08-06 12:32:05 +02:00
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 ( ) ;
2024-04-10 19:49:55 +02:00
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 = " ??? " ;
2024-04-10 19:49:55 +02:00
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 = " " ;
2024-04-10 19:49:55 +02:00
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 ) + " ; " +
2024-12-29 16:22:08 +01:00
theName + " ; " +
2024-12-30 14:51:14 +01:00
theDistance + " ; " +
2024-12-29 16:22:08 +01:00
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 ;
}
2025-08-05 18:30:03 +02:00
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 ) {
2025-08-06 12:32:05 +02:00
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 ) ;
2024-04-10 19:49:55 +02:00
for ( auto & tr : channel . transmitters ) {
if ( ! tr . isStrongest ) {
2025-08-06 12:32:05 +02:00
QString line = build_cont_addLine ( tr ) ;
2024-04-10 19:49:55 +02:00
if ( line = = " " )
continue ;
scanTable_p - > addLine ( line ) ;
}
}
scanTable_p - > show ( ) ;
}
2025-08-05 18:30:03 +02:00
QString RadioInterface : : build_cont_addLine ( const transmitter & tr ) {
2024-04-10 19:49:55 +02:00
QString tii ;
QString theName ;
QString theDistance ;
QString theCorner ;
QString theHeight ;
2025-08-05 18:30:03 +02:00
tii = idsToString ( tr . mainId , tr . subId ) + " ; " ;
if ( tr . transmitterName ! = " " )
theName = tr . transmitterName ;
2024-04-10 19:49:55 +02:00
else
2024-12-30 14:51:14 +01:00
theName = " " ;
2024-04-10 19:49:55 +02:00
2025-08-05 18:30:03 +02:00
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 " ) ;
2025-08-05 18:30:03 +02:00
theHeight = " ( " + QString : : number ( tr . height , ' f ' , 1 ) + " m) " ;
2024-04-10 19:49:55 +02:00
}
else {
2024-12-31 19:44:38 +01:00
theName = " unknown " ;
2024-04-10 19:49:55 +02:00
theDistance = " unknown " ;
theCorner = " ? " ;
theHeight = " ? " ;
}
return QString ( " ; " ) +
" ; " +
" ; " +
" ; " +
tii +
" ; " +
" ; " +
" ; " +
2024-12-29 16:22:08 +01:00
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 ( ) ;
2024-03-18 19:06:37 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
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 " ;
2024-11-09 10:53:40 +01:00
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 ( ) ;
2024-11-09 10:53:40 +01:00
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 ( ) ;
2024-11-09 10:53:40 +01:00
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 ;
2025-06-02 19:54:05 +02:00
int currentVisibility = inputDevice_p - > getVisibility ( ) ;
inputDevice_p - > setVisibility ( ! currentVisibility ) ;
2024-11-09 10:53:40 +01:00
store ( dabSettings_p , DAB_GENERAL , DEVICE_WIDGET_VISIBLE ,
2025-06-02 19:54:05 +02:00
! 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 ( ) ;
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
value_f ( dabSettings_p , MAP_HANDLING , HOME_LATITUDE , 0 ) ;
2024-02-16 15:46:54 +01:00
localPos . longitude =
2024-11-09 10:53:40 +01:00
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 ( ) {
2025-01-17 15:16:20 +01:00
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 ( ) ;
2024-11-09 10:53:40 +01:00
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 ( ) ;
2024-11-09 10:53:40 +01:00
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 ;
2024-11-09 10:53:40 +01:00
QString str = configHandler_p - > currentStream ( ) ;
2024-11-20 16:33:31 +01:00
( ( audioSink * ) ( soundOut_p ) ) - > selectDevice ( k , str ) ;
2024-11-09 10:53:40 +01:00
store ( dabSettings_p , SOUND_HANDLING , AUDIO_STREAM_NAME , str ) ;
2024-01-27 20:16:14 +01:00
}
//
//////////////////////////////////////////////////////////////////////////
2025-06-04 18:57:05 +02: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 =
2024-11-09 10:53:40 +01:00
value_s ( dabSettings_p , MAP_HANDLING , BROWSER_ADDRESS ,
" http://localhost " ) ;
2024-04-19 18:34:50 +02:00
QString mapPort =
2024-11-09 10:53:40 +01:00
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 =
2024-11-09 10:53:40 +01:00
value_s ( dabSettings_p , MAP_HANDLING , BROWSER_ADDRESS ,
" http://localhost " ) ;
2024-01-27 20:16:14 +01:00
QString mapPort =
2024-11-09 10:53:40 +01:00
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 ;
2024-11-09 10:53:40 +01:00
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
}
2025-06-02 19:54:05 +02: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 + + )
2025-08-06 12:32:05 +02:00
if ( ( mainId = = channel . transmitters [ i ] . mainId ) & &
( subId = = channel . transmitters [ i ] . subId ) ) {
2024-12-02 14:46:38 +01:00
channel . transmitters . erase
2025-03-02 16:10:05 +01:00
( channel . transmitters . begin ( ) + i ) ;
2024-12-02 14:46:38 +01:00
break ;
}
}
2025-07-14 17:25:42 +02:00
//
2025-08-05 18:30:03 +02:00
transmitter * RadioInterface : : inList ( uint8_t mainId , uint8_t subId ) {
2024-12-02 14:46:38 +01:00
for ( auto & tr : channel . transmitters )
2025-08-06 12:32:05 +02:00
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-09-23 10:19:31 +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
2025-08-05 18:30:03 +02:00
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 ;
}
}
2025-08-05 18:30:03 +02:00
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 ) ;
2025-08-05 18:30:03 +02:00
transmitter theTransmitter ( tr ) ;
//
if ( ! tr - > valid ) { // nothing found
2025-04-04 16:17:00 +02:00
if ( ! configHandler_p - > get_allTIISelector ( ) )
continue ;
2025-08-06 12:32:05 +02:00
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 ;
2025-01-04 16:03:58 +01:00
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 ;
2025-08-06 12:32:05 +02:00
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
}
2025-08-05 18:30:03 +02:00
else {
// first copy the db data, theTransmitter is properly initalized
// with the db Calues, now the dynamics
2025-08-06 12:32:05 +02:00
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 ;
2025-01-04 16:03:58 +01:00
theTransmitter . pattern = r [ i ] . pattern ;
2025-08-06 12:32:05 +02:00
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-04-10 19:49:55 +02:00
//
2024-12-02 14:46:38 +01:00
int bestIndex = - 1 ;
2025-08-06 12:32:05 +02:00
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 ) {
2025-08-06 12:32:05 +02:00
if ( transm . valid & &
( transm . strength > Strength ) ) {
2025-03-20 18:23:52 +01:00
bestIndex = teller ;
2025-08-06 12:32:05 +02:00
Strength = transm . strength ;
2024-04-10 19:49:55 +02:00
}
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
2025-08-06 12:32:05 +02: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 ) {
2025-08-06 12:32:05 +02:00
transmitter * ce = & channel . transmitters [ bestIndex ] ;
2024-12-02 14:46:38 +01:00
channel . mainId = ce - > mainId ;
2025-03-02 16:10:05 +01:00
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 ;
2025-05-05 16:17:06 +02:00
for ( auto & theTr : channel . transmitters ) {
2025-04-05 12:59:05 +02:00
if ( ! configHandler_p - > get_allTIISelector ( ) ) {
2025-08-06 12:32:05 +02:00
if ( theTr . distance < 0 ) {
2025-04-04 16:17:00 +02:00
continue ;
2025-04-05 12:59:05 +02:00
}
}
2025-05-05 16:17:06 +02:00
if ( bestIndex = = teller ) {
2025-08-06 12:32:05 +02:00
QString labelText = createTIILabel ( theTr ) ;
2025-05-05 16:17:06 +02:00
distanceLabel - > setText ( labelText ) ;
}
2025-08-06 12:32:05 +02:00
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 ) {
2025-08-06 12:32:05 +02:00
if ( theTr . distance < 0 )
2025-04-09 19:42:03 +02:00
continue ;
2024-12-02 14:46:38 +01:00
if ( theTr . isStrongest ) {
2025-08-06 12:32:05 +02:00
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 )
2025-08-05 18:30:03 +02:00
return ;
2024-12-02 14:46:38 +01:00
//
2024-10-17 15:44:28 +02:00
for ( auto & theTr : channel . transmitters ) {
2025-08-06 12:32:05 +02:00
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 ,
2025-08-06 12:32:05 +02:00
theTr ,
2025-08-05 18:30:03 +02:00
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 {
2025-03-02 16:10:05 +01:00
ioPeakAvr = ( iPeak > ioPeakAvr ? iPeak : ioPeakAvr - 0.5f /*decay*/ ) ;
} ;
2024-11-20 16:33:31 +01:00
2025-03-02 16:10:05 +01:00
peak_avr ( iPeakLeft , peakLeftDamped ) ;
peak_avr ( iPeakRight , peakRightDamped ) ;
2024-11-20 16:33:31 +01:00
2025-03-02 16:10:05 +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 )
2024-11-09 10:53:40 +01:00
p . load ( " :res/radio-pictures/volume_on.png " , " png " ) ;
2024-01-27 20:16:14 +01:00
else
2024-11-09 10:53:40 +01:00
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 ) ;
2025-07-30 12:11:48 +02:00
if ( ! ad . defined )
2024-01-27 20:16:14 +01:00
return ;
2025-07-30 12:11:48 +02:00
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
}
2025-07-30 12:11:48 +02: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 ;
2025-07-30 12:11:48 +02:00
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 ( ) ;
2024-11-09 10:53:40 +01:00
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 ( ) {
2024-11-09 10:53:40 +01:00
store ( dabSettings_p , DAB_GENERAL , TECHDATA_VISIBLE , 0 ) ;
2024-02-25 14:18:27 +01:00
}
void RadioInterface : : handle_configFrame_closed ( ) {
2024-11-09 10:53:40 +01:00
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 ( ) {
2024-11-09 10:53:40 +01:00
store ( dabSettings_p , DAB_GENERAL , NEW_DISPLAY_VISIBLE , 0 ) ;
2024-02-25 14:18:27 +01:00
}
2024-03-18 19:06:37 +01:00
void RadioInterface : : setVolume ( int n ) {
2025-05-08 12:55:36 +02:00
audioVolume = n ;
2024-03-18 19:06:37 +01:00
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
}
2024-03-18 19:06:37 +01:00
}
void RadioInterface : : handle_snrLabel ( ) {
2024-03-20 15:05:10 +01:00
if ( running . load ( ) ) {
dynamicLabel - > setStyleSheet ( labelStyle ) ;
QString SNR = " SNR " + QString : : number ( channel . snr ) ;
dynamicLabel - > setText ( SNR ) ;
}
2024-03-18 19:06:37 +01:00
}
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 ) {
2024-11-09 10:53:40 +01:00
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 ] ;
}
2025-08-06 12:32:05 +02:00
QString RadioInterface : : createTIILabel ( const transmitter & theTransmitter ) {
uint8_t mainId = theTransmitter . mainId ;
uint8_t subId = theTransmitter . subId ;
2025-08-05 18:30:03 +02:00
const QString & theTransmitterName
2025-08-06 12:32:05 +02:00
= theTransmitter . transmitterName ;
float theDistance = theTransmitter . distance ;
float theAzimuth = theTransmitter . azimuth ;
2025-04-02 18:30:53 +02:00
QString direction = fromAzimuth_toDirection ( theAzimuth ) ;
2025-08-06 12:32:05 +02:00
// 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 ) + " ) " ;
2025-08-05 18:30:03 +02:00
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 "
2025-03-02 16:10:05 +01:00
+ 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 ;
}
2025-08-06 12:32:05 +02:00
void RadioInterface : : addtoLogFile ( const transmitter & theTransmitter ) {
2024-11-29 20:31:44 +01:00
FILE * theFile = nullptr ;
bool exists = false ;
2025-08-06 12:32:05 +02:00
if ( ( theTransmitter . mainId = = 0 ) | |
( theTransmitter . mainId = = 255 ) )
2024-12-01 14:36:25 +01:00
return ;
2025-03-02 16:10:05 +01:00
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
2024-12-29 16:22:08 +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
2025-08-06 12:32:05 +02:00
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 ) ;
2025-03-02 16:10:05 +01:00
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-27 14:32:11 +01:00
2025-02-15 17:53:47 +01:00
void RadioInterface : : extractServiceInformation ( const QDomDocument & doc ,
2025-02-27 14:32:11 +01:00
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 ;
2025-02-27 14:32:11 +01:00
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
}
}
2025-02-27 14:32:11 +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 " ;
2025-02-27 14:32:11 +01:00
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 ) {
2025-02-27 14:32:11 +01:00
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
}
2025-02-27 14:32:11 +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 ;
2025-02-27 14:32:11 +01:00
for ( auto & me : pictures . elements ) {
if ( ! containsPicture ( pictureElement , me ) ) {
2025-02-25 20:32:17 +01:00
pictureElement . elements . push_back ( me ) ;
2025-02-27 14:32:11 +01:00
break ;
}
}
2025-02-15 17:53:47 +01:00
}
2025-02-25 20:32:17 +01:00
channel . servicePictures . push_back ( pictures ) ;
2025-02-27 14:32:11 +01:00
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 ) ;
2025-02-27 14:32:11 +01:00
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 ) ;
2025-04-12 20:19:09 +02:00
if ( freqList . size ( ) = = 0 )
2025-03-19 12:32:08 +01:00
return ;
2025-04-12 20:19:09 +02:00
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
//
2025-07-27 16:46:13 +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);
2025-07-27 16:46:13 +02:00
}
}
2025-08-06 12:32:05 +02:00
( void ) serviceAvailable ;
2025-07-27 16:46:13 +02:00
}
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
2025-10-02 18:53:42 +02:00
// as it turns out, our "beloved" windows does not let
// the Qt user catch the functon keys, we settle for Ctrl Ii
2025-09-19 19:52:42 +02:00
bool RadioInterface : : handle_keyEvent ( int theKey ) {
2025-10-02 18:53:42 +02:00
if ( theKey ! = Qt : : Key_I )
return false ;
2025-09-19 19:52:42 +02:00
2025-10-02 18:53:42 +02:00
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 ;
2025-09-19 19:52:42 +02:00
}
2025-10-02 18:53:42 +02:00
else
if ( techWindow_p - > hasFocus ( ) ) {
theEnsembleHandler - > activateWindow ( ) ;
theEnsembleHandler - > setFocus ( ) ;
return true ;
}
return false ;
2025-09-19 19:52:42 +02:00
}
2025-10-02 18:53:42 +02:00