1
0
mirror of https://github.com/JvanKatwijk/dabradio synced 2025-10-05 15:52:42 +02:00

major update to sync (more or less) with qt-dab

This commit is contained in:
JvanKatwijk
2018-09-04 12:48:24 +02:00
parent 09243fcb39
commit 4f0d3e920a
76 changed files with 2304 additions and 1247 deletions

View File

@@ -123,14 +123,16 @@ endif ()
${QT_QTGUI_INCLUDE_DIR}
.
./
./service-description
./includes
./includes/ofdm
./includes/backend
./includes/backend/viterbi_768
./includes/backend/audio
./includes/backend/data
./includes/backend/data/journaline
./includes/various
./includes/backend/data/mot
./includes/support
./includes/support/viterbi_768
./includes/output
./devices
/usr/include/
@@ -138,14 +140,17 @@ endif ()
set (${objectName}_HDRS
./dab-processor.h
./service-list.h
./service-display.h
./includes/ofdm/sample-reader.h
./includes/dab-constants.h
./service-description/service-descriptor.h
./service-description/audio-descriptor.h
./includes/country-codes.h
./includes/ofdm/timesyncer.h
./includes/ofdm/sample-reader.h
./includes/ofdm/phasereference.h
./includes/ofdm/phasetable.h
./includes/ofdm/freq-interleaver.h
./includes/backend/viterbi_768/viterbi-768.h
./includes/ofdm/fic-handler.h
./includes/ofdm/fib-processor.h
./includes/backend/protection.h
./includes/backend/uep-protection.h
./includes/backend/eep-protection.h
@@ -163,40 +168,42 @@ endif ()
./includes/backend/audio/mp2processor.h
./includes/backend/data/virtual-datahandler.h
./includes/backend/data/pad-handler.h
./includes/backend/data/mot-handler.h
./includes/backend/data/mot-dir.h
./includes/backend/data/mot-object.h
./includes/backend/data/mot/mot-handler.h
./includes/backend/data/mot/mot-object.h
./includes/backend/data/mot/mot-dir.h
./includes/backend/data/data-processor.h
./devices/virtual-input.h
./includes/output/fir-filters.h
./includes/output/audio-base.h
./includes/output/newconverter.h
./includes/various/fft-handler.h
./includes/various/ringbuffer.h
./includes/various/Xtan2.h
./includes/various/dab-params.h
./includes/various/band-handler.h
./includes/various/text-mapper.h
./includes/support/viterbi_768/viterbi-768.h
./includes/support/fft-handler.h
./includes/support/ringbuffer.h
./includes/support/Xtan2.h
./includes/support/dab-params.h
./includes/support/band-handler.h
./includes/support/text-mapper.h
./includes/support/dab_tables.h
)
set (${objectName}_SRCS
${${objectName}_SRCS}
./main.cpp
./dab-processor.cpp
./service-list.cpp
./service-display.cpp
./service-description/service-descriptor.cpp
./service-description/audio-descriptor.cpp
./src/ofdm/timesyncer.cpp
./src/ofdm/sample-reader.cpp
./src/ofdm/ofdm-decoder.cpp
./src/ofdm/phasereference.cpp
./src/ofdm/phasetable.cpp
./src/ofdm/freq-interleaver.cpp
./src/backend/viterbi_768/viterbi-768.cpp
./src/backend/viterbi_768/spiral-no-sse.c
./src/backend/fic-handler.cpp
./src/ofdm/fic-handler.cpp
./src/ofdm/fib-processor.cpp
./src/backend/protection.cpp
./src/backend/eep-protection.cpp
./src/backend/uep-protection.cpp
./src/backend/fib-processor.cpp
./src/backend/firecode-checker.cpp
./src/backend/frame-processor.cpp
./src/backend/protTables.cpp
@@ -212,9 +219,9 @@ endif ()
./src/backend/audio/mp2processor.cpp
./src/backend/data/virtual-datahandler.cpp
./src/backend/data/pad-handler.cpp
./src/backend/data/mot-handler.cpp
./src/backend/data/mot-dir.cpp
./src/backend/data/mot-object.cpp
./src/backend/data/mot/mot-handler.cpp
./src/backend/data/mot/mot-object.cpp
./src/backend/data/mot/mot-dir.cpp
./src/backend/data/data-processor.cpp
./devices/virtual-input.cpp
./devices/rawfiles/rawfiles.cpp
@@ -222,35 +229,39 @@ endif ()
./src/output/audio-base.cpp
./src/output/newconverter.cpp
./src/output/fir-filters.cpp
./src/various/fft-handler.cpp
./src/various/Xtan2.cpp
./src/various/dab-params.cpp
./src/various/band-handler.cpp
./src/various/text-mapper.cpp
./src/support/fft-handler.cpp
./src/support/Xtan2.cpp
./src/support/dab-params.cpp
./src/support/band-handler.cpp
./src/support/text-mapper.cpp
./src/support/dab_tables.cpp
./src/support/viterbi_768/viterbi-768.cpp
./src/support/viterbi_768/spiral-no-sse.c
)
set (${objectName}_UIS
${${objectName}_UIS} ./forms/dabradio.ui)
${${objectName}_UIS} ./forms/dabradio.ui
./forms/audio-description.ui)
set (${objectName}_MOCS
./dab-processor.h
./service-list.h
./service-display.h
./service-description/service-descriptor.h
./service-description/audio-descriptor.h
./includes/output/audio-base.h
./includes/ofdm/sample-reader.h
./includes/ofdm/ofdm-decoder.h
./includes/ofdm/phasereference.h
./includes/backend/fic-handler.h
./includes/backend/fib-processor.h
./includes/ofdm/fic-handler.h
./includes/ofdm/fib-processor.h
./includes/backend/data-backend.h
./includes/backend/audio/faad-decoder.h
./includes/backend/audio/mp2processor.h
./includes/backend/audio/mp4processor.h
./includes/backend/data/virtual-datahandler.h
./includes/backend/data/pad-handler.h
./includes/backend/data/mot-handler.h
./includes/backend/data/mot-dir.h
./includes/backend/data/mot-object.h
./includes/backend/data/mot/mot-handler.h
./includes/backend/data/mot/mot-object.h
./includes/backend/data/mot/mot-dir.h
./includes/backend/data/data-processor.h
)

View File

@@ -119,136 +119,145 @@ add_definitions (-DTHREADED_DECODING) # uncomment for use for an RPI
${QT_QTGUI_INCLUDE_DIR}
.
./
./includes
./includes/ofdm
./includes/backend
./includes/backend/viterbi_768
./includes/backend/audio
./includes/backend/data
./includes/backend/data/journaline
./includes/various
./includes/output
./devices
./service-description
./includes
./includes/ofdm
./includes/backend
./includes/backend/audio
./includes/backend/data
./includes/backend/data/journaline
./includes/backend/data/mot
./includes/support
./includes/support/viterbi_768
./includes/output
./devices
/usr/include/
)
set (${objectName}_HDRS
./dab-processor.h
./service-list.h
./service-display.h
./includes/ofdm/sample-reader.h
./includes/dab-constants.h
./includes/ofdm/phasereference.h
./includes/ofdm/phasetable.h
./includes/ofdm/freq-interleaver.h
./includes/backend/viterbi_768/viterbi-768.h
./includes/dab-constants.h
./service-description/service-descriptor.h
./service-description/audio-descriptor.h
./includes/country-codes.h
./includes/ofdm/timesyncer.h
./includes/ofdm/sample-reader.h
./includes/ofdm/phasereference.h
./includes/ofdm/phasetable.h
./includes/ofdm/freq-interleaver.h
./includes/ofdm/fic-handler.h
./includes/ofdm/fib-processor.h
./includes/backend/protection.h
./includes/backend/uep-protection.h
./includes/backend/eep-protection.h
./includes/backend/firecode-checker.h
./includes/backend/frame-processor.h
./includes/backend/charsets.h
./includes/backend/galois.h
./incluces/backend/reed-solomon.h
./includes/backend/msc-handler.h
./includes/backend/virtual-backend.h
./includes/backend/audio-backend.h
./includes/backend/databackend.h
./includes/backend/audio/faad-decoder.h
./includes/backend/audio/mp4processor.h
./includes/backend/audio/mp2processor.h
./includes/backend/data/virtual-datahandler.h
./includes/backend/data/pad-handler.h
./includes/backend/data/mot-handler.h
./includes/backend/data/mot-dir.h
./includes/backend/data/mot-object.h
./includes/backend/uep-protection.h
./includes/backend/eep-protection.h
./includes/backend/firecode-checker.h
./includes/backend/frame-processor.h
./includes/backend/charsets.h
./includes/backend/galois.h
./incluces/backend/reed-solomon.h
./includes/backend/msc-handler.h
./includes/backend/virtual-backend.h
./includes/backend/audio-backend.h
./includes/backend/data-backend.h
./includes/backend/audio/faad-decoder.h
./includes/backend/audio/mp4processor.h
./includes/backend/audio/mp2processor.h
./includes/backend/data/virtual-datahandler.h
./includes/backend/data/pad-handler.h
./includes/backend/data/mot/mot-handler.h
./includes/backend/data/mot/mot-object.h
./includes/backend/data/data-processor.h
./devices/virtual-input.h
./includes/output/fir-filters.h
./includes/output/audio-base.h
./includes/output/audiosink.h
./includes/output/newconverter.h
./includes/various/fft-handler.h
./includes/various/ringbuffer.h
./includes/various/Xtan2.h
./includes/various/dab-params.h
./includes/various/band-handler.h
./includes/various/text-mapper.h
./devices/virtual-input.h
./includes/output/fir-filters.h
./includes/output/audio-base.h
./includes/output/newconverter.h
./includes/support/viterbi_768/viterbi-768.h
./includes/support/fft-handler.h
./includes/support/ringbuffer.h
./includes/support/Xtan2.h
./includes/support/dab-params.h
./includes/support/band-handler.h
./includes/support/text-mapper.h
./includes/support/dab_tables.h
)
set (${objectName}_SRCS
${${objectName}_SRCS}
./main.cpp
./dab-processor.cpp
./service-list.cpp
./service-display.cpp
./dab-processor.cpp
./service-description/service-descriptor.cpp
./service-description/audio-descriptor.cpp
./src/ofdm/timesyncer.cpp
./src/ofdm/sample-reader.cpp
./src/ofdm/ofdm-decoder.cpp
./src/ofdm/phasereference.cpp
./src/ofdm/phasetable.cpp
./src/ofdm/freq-interleaver.cpp
./src/backend/viterbi_768/viterbi-768.cpp
./src/backend/viterbi_768/spiral-no-sse.c
./src/backend/fic-handler.cpp
./src/ofdm/ofdm-decoder.cpp
./src/ofdm/phasereference.cpp
./src/ofdm/phasetable.cpp
./src/ofdm/freq-interleaver.cpp
./src/ofdm/fic-handler.cpp
./src/ofdm/fib-processor.cpp
./src/backend/protection.cpp
./src/backend/eep-protection.cpp
./src/backend/uep-protection.cpp
./src/backend/fib-processor.cpp
./src/backend/firecode-checker.cpp
./src/backend/frame-processor.cpp
./src/backend/protTables.cpp
./src/backend/charsets.cpp
./src/backend/galois.cpp
./src/backend/reed-solomon.cpp
./src/backend/msc-handler.cpp
./src/backend/virtual-backend.cpp
./src/backend/audio-backend.cpp
./src/backend/data-backend.cpp
./src/backend/audio/faad-decoder.cpp
./src/backend/audio/mp4processor.cpp
./src/backend/audio/mp2processor.cpp
./src/backend/data/virtual-datahandler.cpp
./src/backend/eep-protection.cpp
./src/backend/uep-protection.cpp
./src/backend/firecode-checker.cpp
./src/backend/frame-processor.cpp
./src/backend/protTables.cpp
./src/backend/charsets.cpp
./src/backend/galois.cpp
./src/backend/reed-solomon.cpp
./src/backend/msc-handler.cpp
./src/backend/virtual-backend.cpp
./src/backend/audio-backend.cpp
./src/backend/data-backend.cpp
./src/backend/audio/faad-decoder.cpp
./src/backend/audio/mp4processor.cpp
./src/backend/audio/mp2processor.cpp
./src/backend/data/virtual-datahandler.cpp
./src/backend/data/pad-handler.cpp
./src/backend/data/mot-handler.cpp
./src/backend/data/mot-dir.cpp
./src/backend/data/mot-object.cpp
./src/backend/data/data-processor.cpp
./devices/virtual-input.cpp
./src/output/audio-base.cpp
./src/output/audiosink.cpp
./src/output/newconverter.cpp
./src/output/fir-filters.cpp
./src/various/fft-handler.cpp
./src/various/Xtan2.cpp
./src/various/dab-params.cpp
./src/various/band-handler.cpp
./src/various/text-mapper.cpp
./src/backend/data/mot/mot-handler.cpp
./src/backend/data/mot/mot-object.cpp
./src/backend/data/mot/mot-dir.cpp
./src/backend/data/data-processor.cpp
./devices/virtual-input.cpp
./devices/rawfiles/rawfiles.cpp
./devices/wavfiles/wavfiles.cpp
./src/output/audio-base.cpp
./src/output/newconverter.cpp
./src/output/fir-filters.cpp
./src/support/fft-handler.cpp
./src/support/Xtan2.cpp
./src/support/dab-params.cpp
./src/support/band-handler.cpp
./src/support/text-mapper.cpp
./src/support/dab_tables.cpp
./src/support/viterbi_768/viterbi-768.cpp
./src/support/viterbi_768/spiral-no-sse.c
)
set (${objectName}_MOCS
./dab-processor.h
./service-list.h
./service-display.h
./service-description/service-descriptor.h
./service-description/audio-descriptor.h
./includes/output/audio-base.h
./includes/ofdm/sample-reader.h
./includes/ofdm/ofdm-decoder.h
./includes/ofdm/phasereference.h
./includes/backend/fic-handler.h
./includes/backend/fib-processor.h
./includes/backend/data-backend.h
./includes/ofdm/fic-handler.h
./includes/ofdm/fib-processor.h
./includes/backend/data-backend.h
./includes/backend/audio/faad-decoder.h
./includes/backend/audio/mp2processor.h
./includes/backend/audio/mp4processor.h
./includes/backend/data/virtual-datahandler.h
./includes/backend/data/pad-handler.h
./includes/backend/data/mot-handler.h
./includes/backend/data/mot-dir.h
./includes/backend/data/mot-object.h
./includes/backend/data/mot/mot-handler.h
./includes/backend/data/mot/mot-object.h
./includes/backend/data/mot/mot-dir.h
./includes/backend/data/data-processor.h
)
set (${objectName}_UIS
${${objectName}_UIS} ./forms/dabradio.ui)
set (${objectName}_UIS
${${objectName}_UIS} ./forms/dabradio.ui
./forms/audio-description.ui)
set (${objectName}_MOCS
${${objectName}_MOCS} ./radio.h)

View File

@@ -123,14 +123,16 @@ endif ()
${QT_QTGUI_INCLUDE_DIR}
.
./
./service-description
./includes
./includes/ofdm
./includes/backend
./includes/backend/viterbi_768
./includes/backend/audio
./includes/backend/data
./includes/backend/data/journaline
./includes/various
./includes/backend/data/mot
./includes/support
./includes/support/viterbi_768
./includes/output
./devices
/usr/include/
@@ -138,14 +140,17 @@ endif ()
set (${objectName}_HDRS
./dab-processor.h
./service-list.h
./service-display.h
./includes/ofdm/sample-reader.h
./includes/dab-constants.h
./service-description/service-descriptor.h
./service-description/audio-descriptor.h
./includes/country-codes.h
./includes/ofdm/timesyncer.h
./includes/ofdm/sample-reader.h
./includes/ofdm/phasereference.h
./includes/ofdm/phasetable.h
./includes/ofdm/freq-interleaver.h
./includes/backend/viterbi_768/viterbi-768.h
./includes/ofdm/fic-handler.h
./includes/ofdm/fib-processor.h
./includes/backend/protection.h
./includes/backend/uep-protection.h
./includes/backend/eep-protection.h
@@ -163,40 +168,42 @@ endif ()
./includes/backend/audio/mp2processor.h
./includes/backend/data/virtual-datahandler.h
./includes/backend/data/pad-handler.h
./includes/backend/data/mot-handler.h
./includes/backend/data/mot-dir.h
./includes/backend/data/mot-object.h
./includes/backend/data/mot/mot-handler.h
./includes/backend/data/mot/mot-object.h
./includes/backend/data/mot/mot-dir.h
./includes/backend/data/data-processor.h
./devices/virtual-input.h
./includes/output/fir-filters.h
./includes/output/audio-base.h
./includes/output/newconverter.h
./includes/various/fft-handler.h
./includes/various/ringbuffer.h
./includes/various/Xtan2.h
./includes/various/dab-params.h
./includes/various/band-handler.h
./includes/various/text-mapper.h
./includes/support/viterbi_768/viterbi-768.h
./includes/support/fft-handler.h
./includes/support/ringbuffer.h
./includes/support/Xtan2.h
./includes/support/dab-params.h
./includes/support/band-handler.h
./includes/support/text-mapper.h
./includes/support/dab_tables.h
)
set (${objectName}_SRCS
${${objectName}_SRCS}
./main.cpp
./dab-processor.cpp
./service-list.cpp
./service-display.cpp
./service-description/service-descriptor.cpp
./service-description/audio-descriptor.cpp
./src/ofdm/timesyncer.cpp
./src/ofdm/sample-reader.cpp
./src/ofdm/ofdm-decoder.cpp
./src/ofdm/phasereference.cpp
./src/ofdm/phasetable.cpp
./src/ofdm/freq-interleaver.cpp
./src/backend/viterbi_768/viterbi-768.cpp
./src/backend/viterbi_768/spiral-no-sse.c
./src/backend/fic-handler.cpp
./src/ofdm/fic-handler.cpp
./src/ofdm/fib-processor.cpp
./src/backend/protection.cpp
./src/backend/eep-protection.cpp
./src/backend/uep-protection.cpp
./src/backend/fib-processor.cpp
./src/backend/firecode-checker.cpp
./src/backend/frame-processor.cpp
./src/backend/protTables.cpp
@@ -212,9 +219,9 @@ endif ()
./src/backend/audio/mp2processor.cpp
./src/backend/data/virtual-datahandler.cpp
./src/backend/data/pad-handler.cpp
./src/backend/data/mot-handler.cpp
./src/backend/data/mot-dir.cpp
./src/backend/data/mot-object.cpp
./src/backend/data/mot/mot-handler.cpp
./src/backend/data/mot/mot-object.cpp
./src/backend/data/mot/mot-dir.cpp
./src/backend/data/data-processor.cpp
./devices/virtual-input.cpp
./devices/rawfiles/rawfiles.cpp
@@ -222,35 +229,39 @@ endif ()
./src/output/audio-base.cpp
./src/output/newconverter.cpp
./src/output/fir-filters.cpp
./src/various/fft-handler.cpp
./src/various/Xtan2.cpp
./src/various/dab-params.cpp
./src/various/band-handler.cpp
./src/various/text-mapper.cpp
./src/support/fft-handler.cpp
./src/support/Xtan2.cpp
./src/support/dab-params.cpp
./src/support/band-handler.cpp
./src/support/text-mapper.cpp
./src/support/dab_tables.cpp
./src/support/viterbi_768/viterbi-768.cpp
./src/support/viterbi_768/spiral-no-sse.c
)
set (${objectName}_UIS
${${objectName}_UIS} ./forms/dabradio.ui)
${${objectName}_UIS} ./forms/dabradio.ui
./forms/audio-description.ui)
set (${objectName}_MOCS
./dab-processor.h
./service-list.h
./service-display.h
./service-description/service-descriptor.h
./service-description/audio-descriptor.h
./includes/output/audio-base.h
./includes/ofdm/sample-reader.h
./includes/ofdm/ofdm-decoder.h
./includes/ofdm/phasereference.h
./includes/backend/fic-handler.h
./includes/backend/fib-processor.h
./includes/ofdm/fic-handler.h
./includes/ofdm/fib-processor.h
./includes/backend/data-backend.h
./includes/backend/audio/faad-decoder.h
./includes/backend/audio/mp2processor.h
./includes/backend/audio/mp4processor.h
./includes/backend/data/virtual-datahandler.h
./includes/backend/data/pad-handler.h
./includes/backend/data/mot-handler.h
./includes/backend/data/mot-dir.h
./includes/backend/data/mot-object.h
./includes/backend/data/mot/mot-handler.h
./includes/backend/data/mot/mot-object.h
./includes/backend/data/mot/mot-dir.h
./includes/backend/data/data-processor.h
)

