1
0
mirror of https://github.com/JvanKatwijk/qt-dab.git synced 2025-10-05 15:52:39 +02:00

Ctrl-I key

This commit is contained in:
Jan
2025-10-02 18:53:42 +02:00
parent d859bf9192
commit 5eeff10916
8 changed files with 188 additions and 203 deletions

View File

@@ -531,7 +531,7 @@ the *qt-dab-6.9.pro* file contains (much) more configuration options
than the *CMakeLists.txt* file that is used when using cmake.
Note that the scheme presented below is applied when building the AppImage
on Ubuntu 20, and was tested on the "bullseye" system on the RPI.
on Ubuntu 22, and was tested on the "bullseye" system on the RPI.
For other distributions (or later Ubuntu versions), names of library
packages may be different. Note that in all cases, the development versions (i.e. the versions with the include (".h") files) are required.

View File

@@ -4,25 +4,12 @@ HERE="$(dirname "$(readlink -f "${0}")")"
rmmod dvb_usb_rtl28xxu || true
cat > /tmp/10-rtl-sdr.rules <<\EOF
cat > ./10-rtl-sdr.rules <<\EOF
SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2832", MODE="0666", SYMLINK+="rtl_sdr"
EOF
mv /tmp/10-rtl-sdr.rules /etc/udev/rules.d/10-rtl-sdr.rules
cat > /tmp/52-airspy.rules <<\EOF
ATTR{idVendor}=="1d50", ATTR{idProduct}=="60a1", SYMLINK+="airspy-%k", MODE="660", GROUP="plugdev"
EOF
mv /tmp/52-airspy.rules /etc/udev/rules.d/52-airspy.rules
cat > /tmp/66-mirics.rules <<\EOF
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="1df7",ATTRS{idProduct}=="2500",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="1df7",ATTRS{idProduct}=="3010",MODE:="0666"
SUBSYSTEM=="usb",ENV{DEVTYPE}=="usb_device",ATTRS{idVendor}=="1df7",ATTRS{idProduct}=="3000",MODE:="0666"
EOF
mv /tmp/66-mirics.rules /etc/udev/rules.d/66-mirics.rules
mv ./10-rtl-sdr.rules /etc/udev/rules.d/10-rtl-sdr.rules
udevadm control --reload-rules
udevadm trigger --attr-match=subsystem=usb

View File

@@ -121,15 +121,15 @@ public:
} FIG18_cluster;
//
// for each type a table
std::vector<SId_struct> SId_table;
std::vector<subChannel> subChannel_table; // FIG0/1
std::vector<serviceComp_C> SC_C_table; // FIG0/2
std::vector<serviceComp_P> SC_P_table; // FIG0/3
std::vector<serviceComp_G> SC_G_table; // FIG0/8
std::vector<SC_language> language_table; // FIG0/5
std::vector<AppType> AppType_table; // FIG0/13
std::vector<programType> programType_table; // FIG017
std::vector<FIG18_cluster> announcement_table; // FIG0/18
std::vector<SId_struct> SId_table;
std::vector<subChannel> subChannel_table; // FIG0/1
std::vector<serviceComp_C> SC_C_table; // FIG0/2
std::vector<serviceComp_P> SC_P_table; // FIG0/3
std::vector<serviceComp_G> SC_G_table; // FIG0/8
std::vector<SC_language> language_table; // FIG0/5
std::vector<AppType> AppType_table; // FIG0/13
std::vector<programType> programType_table; // FIG017
std::vector<FIG18_cluster> announcement_table; // FIG0/18
int32_t dateTime [8];
void reset ();

View File

@@ -1283,6 +1283,78 @@ uint8_t fibDecoder::serviceType (const int index) {
return currentConfig -> SC_C_table [index]. TMid;
}
int fibDecoder::getNrComps (const uint32_t SId) {
for (auto &SId_element : currentConfig -> SId_table)
if (SId_element. SId == SId)
return SId_element. comps. size ();
return 0;
}
// required for ETI generation
int fibDecoder::nrChannels () {
return currentConfig -> subChannel_table. size ();
}
//
// for primary services we return the index of the first
// component, the secondary services, the index of the
// component with the matching SCIds
//
int fibDecoder::getServiceComp (const QString &service) {
// first we check to see if the service is a primary one
for (auto &serv : theEnsemble. primaries) {
if (serv. name != service)
continue;
for (auto & SId_element: currentConfig -> SId_table) {
if (SId_element. SId == serv. SId)
return SId_element. comps [0];
}
}
for (auto &serv : theEnsemble. secondaries) {
if (serv. name != service)
continue;
return getServiceComp_SCIds (serv. SId, serv. SCIds);
}
return -1;
}
//
// Find the component with the indicated number
int fibDecoder::getServiceComp (const uint32_t SId,
const int compnr) {
for (auto &SId_element : currentConfig -> SId_table) {
if (SId_element. SId == SId) {
return SId_element. comps [compnr];
}
}
return -1;
}
// Find the component with the indicated SCIds
int fibDecoder::getServiceComp_SCIds (const uint32_t SId,
const int SCIds) {
// fprintf (stderr, "Looking for serviceComp %X %d\n", SId, SCIds);
for (auto &SId_element : currentConfig -> SId_table) {
if (SId_element. SId != SId)
continue;
for (int i = 0; i < (int) SId_element. comps. size (); i ++) {
int index = SId_element. comps [i];
if (currentConfig -> SCIdsOf (index) == SCIds)
return index;
}
}
return -1;
}
//
//
bool fibDecoder::isPrimary (const QString &s) {
for (auto &serv : theEnsemble. primaries) {
if (s == serv. name)
return true;
}
return false;
}
void fibDecoder::audioData (const int index, audiodata &ad) {
fibConfig::serviceComp_C &comp = currentConfig -> SC_C_table [index];
for (auto &serv : theEnsemble. primaries) {
@@ -1344,69 +1416,13 @@ fibConfig::serviceComp_C &comp = currentConfig -> SC_C_table [index];
pd. defined = true;
}
int fibDecoder::getNrComps (const uint32_t SId) {
for (auto &SId_element : currentConfig -> SId_table)
if (SId_element. SId == SId)
return SId_element. comps. size ();
uint16_t fibDecoder::getAnnouncing (uint16_t SId) {
for (auto &serv : currentConfig -> SId_table)
if (serv. SId == SId)
return serv. announcing;
return 0;
}
//
// for primary services we return the index of the first
// component, the secondary services, the index of the
// component with the matching SCIds
//
int fibDecoder::getServiceComp (const QString &service) {
// first we check to see if the service is a primary one
for (auto &serv : theEnsemble. primaries) {
if (serv. name != service)
continue;
for (auto & SId_element: currentConfig -> SId_table) {
if (SId_element. SId == serv. SId)
return SId_element. comps [0];
}
}
for (auto &serv : theEnsemble. secondaries) {
if (serv. name != service)
continue;
return getServiceComp_SCIds (serv. SId, serv. SCIds);
}
return -1;
}
int fibDecoder::getServiceComp (const uint32_t SId,
const int compnr) {
for (auto &SId_element : currentConfig -> SId_table) {
if (SId_element. SId == SId) {
return SId_element. comps [compnr];
}
}
return -1;
}
int fibDecoder::getServiceComp_SCIds (const uint32_t SId,
const int SCIds) {
// fprintf (stderr, "Looking for serviceComp %X %d\n", SId, SCIds);
for (auto &SId_element : currentConfig -> SId_table) {
if (SId_element. SId != SId)
continue;
for (int i = 0; i < (int) SId_element. comps. size (); i ++) {
int index = SId_element. comps [i];
if (currentConfig -> SCIdsOf (index) == SCIds)
return index;
}
}
return -1;
}
bool fibDecoder::isPrimary (const QString &s) {
for (auto &serv : theEnsemble. primaries) {
if (s == serv. name)
return true;
}
return false;
}
std::vector<int> fibDecoder::getFrequency (const QString &s) {
std::vector<int> res;
for (auto &serv : theEnsemble. primaries) {
@@ -1416,20 +1432,17 @@ std::vector<int> res;
return res;
}
// required for ETI generation
int fibDecoder::nrChannels () {
return currentConfig -> subChannel_table. size ();
}
//
// needed for generating eti files
void fibDecoder::getChannelInfo (channel_data *d, const int n) {
fibConfig::subChannel *selected = &(currentConfig -> subChannel_table [n]);
d -> in_use = true;
d -> id = currentConfig -> subChannel_table [n]. subChId;
d -> start_cu = currentConfig -> subChannel_table [n]. startAddr;
d -> protlev = currentConfig -> subChannel_table [n]. protLevel;
d -> size = currentConfig -> subChannel_table [n]. Length;
d -> bitrate = currentConfig -> subChannel_table [n]. bitRate;
d -> uepFlag = currentConfig -> subChannel_table [n]. shortForm;
d -> id = selected -> subChId;
d -> start_cu = selected -> startAddr;
d -> protlev = selected -> protLevel;
d -> size = selected -> Length;
d -> bitrate = selected -> bitRate;
d -> uepFlag = selected -> shortForm;
}
int32_t fibDecoder::getCIFcount () {
@@ -1456,13 +1469,6 @@ void fibDecoder::handleAnnouncement (uint16_t SId, uint16_t flags,
}
}
uint16_t fibDecoder::getAnnouncing (uint16_t SId) {
for (auto &serv : currentConfig -> SId_table)
if (serv. SId == SId)
return serv. announcing;
return 0;
}
int fibDecoder::freeSpace () {
return currentConfig -> freeSpace ();
}

View File

@@ -44,25 +44,28 @@ public:
void connectChannel ();
void disconnectChannel ();
bool syncReached ();
uint16_t getAnnouncing (uint16_t);
//
// The real interface
uint32_t getSId (int);
uint8_t serviceType (int);
int getNrComps (const uint32_t);
//
// not well chosen name, "subChannels" are meant
int nrChannels ();
int getServiceComp (const QString &);
int getServiceComp (const uint32_t, const int);
int getServiceComp_SCIds (const uint32_t, const int);
bool isPrimary (const QString &);
void audioData (const int, audiodata &);
void packetData (const int, packetdata &);
int getNrComps (const uint32_t);
int nrChannels ();
uint16_t getAnnouncing (uint16_t);
std::vector<int> getFrequency (const QString &);
void getChannelInfo (channel_data *, const int);
int32_t getCIFcount ();
void getCIFcount (int16_t &, int16_t &);
uint32_t julianDate ();
QList<contentType> contentPrint ();
int freeSpace ();
QList<contentType> contentPrint ();
protected:
void processFIB (uint8_t *, uint16_t);

View File

@@ -43,8 +43,10 @@
#define ALPHA 0.005f
static inline
Complex normalize (const Complex &V) {
DABFLOAT Length = jan_abs (V);
return Length == 0.0f ? Complex (0.0, 0.0) : V / (DABFLOAT)Length;
DABFLOAT length = jan_abs (V);
if (length < 0.001)
return Complex (0, 0);
return Complex (V) / length;
}
ofdmDecoder::ofdmDecoder (RadioInterface *mr,
@@ -103,7 +105,7 @@ void ofdmDecoder::reset () {
angleVector [i] = M_PI_4;
}
meanValue = 1.0f;
avgBit = 1.0f;
avgBit = 10.0f;
}
//
void ofdmDecoder::processBlock_0 (std::vector <Complex> buffer) {
@@ -113,8 +115,6 @@ void ofdmDecoder::processBlock_0 (std::vector <Complex> buffer) {
//
memcpy (phaseReference. data (), buffer. data (),
T_u * sizeof (Complex));
Complex temp = Complex (0, 0);
}
//
// Just interested. In the ideal case the constellation of the
@@ -184,7 +184,7 @@ void limit_symmetrically (DABFLOAT &v, DABFLOAT limit) {
//
// Decoder 4 is an interpretation of the so-called "Optimal 3"
// version in the aforementioned paper.
// It is still experimental!!!
// It does not work well
static inline
Complex w (DABFLOAT kn) {
@@ -203,14 +203,34 @@ DABFLOAT IO (DABFLOAT x) {
return std::cyl_bessel_i (0.0f, x);
}
Complex optimum3 (Complex S, Complex prevS, DABFLOAT sigmaSQ) {
Complex rr = Complex (0, 1) * conj (S);
S = S * conj (rr);
prevS = prevS * conj (rr);
DABFLOAT P1 = makeA (1, S, prevS) / sigmaSQ;
DABFLOAT P7 = makeA (7, S, prevS) / sigmaSQ;
DABFLOAT P3 = makeA (3, S, prevS) / sigmaSQ;
DABFLOAT P5 = makeA (5, S, prevS) / sigmaSQ;
DABFLOAT IO_P1 = IO (P1);
DABFLOAT IO_P7 = IO (P7);
DABFLOAT IO_P3 = IO (P3);
DABFLOAT IO_P5 = IO (P5);
DABFLOAT b1 = log ((IO_P1 + IO_P7) / (IO_P3 + IO_P5));
DABFLOAT b2 = log ((IO_P1 + IO_P3) / (IO_P5 + IO_P7));
return Complex (b1, b2);
}
void ofdmDecoder::decode (std::vector <Complex> &buffer,
int32_t blkno,
std::vector<int16_t> &softbits,
DABFLOAT snr) {
DABFLOAT sum = 0;
DABFLOAT bitSum = 0;
static DABFLOAT bitSum = 10;
float oldSum = bitSum;
bitSum = 0;
memcpy (fft_buffer. data (), &((buffer. data ()) [T_g]),
T_u * sizeof (Complex));
// first step: do the FFT
@@ -224,14 +244,14 @@ DABFLOAT bitSum = 0;
int16_t index = myMapper. mapIn (i);
if (index < 0)
index += T_u;
Complex fftBin = fft_buffer [index] *
normalize (conj (phaseReference [index]));
Complex current = fft_buffer [index];
Complex prevS = phaseReference [index];
Complex fftBin = current * normalize (conj (prevS));
conjVector [index] = fftBin;
DABFLOAT binAbsLevel = jan_abs (fftBin);
Complex prevS = phaseReference [index];
//
// updates
Complex fftBin_at_1 = Complex (abs (real (fftBin)),
abs (imag (fftBin)));
@@ -292,45 +312,31 @@ DABFLOAT bitSum = 0;
sum += jan_abs (R1);
}
else
if (this -> decoder == DECODER_3) { // decoder 3
else {
softbits [i] = - real (fftBin) / binAbsLevel *
1.0 * MAX_VITERBI;
softbits [carriers + i]
= - imag (fftBin) / binAbsLevel *
1.0 * MAX_VITERBI;
}
else { // experimental decoder 4
DABFLOAT P1 = makeA (1, fftBin, prevS) /
sigmaSQ_Vector [index];
DABFLOAT P7 = makeA (7, fftBin, prevS) /
sigmaSQ_Vector [index];
DABFLOAT P3 = makeA (3, fftBin, prevS) /
sigmaSQ_Vector [index];
DABFLOAT P5 = makeA (5, fftBin, prevS) /
sigmaSQ_Vector [index];
DABFLOAT IO_P1 = IO (P1);
DABFLOAT IO_P7 = IO (P7);
DABFLOAT IO_P3 = IO (P3);
DABFLOAT IO_P5 = IO (P5);
DABFLOAT b1 = log ((IO_P1 + IO_P7) / (IO_P3 + IO_P5));
DABFLOAT b2 = log ((IO_P1 + IO_P3) / (IO_P5 + IO_P7));
bitSum += (abs (b1) + abs (b2)) / 2;
DABFLOAT scaler = 40 / avgBit;
int s1 = -real (fftBin) < 0 ? -1 : 1;
int s2 = -imag (fftBin) < 0 ? -1 : 1;
DABFLOAT xx1 = s1 * abs (b1) * scaler;
DABFLOAT xx2 = s2 * abs (b2) * scaler;
limit_symmetrically (xx1, MAX_VITERBI);
limit_symmetrically (xx2, MAX_VITERBI);
softbits [i] = (int16_t)xx1;
softbits [carriers + i] = (int16_t)xx2;
}
// else // experimental decoder 3
// Interesting experiment, but does not work properly
// if (this -> decoder == DECODER_3) { // decoder 3
// Complex res = optimum3 (current, prevS,
// sigmaSQ_Vector [index]);
// bitSum += abs (res);
// DABFLOAT scaler = 64.0 / (oldSum / carriers) ;
// DABFLOAT xx1 = - real (res) / scaler;
// DABFLOAT xx2 = - imag (res) / scaler;
// limit_symmetrically (xx1, MAX_VITERBI);
// limit_symmetrically (xx2, MAX_VITERBI);
// softbits [i] = (int16_t)xx1;
// softbits [carriers + i] = (int16_t)xx2;
// }
}
avgBit = compute_avg (avgBit, bitSum / carriers, 0.1);
avgBit = compute_avg (avgBit, bitSum / carriers, 0.1);
meanValue = compute_avg (meanValue, sum /carriers, 0.1);
// end of decoding , now for displaying things //

View File

@@ -153,7 +153,7 @@ auto *buffer = dynVec (std::complex<float>, nrSamples);
dcReal = compute_avg (dcReal, real (v), Alpha);
dcImag = compute_avg (dcImag, imag (v), Alpha);
v = std::complex<float> (real (v) - dcReal, imag (v) - dcImag);
v = theEqualizer. equalize (v);
// v = theEqualizer. equalize (v);
DABFLOAT real_V = abs (real (v));
DABFLOAT imag_V = abs (imag (v));
IQ_Real = compute_avg (IQ_Real, real_V, Alpha);
@@ -164,6 +164,7 @@ auto *buffer = dynVec (std::complex<float>, nrSamples);
((IQ_Real + IQ_Imag) / 2));
teller = 0;
}
// v = std::complex<float> (IQ_Real, IQ_Imag);
}
// first: adjust frequency. We need Hz accuracy

View File

@@ -1922,8 +1922,10 @@ bool RadioInterface::eventFilter (QObject *obj, QEvent *event) {
return true;
}
else // handling function keys
if (handle_keyEvent (keyEvent -> key ()))
return true;
if (QApplication::keyboardModifiers ().
testFlag (Qt::ControlModifier)) {
return handle_keyEvent (keyEvent -> key ());
}
}
// An option is to click - right hand mouse button - on a
// service in the scanlist in order to add it to the
@@ -4779,55 +4781,35 @@ void RadioInterface::focusInEvent (QFocusEvent *evt) {
//
// This function is called whenever a key is touched
// that is not the return key
// as it turns out, our "beloved" windows does not let
// the Qt user catch the functon keys, we settle for Ctrl Ii
bool RadioInterface::handle_keyEvent (int theKey) {
switch (theKey) {
case Qt::Key_F1:
theEnsembleHandler -> activateWindow ();
theEnsembleHandler -> setFocus ();
return true;
if (theKey != Qt::Key_I)
return false;
case Qt::Key_F2:
configHandler_p -> activateWindow ();
configHandler_p -> setFocus ();
return true;
case Qt::Key_F3:
techWindow_p -> activateWindow ();
techWindow_p -> setFocus ();
return true;
case Qt::Key_F4:
this -> activateWindow ();
this -> setFocus ();
return true;
case Qt::Key_F6:
if (theEnsembleHandler -> hasFocus ()) {
this -> activateWindow ();
this -> setFocus ();
return true;
}
else
if (this -> hasFocus ()) {
configHandler_p -> activateWindow ();
configHandler_p -> setFocus ();
return true;
}
else
if (configHandler_p -> hasFocus ()) {
techWindow_p -> activateWindow ();
techWindow_p -> setFocus ();
return true;
}
else
if (techWindow_p -> hasFocus ()) {
theEnsembleHandler -> activateWindow ();
theEnsembleHandler -> setFocus ();
return true;
}
else
return false;
default:
return false;
if (theEnsembleHandler -> hasFocus ()) {
this -> activateWindow ();
this -> setFocus ();
return true;
}
else
if (this -> hasFocus ()) {
configHandler_p -> activateWindow ();
configHandler_p -> setFocus ();
return true;
}
else
if (configHandler_p -> hasFocus ()) {
techWindow_p -> activateWindow ();
techWindow_p -> setFocus ();
return true;
}
else
if (techWindow_p -> hasFocus ()) {
theEnsembleHandler -> activateWindow ();
theEnsembleHandler -> setFocus ();
return true;
}
return false;
}