70
LICENSE
View File

@@ -1,39 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (c) 2013 .. 2017
Jan van Katwijk
Lazy Chair Computing
J.vanKatwijk@gmail.com
The Qt-DAB software - as well as its predecessors DAB-rpi and sdr-j-dab
and derivatives - are made available under GPL license Version 2.
Many of the ideas as implemented in Qt-DAB are derived from
other work, made available through the GNU general Public License.
All copyrights of the original authors are acknowledged.
Qt-DAB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2,
as published by the Free Software Foundation.
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.
Any non-GPL usage of this software or parts of this software is strictly
forbidden. Commercial non-GPL licensing of this software is possible.
For more info contact the author, named above.
===========================================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -42,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@@ -82,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@@ -137,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@@ -195,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@@ -252,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@@ -282,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -304,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@@ -318,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -330,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@@ -363,5 +335,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -4,19 +4,19 @@
* Jan van Katwijk (J.vanKatwijk@gmail.com)
* Lazy Chair Computing
*
* This file is part of the Qt-DAB program
* Qt-DAB is free software; you can redistribute it and/or modify
* This file is part of the dabradio program
* dabradio 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,
* dabradio 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
* along with dabradio if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "dab-processor.h"
@@ -24,6 +24,7 @@
#include "msc-handler.h"
#include "radio.h"
#include "dab-params.h"
#include "timesyncer.h"
//
/**
* \brief dabProcessor
@@ -41,19 +42,21 @@
int16_t diff_length,
QString picturesPath):
params (dabMode),
myReader (mr, theDevice),
myReader (mr,
theDevice,
nullptr),
my_ficHandler (mr, dabMode),
my_mscHandler (mr, dabMode,
picturesPath),
phaseSynchronizer (mr,
dabMode,
threshold,
diff_length),
diff_length,
nullptr),
my_ofdmDecoder (mr,
dabMode,
theDevice -> bitDepth (),
&my_ficHandler,
&my_mscHandler) {
nullptr) {
int32_t i;
this -> myRadioInterface = mr;
@@ -71,8 +74,8 @@ int32_t i;
ofdmBufferIndex = 0;
ofdmSymbolCount = 0;
tokenCount = 0;
fineCorrector = 0;
f2Correction = true;
fineOffset = 0;
correctionNeeded = true;
attempts = 0;
myReader. setRunning (false);
}
@@ -107,89 +110,45 @@ void dabProcessor::start (int frequency, bool giveSignal) {
void dabProcessor::run (void) {
int32_t startIndex;
int32_t i;
std::complex<float> FreqCorr;
int32_t counter;
float cLevel;
int32_t syncBufferIndex = 0;
const
int32_t syncBufferSize = 32768;
const
int32_t syncBufferMask = syncBufferSize - 1;
float envBuffer [syncBufferSize];
int attempts;
fineCorrector = 0;
f2Correction = true;
syncBufferIndex = 0;
std::complex<float> FreqCorr;
timeSyncer myTimeSyncer (&myReader);
fineOffset = 0;
correctionNeeded = true;
attempts = 0;
theDevice -> resetBuffer ();
theDevice -> restartReader ();
coarseOffset = 0;
fineOffset = 0;
myReader. setRunning (true);
my_ofdmDecoder. start ();
my_mscHandler. start ();
//
// to get some idea of the signal strength
try {
for (i = 0; i < T_F / 5; i ++) {
myReader. getSample (0);
}
Initing:
//Initing:
notSynced:
syncBufferIndex = 0;
cLevel = 0;
for (i = 0; i < C_LEVEL_SIZE; i ++) {
std::complex<float> sample = myReader. getSample (0);
envBuffer [syncBufferIndex] = jan_abs (sample);
cLevel += envBuffer [syncBufferIndex];
syncBufferIndex ++;
}
/**
* We now have initial values for cLevel (i.e. the sum
* over the last C_LEVEL_SIZE samples) and sLevel, the long term average.
*/
SyncOnNull:
/**
* here we start looking for the null level, i.e. a dip
*/
counter = 0;
setSynced (false);
while (cLevel / C_LEVEL_SIZE > 0.40 * myReader. get_sLevel ()) {
std::complex<float> sample =
myReader. getSample (coarseOffset + fineCorrector);
envBuffer [syncBufferIndex] = jan_abs (sample);
// update the levels
cLevel += envBuffer [syncBufferIndex] -
envBuffer [(syncBufferIndex - C_LEVEL_SIZE) & syncBufferMask];
syncBufferIndex = (syncBufferIndex + 1) & syncBufferMask;
counter ++;
if (counter > T_F) { // hopeless
if (giveSignal && (++ attempts >= 5)) {
emit (No_Signal_Found ());
switch (myTimeSyncer. sync (T_null, T_F)) {
case TIMESYNC_ESTABLISHED:
break; // yes, we are ready
case NO_DIP_FOUND:
if (giveSignal && (++ attempts >= 5)) {
emit (No_Signal_Found ());
attempts = 0;
}
goto notSynced;
}
}
/**
* It seemed we found a dip that started app 65/100 * 50 samples earlier.
* We now start looking for the end of the null period.
*/
counter = 0;
SyncOnEndNull:
while (cLevel / C_LEVEL_SIZE < 0.75 * myReader. get_sLevel ()) {
std::complex<float> sample =
myReader. getSample (coarseOffset + fineCorrector);
envBuffer [syncBufferIndex] = jan_abs (sample);
// update the levels
cLevel += envBuffer [syncBufferIndex] -
envBuffer [(syncBufferIndex - C_LEVEL_SIZE) & syncBufferMask];
syncBufferIndex = (syncBufferIndex + 1) & syncBufferMask;
counter ++;
//
if (counter > T_null + 50) { // hopeless
goto notSynced;
}
}
goto notSynced;
default: // does not happen
case NO_END_OF_DIP_FOUND:
goto notSynced;
}
/**
* The end of the null period is identified, the actual end
* is probably about 40 samples earlier.
@@ -207,17 +166,18 @@ SyncOnPhase:
* is part of the samples read.
*/
myReader. getSamples (ofdmBuffer. data (),
T_u, coarseOffset + fineCorrector);
T_u, coarseOffset + fineOffset);
//
// and then, call upon the phase synchronizer to verify/compute
// the real "first" sample
startIndex = phaseSynchronizer. findIndex (ofdmBuffer);
if (startIndex < 0) { // no sync, try again
if (!f2Correction) {
if (!correctionNeeded) {
setSyncLost ();
}
goto notSynced;
}
/**
* Once here, we are synchronized, we need to copy the data we
* used for synchronization for block 0
@@ -238,13 +198,13 @@ Block_0:
setSynced (true);
myReader. getSamples (&((ofdmBuffer. data ()) [ofdmBufferIndex]),
T_u - ofdmBufferIndex,
coarseOffset + fineCorrector);
coarseOffset + fineOffset);
my_ofdmDecoder. processBlock_0 (ofdmBuffer);
// Here we look only at the block_0 when we need a coarse
// frequency synchronization.
f2Correction = !my_ficHandler. syncReached ();
if (f2Correction) {
correctionNeeded = !my_ficHandler. syncReached ();
if (correctionNeeded) {
int correction =
phaseSynchronizer. estimate_CarrierOffset (ofdmBuffer);
if (correction != 100) {
@@ -264,39 +224,33 @@ Data_blocks:
* corresponding samples in the datapart.
*/
FreqCorr = std::complex<float> (0, 0);
for (ofdmSymbolCount = 1;
ofdmSymbolCount < 4; ofdmSymbolCount ++) {
myReader. getSamples (ofdmBuffer. data (),
T_s, coarseOffset + fineCorrector);
for (i = (int)T_u; i < (int)T_s; i ++)
FreqCorr += ofdmBuffer [i] * conj (ofdmBuffer [i - T_u]);
for (int ofdmSymbolCount = 1;
ofdmSymbolCount < nrBlocks; ofdmSymbolCount ++) {
std::vector<int16_t> ibits;
ibits. resize (2 * params. get_carriers ());
myReader. getSamples (ofdmBuffer. data (),
T_s, coarseOffset + fineOffset);
for (i = (int)T_u; i < (int)T_s; i ++)
FreqCorr += ofdmBuffer [i] * conj (ofdmBuffer [i - T_u]);
my_ofdmDecoder. decodeFICblock (ofdmBuffer, ofdmSymbolCount);
}
/// and similar for the (params -> L - 4) MSC blocks
for (ofdmSymbolCount = 4;
ofdmSymbolCount < (uint16_t)nrBlocks;
ofdmSymbolCount ++) {
myReader. getSamples (ofdmBuffer. data (),
T_s, coarseOffset + fineCorrector);
for (i = (int32_t)T_u; i < (int32_t)T_s; i ++)
FreqCorr += ofdmBuffer [i] * conj (ofdmBuffer [i - T_u]);
my_ofdmDecoder. decodeMscblock (ofdmBuffer, ofdmSymbolCount);
}
if (ofdmSymbolCount < 4) {
my_ofdmDecoder. decode (ofdmBuffer,
ofdmSymbolCount, ibits. data ());
my_ficHandler. process_ficBlock (ibits, ofdmSymbolCount);
}
my_mscHandler. process_Msc (&((ofdmBuffer. data ()) [T_g]),
ofdmSymbolCount);
}
NewOffset:
// we integrate the newly found frequency error with the
// existing frequency error.
fineCorrector += 0.1 * arg (FreqCorr) / (2 * M_PI) * carrierDiff;
fineOffset += 0.1 * arg (FreqCorr) / (2 * M_PI) * carrierDiff;
//
/**
* OK, here we are at the end of the frame
* Assume everything went well and skip T_null samples
*/
syncBufferIndex = 0;
cLevel = 0;
myReader. getSamples (ofdmBuffer. data (),
T_null, coarseOffset);
/**
@@ -304,60 +258,53 @@ NewOffset:
* samples ahead. Before going for the next frame, we
* we just check the fineCorrector
*/
if (fineCorrector > carrierDiff / 2) {
coarseOffset += carrierDiff;
fineCorrector -= carrierDiff;
if (fineOffset > carrierDiff / 2) {
coarseOffset += carrierDiff;
fineOffset -= carrierDiff;
}
else
if (fineCorrector < -carrierDiff / 2) {
if (fineOffset < -carrierDiff / 2) {
coarseOffset -= carrierDiff;
fineCorrector += carrierDiff;
fineOffset += carrierDiff;
}
ReadyForNewFrame:
/// and off we go, up to the next frame
counter = 0;
goto SyncOnPhase;
}
catch (int e) {
// fprintf (stderr, "dabProcessor is stopping\n");
;
}
theDevice -> stopReader ();
my_ofdmDecoder. stop ();
my_mscHandler. stop ();
my_ficHandler. stop ();
}
void dabProcessor:: reset (void) {
myReader. setRunning (false);
theDevice -> stopReader ();
while (isRunning ())
usleep (1000);
usleep (10000);
my_ofdmDecoder. stop ();
my_mscHandler. reset ();
my_ficHandler. reset ();
QThread::start ();
}
void dabProcessor::stop (void) {
myReader. setRunning (false);
theDevice -> restartReader ();
while (isRunning ())
usleep (1000);
usleep (10000);
my_ofdmDecoder. stop ();
my_mscHandler. reset ();
my_ficHandler. reset ();
theDevice -> stopReader ();
usleep (10000);
my_ficHandler. reset ();
}
void dabProcessor::coarseCorrectorOn (void) {
f2Correction = true;
correctionNeeded = true;
coarseOffset = 0;
}
void dabProcessor::coarseCorrectorOff (void) {
f2Correction = false;
correctionNeeded = false;
}
// we could have derived the dab processor from fic and msc handlers,

View File

@@ -102,10 +102,10 @@ private:
int32_t carriers;
int32_t carrierDiff;
std::vector<std::complex<float> > dataBuffer;
int16_t fineCorrector;
int16_t fineOffset;
int32_t coarseOffset;
bool f2Correction;
bool correctionNeeded;
int32_t tokenCount;
std::vector<std::complex<float> >ofdmBuffer;
uint32_t ofdmBufferIndex;

37
dabradio-1.0_resource.rc Normal file
View File

@@ -0,0 +1,37 @@
#include <windows.h>
IDI_ICON1 ICON DISCARDABLE "/usr/shared/sdr-j-development/systems/dabradio/dabradio.ico"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,0,0,0
PRODUCTVERSION 0,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "\0"
VALUE "FileVersion", "0.0.0.0\0"
VALUE "LegalCopyright", "\0"
VALUE "OriginalFilename", "dabradio-1.0.exe\0"
VALUE "ProductName", "dabradio-1.0\0"
VALUE "ProductVersion", "0.0.0.0\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1200
END
END
/* End of Version info */

View File

@@ -24,14 +24,16 @@ TRANSLATIONS = i18n/de_DE.ts i18n/it_IT.ts i18n/hu_HU.ts
DEPENDPATH += . \
./src \
./service-description \
./includes \
./src/ofdm \
./src/backend \
./src/backend/viterbi_768 \
./src/backend/audio \
./src/backend/data \
./src/backend/data/mot \
./src/output \
./src/various \
./src/support \
./src/support/viterbi_768 \
./devices \
./devices/rawfiles \
./devices/wavfiles \
@@ -39,20 +41,24 @@ DEPENDPATH += . \
./includes/backend \
./includes/backend/audio \
./includes/backend/data \
./includes/backend/data/mot \
./includes/output \
./includes/various
./includes/support \
./includes/support/viterbi_768
INCLUDEPATH += . \
./ \
./src \
./service-description \
./includes \
./includes/ofdm \
./includes/backend \
./includes/backend/viterbi_768 \
./includes/backend/audio \
./includes/backend/data \
./includes/backend/data/mot \
./includes/output \
./includes/various \
./includes/support \
./includes/support/viterbi_768 \
./devices \
./devices/rawfiles \
./devices/wavfiles
@@ -60,20 +66,19 @@ INCLUDEPATH += . \
# Input
HEADERS += ./radio.h \
./dab-processor.h \
./service-list.h \
./service-display.h \
./service-description/service-descriptor.h \
./service-description/audio-descriptor.h \
./includes/dab-constants.h \
./includes/country-codes.h \
./includes/ofdm/timesyncer.h \
./includes/ofdm/sample-reader.h \
./includes/ofdm/ofdm-decoder.h \
./includes/ofdm/phasereference.h \
./includes/ofdm/phasetable.h \
./includes/ofdm/freq-interleaver.h \
# ./includes/backend/viterbi.h \
./includes/backend/viterbi_768/viterbi-768.h \
./includes/backend/fic-handler.h \
./includes/ofdm/fic-handler.h \
./includes/ofdm/fib-processor.h \
./includes/backend/msc-handler.h \
./includes/backend/fib-processor.h \
./includes/backend/galois.h \
./includes/backend/reed-solomon.h \
./includes/backend/rscodec.h \
@@ -89,9 +94,9 @@ HEADERS += ./radio.h \
./includes/backend/data/data-processor.h \
./includes/backend/data/pad-handler.h \
./includes/backend/data/virtual-datahandler.h \
./includes/backend/data/mot-handler.h \
./includes/backend/data/mot-dir.h \
./includes/backend/data/mot-object.h \
./includes/backend/data/mot/mot-handler.h \
./includes/backend/data/mot/mot-object.h \
./includes/backend/data/mot/mot-dir.h \
./includes/backend/protection.h \
./includes/backend/eep-protection.h \
./includes/backend/uep-protection.h \
@@ -99,36 +104,38 @@ HEADERS += ./radio.h \
./includes/output/audio-base.h \
./includes/output/newconverter.h \
./includes/output/audiosink.h \
./includes/various/fft-handler.h \
./includes/various/ringbuffer.h \
./includes/various/Xtan2.h \
./includes/various/dab-params.h \
./includes/various/band-handler.h \
./includes/various/text-mapper.h \
./includes/support/viterbi_768/viterbi-768.h \
./includes/support/fft-handler.h \
./includes/support/ringbuffer.h \
./includes/support/Xtan2.h \
./includes/support/dab-params.h \
./includes/support/band-handler.h \
./includes/support/text-mapper.h \
./includes/support/dab_tables.h \
./devices/virtual-input.h \
./devices/rawfiles/rawfiles.h \
./devices/wavfiles/wavfiles.h
FORMS += ./devices/filereader-widget.ui
FORMS += ./devices/filereader-widget.ui \
./forms/audio-description.ui
SOURCES += ./main.cpp \
./radio.cpp \
./dab-processor.cpp \
./service-list.cpp \
./service-display.cpp \
./service-description/service-descriptor.cpp \
./service-description/audio-descriptor.cpp \
./src/ofdm/timesyncer.cpp \
./src/ofdm/sample-reader.cpp \
./src/ofdm/ofdm-decoder.cpp \
./src/ofdm/phasereference.cpp \
./src/ofdm/phasetable.cpp \
./src/ofdm/freq-interleaver.cpp \
# ./src/backend/viterbi.cpp \
./src/backend/viterbi_768/viterbi-768.cpp \
./src/backend/fic-handler.cpp \
./src/ofdm/fic-handler.cpp \
./src/ofdm/fib-processor.cpp \
./src/backend/msc-handler.cpp \
./src/backend/protection.cpp \
./src/backend/eep-protection.cpp \
./src/backend/uep-protection.cpp \
./src/backend/fib-processor.cpp \
./src/backend/galois.cpp \
./src/backend/reed-solomon.cpp \
./src/backend/rscodec.cpp \
@@ -145,18 +152,19 @@ SOURCES += ./main.cpp \
./src/backend/data/pad-handler.cpp \
./src/backend/data/data-processor.cpp \
./src/backend/data/virtual-datahandler.cpp \
./src/backend/data/mot-handler.cpp \
./src/backend/data/mot-dir.cpp \
./src/backend/data/mot-object.cpp \
# ./src/output/fir-filters.cpp \
./src/backend/data/mot/mot-handler.cpp \
./src/backend/data/mot/mot-object.cpp \
./src/backend/data/mot/mot-dir.cpp \
./src/output/audio-base.cpp \
./src/output/newconverter.cpp \
./src/output/audiosink.cpp \
./src/various/fft-handler.cpp \
./src/various/Xtan2.cpp \
./src/various/dab-params.cpp \
./src/various/band-handler.cpp \
./src/various/text-mapper.cpp \
./src/support/viterbi_768/viterbi-768.cpp \
./src/support/fft-handler.cpp \
./src/support/Xtan2.cpp \
./src/support/dab-params.cpp \
./src/support/band-handler.cpp \
./src/support/text-mapper.cpp \
./src/support/dab_tables.cpp \
./devices/virtual-input.cpp \
./devices/rawfiles/rawfiles.cpp \
./devices/wavfiles/wavfiles.cpp
@@ -346,8 +354,8 @@ NEON_RPI2 {
DEFINES += NEON_AVAILABLE
QMAKE_CFLAGS += -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4
QMAKE_CXXFLAGS += -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4
HEADERS += ./src/backend/viterbi_768/spiral-neon.h
SOURCES += ./src/backend/viterbi_768/spiral-neon.c
HEADERS += ./src/support/viterbi_768/spiral-neon.h
SOURCES += ./src/support/viterbi_768/spiral-neon.c
}
# for RPI3 use:
@@ -355,18 +363,18 @@ NEON_RPI3 {
DEFINES += NEON_AVAILABLE
# QMAKE_CFLAGS += -mcpu=cortex-a53 -mfloat-abi=hard -mfpu=neon-fp-armv8 -mneon-for-64bits
# QMAKE_CXXFLAGS += -mcpu=cortex-a53 -mfloat-abi=hard -mfpu=neon-fp-armv8 -mneon-for-64bits
HEADERS += ./src/backend/viterbi_768/spiral-neon.h
SOURCES += ./src/backend/viterbi_768/spiral-neon.c
HEADERS += ./src/support/viterbi_768/spiral-neon.h
SOURCES += ./src/support/viterbi_768/spiral-neon.c
}
SSE {
DEFINES += SSE_AVAILABLE
HEADERS += ./src/backend/viterbi_768/spiral-sse.h
SOURCES += ./src/backend/viterbi_768/spiral-sse.c
HEADERS += ./src/support/viterbi_768/spiral-sse.h
SOURCES += ./src/support/viterbi_768/spiral-sse.c
}
NO_SSE {
HEADERS += ./src/backend/viterbi_768/spiral-no-sse.h
SOURCES += ./src/backend/viterbi_768/spiral-no-sse.c
HEADERS += ./src/support/viterbi_768/spiral-no-sse.h
SOURCES += ./src/support/viterbi_768/spiral-no-sse.c
}

327
forms/audio-description.ui Normal file
View File

@@ -0,0 +1,327 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>audioDescription</class>
<widget class="QWidget" name="audioDescription">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>329</width>
<height>311</height>
</rect>
</property>
<property name="windowTitle">
<string>audio description</string>
</property>
<widget class="QLabel" name="serviceName">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>151</width>
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans Mono</family>
<pointsize>10</pointsize>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="subChannelId">
<property name="geometry">
<rect>
<x>130</x>
<y>140</y>
<width>111</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="startAddress">
<property name="geometry">
<rect>
<x>130</x>
<y>160</y>
<width>171</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="Length">
<property name="geometry">
<rect>
<x>130</x>
<y>180</y>
<width>171</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>10</x>
<y>200</y>
<width>101</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>bitRate</string>
</property>
</widget>
<widget class="QLabel" name="protectionLevel">
<property name="geometry">
<rect>
<x>130</x>
<y>220</y>
<width>161</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="programType">
<property name="geometry">
<rect>
<x>130</x>
<y>240</y>
<width>161</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="Language">
<property name="geometry">
<rect>
<x>130</x>
<y>260</y>
<width>181</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>10</x>
<y>140</y>
<width>111</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>subchannel Id</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>10</x>
<y>160</y>
<width>91</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Start Address</string>
</property>
</widget>
<widget class="QLabel" name="label_4">
<property name="geometry">
<rect>
<x>10</x>
<y>180</y>
<width>81</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Length</string>
</property>
</widget>
<widget class="QLabel" name="bitrate">
<property name="geometry">
<rect>
<x>130</x>
<y>200</y>
<width>59</width>
<height>15</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="label_6">
<property name="geometry">
<rect>
<x>10</x>
<y>220</y>
<width>101</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Protection level</string>
</property>
</widget>
<widget class="QLabel" name="label_7">
<property name="geometry">
<rect>
<x>10</x>
<y>240</y>
<width>111</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>ProgramType</string>
</property>
</widget>
<widget class="QLabel" name="label_8">
<property name="geometry">
<rect>
<x>10</x>
<y>260</y>
<width>91</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Language</string>
</property>
</widget>
<widget class="QLabel" name="dabType">
<property name="geometry">
<rect>
<x>200</x>
<y>50</y>
<width>81</width>
<height>21</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans Mono</family>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="label_5">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>161</width>
<height>21</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans Mono</family>
<pointsize>11</pointsize>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>audio service</string>
</property>
</widget>
<widget class="QLabel" name="label_9">
<property name="geometry">
<rect>
<x>10</x>
<y>80</y>
<width>141</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>received on channel</string>
</property>
</widget>
<widget class="QLabel" name="channelLabel">
<property name="geometry">
<rect>
<x>170</x>
<y>80</y>
<width>81</width>
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans Mono</family>
<pointsize>11</pointsize>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="label_10">
<property name="geometry">
<rect>
<x>10</x>
<y>120</y>
<width>101</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>serviceId</string>
</property>
</widget>
<widget class="QLabel" name="serviceLabel">
<property name="geometry">
<rect>
<x>130</x>
<y>120</y>
<width>59</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -345,6 +345,9 @@
<height>31</height>
</rect>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Reset button. Press this and a scan is made over all channels in the selected band (BAND III by default)&lt;/p&gt;&lt;p&gt;to collect data on available services in these channels.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>reset</string>
</property>
@@ -377,6 +380,9 @@
<height>21</height>
</rect>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Synchronization indicator. Greem means sync is OK&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string/>
</property>

View File

@@ -29,6 +29,8 @@
#include <QByteArray>
#include <QString>
#include <QDir>
#include <map>
#include <iterator>
#ifdef TRY_EPG
#include "epgdec.h"
#endif
@@ -64,12 +66,11 @@ private:
int contentType;
int contentsubType;
QString name;
bool marked [128];
QByteArray segments [128];
void handleComplete (void);
#ifdef TRY_EPG
CEPGDecoder epgHandler;
CEPGDecoder epgHandler;
#endif
std::map<int, QByteArray> motMap;
signals:
void the_picture (QByteArray, int, QString);

View File

@@ -42,9 +42,9 @@ private:
void handle_variablePAD (uint8_t *, int16_t, uint8_t);
void handle_shortPAD (uint8_t *, int16_t, uint8_t);
void dynamicLabel (uint8_t *, int16_t, uint8_t);
void new_MSC_element (std::vector<uint8_t>, int);
void new_MSC_element (std::vector<uint8_t>);
void add_MSC_element (std::vector<uint8_t>);
void build_MSC_segment (std::vector<uint8_t>, int);
void build_MSC_segment (std::vector<uint8_t>);
bool pad_crc (uint8_t *, int16_t);
QString picturePath;
QString dynamicLabelText;
@@ -61,11 +61,6 @@ private:
// dataGroupLength is set when having processed an appType 1
int dataGroupLength;
//
// msc_dataGroupLength is used while assembling an msc_data group,
// in the end it should be equal or somewhat larger than dataGroupLength
int msc_dataGroupLength;
//
// The msc_dataGroupBuffer is - as the name suggests - used for
// assembling the msc_data group.
std::vector<uint8_t> msc_dataGroupBuffer;

View File

@@ -23,26 +23,33 @@
#ifndef __MSC_HANDLER__
#define __MSC_HANDLER__
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QSemaphore>
#include <atomic>
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
#include <vector>
#include <atomic>
#include "dab-constants.h"
#include "ringbuffer.h"
#include "dab-params.h"
#include "fft-handler.h"
#include "ringbuffer.h"
#include "phasetable.h"
#include "freq-interleaver.h"
class RadioInterface;
class virtualBackend;
class mscHandler {
class mscHandler: public QThread {
public:
mscHandler (RadioInterface *,
uint8_t,
QString);
~mscHandler (void);
void process_mscBlock (std::vector<int16_t>, int16_t);
void processBlock_0 (std::complex<float> *);
void process_Msc (std::complex<float> *, int);
void set_audioChannel (audiodata *,
RingBuffer<int16_t> *);
void set_dataChannel (packetdata *,
@@ -55,10 +62,17 @@ public:
// This function will kill
void stop (void);
private:
void process_mscBlock (std::vector<int16_t>, int16_t);
RadioInterface *myRadioInterface;
RingBuffer<uint8_t> *dataBuffer;
QString picturesPath;
dabParams params;
fftHandler my_fftHandler;
std::complex<float> *fft_buffer;
std::vector<complex<float>> phaseReference;
interLeaver myMapper;
QMutex locker;
bool audioService;
std::vector<virtualBackend *>theBackends;
@@ -83,9 +97,17 @@ private:
int16_t BitsperBlock;
int16_t numberofblocksperCIF;
int16_t blockCount;
int16_t **interleaveData;
int16_t interleaverIndex;
void run (void);
std::atomic<bool> running;
std::vector<std::vector<std::complex<float>>> command;
int16_t amount;
int16_t currentBlock;
void processBlock_0 (void);
void processMsc (int32_t n);
QSemaphore bufferSpace;
QWaitCondition commandHandler;
QMutex helper;
int nrBlocks;
};
#endif

View File

@@ -0,0 +1,71 @@
#
/*
* Copyright (C) 2013 .. 2017
* Jan van Katwijk (J.vanKatwijk@gmail.com)
* Lazy Chair Computing
*
* This file is part of 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
*/
#
/*
* FIC data
*/
#ifndef __FIC_HANDLER__
#define __FIC_HANDLER__
#include <stdio.h>
#include <stdint.h>
#include <vector>
#include "viterbi-768.h"
#include <QObject>
#include "fib-processor.h"
#include "dab-params.h"
class RadioInterface;
class ficHandler: public fib_processor {
Q_OBJECT
public:
ficHandler (RadioInterface *, uint8_t);
~ficHandler (void);
void process_ficBlock (std::vector<int16_t>, int16_t);
void stop (void);
void reset (void);
private:
viterbi_768 myViterbi;
dabParams params;
uint8_t bitBuffer_out [768];
int16_t ofdm_input [2304];
bool punctureTable [3072 + 24];
void process_ficInput (int16_t);
int16_t index;
int16_t BitsperBlock;
int16_t ficno;
int16_t ficBlocks;
int16_t ficMissed;
int16_t ficRatio;
uint16_t convState;
uint8_t PRBS [768];
uint8_t shiftRegister [9];
signals:
void show_ficSuccess (bool);
};
#endif

View File

@@ -41,67 +41,50 @@
#include "dab-params.h"
class RadioInterface;
class ficHandler;
class mscHandler;
#ifdef __THREADED_DECODING
class ofdmDecoder: public QThread {
#else
class ofdmDecoder: public QObject {
#endif
Q_OBJECT
public:
ofdmDecoder (RadioInterface *,
uint8_t,
int16_t,
ficHandler *,
mscHandler *);
RingBuffer<std::complex<float>> *ifBuffer = nullptr);
~ofdmDecoder (void);
void processBlock_0 (std::vector<std::complex<float> >);
void decodeFICblock (std::vector<std::complex<float> >, int32_t n);
void decodeMscblock (std::vector<std::complex<float> >, int32_t n);
void decode (std::vector<std::complex<float> >,
int32_t n, int16_t *);
int16_t get_snr (std::complex<float> *);
void stop (void);
void reset (void);
#ifndef __THREADED_DECODING
void start (void);
#endif
private:
RadioInterface *myRadioInterface;
dabParams params;
fftHandler my_fftHandler;
ficHandler *my_ficHandler;
mscHandler *my_mscHandler;
#ifdef __THREADED_DECODING
void run (void);
std::atomic<bool> running;
std::complex<float> **command;
int16_t amount;
int16_t currentBlock;
void processBlock_0 (void);
void decodeFICblock (int32_t n);
void decodeMscblock (int32_t n);
QSemaphore bufferSpace;
QWaitCondition commandHandler;
QMutex helper;
#endif
int32_t T_s;
int32_t T_u;
int32_t T_g;
int32_t nrBlocks;
int32_t carriers;
int16_t getMiddle (void);
std::vector<complex<float>> phaseReference;
std::vector<int16_t> ibits;
std::complex<float> *fft_buffer;
interLeaver myMapper;
phaseTable *phasetable;
int32_t blockIndex;
int16_t snrCount;
int16_t snr;
RadioInterface *myRadioInterface;
dabParams params;
fftHandler my_fftHandler;
interLeaver myMapper;
RingBuffer<std::complex<float>> *iqBuffer;
float computeQuality (std::complex<float> *);
int32_t T_s;
int32_t T_u;
int32_t T_g;
int32_t nrBlocks;
int32_t carriers;
int16_t getMiddle (void);
std::vector<complex<float>> phaseReference;
std::vector<int16_t> ibits;
std::complex<float> *fft_buffer;
phaseTable *phasetable;
int32_t blockIndex;
int16_t snrCount;
int16_t snr;
int16_t maxSignal;
signals:
void show_snr (int);
void showIQ (int);
void showQuality (float);
};
#endif

View File

@@ -38,10 +38,9 @@ Q_OBJECT
public:
phaseReference (RadioInterface *,
uint8_t,
#ifdef IMPULSE_RESPONSE
RingBuffer<float> *b,
#endif
int16_t, int16_t);
int16_t,
int16_t,
RingBuffer<float> *b = NULL);
~phaseReference (void);
int32_t findIndex (std::vector<std::complex<float>>);
int16_t estimate_CarrierOffset (std::vector<std::complex<float>>);
@@ -52,9 +51,7 @@ public:
private:
fftHandler my_fftHandler;
dabParams params;
#ifdef IMPULSE_RESPONSE
RingBuffer<float> *response;
#endif
std::vector<float> phaseDifferences;
int16_t threshold;
int16_t diff_length;

View File

@@ -45,7 +45,8 @@ class sampleReader : public QObject {
Q_OBJECT
public:
sampleReader (RadioInterface *mr,
virtualInput *theRig);
virtualInput *theRig
,RingBuffer<std::complex<float>> *spectrumBuffer = NULL);
~sampleReader (void);
void setRunning (bool b);
@@ -59,6 +60,7 @@ public:
private:
RadioInterface *myRadioInterface;
virtualInput *theRig;
RingBuffer<std::complex<float>> *spectrumBuffer;
std::vector<std::complex<float>> localBuffer;
int32_t localCounter;
int32_t bufferSize;

View File

@@ -0,0 +1,24 @@
#ifndef __TIMESYNCER__
#define __TIMESYNCER__
#include "dab-constants.h"
#define TIMESYNC_ESTABLISHED 0100
#define NO_DIP_FOUND 0101
#define NO_END_OF_DIP_FOUND 0102
class sampleReader;
class timeSyncer {
public:
timeSyncer (sampleReader *mr);
~timeSyncer (void);
int sync (int, int);
private:
sampleReader *myReader;
int32_t syncBufferIndex = 0;
const int32_t syncBufferSize = 4096;
};
#endif

View File

@@ -0,0 +1,16 @@
#pragma once
#include <inttypes.h>
const char * getASCTy (int16_t ASCTy);
const char * getDSCTy (int16_t DSCTy);
const char * getLanguage (int16_t language);
const char * getCountry (uint8_t ecc, uint8_t countryId);
const char * getProgramType_Not_NorthAmerica(int16_t programType);
const char * getProgramType_For_NorthAmerica(int16_t programType);
const char * getProgramType(bool, uint8_t interTabId, int16_t programType);
const char * getUserApplicationType(int16_t appType);
const char * getFECscheme(int16_t FEC_scheme);
const char * getProtectionLevel (bool shortForm, int16_t protLevel);
const char * getCodeRate (bool shortForm, int16_t protLevel);

170
radio.cpp
View File

@@ -29,11 +29,12 @@
#include <numeric>
#include <unistd.h>
#include <vector>
#include <QMouseEvent>
#include "radio.h"
#include "band-handler.h"
#include "audiosink.h"
#include "audio-descriptor.h"
#include <mutex>
#include "service-display.h"
/**
* We use the creation function merely to set up the
@@ -61,11 +62,6 @@ int gain;
scanning = false;
isSynced = UNSYNCED;
audioBuffer = new RingBuffer<int16_t>(16 * 32768);
/** threshold is used in the phaseReference class
* as threshold for checking the validity of the correlation result
* 3 is a reasonable value
*/
threshold =
dabSettings -> value ("threshold", 3). toInt ();
//
@@ -82,7 +78,6 @@ int gain;
dabMode = 1;
dataBuffer = new RingBuffer<uint8_t>(32768);
currentName = QString ("");
saveSlides = dabSettings -> value ("saveSlides", 1). toInt ();
showSlides = dabSettings -> value ("showPictures", 1). toInt ();
@@ -127,8 +122,9 @@ int gain;
copyrightLabel -> setToolTip (versionText);
ensembleDisplay = new serviceList (this, serviceNames);
ensembleDisplay = new QListView (NULL);
ensembleDisplay -> show ();
ensembleDisplay -> setToolTip ("Right clicking on a service name will make some technical details on the selected service visible");
soundOut = new audioSink (latency);
((audioSink *)soundOut) -> setupChannels (streamoutSelector);
@@ -167,15 +163,11 @@ int gain;
my_dabProcessor = new dabProcessor (this,
inputDevice,
dabMode,
threshold, diff_length,
threshold,
diff_length,
picturesPath);
connect (my_dabProcessor, SIGNAL (setSynced (char)),
this, SLOT (setSynced (char)));
//
serviceDescriptor *ss = new serviceDescriptor (" ", " ");
services. resize (1);
services [0] = ss; // a dummy
//
connect (gainSlider, SIGNAL (valueChanged (int)),
this, SLOT (handle_gainSlider (int)));
@@ -183,7 +175,14 @@ int gain;
this, SLOT (handle_autoButton (void)));
serviceCharacteristics = NULL;
secondsTimer. setInterval (1000);
connect (&secondsTimer, SIGNAL (timeout (void)),
this, SLOT (updateTime (void)));
secondsTimer. start (1000);
startScanning ();
qApp -> installEventFilter (this);
serviceDescription = NULL;
}
RadioInterface::~RadioInterface (void) {
@@ -199,9 +198,6 @@ void RadioInterface:: startScanning (void) {
this, SLOT (nextChannel (void)));
disconnect (my_dabProcessor, SIGNAL (No_Signal_Found (void)),
this, SLOT (nextChannel (void)));
disconnect (ensembleDisplay,
SIGNAL (newService (const QString &, const QString &)),
this, SLOT (selectService (const QString &, const QString &)));
serviceCount = 0;
serviceCountDisplay -> display (serviceCount);
channelNumber = 0;
@@ -222,9 +218,6 @@ void RadioInterface:: startScanning (void) {
this, SLOT (nextChannel (void)));
disconnect (my_dabProcessor, SIGNAL (No_Signal_Found (void)),
this, SLOT (nextChannel (void)));
connect (ensembleDisplay,
SIGNAL (newService (const QString &, const QString &)),
this, SLOT (selectService (const QString &, const QString &)));
connect (resetButton, SIGNAL (clicked (void)),
this, SLOT (reset (void)));
return;
@@ -234,10 +227,6 @@ void RadioInterface:: startScanning (void) {
QString text = "scanning ch ";
text. append (theBand -> channel (channelNumber. load ()));
set_ensembleName (text);
ensembleDisplay -> reset ();
services. resize (1);
serviceDescriptor *ss = new serviceDescriptor (" ", " ");
services [0] = ss; // a dummy
int tunedFrequency =
theBand -> Frequency (channelNumber. load ());
connect (&signalTimer, SIGNAL (timeout (void)),
@@ -275,8 +264,8 @@ void RadioInterface::nextChannel (void) {
serviceLabel -> setText ("select a services");
serviceLabel -> setStyleSheet ("QLabel {background-color : green}");
connect (ensembleDisplay,
SIGNAL (newService (const QString &, const QString &)),
this, SLOT (selectService (const QString &, const QString &)));
SIGNAL (clicked (QModelIndex)),
this, SLOT (selectService (QModelIndex)));
connect (resetButton, SIGNAL (clicked (void)),
this, SLOT (reset (void)));
return;
@@ -298,14 +287,25 @@ void RadioInterface::nextChannel (void) {
void RadioInterface::reset (void) {
my_dabProcessor -> stop ();
disconnect (ensembleDisplay,
SIGNAL (newService (const QString &, const QString &)),
this, SLOT (selectService (const QString &, const QString &)));
SIGNAL (clicked (QModelIndex)),
this, SLOT (selectService (QModelIndex)));
disconnect (resetButton, SIGNAL (clicked (void)),
this, SLOT (reset (void)));
for (int i = 0; i < channels; i ++) {
QString channel = theBand -> channel (i);
dabSettings -> setValue (channel, 1);
}
if (serviceDescription != NULL)
delete serviceDescription;
serviceDescription = NULL;
Services = QStringList ();
ensemble. setStringList (Services);
ensembleDisplay -> setModel (&ensemble);
for (std::map<QString, serviceDescriptor *>
::iterator it = serviceMap. begin ();
it != serviceMap. end (); it ++)
delete (it -> second);
serviceMap. clear ();
startScanning ();
}
//
@@ -314,7 +314,8 @@ void RadioInterface::reset (void) {
// when setting the channel for selecting a service in
// the large list
void RadioInterface::addtoEnsemble (const QString &s) {
if (!scanning && (services. size () > 0))
if (!scanning)
// if (!scanning && (services. size () > 0))
return;
if (scanning) {
@@ -329,12 +330,14 @@ void RadioInterface::addtoEnsemble (const QString &s) {
new serviceDescriptor (t,
channel,
&d);
services. push_back (service);
ensembleDisplay -> addRow (t,
channel,
QString::number (d. bitRate),
service -> programType);
Services << s;
Services. removeDuplicates ();
ensemble. setStringList (Services);
ensembleDisplay -> setModel (&ensemble);
dabSettings -> setValue (channel, 1);
serviceMap. insert (mapElement (t, service));
}
}
}
@@ -425,6 +428,26 @@ void RadioInterface::show_motHandling (bool b) {
setColor (motLabel, b);
}
void RadioInterface::showSpectrum (int s) {
(void)s;
}
void RadioInterface::showIQ (int s) {
(void)s;
}
void RadioInterface::showQuality (float f) {
(void)f;
}
void RadioInterface::show_snr (int s) {
(void)s;
}
void RadioInterface::set_CorrectorDisplay (int c) {
(void)c;
}
void RadioInterface::show_frameErrors (int e) {
emit set_quality (e);
}
@@ -520,7 +543,10 @@ void RadioInterface::showMOT (QByteArray data,
}
}
//
//
void RadioInterface::showImpulse (int a) {
(void)a;
}
/**
* \brief changeinConfiguration
@@ -571,6 +597,8 @@ void RadioInterface::TerminateProcess (void) {
fprintf (stderr, "deleted dabProcessor\n");
if (ensembleDisplay != NULL)
delete ensembleDisplay;
if (serviceDescription != NULL)
delete serviceDescription;
if (pictureLabel != NULL)
delete pictureLabel;
pictureLabel = NULL; // signals may be pending, so careful
@@ -580,61 +608,59 @@ void RadioInterface::TerminateProcess (void) {
fprintf (stderr, ".. end the radio silences\n");
}
void RadioInterface::updateTimeDisplay (void) {
time_t now = time (0);
char * dt = ctime (&now);
timeDisplay -> setText (QString (dt));
}
//
// Signals from the GUI
/////////////////////////////////////////////////////////////////////////
// Selecting a service is easy, the fib is asked to
// hand over the relevant data in two steps
void RadioInterface::selectService (const QString &currentProgram,
const QString &channel) {
void RadioInterface::selectService (QModelIndex ind ) {
if (scanning) // be polite, wait until we finished scanning
return;
if (serviceCharacteristics != NULL)
delete serviceCharacteristics;
QString currentProgram = ensemble. data (ind, Qt::DisplayRole). toString ();
running. store (true);
serviceLabel -> setStyleSheet ("QLabel {background-color : white}");
serviceLabel -> setText (currentProgram);
services [0] = new serviceDescriptor (currentProgram, channel);
std::map<QString, serviceDescriptor *>::iterator it;
it = serviceMap. find (currentProgram);
if (it == serviceMap. end ())
return;
serviceDescriptor *sd = it -> second;
fprintf (stderr, "channel = %s, currentChannel %s\n",
channel. toLatin1 (). data (),
sd -> channel. toLatin1 (). data (),
selectedChannel. toLatin1 (). data ());
if (selectedChannel != channel) {
if (selectedChannel != sd -> channel) {
my_dabProcessor -> stop ();
connect (&channelTimer, SIGNAL (timeout (void)),
this, SLOT (channelTimer_timeout (void)));
channelTimer. start (5000);
int tunedFrequency = theBand -> Frequency (channel);
int tunedFrequency = theBand -> Frequency (sd -> channel);
my_dabProcessor -> start (tunedFrequency, false);
selectedChannel = channel;
selectedChannel = sd -> channel;
fprintf (stderr, "ready to start %s (%s)\n",
currentProgram. toLatin1 (). data (),
channel. toLatin1 (). data ());
(sd -> channel). toLatin1 (). data ());
currentService = currentProgram;
}
else
selectService (currentProgram);
startService (currentProgram);
}
void RadioInterface::channelTimer_timeout (void) {
// so, we were looking for a channel. Let us see if
// it has provided us with data
QString currentService = services [0] -> name;
disconnect (&channelTimer, SIGNAL (timeout (void)),
this, SLOT (channelTimer_timeout (void)));
if (my_dabProcessor -> kindofService (currentService) !=
AUDIO_SERVICE)
return;
selectService (currentService);
startService (currentService);
}
void RadioInterface::selectService (QString currentService) {
void RadioInterface::startService (QString currentService) {
my_dabProcessor -> reset_msc ();
setStereo (false);
@@ -646,9 +672,6 @@ void RadioInterface::selectService (QString currentService) {
return;
}
serviceCharacteristics = new serviceDisplay (&d);
connect (this, SIGNAL (set_quality (int)),
serviceCharacteristics, SLOT (set_qualityIndicator (int)));
my_dabProcessor -> set_audioChannel (&d, audioBuffer, dataBuffer);
soundOut -> restart ();
showLabel (QString (" "));
@@ -712,4 +735,35 @@ QString defaultPath = QDir::tempPath ();
testdir. mkdir (picturesPath);
}
void RadioInterface::updateTime (void) {
QDateTime currentTime = QDateTime::currentDateTime ();
timeDisplay -> setText (currentTime.
toString (QString ("dd.MM.yy:hh:mm:ss")));
}
bool RadioInterface::eventFilter (QObject *obj, QEvent *event) {
if ((obj == ensembleDisplay -> viewport ()) &&
(event -> type () == QEvent::MouseButtonPress )) {
QMouseEvent *ev = static_cast<QMouseEvent *>(event);
if (ev -> buttons () & Qt::RightButton) {
audiodata ad;
QString serviceName =
this -> ensembleDisplay -> indexAt (ev -> pos()). data ().toString ();
if (serviceDescription != NULL)
delete serviceDescription;
std::map<QString, serviceDescriptor *>::iterator it;
it = serviceMap. find (serviceName);
if (it == serviceMap. end ())
return true;
serviceDescriptor *sd = it -> second;
if (sd -> defined) {
serviceDescription = new audioDescriptor (sd);
return true;
}
}
}
return QMainWindow::eventFilter (obj, event);
}

80
radio.h
View File

@@ -29,22 +29,25 @@
#include "dab-constants.h"
#include <QMainWindow>
#include <QStringList>
#include <QStringListModel>
#include <QListView>
#include <QComboBox>
#include <QLabel>
#include <QTimer>
#include <sndfile.h>
#include <atomic>
#include <map>
#include "ui_dabradio.h"
#include "dab-processor.h"
#include "ringbuffer.h"
#include "band-handler.h"
#include "text-mapper.h"
#include "service-list.h"
#include <atomic>
#include "service-descriptor.h"
class QSettings;
class virtualInput;
class audioBase;
class common_fft;
class audioDescriptor;
class spectrumhandler;
/*
@@ -52,50 +55,6 @@ class spectrumhandler;
* QDialog and the generated form
*/
class serviceDescriptor {
public:
QString name;
QString channel;
int32_t serviceId;
uint8_t shortForm;
uint8_t protLevel;
int32_t bitRate;
int32_t startAddr;
int32_t length;
QString language;
QString programType;
serviceDescriptor (QString name, QString channel, audiodata *d) {
textMapper the_textMapper;
this -> name = name;
this -> channel = channel;
this -> serviceId = d -> serviceId;
this -> shortForm = d -> shortForm;
this -> protLevel = d -> protLevel;
this -> bitRate = d -> bitRate;
this -> startAddr = d -> startAddr;
this -> length = d -> length;
this -> language = the_textMapper.
get_programm_language_string (d -> language);
this -> programType = the_textMapper.
get_programm_type_string (d -> programType);
}
serviceDescriptor (QString name, QString channel) {
this -> name = name;
this -> channel = channel;
this -> serviceId = 0;
this -> shortForm = 0;
this -> protLevel = 0;
this -> bitRate = 0;
this -> startAddr = 0;
this -> length = 0;
this -> language = QString ("");
this -> programType = QString ("");
}
~serviceDescriptor (void) {}
};
class RadioInterface: public QMainWindow,
private Ui_dabradio {
Q_OBJECT
@@ -116,10 +75,16 @@ private:
void setColor (QLabel *l, uint8_t b);
void setColor (QPushButton *l, uint8_t b);
QTimer secondsTimer;
typedef std::pair <QString, serviceDescriptor *> mapElement;
std::map<QString, serviceDescriptor *> serviceMap;
std::atomic<int> channelNumber;
int serviceCount;
QString selectedChannel;
std::vector<serviceDescriptor *> services;
QStringListModel ensemble;
QStringList Services;
QListView *ensembleDisplay;
uint8_t dabBand;
uint8_t dabMode;
uint8_t isSynced;
@@ -140,11 +105,10 @@ private:
bool saveSlides;
bool showSlides;
QFrame *serviceCharacteristics;
serviceList *ensembleDisplay;
QTimer displayTimer;
QTimer signalTimer;
QTimer channelTimer;
QString currentName;
QString currentService;
bool has_presetName;
int32_t numberofSeconds;
int16_t ficBlocks;
@@ -152,10 +116,15 @@ private:
int autogain;
QString picturesPath;
void selectService (QString);
void startService (QString);
void startScanning (void);
void TerminateProcess (void);
audioDescriptor *serviceDescription;
protected:
bool eventFilter (QObject *obj, QEvent *event);
public slots:
void set_CorrectorDisplay (int);
void addtoEnsemble (const QString &);
void nameofEnsemble (int, const QString &);
void set_ensembleName (const QString &);
@@ -172,19 +141,24 @@ public slots:
void set_streamSelector (int);
void nextChannel (void);
void closeEvent (QCloseEvent *event);
void updateTime (void);
void show_motHandling (bool);
void showImpulse (int);
void showSpectrum (int);
void showIQ (int);
void show_frameErrors (int);
void show_rsErrors (int);
void show_aacErrors (int);
void showQuality (float);
void show_snr (int);
// Somehow, these must be connected to the GUI
private slots:
void handle_gainSlider (int);
void handle_autoButton (void);
void reset (void);
void updateTimeDisplay (void);
void channelTimer_timeout (void);
void selectService (const QString &, const QString &);
void selectService (QModelIndex);
signals:
void set_quality (int);
};

View File

@@ -0,0 +1,34 @@
#include <QFont>
#include "dab_tables.h"
#include "audio-descriptor.h"
#include "service-descriptor.h"
audioDescriptor::audioDescriptor (serviceDescriptor *ad):
myFrame (NULL) {
setupUi (&myFrame);
myFrame. show ();
serviceLabel -> setText
(QString ().number (ad -> serviceId, 16). toUpper ());
QFont font = serviceLabel -> font ();
font. setBold (true);
serviceLabel -> setFont (font);
channelLabel -> setText (ad -> channel);
serviceName -> setText (ad -> name);
subChannelId -> setText (QString::number (ad -> subchId));
startAddress -> setText (QString::number (ad -> startAddr));
Length -> setText (QString::number (ad -> length));
bitrate -> setText (QString::number (ad -> bitRate));
QString protL = getProtectionLevel (ad -> shortForm,
ad -> protLevel);
protectionLevel -> setText (protL);
dabType -> setText (ad -> ASCTy == 077 ? "DAB+" : "DAB");
Language -> setText (getLanguage (ad -> language));
programType ->
setText (the_textMapper.
get_programm_type_string (ad -> programType));
}
audioDescriptor::~audioDescriptor (void) {
}

View File

@@ -0,0 +1,25 @@
#ifndef __AUDIO_DESCRIPTOR__
#define __AUDIO_DESCRIPTOR__
#include <QObject>
#include <QFrame>
#include <QSettings>
#include <atomic>
#include "dab-constants.h"
#include "ui_audio-description.h"
#include "text-mapper.h"
class serviceDescriptor;
class audioDescriptor : public Ui_audioDescription {
public:
audioDescriptor (serviceDescriptor *ad);
~audioDescriptor (void);
private:
QFrame myFrame;
textMapper the_textMapper;
};
#endif

View File

@@ -0,0 +1,25 @@
#include "dab_tables.h"
#include "data-descriptor.h"
dataDescriptor::dataDescriptor (packetdata *pd):
myFrame (NULL) {
setupUi (&myFrame);
myFrame. show ();
serviceName -> setText (pd -> serviceName);
subChannelId -> setText (QString::number (pd -> subchId));
startAddress -> setText (QString::number (pd -> startAddr));
Length -> setText (QString::number (pd -> length));
bitrate -> setText (QString::number (pd -> bitRate));
packetAddress-> setText (QString::number (pd -> packetAddress));
QString protL = getProtectionLevel (pd -> shortForm,
pd -> protLevel);
protectionLevel -> setText (protL);
appType -> setText (getDSCTy (pd -> DSCTy));
FECscheme -> setText (getFECscheme (pd -> FEC_scheme));
}
dataDescriptor::~dataDescriptor (void) {
}

View File

@@ -0,0 +1,23 @@
#ifndef __DATA_DESCRIPTOR__
#define __DATA_DESCRIPTOR__
#include <QObject>
#include <QFrame>
#include <QSettings>
#include <atomic>
#include "dab-constants.h"
#include "service-descriptor.h"
#include "ui_data-description.h"
#include "text-mapper.h"
class dataDescriptor : public serviceDescriptor, public Ui_dataDescription {
public:
dataDescriptor (packetdata *ad);
~dataDescriptor (void);
private:
QFrame myFrame;
textMapper the_textMapper;
};
#endif

View File

@@ -0,0 +1,24 @@
#include "service-descriptor.h"
#include "dab-constants.h"
serviceDescriptor::serviceDescriptor (QString name,
QString channel, audiodata *d) {
this -> defined = d -> defined;
if (d -> defined) {
this -> name = name;
this -> channel = channel;
this -> serviceId = d -> serviceId;
this -> subchId = d -> subchId;
this -> startAddr = d -> startAddr;
this -> shortForm = d -> shortForm;
this -> protLevel = d -> protLevel;
this -> length = d -> length;
this -> bitRate = d -> bitRate;
this -> ASCTy = d -> ASCTy;
this -> language = d -> language;
this -> programType = d -> programType;
}
}
serviceDescriptor::~serviceDescriptor (void) {}

View File

@@ -0,0 +1,30 @@
#ifndef __SERVICE_DESCRIPTOR__
#define __SERVICE_DESCRIPTOR__
#include <QString>
#include <stdio.h>
#include "dab-constants.h"
class serviceDescriptor {
public:
bool defined;
QString name;
QString channel;
int32_t serviceId;
int16_t subchId;
int16_t startAddr;
bool shortForm;
int16_t protLevel;
int16_t length;
int16_t bitRate;
int16_t ASCTy;
int16_t language;
int16_t programType;
serviceDescriptor (QString name, QString channel, audiodata *d);
~serviceDescriptor (void);
};
#endif

View File

@@ -1,71 +0,0 @@
#include "service-display.h"
#include <QLabel>
#include <QVBoxLayout>
#include "text-mapper.h"
serviceDisplay::serviceDisplay (audiodata *d, QWidget *parent):
QFrame (parent) {
QVBoxLayout *mainLayout = new QVBoxLayout ();
QLabel *nameofService = new QLabel (d -> serviceName);
QLabel *bitrateDisplay = new QLabel;
QString t1 = "bitrate ";
t1. append (QString::number (d -> bitRate));
bitrateDisplay -> setText (t1);
QLabel *lengthDisplay = new QLabel;
t1 = "segment length ";
t1. append (QString::number (d -> length));
lengthDisplay -> setText (t1);
uint16_t h = d -> protLevel;
QString protL;
if (!d -> shortForm) {
protL = "EEP ";
protL. append (QString::number ((h & 03) + 1));
if ((h & (1 << 2)) == 0)
protL. append ("-A");
else
protL. append ("-B");
}
else {
protL = "UEP ";
protL. append (QString::number (h));
}
QLabel * protectionLabel = new QLabel;
t1 = "protection ";
t1. append (protL);
protectionLabel -> setText (t1);
QLabel *typeLabel = new QLabel;
typeLabel -> setText (d -> ASCTy == 077 ? "DAB+" : "DAB");
QLabel *languageLabel = new QLabel;
languageLabel ->
setText (the_textMapper.
get_programm_language_string (d -> language));
QLabel *programtypeLabel = new QLabel;
programtypeLabel ->
setText (the_textMapper.
get_programm_type_string (d -> programType));
qualityIndicator = new QLabel ("Quality ");
mainLayout -> addWidget (nameofService);
mainLayout -> addWidget (bitrateDisplay);
mainLayout -> addWidget (lengthDisplay);
mainLayout -> addWidget (protectionLabel);
mainLayout -> addWidget (typeLabel);
mainLayout -> addWidget (languageLabel);
mainLayout -> addWidget (programtypeLabel);
mainLayout -> addWidget (qualityIndicator);
setLayout (mainLayout);
this -> setVisible (true);
}
serviceDisplay::~serviceDisplay (void) {
}
void serviceDisplay::set_qualityIndicator (int q) {
QString t = "Quality ";
t. append (QString::number (q));
qualityIndicator -> setText (t);
}

View File

@@ -1,21 +0,0 @@
#ifndef __SERVICE_DISPLAY__
#define __SERVICE_DISPLAY__
#include "dab-constants.h"
#include <QFrame>
#include <QLabel>
#include <QVBoxLayout>
#include "text-mapper.h"
class serviceDisplay : public QFrame {
Q_OBJECT
public:
serviceDisplay (audiodata *d, QWidget *parent = NULL);
~serviceDisplay (void);
private:
textMapper the_textMapper;
QLabel *qualityIndicator;
public slots:
void set_qualityIndicator (int);
};
#endif

View File

@@ -1,158 +0,0 @@
#
/*
* Copyright (C) 2018
* Jan van Katwijk (J.vanKatwijk@gmail.com)
* Lazy Chair Programming
*
* This file is part of the dabradio
*
* dabradio 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.
*
* dabradio 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
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <QFile>
#include <QDataStream>
#include "service-list.h"
#include "radio.h"
serviceList::serviceList (RadioInterface *mr,
QString saveName) {
this -> saveName = saveName;
myWidget = new QScrollArea (NULL);
myWidget -> resize (240, 200);
myWidget -> setWidgetResizable(true);
tableWidget = new QTableWidget (0, 4);
myWidget -> setWidget(tableWidget);
tableWidget -> setHorizontalHeaderLabels (
QStringList () << tr ("station") << tr ("channel") << tr ("bitrate") << tr ("program type"));
connect (tableWidget, SIGNAL (cellClicked (int, int)),
this, SLOT (tableSelect (int, int)));
// connect (tableWidget, SIGNAL (cellDoubleClicked (int, int)),
// this, SLOT (removeRow (int, int)));
// loadTable ();
}
serviceList::~serviceList (void) {
int16_t i;
int16_t rows = tableWidget -> rowCount ();
// saveTable ();
for (i = rows; i > 0; i --)
tableWidget -> removeRow (i);
delete tableWidget;
delete myWidget;
}
void serviceList::reset (void) {
int16_t i;
int16_t rows = tableWidget -> rowCount ();
saveTable ();
for (i = rows; i > 0; i --)
tableWidget -> removeRow (i - 1);
}
bool serviceList::isEmpty (void) {
return tableWidget -> rowCount () < 2;
}
void serviceList::show (void) {
myWidget -> show ();
}
void serviceList::hide (void) {
myWidget -> hide ();
}
void serviceList::addRow (const QString &name,
const QString &channel,
QString bitRate,
QString programType) {
int16_t row = tableWidget -> rowCount ();
tableWidget -> insertRow (row);
QTableWidgetItem *item0 = new QTableWidgetItem;
item0 -> setTextAlignment (Qt::AlignRight |Qt::AlignVCenter);
tableWidget -> setItem (row, 0, item0);
QTableWidgetItem *item1 = new QTableWidgetItem;
item1 -> setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
tableWidget -> setItem (row, 1, item1);
QTableWidgetItem *item2 = new QTableWidgetItem;
item2 -> setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
tableWidget -> setItem (row, 2, item2);
QTableWidgetItem *item3 = new QTableWidgetItem;
item3 -> setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
tableWidget -> setItem (row, 3, item3);
tableWidget -> setCurrentItem (item0);
tableWidget -> item (row, 0) -> setText (name);
tableWidget -> item (row, 1) -> setText (channel);
tableWidget -> item (row, 2) -> setText (bitRate);
tableWidget -> item (row, 3) -> setText (programType);
}
// Locally we dispatch the "click" and "translate"
// it into a frequency and a call to the main gui to change
// the frequency
void serviceList::tableSelect (int row, int column) {
QTableWidgetItem* serviceItem = tableWidget -> item (row, 0);
QTableWidgetItem* channelItem = tableWidget -> item (row, 1);
emit newService (serviceItem -> text (), channelItem -> text ());
}
void serviceList::removeRow (int row, int column) {
tableWidget -> removeRow (row);
(void)column;
}
void serviceList::saveTable (void) {
QFile file (saveName);
if (file. open (QIODevice::WriteOnly)) {
QDataStream stream (&file);
int32_t n = tableWidget -> rowCount ();
int32_t m = tableWidget -> columnCount ();
stream << n << m;
for (int i = 0; i < n; i ++)
for (int j = 0; j < m; j ++)
tableWidget -> item (i, j) -> write (stream);
file. close ();
}
}
void serviceList::loadTable (void) {
QFile file (saveName);
if (file. open (QIODevice::ReadOnly)) {
QDataStream stream (&file);
int32_t n, m;
stream >> n >> m;
tableWidget -> setRowCount (n);
tableWidget -> setColumnCount (m);
for (int i = 0; i < n; i ++) {
for (int j = 0; j < m; j ++) {
QTableWidgetItem *item = new QTableWidgetItem;
item -> read (stream);
tableWidget -> setItem (i, j, item);
}
}
file. close ();
}
}

View File

@@ -1,60 +0,0 @@
#
/*
* Copyright (C) 2014
* Jan van Katwijk (J.vanKatwijk@gmail.com)
* Lazy Chair Programming
*
* This file is part of the SDR-J series.
*
* SDR-J 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.
*
* SDR-J 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
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __SERVICE_LIST__
#define __SERVICE_LIST__
#include <QWidget>
#include <QScrollArea>
#include <QTableWidget>
#include <QStringList>
#include <QTableWidgetItem>
#include <QObject>
#include <QString>
class RadioInterface;
class serviceList:public QObject {
Q_OBJECT
public:
serviceList (RadioInterface *, QString);
~serviceList (void);
void addRow (const QString &, const QString &,
QString, QString);
void show (void);
void hide (void);
void loadTable (void);
void saveTable (void);
bool isEmpty (void);
void reset (void);
private slots:
void tableSelect (int, int);
void removeRow (int, int);
signals:
void newService (const QString &, const QString &);
private:
QScrollArea *myWidget;
QTableWidget *tableWidget;
QString saveName;
};
#endif

View File

@@ -27,43 +27,41 @@
/**
* This table maps "EBU Latin" charset to corresponding
* Unicode (UCS2-encoded) characters.
* See ETSI TS 101 756 v1.6.1, Annex C
* See ETSI TS 101 756 v1.8.1, Annex C
*/
static const unsigned short ebuLatinToUcs2[] = {
/* 0x00 - 0x07 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
/* 0x08 - 0x0f */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
/* 0x10 - 0x17 */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
/* 0x18 - 0x1f */ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x2d,
/* 0x20 - 0x27 */ 0x20, 0x21, 0x22, 0x23, 0xa4, 0x25, 0x26, 0x27,
/* 0x28 - 0x2f */ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
/* 0x30 - 0x37 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
/* 0x38 - 0x3f */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
/* 0x40 - 0x47 */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
/* 0x48 - 0x4f */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
/* 0x50 - 0x57 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
/* 0x58 - 0x5f */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x2015, 0x5f,
/* 0x60 - 0x67 */ 0x2551, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
/* 0x68 - 0x6f */ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
/* 0x70 - 0x77 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
/* 0x78 - 0x7f */ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0xaf, 0x7f,
/* 0x80 - 0x87 */ 0xe1, 0xe0, 0xe9, 0xe8, 0xed, 0xec, 0xf3, 0xf2,
/* 0x88 - 0x8f */ 0xfa, 0xf9, 0xd1, 0xc7, 0x015e, 0xdf, 0xa1, 0x0132,
/* 0x90 - 0x97 */ 0xe2, 0xe4, 0xea, 0xeb, 0xee, 0xef, 0xf4, 0xf6,
/* 0x98 - 0x9f */ 0xfb, 0xfc, 0xf1, 0xe7, 0x015f, 0x011f, 0x0131, 0x0133,
/* 0xa0 - 0xa7 */ 0xaa, 0x03b1, 0xa9, 0x2030, 0x011e, 0x011b, 0x0148, 0x0151,
/* 0xa8 - 0xaf */ 0x03c0, 0x20ac, 0xa3, 0x24, 0x2190, 0x2191, 0x2192, 0x2193,
/* 0xb0 - 0xb7 */ 0xba, 0xb9, 0xb2, 0xb3, 0xb1, 0x0130, 0x0144, 0x0171,
/* 0xb8 - 0xbf */ 0xb5, 0xbf, 0xf7, 0xb0, 0xbc, 0xbd, 0xbe, 0xa7,
/* 0xc0 - 0xc7 */ 0xc1, 0xc0, 0xc9, 0xc8, 0xcd, 0xcc, 0xd3, 0xd2,
/* 0xc8 - 0xcf */ 0xda, 0xd9, 0x0158, 0x010c, 0x0160, 0x017d, 0xd0, 0x13f,
/* 0xd0 - 0xd7 */ 0xc2, 0xc4, 0xca, 0xcb, 0xce, 0xcf, 0xd4, 0xd6,
/* 0xd8 - 0xdf */ 0xdb, 0xdc, 0x0159, 0x010d, 0x0161, 0x017e, 0x0111, 0x0140,
/* 0xe0 - 0xe7 */ 0x00c3, 0x00c5, 0x00c6, 0x0152, 0x0177, 0xdd, 0xd5, 0xd8,
/* 0xe8 - 0xef */ 0xde, 0x014a, 0x0154, 0x0106, 0x015a, 0x0179, 0x0166, 0xf0,
/* 0xf0 - 0xf7 */ 0xe3, 0xe5, 0xe6, 0x0153, 0x0175, 0xfd, 0xf5, 0xf8,
/* 0xf8 - 0xff */ 0xfe, 0x014b, 0x0155, 0x0107, 0x015b, 0x017a, 0x0167, 0xff
/* 0x00 - 0x07 */ 0x00, 0x118, 0x12e, 0x172, 0x102, 0x116, 0x10e, 0x218,
/* 0x8 - 0xf */ 0x21a, 0x10a, 0xa, 0xb, 0x120, 0x139, 0x17b, 0x143,
/* 0x10 - 0x17 */ 0x105, 0x119, 0x12f, 0x173, 0x103, 0x117, 0x10f, 0x219,
/* 0x18 - 0x1f */ 0x21b, 0x10b, 0x147, 0x11a, 0x121, 0x13a, 0x17c, 0x82,
/* 0x20 - 0x27 */ 0x20, 0x21, 0x22, 0x23, 0x142, 0x25, 0x26, 0x27,
/* 0x28 - 0x2f */ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
/* 0x30 - 0x37 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
/* 0x38 - 0x3f */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
/* 0x40 - 0x47 */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
/* 0x48 - 0x4f */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
/* 0x50 - 0x57 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
/* 0x58 - 0x5f */ 0x58, 0x59, 0x5a, 0x5b, 0x16e, 0x5d, 0x141, 0x5f,
/* 0x60 - 0x67 */ 0x104, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
/* 0x68 - 0x6f */ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
/* 0x70 - 0x77 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
/* 0x78 - 0x7f */ 0x78, 0x79, 0x7a, 0xab, 0x16f, 0xbb, 0x13d, 0x126,
/* 0x80 - 0x87 */ 0xe1, 0xe0, 0xe9, 0xe8, 0xed, 0xec, 0xf3, 0xf2,
/* 0x88 - 0x8f */ 0xfa, 0xf9, 0xd1, 0xc7, 0x15e, 0xdf, 0xa1, 0x178,
/* 0x90 - 0x97 */ 0xe2, 0xe4, 0xea, 0xeb, 0xee, 0xef, 0xf4, 0xf6,
/* 0x98 - 0x9f */ 0xfb, 0xfc, 0xf1, 0xe7, 0x15f, 0x11f, 0x131, 0xff,
/* 0xa0 - 0xa7 */ 0x136, 0x145, 0xa9, 0x122, 0x11e, 0x11b, 0x148, 0x151,
/* 0xa8 - 0xaf */ 0x150, 0x20ac, 0xa3, 0x24, 0x100, 0x112, 0x12a, 0x16a,
/* 0xb0 - 0xb7 */ 0x137, 0x146, 0x13b, 0x123, 0x13c, 0x130, 0x144, 0x171,
/* 0xb8 - 0xbf */ 0x170, 0xbf, 0x13e, 0xb0, 0x101, 0x113, 0x12b, 0x16b,
/* 0xc0 - 0xc7 */ 0xc1, 0xc0, 0xc9, 0xc8, 0xcd, 0xcc, 0xd3, 0xd2,
/* 0xc8 - 0xcf */ 0xda, 0xd9, 0x158, 0x10c, 0x160, 0x17d, 0xd0, 0x13f,
/* 0xd0 - 0xd7 */ 0xc2, 0xc4, 0xca, 0xcb, 0xce, 0xcf, 0xd4, 0xd6,
/* 0xd8 - 0xdf */ 0xdb, 0xdc, 0x159, 0x10d, 0x161, 0x17e, 0x111, 0x140,
/* 0xe0 - 0xe7 */ 0xc3, 0xc5, 0xc6, 0x152, 0x177, 0xdd, 0xd5, 0xd8,
/* 0xe8 - 0xef */ 0xde, 0x14a, 0x154, 0x106, 0x15a, 0x179, 0x164, 0xf0,
/* 0xf0 - 0xf7 */ 0xe3, 0xe5, 0xe6, 0x153, 0x175, 0xfd, 0xf5, 0xf8,
/* 0xf8 - 0xff */ 0xfe, 0x14b, 0x155, 0x107, 0x15b, 0x17a, 0x165, 0x127
};
QString toQStringUsingCharset (const char* buffer,

View File

@@ -40,7 +40,7 @@ struct {
this -> picturesPath = picturesPath;
orderNumber = 0;
theDirectory = NULL;
theDirectory = nullptr;
for (int i = 0; i < 15; i ++)
motTable [i]. orderNumber = -1;
}
@@ -51,7 +51,7 @@ int i;
for (i = 0; i < 15; i ++)
if (motTable [i]. orderNumber > 0)
delete motTable [i]. motSlide;
if (theDirectory != NULL)
if (theDirectory != nullptr)
delete theDirectory;
}
@@ -116,7 +116,7 @@ int32_t i;
case 3:
if (segmentNumber == 0) {
motObject *h = getHandle (transportId);
if (h != NULL)
if (h != nullptr)
break;
h = new motObject (myRadioInterface,
picturesPath,
@@ -131,7 +131,7 @@ int32_t i;
case 4: {
motObject *h = getHandle (transportId);
if (h == NULL)
if (h == nullptr)
break;
h -> addBodySegment (&motVector [2],
segmentNumber,
@@ -142,11 +142,11 @@ int32_t i;
case 6:
if (segmentNumber == 0) { // MOT directory
if (theDirectory != NULL)
if (theDirectory != nullptr)
if (theDirectory -> get_transportId () == transportId)
break; // already existing
if (theDirectory != NULL) // an old one, replace it
if (theDirectory != nullptr) // an old one, replace it
delete theDirectory;
int32_t segmentSize = ((motVector [0] & 0x1F) << 8) |
@@ -171,7 +171,7 @@ int32_t i;
segment);
}
else {
if ((theDirectory == NULL) ||
if ((theDirectory == nullptr) ||
(theDirectory -> get_transportId () != transportId))
break;
theDirectory -> directorySegment (transportId,
@@ -194,9 +194,9 @@ int i;
if ((motTable [i]. orderNumber >= 0) &&
(motTable [i]. transportId == transportId))
return motTable [i]. motSlide;
if (theDirectory != NULL)
if (theDirectory != nullptr)
return theDirectory -> getHandle (transportId);
return NULL;
return nullptr;
}
void motHandler::setHandle (motObject *h, uint16_t transportId) {
@@ -213,15 +213,16 @@ int index = 0;
}
//
// if here, the cache is full, so we delete the oldest one
index = 0;
for (i = 0; i < 15; i ++)
if (motTable [i]. orderNumber < oldest) {
oldest = motTable [i]. orderNumber;
index = i;
}
delete motTable [i]. motSlide;
motTable [i]. orderNumber = orderNumber ++;
motTable [i]. transportId = transportId;
motTable [i]. motSlide = h;
delete motTable [index]. motSlide;
motTable [index]. orderNumber = orderNumber ++;
motTable [index]. transportId = transportId;
motTable [index]. motSlide = h;
}

View File

@@ -87,10 +87,6 @@ int32_t pointer = 7;
pointer += length;
}
}
//
// no segments as yet
for (int i = 0; i < 128; i ++)
marked [i] = false;
}
motObject::~motObject (void) {
@@ -111,17 +107,22 @@ void motObject::addBodySegment (uint8_t *bodySegment,
bool lastFlag) {
int32_t i;
if (marked [segmentNumber]) // we already have the segment
return;
// fprintf (stderr, "adding segment %d\n", segmentNumber);
if ((segmentNumber < 0) || (segmentNumber >= 8192))
return;
if (motMap. find (segmentNumber) != motMap. end ())
return;
// Note that the last segment may have a different size
if (!lastFlag && (this -> segmentSize == -1))
this -> segmentSize = segmentSize;
//
segments [segmentNumber]. resize (segmentSize);
for (i = 0; i < segmentSize; i ++)
segments [segmentNumber][i] = bodySegment [i];
marked [segmentNumber] = true;
QByteArray segment;
segment. resize (segmentSize);
for (i = 0; i < segmentSize; i ++)
segment [i] = bodySegment [i];
motMap. insert (std::make_pair (segmentNumber, segment));
//
if (lastFlag)
numofSegments = segmentNumber + 1;
@@ -131,22 +132,21 @@ int32_t i;
//
// once we know how many segments there are/should be,
// we check for completeness
for (i = 0; i < numofSegments; i ++)
if (!(marked [i])) {
for (i = 0; i < numofSegments; i ++) {
if (motMap. find (i) == motMap. end ())
return;
}
//
}
// The motObject is (seems to be) complete
handleComplete ();
}
void motObject::handleComplete (void) {
int i;
QByteArray result;
for (i = 0; i < numofSegments; i ++)
result. append (segments [i]);
for (const auto &it : motMap)
result. append (it. second);
if (contentType == 7) { // epg data
#ifdef TRY_EPG
@@ -168,7 +168,7 @@ QByteArray result;
realName. toLatin1 (). data ());
checkDir (realName);
FILE *x = fopen (realName. toLatin1 (). data (), "w+b");
if (x == NULL)
if (x == nullptr)
fprintf (stderr, "cannot write file %s\n",
realName. toLatin1 (). data ());
else {

View File

@@ -35,7 +35,7 @@
connect (this, SIGNAL (show_motHandling (bool)),
mr, SLOT (show_motHandling (bool)));
this -> picturePath = picturesPath;
currentSlide = NULL;
currentSlide = nullptr;
//
// mscGroupElement indicates whether we are handling an
// msc datagroup or not.
@@ -54,7 +54,7 @@
}
padHandler::~padHandler (void) {
if (currentSlide != NULL)
if (currentSlide != nullptr)
delete currentSlide;
}
@@ -65,8 +65,9 @@ void padHandler::processPAD (uint8_t *buffer, int16_t last,
uint8_t L1, uint8_t L0) {
uint8_t fpadType = (L1 >> 6) & 03;
if (fpadType != 00)
if (fpadType != 00) {
return;
}
//
// OK, we'll try
@@ -90,7 +91,7 @@ uint8_t fpadType = (L1 >> 6) & 03;
// on the vector address and the offset of the last element
// in that vector
//
// shortPad's are 4 byte values. If the CI is on, then the type 2
// shortPad's are 4 byte values. If the CI is on, then type 2
// indicates the start of a segment. Type 3 the continuation.
// The start of a message, i.e. segment 0 is (a.o) found by
// a (1, 0) value of the firstSegment/lastSegment values.
@@ -107,6 +108,7 @@ int16_t i;
lastSegment = (b [last - 1] & 0x20) != 0;
charSet = b [last - 2] & 0x0F;
uint8_t AcTy = CI & 037; // application type
switch (AcTy) {
default:
break;
@@ -114,6 +116,18 @@ int16_t i;
case 0: // end marker
break;
//
case 2: // start of fragment, extract the length
if (firstSegment && !lastSegment) {
segmentNumber = b [last - 2] >> 4;
if (dynamicLabelText. size () > 0)
showLabel (dynamicLabelText);
dynamicLabelText. clear ();
}
still_to_go = b [last - 1] & 0x0F;
shortpadData. resize (0);
shortpadData. push_back (b [last - 3]);
break;
case 3: // continuation of fragment
for (i = 0; (i < 3) && (still_to_go > 0); i ++) {
still_to_go --;
@@ -131,17 +145,6 @@ int16_t i;
}
break;
case 2: // start of fragment, extract the length
if (firstSegment && !lastSegment) {
segmentNumber = b [last - 2] >> 4;
if (dynamicLabelText. size () > 0)
showLabel (dynamicLabelText);
dynamicLabelText. clear ();
}
still_to_go = b [last - 1] & 0x0F;
shortpadData. resize (0);
shortpadData. push_back (b [last - 3]);
break;
}
}
else { // No CI flag
@@ -215,12 +218,14 @@ std::vector<uint8_t> data; // for the local addition
for (i = 0; i < CI_Index; i ++)
xpadLength += lengthTable [CI_table [i] >> 5];
xpadLength += CI_Index == 4 ? 4 : CI_Index + 1;
// fprintf (stderr, "xpadLength set to %d\n", xpadLength);
}
//
// Handle the contents
for (i = 0; i < CI_Index; i ++) {
uint8_t appType = CI_table [i] & 037;
int16_t length = lengthTable [CI_table [i] >> 5];
if (appType == 1) {
dataGroupLength = ((b [base] & 077) << 8) | b [base - 1];
base -= 4;
@@ -244,7 +249,7 @@ std::vector<uint8_t> data; // for the local addition
break;
case 12: // MOT, start of X-PAD data group
new_MSC_element (data, dataGroupLength);
new_MSC_element (data);
break;
case 13: // MOT, continuation of X-PAD data group
@@ -349,43 +354,62 @@ int16_t dataLength = 0;
//
// Called at the start of the msc datagroupfield,
// the msc_length was given by the preceding appType "1"
void padHandler::new_MSC_element (std::vector<uint8_t> data,
int msc_length) {
void padHandler::new_MSC_element (std::vector<uint8_t> data) {
// if (mscGroupElement) {
//// if (msc_dataGroupBuffer. size () < dataGroupLength)
//// fprintf (stderr, "short ? %d %d\n",
//// msc_dataGroupBuffer. size (),
//// dataGroupLength);
// msc_dataGroupBuffer. clear ();
// build_MSC_segment (data);
// mscGroupElement = true;
// show_motHandling (true);
// }
if (data. size () >= dataGroupLength) { // msc element is single item
msc_dataGroupBuffer. clear ();
build_MSC_segment (data);
mscGroupElement = false;
show_motHandling (true);
// fprintf (stderr, "msc element is single\n");
return;
}
mscGroupElement = true;
msc_dataGroupBuffer. clear ();
msc_dataGroupBuffer = data;
msc_dataGroupLength = msc_length;
show_motHandling (true);
}
//
void padHandler::add_MSC_element (std::vector<uint8_t> data) {
int16_t i;
int16_t currentLength = msc_dataGroupBuffer. size ();
int32_t currentLength = msc_dataGroupBuffer. size ();
//
// just to ensure that, when a "12" appType is missing, the
// data of "13" appType elements is not endlessly collected.
if (currentLength == 0)
if (currentLength == 0) {
return;
}
msc_dataGroupBuffer. insert (std::end (msc_dataGroupBuffer),
std::begin (data), std::end (data));
if (msc_dataGroupBuffer. size () >= msc_dataGroupLength) {
build_MSC_segment (msc_dataGroupBuffer, msc_dataGroupLength);
if (msc_dataGroupBuffer. size () >= dataGroupLength) {
build_MSC_segment (msc_dataGroupBuffer);
msc_dataGroupBuffer. clear ();
// mscGroupElement = false;
xpadLength = -1;
show_motHandling (false);
}
}
void padHandler::build_MSC_segment (std::vector<uint8_t> data,
int msc_length) {
void padHandler::build_MSC_segment (std::vector<uint8_t> data) {
// we have a MOT segment, let us look what is in it
// according to DAB 300 401 (page 37) the header (MSC data group)
// is
int16_t size = data. size ();
int32_t size = data. size () < dataGroupLength ? data. size () :
dataGroupLength;
uint8_t groupType = data [0] & 0xF;
uint8_t continuityIndex = (data [1] & 0xF0) >> 4;
uint8_t repetitionIndex = data [1] & 0xF;
@@ -395,26 +419,29 @@ int16_t size = data. size ();
uint16_t index;
if ((data [0] & 0x40) != 0) {
bool res = check_crc_bytes (data. data (), msc_length - 2);
bool res = check_crc_bytes (data. data (), size - 2);
if (!res) {
// fprintf (stderr, "build_MSC_segment fails on crc check\n");
return;
}
// else
// fprintf (stderr, "crc success ");
}
if ((groupType != 3) && (groupType != 4))
if ((groupType != 3) && (groupType != 4)) {
return; // do not know yet
}
// extensionflag
bool extensionFlag = (data [0] & 0x80) != 0;
// if the segmentflag is on, then a lastflag and segmentnumber are
// available, i.e. 2 bytes more
// available, i.e. 2 bytes more.
// Theoretically, the segment number can be as large as 16384
index = extensionFlag ? 4 : 2;
bool segmentFlag = (data [0] & 0x20) != 0;
if ((segmentFlag) != 0) {
lastFlag = data [index] & 0x80;
segmentNumber = ((data [index] & 0x7F) << 8) | data [index + 1];
segmentNumber = ((data [index] & 0x7F) << 8) |
data [index + 1];
index += 2;
}
@@ -427,20 +454,25 @@ int16_t size = data. size ();
index += 3;
}
else {
fprintf (stderr, "sorry no transportId\n");
// fprintf (stderr, "sorry no transportId\n");
return;
}
index += (lengthIndicator - 2);
}
if (transportId == 0) // no idea wat it means
return;
uint32_t segmentSize = ((data [index + 0] & 0x1F) << 8) |
data [index + 1];
// fprintf (stderr, "segmentSize = %d (transportId = %d)\n",
// segmentSize, transportId);
//
// handling MOT in the PAD, we only deal here with type 3/4
switch (groupType) {
case 3:
if (currentSlide == NULL) {
if (currentSlide == nullptr) {
// fprintf (stderr, "creating %d\n", transportId);
currentSlide = new motObject (myRadioInterface,
picturePath,
false,
@@ -452,7 +484,9 @@ int16_t size = data. size ();
else {
if (currentSlide -> get_transportId () == transportId)
break;
// fprintf (stderr, "out goes %d, in comes %d\n",
// currentSlide -> get_transportId (),
// transportId);
delete currentSlide;
currentSlide = new motObject (myRadioInterface,
picturePath,
@@ -465,17 +499,19 @@ int16_t size = data. size ();
break;
case 4:
if (currentSlide == NULL)
break; // no header yet
if (currentSlide -> get_transportId () == transportId)
if (currentSlide == nullptr)
return;
if (currentSlide -> get_transportId () == transportId) {
// fprintf (stderr, "add segment %d of %d\n",
// segmentNumber, transportId);
currentSlide -> addBodySegment (&data [index + 2],
segmentNumber,
segmentSize,
lastFlag);
}
break;
default: // cannot happen
break;
}
}

View File

@@ -33,59 +33,144 @@
// a service is selected or not.
#define CUSize (4 * 16)
static int cifTable [] = {18, 72, 0, 36};
// Note CIF counts from 0 .. 3
//
mscHandler::mscHandler (RadioInterface *mr,
uint8_t mode,
uint8_t dabMode,
QString picturesPath) :
params (mode) {
params (dabMode),
my_fftHandler (dabMode),
myMapper (dabMode),
bufferSpace (params. get_L ()){
myRadioInterface = mr;
this -> picturesPath = picturesPath;
cifVector. resize (55296);
theBackends. push_back (new virtualBackend (0, 0));
BitsperBlock = 2 * params. get_carriers ();
switch (mode) {
case 4: // 2 CIFS per 76 blocks
numberofblocksperCIF = 36;
break;
nrBlocks = params. get_L ();
case 1: // 4 CIFS per 76 blocks
numberofblocksperCIF = 18;
break;
command. resize (nrBlocks);
for (int i = 0; i < nrBlocks; i ++)
command [i]. resize (params. get_T_u ());
amount = 0;
fft_buffer = my_fftHandler. getVector ();
phaseReference .resize (params. get_T_u ());
case 2: // 1 CIF per 76 blocks
numberofblocksperCIF = 72;
break;
default:
numberofblocksperCIF = 18;
break;
}
numberofblocksperCIF = cifTable [(dabMode - 1) & 03];
work_to_be_done. store (false);
}
mscHandler::~mscHandler (void) {
reset ();
running. store (false);
while (isRunning ())
usleep (100);
locker. lock ();
work_to_be_done. store (false);
for (auto const &b : theBackends) {
b -> stopRunning ();
delete b;
}
locker. unlock ();
theBackends. resize (0);
}
//
// Input is put into a buffer, a the code in a separate thread
// will handle the data from the buffer
void mscHandler::processBlock_0 (std::complex<float> *b) {
bufferSpace. acquire (1);
memcpy (command [0]. data (), b,
params. get_T_u () * sizeof (std::complex<float>));
helper. lock ();
amount ++;
commandHandler. wakeOne ();
helper. unlock ();
}
void mscHandler::process_Msc (std::complex<float> *b, int blkno) {
bufferSpace. acquire (1);
memcpy (command [blkno]. data (), b,
params. get_T_u () * sizeof (std::complex<float>));
helper. lock ();
amount ++;
commandHandler. wakeOne ();
helper. unlock ();
}
void mscHandler::run (void) {
int currentBlock = 0;
std::vector<int16_t> ibits;
running. store (true);
ibits. resize (BitsperBlock);
while (running. load ()) {
helper. lock ();
commandHandler. wait (&helper, 100);
helper. unlock ();
while ((amount > 0) && running. load ()) {
memcpy (fft_buffer, command [currentBlock]. data (),
params. get_T_u () * sizeof (std::complex<float>));
//
// block 3 and up are needed as basis for demodulation the "mext" block
// "our" msc blocks start with blkno 4
my_fftHandler. do_FFT ();
if (currentBlock >= 4) {
for (int i = 0; i < params. get_carriers (); i ++) {
int16_t index = myMapper. mapIn (i);
if (index < 0)
index += params. get_T_u ();
std::complex<float> r1 = fft_buffer [index] *
conj (phaseReference [index]);
float ab1 = jan_abs (r1);
// Recall: the viterbi decoder wants 127 max pos, - 127 max neg
// we make the bits into softbits in the range -127 .. 127
ibits [i] = - real (r1) / ab1 * 127.0;
ibits [params. get_carriers () + i]
= - imag (r1) / ab1 * 127.0;
}
process_mscBlock (ibits, currentBlock);
}
memcpy (phaseReference. data (), fft_buffer,
params. get_T_u () * sizeof (std::complex<float>));
bufferSpace. release (1);
helper. lock ();
currentBlock = (currentBlock + 1) % (nrBlocks);
amount -= 1;
helper. unlock ();
}
}
}
// This function is to be called between invocations of
// services
// It might be called several times, so ...
void mscHandler::reset (void) {
int i;
locker. lock ();
work_to_be_done. store (false);
for (i = 0; i < theBackends. size (); i ++) {
theBackends [i] -> stopRunning ();
delete theBackends [i];
}
theBackends. resize (0);
locker. unlock ();
void mscHandler::reset (void) {
int i;
running. store (false);
while (isRunning ())
usleep (100);
locker. lock ();
work_to_be_done. store (false);
for (auto const &b : theBackends) {
b -> stopRunning ();
delete b;
}
theBackends. resize (0);
bufferSpace. release (nrBlocks - bufferSpace. available ());
locker. unlock ();
start ();
}
void mscHandler::stop (void) {
reset ();
}
//
// Note, the set_xxx functions are called from within a
// different thread than the process_mscBlock method,
// different thread than the process_mscBlock method is,
// so, a little bit of locking seems wise while
// the actual changing of the settings is done in the
// thread executing process_mscBlock
@@ -93,7 +178,7 @@ void mscHandler::set_audioChannel (audiodata *d,
RingBuffer<int16_t> *audioBuffer) {
locker. lock ();
//
// we could assert here that theBackend == NULL
// we could assert here that theBackend == nullptr
theBackends. push_back (new audioBackend (myRadioInterface,
d,
audioBuffer,
@@ -114,10 +199,11 @@ void mscHandler::set_dataChannel (packetdata *d,
}
//
// add blocks. First is (should be) block 5, last is (should be) 76
// add blocks. First is (should be) block 4, last is (should be)
// nrBlocks -1.
// Note that this method is called from within the ofdm-processor thread
// while the set_xxx methods are called from within the
// gui thread
// gui thread, so some locking is added
//
// Any change in the selected service will only be active
// during te next process_mscBlock call.
@@ -140,21 +226,17 @@ int16_t i;
// be done. We assume that the backend itself
// does the work in a separate thread.
locker. lock ();
for (i = 0; i < theBackends. size (); i ++) {
int16_t startAddr = theBackends [i] -> startAddr ();
int16_t Length = theBackends [i] -> Length ();
for (auto const& b: theBackends) {
int16_t startAddr = b -> startAddr ();
int16_t Length = b -> Length ();
if (Length > 0) { // Length = 0? virtual Backend
int16_t temp [Length * CUSize];
memcpy (temp, &cifVector [startAddr * CUSize],
Length * CUSize * sizeof (int16_t));
(void) theBackends [i] -> process (temp, Length * CUSize);
(void) b -> process (temp, Length * CUSize);
}
}
locker. unlock ();
}
//
void mscHandler::stop (void) {
reset ();
}

View File

@@ -48,176 +48,49 @@
ofdmDecoder::ofdmDecoder (RadioInterface *mr,
uint8_t dabMode,
int16_t bitDepth,
ficHandler *my_ficHandler,
mscHandler *my_mscHandler):
RingBuffer<std::complex<float>> *iqBuffer) :
params (dabMode),
my_fftHandler (dabMode),
#ifdef __THREADED_DECODING
bufferSpace (params. get_L ()),
#endif
myMapper (dabMode) {
int16_t i;
this -> myRadioInterface = mr;
this -> iqBuffer = iqBuffer;
connect (this, SIGNAL (showIQ (int)),
myRadioInterface, SLOT (showIQ (int)));
connect (this, SIGNAL (showQuality (float)),
myRadioInterface, SLOT (showQuality (float)));
//
this -> my_ficHandler = my_ficHandler;
this -> my_mscHandler = my_mscHandler;
this -> T_s = params. get_T_s ();
this -> T_u = params. get_T_u ();
this -> nrBlocks = params. get_L ();
this -> carriers = params. get_carriers ();
ibits. resize (2 * this -> carriers);
this -> T_g = T_s - T_u;
fft_buffer = my_fftHandler. getVector ();
phaseReference .resize (T_u);
connect (this, SIGNAL (show_snr (int)),
mr, SLOT (show_snr (int)));
snrCount = 0;
snr = 0;
#ifdef __THREADED_DECODING
/**
* When implemented in a thread, the thread controls the
* reading in of the data and processing the data through
* functions for handling block 0, FIC blocks and MSC blocks.
*
* We just create a large buffer where index i refers to block i.
*
*/
command = new std::complex<float> * [nrBlocks];
for (i = 0; i < nrBlocks; i ++)
command [i] = new std::complex<float> [T_u];
amount = 0;
#endif
}
ofdmDecoder::~ofdmDecoder (void) {
int16_t i;
#ifdef __THREADED_DECODING
running. store (false);
while (isRunning ()) {
commandHandler. wakeAll ();
usleep (1000);
}
for (i = 0; i < nrBlocks; i ++)
delete[] command [i];
delete[] command;
#endif
}
//
// the client of this class should not know whether
// we run with a separate thread or not,
#ifndef __THREADED_DECODING
void ofdmDecoder::start (void) {
}
#endif
void ofdmDecoder::stop (void) {
#ifdef __THREADED_DECODING
running. store (false);
while (isRunning ()) {
commandHandler. wakeAll ();
usleep (1000);
}
#endif
}
void ofdmDecoder::reset (void) {
#ifdef __THREADED_DECODING
stop ();
usleep (10000);
start ();
#endif
}
//
#ifdef __THREADED_DECODING
/**
* The code in the thread executes a simple loop,
* waiting for the next block and executing the interpretation
* operation for that block.
* In our original code the block count was 1 higher than
* our count here.
*/
void ofdmDecoder::run (void) {
int16_t currentBlock = 0;
running. store (true);
while (running. load ()) {
helper. lock ();
commandHandler. wait (&helper, 100);
helper. unlock ();
while ((amount > 0) && running. load ()) {
if (currentBlock == 0)
processBlock_0 ();
else
if (currentBlock < 4)
decodeFICblock (currentBlock);
else
decodeMscblock (currentBlock);
bufferSpace. release (1);
helper. lock ();
currentBlock = (currentBlock + 1) % (nrBlocks);
amount -= 1;
helper. unlock ();
}
}
fprintf (stderr, "ofdm decoder is closing down now\n");
}
/**
* We need some functions to enter the ofdmProcessor data
* in the buffer.
*/
void ofdmDecoder::processBlock_0 (std::vector<std::complex<float>>vi) {
bufferSpace. acquire (1);
memcpy (command [0], vi. data (), sizeof (std::complex<float>) * T_u);
helper. lock ();
amount ++;
commandHandler. wakeOne ();
helper. unlock ();
void ofdmDecoder::stop (void) {
}
void ofdmDecoder::decodeFICblock (std::vector<std::complex<float>> vi,
int32_t blkno) {
bufferSpace. acquire (1);
memcpy (command [blkno], &((vi. data ()) [T_g]),
sizeof (std::complex<float>) * T_u);
helper. lock ();
amount ++;
commandHandler. wakeOne ();
helper. unlock ();
void ofdmDecoder::reset (void) {
}
void ofdmDecoder::decodeMscblock (std::vector<std::complex<float> > vi,
int32_t blkno) {
bufferSpace. acquire (1);
memcpy (command [blkno], &((vi. data ()) [T_g]),
sizeof (std::complex<float>) * T_u);
helper. lock ();
amount ++;
commandHandler. wakeOne ();
helper. unlock ();
}
#endif
/**
* Note that the distinction, made in the ofdmProcessor class
* does not add much here, iff we decide to choose the multi core
* option definitely, then code may be simplified there.
*/
/**
* handle block 0 as collected from the buffer
*/
#ifdef __THREADED_DECODING
void ofdmDecoder::processBlock_0 (void) {
memcpy (fft_buffer, command [0], T_u * sizeof (std::complex<float>));
#else
void ofdmDecoder::processBlock_0 (std::vector <std::complex<float> > buffer) {
memcpy (fft_buffer, buffer. data (),
T_u * sizeof (std::complex<float>));
#endif
my_fftHandler. do_FFT ();
/**
@@ -226,6 +99,11 @@ void ofdmDecoder::processBlock_0 (std::vector <std::complex<float> > buffer) {
* It is just an indication
*/
if (++snrCount > 10) {
snr = 0.8 * snr + 0.2 * get_snr (fft_buffer);
// show_snr (snr);
snrCount = 0;
}
/**
* we are now in the frequency domain, and we keep the carriers
* as coming from the FFT as phase reference.
@@ -234,25 +112,50 @@ void ofdmDecoder::processBlock_0 (std::vector <std::complex<float> > buffer) {
T_u * sizeof (std::complex<float>));
}
//
// Just interested. In the ideal case the constellation of the
// decoded symbols is precisely in the four points
// k * (1, 1), k * (1, -1), k * (-1, -1), k * (-1, 1)
// To ease computation, we map all incoming values onto quadrant 1
float ofdmDecoder::computeQuality (std::complex<float> *v) {
int16_t i;
std::complex<float> avgPoint = std::complex<float> (0, 0);
std::complex<float> x [T_u];
float avg = 0;
float S = 0;
for (i = 0; i < carriers; i ++) {
x [i] = std::complex<float> (abs (real (v [T_u / 2 - carriers / 2 + i])), abs (imag (v [T_u / 2 - carriers / 2 + i])));
avgPoint += x [i];
}
avg = arg (avgPoint * conj (std::complex<float> (1, 1)));
for (i = 0; i < carriers; i ++) {
float f = arg (x [i] * conj (std::complex<float> (1, 1))) - avg;
f = f / M_PI * 360;
S += f * f;
}
S /= (carriers - 1);
return sqrt (S);
}
/**
* for the other blocks of data, the first step is to go from
* time to frequency domain, to get the carriers.
* we distinguish between FIC blocks and other blocks,
* only to spare a test. The mapping code is the same
*/
static
int cnt = 0;
#ifdef __THREADED_DECODING
void ofdmDecoder::decodeFICblock (int32_t blkno) {
int16_t i;
memcpy (fft_buffer, command [blkno], T_u * sizeof (std::complex<float>));
#else
void ofdmDecoder::decodeFICblock (std::vector <std::complex<float>> buffer,
int32_t blkno) {
static int cnt = 0;
void ofdmDecoder::decode (std::vector <std::complex<float>> buffer,
int32_t blkno, int16_t *ibits) {
int16_t i;
memcpy (fft_buffer, &((buffer. data ()) [T_g]),
T_u * sizeof (std::complex<float>));
#endif
std::complex<float> conjVector [T_u];
std::complex<float> freqOff = std::complex<float> (0, 0);
fftlabel:
@@ -268,9 +171,8 @@ fftlabel:
toBitsLabel:
/**
* Note that from here on, we are only interested in the
* "carriers" useful carriers of the FFT output
* "carriers", the useful carriers of the FFT output
*/
for (i = 0; i < carriers; i ++) {
int16_t index = myMapper. mapIn (i);
if (index < 0)
@@ -283,6 +185,7 @@ toBitsLabel:
*/
std::complex<float> r1 = fft_buffer [index] *
conj (phaseReference [index]);
conjVector [index] = r1;
float ab1 = jan_abs (r1);
// split the real and the imaginary part and scale it
// we make the bits into softbits in the range -127 .. 127
@@ -291,55 +194,17 @@ toBitsLabel:
}
memcpy (phaseReference. data (), fft_buffer,
T_u * sizeof (std::complex<float>));
handlerLabel:
my_ficHandler -> process_ficBlock (ibits, blkno);
}
/**
* Msc block decoding is equal to FIC block decoding,
* further processing is different though
*/
#ifdef __THREADED_DECODING
void ofdmDecoder::decodeMscblock (int32_t blkno) {
int16_t i;
memcpy (fft_buffer, command [blkno], T_u * sizeof (std::complex<float>));
#else
void ofdmDecoder::decodeMscblock (std::vector <std::complex<float>>buffer,
int32_t blkno) {
int16_t i;
memcpy (fft_buffer, &((buffer. data ())[T_g]), T_u * sizeof (std::complex<float>));
#endif
fftLabel:
my_fftHandler. do_FFT ();
//
// Note that "mapIn" maps to -carriers / 2 .. carriers / 2
// we did not set the fft output to low .. high
toBitsLabel:
for (i = 0; i < carriers; i ++) {
int16_t index = myMapper. mapIn (i);
if (index < 0)
index += T_u;
std::complex<float> r1 = fft_buffer [index] *
conj (phaseReference [index]);
float ab1 = jan_abs (r1);
// Recall: the viterbi decoder wants 127 max pos, - 127 max neg
// we make the bits into softbits in the range -127 .. 127
ibits [i] = - real (r1) / ab1 * 127.0;
ibits [carriers + i] = - imag (r1) / ab1 * 127.0;
// From time to time we show the constellation of symbol 2.
if ((blkno == 2) && (iqBuffer != nullptr)) {
if (++cnt > 7) {
iqBuffer -> putDataIntoBuffer (&conjVector [T_u / 2 - carriers / 2],
carriers);
showIQ (carriers);
showQuality (computeQuality (conjVector));
cnt = 0;
}
}
memcpy (phaseReference. data (), fft_buffer,
T_u * sizeof (std::complex<float>));
handlerLabel:;
my_mscHandler -> process_mscBlock (ibits, blkno);
}
//
//
/**
* for the snr we have a full T_u wide vector, with in the middle
* K carriers.

View File

@@ -32,20 +32,16 @@
phaseReference::phaseReference (RadioInterface *mr,
uint8_t dabMode,
#ifdef IMPULSE_RESPONSE
RingBuffer<float> *b,
#endif
int16_t threshold,
int16_t diff_length):
int16_t diff_length,
RingBuffer<float> *b):
phaseTable (dabMode),
params (dabMode),
my_fftHandler (dabMode) {
int32_t i;
float Phi_k;
#ifdef IMPULSE_RESPONSE
this -> response = b;
#endif
this -> threshold = threshold;
this -> diff_length = diff_length;
this -> T_u = params. get_T_u ();
@@ -73,10 +69,9 @@ float Phi_k;
for (i = 1; i <= diff_length; i ++)
phaseDifferences [i - 1] = abs (arg (refTable [(T_u + i) % T_u] *
conj (refTable [(T_u + i + 1) % T_u])));
#ifdef IMPULSE_RESPONSE
connect (this, SIGNAL (showImpulse (int)),
mr, SLOT (showImpulse (int)));
#endif
}
phaseReference::~phaseReference (void) {
@@ -120,13 +115,13 @@ float lbuf [T_u];
}
}
#ifdef IMPULSE_RESPONSE
if (++displayCounter > framesperSecond / 4) {
response -> putDataIntoBuffer (lbuf, T_u);
showImpulse (T_u);
displayCounter = 0;
if (response != NULL) {
if (++displayCounter > framesperSecond / 4) {
response -> putDataIntoBuffer (lbuf, T_u);
showImpulse (T_u);
displayCounter = 0;
}
}
#endif
/**
* that gives us a basis for defining the actual threshold value
*/

View File

@@ -32,11 +32,18 @@ int16_t res = 1;
}
sampleReader::sampleReader (RadioInterface *mr,
virtualInput *theRig) {
virtualInput *theRig,
RingBuffer<std::complex<float>>*spectrumBuffer) {
int i;
this -> theRig = theRig;
this -> spectrumBuffer = spectrumBuffer;
bufferSize = 32768;
localCounter = 0;
connect (this, SIGNAL (show_Spectrum (int)),
mr, SLOT (showSpectrum (int)));
localBuffer. resize (bufferSize);
localCounter = 0;
connect (this, SIGNAL (show_Corrector (int)),
mr, SLOT (set_CorrectorDisplay (int)));
currentPhase = 0;
sLevel = 0;
sampleCount = 0;
@@ -48,7 +55,7 @@ int i;
bufferContent = 0;
corrector = 0;
dumpfilePointer. store (NULL);
dumpfilePointer. store (nullptr);
dumpIndex = 0;
dumpScale = valueFor (theRig -> bitDepth ());
}
@@ -69,7 +76,7 @@ std::complex<float> sampleReader::getSample (int32_t phaseOffset) {
std::complex<float> temp;
corrector = phaseOffset;
if (!running. load ())
if (!running. load ())
throw 21;
/// bufferContent is an indicator for the value of ... -> Samples ()
@@ -87,7 +94,7 @@ std::complex<float> temp;
// so here, bufferContent > 0
theRig -> getSamples (&temp, 1);
bufferContent --;
if (dumpfilePointer. load () != NULL) {
if (dumpfilePointer. load () != nullptr) {
dumpBuffer [2 * dumpIndex ] = real (temp) * dumpScale;
dumpBuffer [2 * dumpIndex + 1] = imag (temp) * dumpScale;
if ( ++dumpIndex >= DUMPSIZE / 2) {
@@ -97,6 +104,9 @@ std::complex<float> temp;
}
}
if (localCounter < bufferSize)
localBuffer [localCounter ++] = temp;
// OK, we have a sample!!
// first: adjust frequency. We need Hz accuracy
currentPhase -= phaseOffset;
@@ -109,6 +119,12 @@ std::complex<float> temp;
if (++ sampleCount > INPUT_RATE / N) {
show_Corrector (corrector);
sampleCount = 0;
if (spectrumBuffer != nullptr) {
spectrumBuffer -> putDataIntoBuffer (localBuffer. data (),
localCounter);
emit show_Spectrum (bufferSize);
}
localCounter = 0;
}
return temp;
}
@@ -133,8 +149,10 @@ int32_t i;
//
// so here, bufferContent >= n
n = theRig -> getSamples (v, n);
if (!running. load ())
throw 20;
bufferContent -= n;
if (dumpfilePointer. load () != NULL) {
if (dumpfilePointer. load () != nullptr) {
for (i = 0; i < n; i ++) {
dumpBuffer [2 * dumpIndex ] = real (v [i]) * dumpScale;
dumpBuffer [2 * dumpIndex + 1] = imag (v [i]) * dumpScale;
@@ -153,6 +171,8 @@ int32_t i;
//
// Note that "phase" itself might be negative
currentPhase = (currentPhase + INPUT_RATE) % INPUT_RATE;
if (localCounter < bufferSize)
localBuffer [localCounter ++] = v [i];
v [i] *= oscillatorTable [currentPhase];
sLevel = 0.00001 * jan_abs (v [i]) + (1 - 0.00001) * sLevel;
}
@@ -160,7 +180,11 @@ int32_t i;
sampleCount += n;
if (sampleCount > INPUT_RATE / N) {
show_Corrector (corrector);
localCounter = 0;
if (spectrumBuffer != nullptr) {
spectrumBuffer -> putDataIntoBuffer (localBuffer. data (),
bufferSize);
emit show_Spectrum (bufferSize);
}
sampleCount = 0;
}
}
@@ -170,6 +194,6 @@ void sampleReader::startDumping (SNDFILE *f) {
}
void sampleReader::stopDumping (void) {
dumpfilePointer. store (NULL);
dumpfilePointer. store (nullptr);
}

65
src/ofdm/timesyncer.cpp Normal file
View File

@@ -0,0 +1,65 @@
#include "timesyncer.h"
#include "sample-reader.h"
#define C_LEVEL_SIZE 50
timeSyncer::timeSyncer (sampleReader *mr) {
myReader = mr;
}
timeSyncer::~timeSyncer (void) {}
int timeSyncer::sync (int T_null, int T_F) {
float cLevel = 0;
int counter = 0;
float envBuffer [syncBufferSize];
const
int syncBufferMask = syncBufferSize - 1;
int i;
syncBufferIndex = 0;
for (i = 0; i < C_LEVEL_SIZE; i ++) {
std::complex<float> sample = myReader -> getSample (0);
envBuffer [syncBufferIndex] = jan_abs (sample);
cLevel += envBuffer [syncBufferIndex];
syncBufferIndex ++;
}
//SyncOnNull:
counter = 0;
while (cLevel / C_LEVEL_SIZE > 0.50 * myReader -> get_sLevel ()) {
std::complex<float> sample =
myReader -> getSample (0);
// myReader. getSample (coarseOffset + fineCorrector);
envBuffer [syncBufferIndex] = jan_abs (sample);
// update the levels
cLevel += envBuffer [syncBufferIndex] -
envBuffer [(syncBufferIndex - C_LEVEL_SIZE) & syncBufferMask];
syncBufferIndex = (syncBufferIndex + 1) & syncBufferMask;
counter ++;
if (counter > T_F) { // hopeless
return NO_DIP_FOUND;
}
}
/**
* It seemed we found a dip that started app 65/100 * 50 samples earlier.
* We now start looking for the end of the null period.
*/
counter = 0;
//SyncOnEndNull:
while (cLevel / C_LEVEL_SIZE < 0.75 * myReader -> get_sLevel ()) {
std::complex<float> sample =
myReader -> getSample (0);
envBuffer [syncBufferIndex] = jan_abs (sample);
// update the levels
cLevel += envBuffer [syncBufferIndex] -
envBuffer [(syncBufferIndex - C_LEVEL_SIZE) & syncBufferMask];
syncBufferIndex = (syncBufferIndex + 1) & syncBufferMask;
counter ++;
if (counter > T_null + 50) { // hopeless
return NO_END_OF_DIP_FOUND;
}
}
return TIMESYNC_ESTABLISHED;
}

673
src/support/dab_tables.cpp Normal file
View File

@@ -0,0 +1,673 @@
#
/*
* Copyright (C) 2018
* Hayati Ayguen (h_ayguen@web.de)
*
* DAB-library 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.
*
* DAB-library 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 DAB-library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "dab_tables.h"
#include <string.h>
#include <stdlib.h>
// ETSI TS 101 756 V2.2.1: Registered Tables
// for Extended Country Code, Country Id, Language Code,
// Program Type, User Application Type, Content Type
// https://www.etsi.org/deliver/etsi_ts/101700_101799/101756/02.02.01_60/ts_101756v020201p.pdf
// ETSI TR 101 496-3 V1.1.2
// protection level/classes, ..
// https://www.etsi.org/deliver/etsi_tr/101400_101499/10149603/01.01.02_60/tr_10149603v010102p.pdf
static const char *uep_rates [] = {"7/20", "2/5", "1/2", "3/5"};
static const char *eep_Arates[] = {"1/4", "3/8", "1/2", "3/4"}; // see ETSI EN 300 401 V1.3.2 (2000-09), Table 8, page 46
static const char *eep_Brates[] = {"4/9", "4/7", "4/6", "4/5"}; // see ETSI EN 300 401 V1.3.2 (2000-09), Table 9, page 46
struct country_codes {
uint8_t ecc;
uint8_t countryId;
const char *countryName;
};
// following countryTable[] is sorted over all regions to make
// it easier to find "missing" / "old" but still unused entries.
// achieved by searching old standard tables document for each ECC code.
// Table 3: ITU Region 1 - European broadcasting area
// Table 4: ITU Region 1 - African broadcasting area
// Table 6: ITU Region 2 - North and South Americas
// Table 7: ITU Region 3 - Asia and Pacific
static country_codes countryTable[] = {
{0xA0, 0x1, "United States of America"},
{0xA0, 0x2, "United States of America"},
{0xA0, 0x3, "United States of America"},
{0xA0, 0x4, "United States of America"},
{0xA0, 0x5, "United States of America"},
{0xA0, 0x6, "United States of America"},
{0xA0, 0x7, "United States of America"},
{0xA0, 0x8, "United States of America"},
{0xA0, 0x9, "United States of America"},
{0xA0, 0xA, "United States of America"},
{0xA0, 0xB, "United States of America"},
{0xA0, 0xC, "United States of America"},
{0xA0, 0xD, "United States of America"},
{0xA0, 0xE, "United States of America"},
{0xA1, 0xC, "Canada"},
{0xA1, 0xF, "Greenland"},
{0xA2, 0x1, "Anguilla"},
{0xA2, 0x2, "Antigua and Barbuda"},
{0xA2, 0x3, "Equador"},
{0xA2, 0x4, "Falkland Islands"},
{0xA2, 0x5, "Barbados"},
{0xA2, 0x6, "Belize"},
{0xA2, 0x7, "Cayman Islands"},
{0xA2, 0x8, "Costa Rica"},
{0xA2, 0x9, "Cuba"},
{0xA2, 0xA, "Argentina"},
{0xA2, 0xB, "Brazil"},
{0xA2, 0xC, "Bermuda"},
{0xA2, 0xD, "Netherlands Antilles"},
{0xA2, 0xE, "Guadeloupe"},
{0xA2, 0xF, "Bahamas"},
{0xA3, 0x1, "Bolivia"},
{0xA3, 0x2, "Colombia"},
{0xA3, 0x3, "Jamaica"},
{0xA3, 0x4, "Martinique"},
{0xA3, 0x6, "Paraguay"},
{0xA3, 0x7, "Nicaragua"},
{0xA3, 0x8, "Puerto Rico"},
{0xA3, 0x9, "Panama"},
{0xA3, 0xA, "Dominica"},
{0xA3, 0xB, "Dominican Republic"},
{0xA3, 0xC, "Chile"},
{0xA3, 0xD, "Grenada"},
{0xA3, 0xE, "Turks and Caicos islands"},
{0xA3, 0xF, "Guyana"},
{0xA4, 0x1, "Guatemala"},
{0xA4, 0x2, "Honduras"},
{0xA4, 0x3, "Aruba"},
{0xA4, 0x5, "Montserrat"},
{0xA4, 0x6, "Trinidad and Tobago"},
{0xA4, 0x7, "Peru"},
{0xA4, 0x8, "Surinam"},
{0xA4, 0x9, "Uruguay"},
{0xA4, 0xA, "St. Kitts"},
{0xA4, 0xB, "St. Lucia"},
{0xA4, 0xC, "El Salvador"},
{0xA4, 0xD, "Haiti"},
{0xA4, 0xE, "Venezuela"},
{0xA4, 0xF, "Mexico"},
{0xA5, 0xC, "St. Vincent"},
{0xA5, 0xF, "Virgin islands (British or USA)"}, // British and USA have same IDs! amended "or USA"
{0xA5, 0xF, "Virgin islands (USA)"}, // keep this entry .. doesn't hurt
{0xA6, 0xF, "St. Pierre and Miquelon"},
{0xD0, 0x1, "Cameroon"},
{0xD0, 0x2, "Central African Republic"},
{0xD0, 0x3, "Djibouti"},
{0xD0, 0x4, "Madagascar"},
{0xD0, 0x5, "Mali"},
{0xD0, 0x6, "Angola"},
{0xD0, 0x7, "Equatorial Guinea"},
{0xD0, 0x8, "Gabon"},
{0xD0, 0x9, "Republic of Guinea"},
{0xD0, 0xA, "South Africa"},
{0xD0, 0xB, "Burkina Faso"},
{0xD0, 0xC, "Congo"},
{0xD0, 0xD, "Togo"},
{0xD0, 0xE, "Benin"},
{0xD0, 0xF, "Malawi"},
{0xD1, 0x1, "Namibia"},
{0xD1, 0x2, "Liberia"},
{0xD1, 0x3, "Ghana"},
{0xD1, 0x4, "Mauritania"},
{0xD1, 0x5, "Sao Tome & Principe"},
{0xD1, 0x6, "Cape Verde"},
{0xD1, 0x7, "Senegal"},
{0xD1, 0x8, "Gambia"},
{0xD1, 0x9, "Burundi"},
{0xD1, 0xA, "Ascension island"},
{0xD1, 0xB, "Botswana"},
{0xD1, 0xC, "Comoros"},
{0xD1, 0xD, "Tanzania"},
{0xD1, 0xE, "Ethiopia"},
{0xD1, 0xF, "Nigeria"},
{0xD2, 0x1, "Sierra Leone"},
{0xD2, 0x2, "Zimbabwe"},
{0xD2, 0x3, "Mozambique"},
{0xD2, 0x4, "Uganda"},
{0xD2, 0x5, "Swaziland"},
{0xD2, 0x6, "Kenya"},
{0xD2, 0x7, "Somalia"},
{0xD2, 0x8, "Niger"},
{0xD2, 0x9, "Chad"},
{0xD2, 0xA, "Guinea-Bissau"},
{0xD2, 0xB, "Zaire"},
{0xD2, 0xC, "Cote d'Ivoire"},
{0xD2, 0xD, "Zanzibar"},
{0xD2, 0xE, "Zambia"},
{0xD3, 0x3, "Western Sahara"},
{0xD3, 0x4, "Cabinda"}, // was in V1.4.1. was removed later. but IDs are unused .. so keep it here
{0xD3, 0x5, "Rwanda"},
{0xD3, 0x6, "Lesotho"},
{0xD3, 0x8, "Seychelles"},
{0xD3, 0xA, "Mauritius"},
{0xD3, 0xC, "Sudan"},
{0xE0, 0x1, "Germany"},
{0xE0, 0x2, "Algeria"},
{0xE0, 0x3, "Andorra"},
{0xE0, 0x4, "Israel"},
{0xE0, 0x5, "Italy"},
{0xE0, 0x6, "Belgium"},
{0xE0, 0x7, "Russian Federation"},
{0xE0, 0x8, "Azores (Portugal)"}, // was in V1.4.1. was removed later. but IDs are unused .. so keep it here
{0xE0, 0x9, "Albania"},
{0xE0, 0xA, "Austria"},
{0xE0, 0xB, "Hungary"},
{0xE0, 0xC, "Malta"},
{0xE0, 0xD, "Germany"},
{0xE0, 0xE, "Canary Islands (Spain)"}, // amended "(Spain)"
{0xE0, 0xF, "Egypt"},
{0xE1, 0x1, "Greece"},
{0xE1, 0x2, "Cyprus"},
{0xE1, 0x3, "San Marino"},
{0xE1, 0x4, "Switzerland"},
{0xE1, 0x5, "Jordan"},
{0xE1, 0x6, "Finland"},
{0xE1, 0x7, "Luxembourg"},
{0xE1, 0x8, "Bulgaria"},
{0xE1, 0x9, "Faroe (Denmark)"},
{0xE1, 0xA, "Gibraltar (UK)"}, // amended "(UK)"
{0xE1, 0xB, "Iraq"},
{0xE1, 0xC, "United Kingdom"},
{0xE1, 0xD, "Libya"},
{0xE1, 0xE, "Romania"},
{0xE1, 0xF, "France"},
{0xE2, 0x1, "Marocco"},
{0xE2, 0x2, "Czech Republic"},
{0xE2, 0x3, "Poland"},
{0xE2, 0x4, "Vatican"},
{0xE2, 0x5, "Slovak Republic"},
{0xE2, 0x6, "Syria"},
{0xE2, 0x7, "Tunisia"},
{0xE2, 0x8, "Madeira"}, // was in V1.4.1. was removed later. but IDs are unused .. so keep it here
{0xE2, 0x9, "Liechtenstein"},
{0xE2, 0xA, "Iceland"},
{0xE2, 0xB, "Monaco"},
{0xE2, 0xC, "Lithuania"},
{0xE2, 0xD, "Serbia"},
{0xE2, 0xE, "Spain"},
{0xE2, 0xF, "Norway"},
{0xE3, 0x1, "Montenegro"},
{0xE3, 0x2, "Ireland"},
{0xE3, 0x3, "Turkey"},
{0xE3, 0x4, "Macedonia"},
{0xE3, 0x5, "Tajikistan"}, // was in V1.4.1. was removed later. but IDs are unused .. so keep it here
{0xE3, 0x8, "Netherlands"},
{0xE3, 0x9, "Latvia"},
{0xE3, 0xA, "Lebanon"},
{0xE3, 0xB, "Azerbaijan"}, // was in V1.4.1. was removed later. but IDs are unused .. so keep it here
{0xE3, 0xC, "Croatia"},
{0xE3, 0xD, "Kazakhstan"}, // was in V1.4.1. was removed later. but IDs are unused .. so keep it here
{0xE3, 0xE, "Sweden"},
{0xE3, 0xF, "Belarus"},
{0xE4, 0x1, "Moldova"},
{0xE4, 0x2, "Estonia"},
{0xE4, 0x3, "Macedonia / Kyrghyzstan"}, // amended "/ Kyrghyzstan" double used Id
{0xE4, 0x3, "Kyrghyzstan"}, // keep this entry .. doesn't hurt
{0xE4, 0x6, "Ukraine"},
{0xE4, 0x7, "Kosovo"},
{0xE4, 0x8, "Portugal"},
{0xE4, 0x9, "Slovenia"},
{0xE4, 0xA, "Armenia"},
{0xE4, 0xB, "Uzbekistan"},
{0xE4, 0xC, "Georgia"},
{0xE4, 0xE, "Turkmenistan"},
{0xE4, 0xF, "Bosnia Herzegovina"},
{0xF0, 0x1, "Australia: Capital Cities (commercial and community)"},
{0xF0, 0x2, "Australia: New South Wales and ACT"},
{0xF0, 0x3, "Australia: Capital Cities (national broadcasters, was Victoria)"},
{0xF0, 0x4, "Australia: Queensland"},
{0xF0, 0x5, "Australia: South and Northern Territory"},
{0xF0, 0x6, "Australia: Western"},
{0xF0, 0x7, "Australia: Victoria and Tasmania"},
{0xF0, 0x8, "Australia: (future, was Northern Territory)"},
{0xF0, 0x9, "Saudi Arabia"},
{0xF0, 0xA, "Afghanistan"},
{0xF0, 0xB, "Myanmar (Burma)"},
{0xF0, 0xC, "China"},
{0xF0, 0xD, "Korea (North)"},
{0xF0, 0xE, "Bahrain"},
{0xF0, 0xF, "Malaysia"},
{0xF1, 0x1, "Kiribati"},
{0xF1, 0x2, "Bhutan"},
{0xF1, 0x3, "Bangladesh"},
{0xF1, 0x4, "Pakistan"},
{0xF1, 0x5, "Fiji"},
{0xF1, 0x6, "Oman"},
{0xF1, 0x7, "Nauru"},
{0xF1, 0x8, "Iran"},
{0xF1, 0x9, "New Zealand"},
{0xF1, 0xA, "Solomon Islands"},
{0xF1, 0xB, "Brunei Darussalam"},
{0xF1, 0xC, "Sri Lanka"},
{0xF1, 0xD, "Taiwan"},
{0xF1, 0xE, "Korea (South)"},
{0xF1, 0xF, "Hong Kong"},
{0xF2, 0x1, "Kuwait"},
{0xF2, 0x2, "Qatar"},
{0xF2, 0x3, "Cambodia"},
{0xF2, 0x4, "Western Samoa"},
{0xF2, 0x5, "India"},
{0xF2, 0x6, "Macau"},
{0xF2, 0x7, "Vietnam"},
{0xF2, 0x8, "Philippines"},
{0xF2, 0x9, "Japan"},
{0xF2, 0xA, "Singapore"},
{0xF2, 0xB, "Maldives"},
{0xF2, 0xC, "Indonesia"},
{0xF2, 0xD, "United Arab Emirates"},
{0xF2, 0xE, "Nepal"},
{0xF2, 0xF, "Vanuatu"},
{0xF3, 0x1, "Laos"},
{0xF3, 0x2, "Thailand"},
{0xF3, 0x3, "Tonga"},
{0xF3, 0x9, "Papua New Guinea"},
{0xF3, 0xB, "Yemen"},
{0xF3, 0xE, "Micronesia"},
{0xF3, 0xF, "Mongolia"},
{0x00, 0x0, nullptr }
};
// from Table 2a
const char * getASCTy (int16_t ASCTy) {
switch (ASCTy) {
case 0: return "DAB";
case 63: return "DAB+";
default: return "unknown";
}
}
// from Table 2b
const char * getDSCTy (int16_t DSCTy) {
switch (DSCTy) {
case 1: return "Traffic Message CHannel (TMC)";
case 2: return "Emergency Warning System (EWS)";
case 3: return "Interactive Text Transmission System (ITTS)";
case 4: return "Paging";
case 5: return "Transparent Data Channel (TDC)";
case 24: return "MPEG-2 Transport Stream";
case 59: return "Embedded IP packets";
case 60: return "Multimedia Object Transfer (MOT)";
case 61: return "Proprietary service";
default: return "unknown";
}
}
// from Table 9 and 10
const char * getLanguage (int16_t language) {
switch (language) {
case 0x00: return "Unknown/not applicable";
case 0x01: return "Albanian";
case 0x02: return "Breton";
case 0x03: return "Catalan";
case 0x04: return "Croatian";
case 0x05: return "Welsh";
case 0x06: return "Czech";
case 0x07: return "Danish";
case 0x08: return "German";
case 0x09: return "English";
case 0x0A: return "Spanish";
case 0x0B: return "Esperanto";
case 0x0C: return "Estonian";
case 0x0D: return "Basque";
case 0x0E: return "Faroese";
case 0x0F: return "French";
case 0x10: return "Frisian";
case 0x11: return "Irish";
case 0x12: return "Gaelic";
case 0x13: return "Galician";
case 0x14: return "Icelandic";
case 0x15: return "Italian";
case 0x16: return "Sami";
case 0x17: return "Latin";
case 0x18: return "Latvian";
case 0x19: return "Luxembourgian";
case 0x1A: return "Lithuanian";
case 0x1B: return "Hungarian";
case 0x1C: return "Maltese";
case 0x1D: return "Dutch";
case 0x1E: return "Norwegian";
case 0x1F: return "Occitan";
case 0x20: return "Polish";
case 0x21: return "Portuguese";
case 0x22: return "Romanian";
case 0x23: return "Romansh";
case 0x24: return "Serbian";
case 0x25: return "Slovak";
case 0x26: return "Slovene";
case 0x27: return "Finnish";
case 0x28: return "Swedish";
case 0x29: return "Turkish";
case 0x2A: return "Flemish";
case 0x2B: return "Walloon";
case 0x30: // no break
case 0x31: // no break
case 0x32: // no break
case 0x33: // no break
case 0x34: // no break
case 0x35: // no break
case 0x36: // no break
case 0x37: // no break
case 0x38: // no break
case 0x39: // no break
case 0x3A: // no break
case 0x3B: // no break
case 0x3C: // no break
case 0x3D: // no break
case 0x3E: // no break
case 0x3F: return "Reserved for national assignment";
case 0x7F: return "Amharic";
case 0x7E: return "Arabic";
case 0x7D: return "Armenian";
case 0x7C: return "Assamese";
case 0x7B: return "Azerbaijani";
case 0x7A: return "Bambora";
case 0x79: return "Belorussian";
case 0x78: return "Bengali";
case 0x77: return "Bulgarian";
case 0x76: return "Burmese";
case 0x75: return "Chinese";
case 0x74: return "Chuvash";
case 0x73: return "Dari";
case 0x72: return "Fulani";
case 0x71: return "Georgian";
case 0x70: return "Greek";
case 0x6F: return "Gujurati";
case 0x6E: return "Gurani";
case 0x6D: return "Hausa";
case 0x6C: return "Hebrew";
case 0x6B: return "Hindi";
case 0x6A: return "Indonesian";
case 0x69: return "Japanese";
case 0x68: return "Kannada";
case 0x67: return "Kazakh";
case 0x66: return "Khmer";
case 0x65: return "Korean";
case 0x64: return "Laotian";
case 0x63: return "Macedonian";
case 0x62: return "Malagasay";
case 0x61: return "Malaysian";
case 0x60: return "Moldavian";
case 0x5F: return "Marathi";
case 0x5E: return "Ndebele";
case 0x5D: return "Nepali";
case 0x5C: return "Oriya";
case 0x5B: return "Papiamento";
case 0x5A: return "Persian";
case 0x59: return "Punjabi";
case 0x58: return "Pushtu";
case 0x57: return "Quechua";
case 0x56: return "Russian";
case 0x55: return "Rusyn";
case 0x54: return "Serbo-Croat";
case 0x53: return "Shona";
case 0x52: return "Sinhalese";
case 0x51: return "Somali";
case 0x50: return "Sranan Tongo";
case 0x4F: return "Swahili";
case 0x4E: return "Tadzhik";
case 0x4D: return "Tamil";
case 0x4C: return "Tatar";
case 0x4B: return "Telugu";
case 0x4A: return "Thai";
case 0x49: return "Ukranian";
case 0x48: return "Urdu";
case 0x47: return "Uzbek";
case 0x46: return "Vietnamese";
case 0x45: return "Zulu";
case 0x40: return "Background sound/clean feed";
default: return "unknown";
}
}
const char *getCountry (uint8_t ecc, uint8_t countryId) {
int16_t i = 0;
while (countryTable [i].ecc != 0) {
if ((countryTable[i].ecc == ecc) &&
(countryTable[i].countryId == countryId) )
return countryTable[i].countryName;
++i;
}
return nullptr;
}
// from Table 12
const char *getProgramType_Not_NorthAmerica (int16_t programType) {
switch (programType) {
case 0: return "No programme type";
case 1: return "News";
case 2: return "Current Affairs";
case 3: return "Information";
case 4: return "Sport";
case 5: return "Education";
case 6: return "Drama";
case 7: return "Culture";
case 8: return "Science";
case 9: return "Varied"; //Talk
case 10: return "Pop Music";
case 11: return "Rock Music";
case 12: return "Easy Listening Music";
case 13: return "Light Classical";
case 14: return "Serious Classical";
case 15: return "Other Music";
case 16: return "Weather/meteorology";
case 17: return "Finance/Business";
case 18: return "Children's programmes";
case 19: return "Social Affairs"; //Factual
case 20: return "Religion";
case 21: return "Phone In";
case 22: return "Travel";
case 23: return "Leisure";
case 24: return "Jazz Music";
case 25: return "Country Music";
case 26: return "National Music";
case 27: return "Oldies Music";
case 28: return "Folk Music";
case 29: return "Documentary";
case 30: return "unknown programme type 30";
case 31: return "unknown programme type 31";
default: return "unknown programme type";
}
}
// from Table 13
const char *getProgramType_For_NorthAmerica (int16_t programType) {
switch (programType) {
case 0: return "No programme type";
case 1: return "News";
case 2: return "Information";
case 3: return "Sports";
case 4: return "Talk";
case 5: return "Rock";
case 6: return "Classic Rock";
case 7: return "Adult Hits";
case 8: return "Soft Rock";
case 9: return "Top 40";
case 10: return "Country";
case 11: return "Oldies";
case 12: return "Soft";
case 13: return "Nostalgia";
case 14: return "Jazz";
case 15: return "Classical";
case 16: return "Rhythm and Blues";
case 17: return "Soft Rhythm and Blues";
case 18: return "Foreign Language";
case 19: return "Religious Music";
case 20: return "Religious Talk";
case 21: return "Personality";
case 22: return "Public";
case 23: return "College";
case 24: return "unknown programme type 24";
case 25: return "unknown programme type 25";
case 26: return "unknown programme type 26";
case 27: return "unknown programme type 27";
case 28: return "unknown programme type 28";
case 29: return "Weather";
case 30: return "unknown programme type 30";
case 31: return "unknown programme type 31";
default: return "unknown programme type";
}
}
const char *getProgramType (bool gotInterTabId,
uint8_t interTabId, int16_t programType) {
if (gotInterTabId && (interTabId == 1))
return getProgramType_Not_NorthAmerica (programType);
else
if (gotInterTabId && (interTabId == 2))
return getProgramType_For_NorthAmerica (programType);
else {
switch (programType) {
case 0: return "unknown programme type 0";
case 1: return "unknown programme type 1";
case 2: return "unknown programme type 2";
case 3: return "unknown programme type 3";
case 4: return "unknown programme type 4";
case 5: return "unknown programme type 5";
case 6: return "unknown programme type 6";
case 7: return "unknown programme type 7";
case 8: return "unknown programme type 8";
case 9: return "unknown programme type 9";
case 10: return "unknown programme type 10";
case 11: return "unknown programme type 11";
case 12: return "unknown programme type 12";
case 13: return "unknown programme type 13";
case 14: return "unknown programme type 14";
case 15: return "unknown programme type 15";
case 16: return "unknown programme type 16";
case 17: return "unknown programme type 17";
case 18: return "unknown programme type 18";
case 19: return "unknown programme type 19";
case 20: return "unknown programme type 20";
case 21: return "unknown programme type 21";
case 22: return "unknown programme type 22";
case 23: return "unknown programme type 23";
case 24: return "unknown programme type 24";
case 25: return "unknown programme type 25";
case 26: return "unknown programme type 26";
case 27: return "unknown programme type 27";
case 28: return "unknown programme type 28";
case 29: return "unknown programme type 29";
case 30: return "unknown programme type 30";
case 31: return "unknown programme type 31";
default: return "unknown programme type";
}
}
return "unknown programme type";
}
// 11-bit from HandleFIG0Extension13, see ETSI TS 101 756 table 16
const char *getUserApplicationType (int16_t appType) {
switch (appType) {
case 1: return "Dynamic labels (X-PAD only)";
case 2: return "MOT Slide Show";
case 3: return "MOT Broadcast Web Site";
case 4: return "TPEG";
case 5: return "DGPS";
case 6: return "TMC";
case 7: return "SPI, was EPG";
case 8: return "DAB Java";
case 9: return "DMB";
case 0x00a: return "IPDC services";
case 0x00b: return "Voice applications";
case 0x00c: return "Middleware";
case 0x00d: return "Filecasting";
case 0x44a: return "Journaline";
default: return "unknown";
}
}
const char * getFECscheme (int16_t FEC_scheme) {
switch (FEC_scheme) {
case 0: return "no FEC";
case 1: return "FEC";
default: return "unknown";
}
}
const char * getProtectionLevel (bool shortForm, int16_t protLevel) {
if (!shortForm) {
switch (protLevel) {
case 0: return "EEP 1-A";
case 1: return "EEP 2-A";
case 2: return "EEP 3-A";
case 3: return "EEP 4-A";
case 4: return "EEP 1-B";
case 5: return "EEP 2-B";
case 6: return "EEP 3-B";
case 7: return "EEP 4-B";
default: return "EEP unknown";
}
}
else {
switch (protLevel) {
case 1: return "UEP 1";
case 2: return "UEP 2";
case 3: return "UEP 3";
case 4: return "UEP 4";
case 5: return "UEP 5";
default: return "UEP unknown";
}
}
}
const char *getCodeRate (bool shortForm, int16_t protLevel) {
int h = protLevel;
if (!shortForm)
return ((h & (1 << 2)) == 0) ?
eep_Arates [h & 03] :
eep_Brates [h & 03]; // EEP -A/-B
else
return uep_rates [h & 03]; // UEP
}