Compare commits

..

No commits in common. 'dev' and 'master' have entirely different histories.
dev ... master

  1. 1
      .gitignore
  2. BIN
      Bildschirmfoto89_graphs.png
  3. BIN
      Bildschirmfoto90_table.png
  4. 66
      MANUAL.md
  5. 53
      README.md
  6. 6907
      apps/fft-multi-decoder_auto_freqs_slider-update.grc
  7. 6737
      apps/fft-multi-decoder_auto_freqs_slider-update_8dec.grc
  8. 1780
      apps/fft-multi-decoder_fixed_hackrf.grc
  9. 65
      apps/fft-multi-decoder_fixed_rtlsdr.grc
  10. 6724
      apps/fft-single-decoder_fixed_hackrf.grc
  11. 480
      apps/ifft-RDS-decoder_hier-block.grc
  12. 2719
      apps/read_fmdec.grc
  13. 1005
      apps/read_sync_decim.grc
  14. 1
      data/LCL/README.md
  15. 49038
      data/LCL15.1.D-160122_utf8.csv
  16. 1441
      data/event-list_code+de-name_sort.csv
  17. 1572
      data/event-list_with_forecast_sort.csv
  18. 235
      data/label6-supplementary-information-codes.csv
  19. 40
      data/tmc_update_class_names.csv
  20. 5
      grc/CMakeLists.txt
  21. 6
      grc/multirds_max_freq.xml
  22. 38
      grc/multirds_multi_rds_printer.xml
  23. 11
      grc/multirds_sync_decim.xml
  24. 2
      include/multirds/CMakeLists.txt
  25. 16
      include/multirds/sync_decim.h
  26. 2
      lib/CMakeLists.txt
  27. 211
      lib/rds_decoder_redsea_impl.cc
  28. 7
      lib/rds_decoder_redsea_impl.h
  29. 108
      lib/sync_decim_impl.cc
  30. 16
      lib/sync_decim_impl.h
  31. 5
      python/CMakeLists.txt
  32. 219
      python/RDS-decoder-instanciation.grc
  33. 4
      python/__init__.py
  34. BIN
      python/core
  35. 186
      python/max_freq.py
  36. 69
      python/multi_rds_printer.py
  37. 44
      python/qa_rds_parser_table_qt.py
  38. 45
      python/qa_tmc_parser.py
  39. 9
      python/qtgui_range.py
  40. 262
      python/rds_parser_table_qt.py
  41. 1764
      python/tmc_classes.py
  42. 169
      python/tmc_parser.py
  43. 105
      python/top_block.py
  44. 6
      swig/multirds_swig.i

1
.gitignore vendored

@ -5,4 +5,3 @@ apps/*.py
apps/*.pyc
build-manlap
*.bak
directory_writable

BIN
Bildschirmfoto89_graphs.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

BIN
Bildschirmfoto90_table.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 KiB

66
MANUAL.md

@ -1,66 +0,0 @@
# Manual
This manual applies to the "fft-multi-decoder_fixed_hackrf.grc" flowgraph
## graphs
![screenshot graphs tab](Bildschirmfoto89_graphs.png)
### freq and volume sliders
freq_tune = frequency of SDR hardware
volumeLR = volume for left and right channel
volumeC = volume for center channel
freq1..9 = frequency of all channels
### scopes
spectrum of input signal
spectrum of filtered input signal for single channel (first 6 channels)
spectrum of signal after FM demodulation (first 6 channels)
constellation after PSK decoder (first 6 channels)
### gain and loop_bw sliders
intermediate frequency-, baseband- and radio frequency gain of SDR hardware
loop_bw = loop bandwidth of all PSK decoders
## RDS Table
![screenshot table tab](Bildschirmfoto90_table.png)
### table
hint: hover over text to get more details e.g. time -> date, RT -> RT+
click LCR buttons to hear this channel on left/right/center audio
### buttons
code.interact
- launches interactive python console (inside "rds_parser_table_qt_Widget" instance) in the terminal window GRC was launched from
parser object accessible via "self.tableobj" variable
- can only be used, if GRC was launched from the terminal
- pauses execution of parser
- exit shell and resume execution with CTRL-D or "exit()"
show IH data
- display InHouse (groupType 6A) data of all stations
save
- save current state of parser to data directory
print profile
- print profiler info (currently disabled)
searchMode
- switch station_search block on/off
### decoder info
- red/green : RDS decoder sync status
- overline/underline: symbol combiner status
## TMC list
### event/location filters
enter = apply filter
### event list
scroll to bottom to follow new events
## TMC map
open google_maps.html from /data in webbrowser
- click on background = reload/update markers (closes all info windows)
- click on marker = open info window
- hover over text in info window to get more details (time-> date, event string -> raw MGM data)
- t-key = toggle (google) traffic layer on/off
- red lines from tmc event markers show extent of event

53
README.md

@ -2,10 +2,8 @@
### Dependencies
- GNU Radio v3.7.X
```
sudo apt-get install gnuradio (3.7.9.1-2ubuntu1)
```
- Build dependencies (cmake, libboost, swig)
- Software from your package manager. For Ubuntu systems, it's
```
sudo apt-get install cmake libboost-all-dev liblog4cpp5-dev swig
```
@ -13,31 +11,17 @@ sudo apt-get install cmake libboost-all-dev liblog4cpp5-dev swig
```
sudo pip install bitstring
or
sudo apt-get install python-bitstring
sudo apt-get insall python-bitstring
```
- Source Block for RTL-SDR dongle
ubuntu 16.04: sudo apt-get install gnuradio cmake (3.7.9.1-2ubuntu1)
git://git.osmocom.org/rtl-sdr.git
sudo apt-get install libusb-1.0-0-dev libusb-dev swig
swig -> "python support" in osmocomsdr
http://osmocom.org/projects/sdr/wiki/rtl-sdr
```
sudo apt-get install gr-osmosdr
or build from source:
sudo apt-get install libusb-1.0-0-dev libusb-dev
git clone git://git.osmocom.org/rtl-sdr.git
cd rtl-sdr/
mkdir build
cd build
cmake ../
make
sudo make install
sudo ldconfig
```
or you can use the [GNU Radio Live Image](https://wiki.gnuradio.org/index.php/GNU_Radio_Live_SDR_Environment)
, which can be written to a USB drive with Unetbootin.
It comes with all dependencies except the "bitstring" module, which can be installed with
```
sudo pip install bitstring
```
apt-get install gr-osmosdr
### Installation
```
@ -68,29 +52,20 @@ cmake -DCMAKE_INSTALL_PREFIX:PATH=/home/user/gnuradio-prefix ..
```
now make should install the module to the specified folder, without needing root privileges
### TMC Location Lists
to use the tmc_parser block you need to download the TMC location table for your country and put the .DAT files in a subfolder called "LCL" in the data folder
links:
[wikipedia info](https://en.wikipedia.org/wiki/Traffic_message_channel#TMC_services_in_operation)
finland [download here](http://www.liikennevirasto.fi/web/en/open-data/materials/tmc-location-data)
germany: [request here](http://www.bast.de/DE/Verkehrstechnik/Fachthemen/v2-LCL/location-code-list.html)
sweden: [request here](http://www.trafikverket.se/en/startpage/operations/Operations-road/Traffic-information/The-Swedish-Location-Table-for-TMC/tmc-download-page/)
norway: [download here](http://www.vegvesen.no/en/professional/Technology/RDS+TMC)
italy: [download here](http://www.cciss.it/portale/cciss.portal?_nfpb=true&_windowLabel=quicklinks_1&quicklinks_1_actionOverride=%2Fportlets%2Fquicklinks%2FgoRdsTmc)
### Usage
open the apps/ifft-RDS-decoder_hier-block.grc flow graph in GNU Radio Companion.
open apps/ifft-RDS-decoder_hier-block.grc flow graph in GNU Radio Companion.
Click "generate" to create the hierarchical decoder block.
Click "reload" to load the generated block
open the apps/fft-multi-decoder.grc flow graph.
open apps/fft-multi-decoder.grc flow graph.
set the work directory of the "RDS parser Table" block as the full path (~ shortcut doesnt work) of the data directory (with trailing slash)
run the flowgraph
for more infos look in MANUAL.md
### Demos
### History
forked from https://github.com/bastibl/gr-rds
Continuation of gr-rds on BitBucket (originally from Dimitrios Symeonidis https://bitbucket.org/azimout/gr-rds/ and also on CGRAN https://www.cgran.org/wiki/RDS).
contains code from https://github.com/windytan/redsea

6907
apps/fft-multi-decoder_auto_freqs_slider-update.grc

File diff suppressed because it is too large Load Diff

6737
apps/fft-multi-decoder_auto_freqs_slider-update_8dec.grc

File diff suppressed because it is too large Load Diff

1780
apps/fft-multi-decoder_fixed_hackrf.grc

File diff suppressed because it is too large Load Diff

65
apps/fft-multi-decoder_fixed_rtlsdr.grc

@ -2289,65 +2289,6 @@ class blk(gr.sync_block): # other base classes are basic_block, decim_block, in
<value>False</value>
</param>
</block>
<block>
<key>multirds_tmc_parser</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>debug</key>
<value>False</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(1896, 460)</value>
</param>
<param>
<key>gui_hint</key>
<value></value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>multirds_tmc_parser_0</value>
</param>
<param>
<key>label</key>
<value></value>
</param>
<param>
<key>log</key>
<value>False</value>
</param>
<param>
<key>maxheight</key>
<value>160</value>
</param>
<param>
<key>workdir</key>
<value>/media/clemens/intdaten/uni_bulk/forschungsarbeit/data/</value>
</param>
<param>
<key>writeDB</key>
<value>False</value>
</param>
</block>
<block>
<key>osmosdr_source</key>
<param>
@ -6731,12 +6672,6 @@ class blk(gr.sync_block): # other base classes are basic_block, decim_block, in
<source_key>rds</source_key>
<sink_key>in2</sink_key>
</connection>
<connection>
<source_block_id>multirds_rds_parser_table_qt_0_0</source_block_id>
<sink_block_id>multirds_tmc_parser_0</sink_block_id>
<source_key>tmc_raw</source_key>
<sink_key>in</sink_key>
</connection>
<connection>
<source_block_id>osmosdr_source_0</source_block_id>
<sink_block_id>blocks_stream_to_vector_0</sink_block_id>

6724
apps/fft-single-decoder_fixed_hackrf.grc

File diff suppressed because it is too large Load Diff

480
apps/ifft-RDS-decoder_hier-block.grc

@ -147,7 +147,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(359, 347)</value>
<value>(519, 3)</value>
</param>
<param>
<key>_rotation</key>
@ -159,7 +159,7 @@
</param>
<param>
<key>value</key>
<value>audio_rate*audio_decim</value>
<value>240000</value>
</param>
</block>
<block>
@ -197,11 +197,11 @@
</param>
<param>
<key>_enabled</key>
<value>1</value>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(247, 395)</value>
<value>(646, 75)</value>
</param>
<param>
<key>_rotation</key>
@ -216,33 +216,6 @@
<value>audio_rate*audio_decim*bb_decim</value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(335, 419)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>chan_rate</value>
</param>
<param>
<key>value</key>
<value>int(600e3)</value>
</param>
</block>
<block>
<key>variable</key>
<param>
@ -294,7 +267,7 @@
</param>
<param>
<key>_coordinate</key>
<value>(359, 155)</value>
<value>(327, 155)</value>
</param>
<param>
<key>_rotation</key>
@ -314,7 +287,7 @@
</param>
<param>
<key>quad_rate</key>
<value>2*baseband_rate</value>
<value>chan_rate</value>
</param>
</block>
<block>
@ -513,11 +486,11 @@
</param>
<param>
<key>file</key>
<value>"/tmp/cr/fm_dec_240k_"+str(cutpoint)</value>
<value>"/tmp/fm_dec_240k_"+str(cutpoint)</value>
</param>
<param>
<key>_coordinate</key>
<value>(718, 355)</value>
<value>(750, 371)</value>
</param>
<param>
<key>_rotation</key>
@ -560,11 +533,11 @@
</param>
<param>
<key>_enabled</key>
<value>1</value>
<value>0</value>
</param>
<param>
<key>file</key>
<value>"/tmp/cr/psk_out_2375_"+str(cutpoint)</value>
<value>"/tmp/psk_out_2375_"+str(cutpoint)</value>
</param>
<param>
<key>_coordinate</key>
@ -611,11 +584,11 @@
</param>
<param>
<key>_enabled</key>
<value>1</value>
<value>0</value>
</param>
<param>
<key>file</key>
<value>"/tmp/cr/symbol_combiner_out_"+str(cutpoint)</value>
<value>"/tmp/cr/sync_decim_out_"+str(cutpoint)</value>
</param>
<param>
<key>_coordinate</key>
@ -642,57 +615,6 @@
<value>1</value>
</param>
</block>
<block>
<key>blocks_keep_one_in_n</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(1206, 335)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blocks_keep_one_in_n_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>n</key>
<value>2</value>
</param>
<param>
<key>type</key>
<value>float</value>
</param>
<param>
<key>vlen</key>
<value>1</value>
</param>
</block>
<block>
<key>blocks_null_sink</key>
<param>
@ -1088,120 +1010,6 @@
<value>0</value>
</param>
</block>
<block>
<key>digital_clock_recovery_mm_xx</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(798, 279)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>gain_mu</key>
<value>0.050</value>
</param>
<param>
<key>gain_omega</key>
<value>0.001</value>
</param>
<param>
<key>id</key>
<value>digital_clock_recovery_mm_xx_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>mu</key>
<value>0.5</value>
</param>
<param>
<key>omega_relative_limit</key>
<value>0.005</value>
</param>
<param>
<key>omega</key>
<value>16*(1+0.0)</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
</block>
<block>
<key>digital_costas_loop_cc</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(543, 311)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>digital_costas_loop_cc_0</value>
</param>
<param>
<key>w</key>
<value>loop_bw</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>order</key>
<value>2</value>
</param>
<param>
<key>use_snr</key>
<value>False</value>
</param>
</block>
<block>
<key>digital_diff_decoder_bb</key>
<param>
@ -1446,7 +1254,7 @@
</param>
<param>
<key>omega</key>
<value>audio_rate / 2375.0</value>
<value>48000 / 2375.0</value>
</param>
<param>
<key>theta</key>
@ -1730,7 +1538,7 @@
</param>
<param>
<key>value</key>
<value>1024*40</value>
<value>1024*10</value>
</param>
</block>
<block>
@ -2185,6 +1993,81 @@
<value>3.14/150.0</value>
</param>
</block>
<block>
<key>low_pass_filter</key>
<param>
<key>beta</key>
<value>6.76</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>cutoff_freq</key>
<value>90e3</value>
</param>
<param>
<key>decim</key>
<value>1</value>
</param>
<param>
<key>_enabled</key>
<value>2</value>
</param>
<param>
<key>type</key>
<value>fir_filter_ccf</value>
</param>
<param>
<key>_coordinate</key>
<value>(120, 120)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>gain</key>
<value>1</value>
</param>
<param>
<key>id</key>
<value>low_pass_filter_0</value>
</param>
<param>
<key>interp</key>
<value>1</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>samp_rate</key>
<value>baseband_rate</value>
</param>
<param>
<key>width</key>
<value>30e3</value>
</param>
<param>
<key>win</key>
<value>firdes.WIN_HAMMING</value>
</param>
</block>
<block>
<key>multirds_pilot_SNR</key>
<param>
@ -2456,7 +2339,7 @@
</param>
<param>
<key>debug</key>
<value>False</value>
<value>True</value>
</param>
<param>
<key>_enabled</key>
@ -2488,7 +2371,7 @@
</param>
</block>
<block>
<key>multirds_symbol_combiner</key>
<key>multirds_sync_decim</key>
<param>
<key>alias</key>
<value></value>
@ -2503,7 +2386,7 @@
</param>
<param>
<key>_enabled</key>
<value>1</value>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
@ -2515,11 +2398,11 @@
</param>
<param>
<key>id</key>
<value>multirds_symbol_combiner_0</value>
<value>multirds_sync_decim_0</value>
</param>
<param>
<key>log</key>
<value>False</value>
<value>log</value>
</param>
<param>
<key>maxoutbuf</key>
@ -2531,7 +2414,7 @@
</param>
<param>
<key>threshold</key>
<value>1</value>
<value>0.25</value>
</param>
<param>
<key>min_diff</key>
@ -2539,7 +2422,7 @@
</param>
</block>
<block>
<key>multirds_symbol_combiner</key>
<key>multirds_sync_decim</key>
<param>
<key>alias</key>
<value></value>
@ -2566,7 +2449,7 @@
</param>
<param>
<key>id</key>
<value>multirds_symbol_combiner_0_0</value>
<value>multirds_sync_decim_0_0</value>
</param>
<param>
<key>log</key>
@ -2590,7 +2473,7 @@
</param>
</block>
<block>
<key>multirds_symbol_combiner</key>
<key>multirds_sync_decim</key>
<param>
<key>alias</key>
<value></value>
@ -2617,7 +2500,7 @@
</param>
<param>
<key>id</key>
<value>multirds_symbol_combiner_0_1</value>
<value>multirds_sync_decim_0_1</value>
</param>
<param>
<key>log</key>
@ -2641,7 +2524,7 @@
</param>
</block>
<block>
<key>multirds_symbol_combiner</key>
<key>multirds_sync_decim</key>
<param>
<key>alias</key>
<value></value>
@ -2668,7 +2551,7 @@
</param>
<param>
<key>id</key>
<value>multirds_symbol_combiner_0_1_0</value>
<value>multirds_sync_decim_0_1_0</value>
</param>
<param>
<key>log</key>
@ -3008,65 +2891,6 @@
<value>fft_len</value>
</param>
</block>
<block>
<key>rational_resampler_xxx</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value>firdes.low_pass(1.0,chan_rate,250e3,50e3,firdes.WIN_HAMMING)</value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>decim</key>
<value>chan_rate/120000</value>
</param>
<param>
<key>_enabled</key>
<value>2</value>
</param>
<param>
<key>fbw</key>
<value>0</value>
</param>
<param>
<key>_coordinate</key>
<value>(167, 135)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>rational_resampler_xxx_0</value>
</param>
<param>
<key>interp</key>
<value>baseband_rate*2/120000</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>taps</key>
<value></value>
</param>
<param>
<key>type</key>
<value>ccc</value>
</param>
</block>
<block>
<key>root_raised_cosine_filter</key>
<param>
@ -3444,43 +3268,25 @@
</connection>
<connection>
<source_block_id>blocks_complex_to_real_0</source_block_id>
<sink_block_id>blocks_keep_one_in_n_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_complex_to_real_0</source_block_id>
<sink_block_id>multirds_symbol_combiner_0</sink_block_id>
<sink_block_id>multirds_sync_decim_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_complex_to_real_0_0</source_block_id>
<sink_block_id>multirds_symbol_combiner_0_0</sink_block_id>
<sink_block_id>multirds_sync_decim_0_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_complex_to_real_0_1</source_block_id>
<sink_block_id>multirds_symbol_combiner_0_1</sink_block_id>
<sink_block_id>multirds_sync_decim_0_1</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_complex_to_real_0_1_0</source_block_id>
<sink_block_id>multirds_symbol_combiner_0_1_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_keep_one_in_n_0</source_block_id>
<sink_block_id>blocks_file_sink_0_0_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_keep_one_in_n_0</source_block_id>
<sink_block_id>digital_binary_slicer_fb_0</sink_block_id>
<sink_block_id>multirds_sync_decim_0_1_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
@ -3492,7 +3298,7 @@
</connection>
<connection>
<source_block_id>blocks_vector_to_stream_0_0_1</source_block_id>
<sink_block_id>rational_resampler_xxx_0</sink_block_id>
<sink_block_id>low_pass_filter_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
@ -3520,24 +3326,6 @@
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>digital_clock_recovery_mm_xx_0</source_block_id>
<sink_block_id>blocks_complex_to_real_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>digital_clock_recovery_mm_xx_0</source_block_id>
<sink_block_id>pad_sink_1</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>digital_costas_loop_cc_0</source_block_id>
<sink_block_id>digital_clock_recovery_mm_xx_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>digital_diff_decoder_bb_0</source_block_id>
<sink_block_id>multirds_rds_decoder_3</sink_block_id>
@ -3640,6 +3428,18 @@
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>low_pass_filter_0</source_block_id>
<sink_block_id>analog_wfm_rcv_0_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>low_pass_filter_0</source_block_id>
<sink_block_id>pad_sink_0_1</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>multirds_pilot_SNR_0</source_block_id>
<sink_block_id>pad_sink_0_0</sink_block_id>
@ -3648,7 +3448,7 @@
</connection>
<connection>
<source_block_id>multirds_rds_decoder_3</source_block_id>
<sink_block_id>multirds_symbol_combiner_0</sink_block_id>
<sink_block_id>multirds_sync_decim_0</sink_block_id>
<source_key>out</source_key>
<sink_key>ctrl</sink_key>
</connection>
@ -3660,25 +3460,25 @@
</connection>
<connection>
<source_block_id>multirds_rds_decoder_3_0</source_block_id>
<sink_block_id>multirds_symbol_combiner_0_0</sink_block_id>
<sink_block_id>multirds_sync_decim_0_0</sink_block_id>
<source_key>out</source_key>
<sink_key>ctrl</sink_key>
</connection>
<connection>
<source_block_id>multirds_rds_decoder_3_1</source_block_id>
<sink_block_id>multirds_symbol_combiner_0_1</sink_block_id>
<sink_block_id>multirds_sync_decim_0_1</sink_block_id>
<source_key>out</source_key>
<sink_key>ctrl</sink_key>
</connection>
<connection>
<source_block_id>multirds_rds_decoder_3_1_0</source_block_id>
<sink_block_id>multirds_symbol_combiner_0_1_0</sink_block_id>
<sink_block_id>multirds_sync_decim_0_1_0</sink_block_id>
<source_key>out</source_key>
<sink_key>ctrl</sink_key>
</connection>
<connection>
<source_block_id>multirds_rds_decoder_redsea_0</source_block_id>
<sink_block_id>multirds_symbol_combiner_0</sink_block_id>
<sink_block_id>multirds_sync_decim_0</sink_block_id>
<source_key>out</source_key>
<sink_key>ctrl</sink_key>
</connection>
@ -3689,37 +3489,31 @@
<sink_key>in</sink_key>
</connection>
<connection>
<source_block_id>multirds_symbol_combiner_0</source_block_id>
<sink_block_id>pad_sink_0_0</sink_block_id>
<source_key>ctrl</source_key>
<sink_key>in</sink_key>
</connection>
<connection>
<source_block_id>multirds_symbol_combiner_0</source_block_id>
<source_block_id>multirds_sync_decim_0</source_block_id>
<sink_block_id>blocks_file_sink_0_0_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>multirds_symbol_combiner_0</source_block_id>
<source_block_id>multirds_sync_decim_0</source_block_id>
<sink_block_id>digital_binary_slicer_fb_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>multirds_symbol_combiner_0_0</source_block_id>
<source_block_id>multirds_sync_decim_0_0</source_block_id>
<sink_block_id>digital_binary_slicer_fb_0_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>multirds_symbol_combiner_0_1</source_block_id>
<source_block_id>multirds_sync_decim_0_1</source_block_id>
<sink_block_id>digital_binary_slicer_fb_0_1</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>multirds_symbol_combiner_0_1_0</source_block_id>
<source_block_id>multirds_sync_decim_0_1_0</source_block_id>
<sink_block_id>digital_binary_slicer_fb_0_1_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
@ -3736,24 +3530,6 @@
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>rational_resampler_xxx_0</source_block_id>
<sink_block_id>analog_wfm_rcv_0_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>rational_resampler_xxx_0</source_block_id>
<sink_block_id>pad_sink_0_1</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>root_raised_cosine_filter_0</source_block_id>
<sink_block_id>digital_costas_loop_cc_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>root_raised_cosine_filter_0</source_block_id>
<sink_block_id>digital_mpsk_receiver_cc_0</sink_block_id>

2719
apps/read_fmdec.grc

File diff suppressed because it is too large Load Diff

1005
apps/read_sync_decim.grc

File diff suppressed because it is too large Load Diff

1
data/LCL/README.md

@ -1 +0,0 @@
put TMC location table (.DAT files) in this directory

49038
data/LCL15.1.D-160122_utf8.csv

File diff suppressed because it is too large Load Diff

1441
data/event-list_code+de-name_sort.csv

File diff suppressed because it is too large Load Diff

1572
data/event-list_with_forecast_sort.csv

File diff suppressed because it is too large Load Diff

235
data/label6-supplementary-information-codes.csv

@ -1,235 +0,0 @@
code,text CEN english,text german
1,heavy lorries are recommended to avoid the area,"LKW wird empfohlen, das Gebiet weiträumig zu umfahren"
2,follow signs,folgen Sie den Schildern
3,follow diversion signs,der Umleitungsbeschilderung folgen
4,diversion in operation,eine Umleitung ist eingerichtet
5,no suitable diversion available,keine Umleitungsempfehlung
6,diversion is no longer recommended,Umleitung wird nicht mehr empfohlen
7,for exceptional loads only,für Großraum- und Schwertransporte
8,for heavy vehicles only,für LKW
9,for cars and light vehicles only,für PKW und leichte LKW
10,snowploughs in use,Schneeräumfahrzeuge im Einsatz
11,gritting vehicles in use,Streufahrzeuge im Einsatz
12,drive carefully,bitte vorsichtig fahren
13,keep your distance,Abstand halten
14,observe signals,auf Signalregelung achten
15,overtake with care,Vorsicht beim Überholen
16,cross junction with care,Vorsicht an der Kreuzung
17,no overtaking,Überholen verboten
18,use headlights,Licht einschalten
19,use fog lights,Nebelscheinwerfer einschalten
20,do not leave your vehicle,bitte das Fahrzeug nicht verlassen
21,switch off engine,Motor abstellen
22,close all windows. Turn off heater and vents,Fenster schließen und Lüftung abstellen
23,test your brakes,Bremsen überprüfen
24,winter equipment recommended ,Winterausrüstung empfohlen
25,snow chains recommended,Schneeketten empfohlen
26,snow chains mandatory,Schneekettenpflicht
27,keep to the left,links fahren
28,keep to the right,rechts fahren
29,use hard shoulder as lane,Standstreifen mitbenutzen
30,do not drive on the hard shoulder,Standstreifen nicht befahren
31,in the opposite direction,in der Gegenrichtung
32,in the opposing lanes,auf der Gegenfahrspur
33,in the overtaking lane,auf dem Überholstreifen
34,in the crawler lane,auf der Kriechspur
35,in the right lane,auf dem rechten Fahrstreifen
36,in the middle lane,auf dem mittleren Fahrstreifen
37,in the left lane,auf dem linken Fahrstreifen
38,on the roadway,auf der Fahrbahn
39,police directing traffic,Polizei regelt den Verkehr
40,police in attendance,Unfallaufnahme
41,extra police patrols in operation,Polizei fährt verstärkt Streife
42,rescue and recovery work in progress,wegen Bergungsarbeiten
43,look out for flagman,auf Sicherungsposten achten
44,why not park-and-ride?,P+R anfahren und öffentliche Verkehrsmittel benutzen
45,why not try public transport?,nutzen Sie die öffentlichen Verkehrsmittel
46,only travel if absolutely necessary,nur im Notfall fahren
47,increased risk of accident,erhöhte Unfallgefahr
48,on bridges,auf Brücken
49,in shaded areas,in schattigen Bereichen
50,entering or leaving tunnels,an Tunnelein- oder -ausgängen
51,winter closure,Wintersperre
52,batch service in progress,Blockabfertigung
53,the north,in nördlicher Richtung
54,the north-east,in nordöstlicher Richtung
55,the east,in östlicher Richtung
56,the south-east,in südöstlicher Richtung
57,the south,in südlicher Richtung
58,the south-west,in südwestlicher Richtung
59,the west,in westlicher Richtung
60,the north-west,in nordwestlicher Richtung
61,follow special diversion markers,folgen Sie den Schildern mit den orangen Pfeilen
62,do not follow diversion signs,nicht der Umleitungsbeschilderung folgen
63,follow local diversion,eine örtliche Umleitung ist eingerichtet
64,compulsory diversion in operation,obligatorische Umleitung eingerichtet
65,for petrol-engined vehicles only,für Fahrzeuge mit Verbrennungsmotoren
66,for diesel-engined vehicles only,für Fahrzeuge mit Dieselmotoren
67,for LPG vehicles only,für Fahrzeuge mit Gasmotoren
68,local drivers are recommended to avoid the area,"ortskundige Autofahrer werden gebeten, das Gebiet weiträumig zu umfahren"
69,for 4-wheel-drive with snow tyres or chains only,für Allradfahrzeuge mit Winterreifen oder Schneeketten
70,in the median,am Mittelstreifen
71,for cars only,für PKW
72,for light vehicles only,für leichte LKW
73,for vehicles with catalytic converters ,für Fahrzeuge mit Katalysatoren
74,for vehicles without catalytic converters ,für Fahrzeuge ohne Katalysatoren
75,for cars with trailers only,für PKW mit Anhänger
76,for cars with caravans only,für Fahrzeuge mit Wohnanhänger
77,for vehicles with trailers only,für Fahrzeuge mit Anhänger
78,for heavy lorries only,für Schwerlastverkehr
79,for buses only,für Busse
80,for articulated vehicles only,für Spezialfahrzeuge
81,for high-sided vehicles only,für Fahrzeuge mit hohen Aufbauten
82,for hazardous loads only,für Gefahrguttransporte
83,for abnormal loads only,"für Großraum-, Schwer- und Gefahrguttransporte"
84,with even-numbered registration plates,für KFZ mit geradzahligen Kennzeichen
85,with odd-numbered registration plates,für KFZ mit ungeradzahligen Kennzeichen
86,for all vehicles,für alle Fahrzeuge
88,for through traffic,für Durchgangsverkehr
89,for rail services,für Schienenverkehr
90,on the underground,im U-Bahn-Verkehr
91,danger,Gefahr
92,repairs in progress,Reparaturarbeiten
93,pilot car in operation,Lotsendienst im Einsatz
94,emergency vehicles at scene,Rettungsfahrzeuge im Einsatz
95,traffic being directed around accident area,Verkehr wird an der Unfallstelle vorbeigeführt
96,danger of explosion ,Explosionsgefahr
97,danger of fire ,Brandgefahr
98,radiation hazard,Strahlungsgefahr
99,toxic leak,Gasaustritt
100,firemen directing traffic,Feuerwehr regelt den Verkehr
101,police speed checks in operation,Geschwindigkeitskontrollen
102,mandatory speed limit in force,die Geschwindigkeit ist begrenzt
103,speed limit in force for heavy vehicles,Geschwindigkeitsbeschränkung für LKW
104,reduce your speed ,langsam fahren
105,observe speed limits,auf Geschwindigkeitsbeschränkung achten
106,observe recommended speed,die empfohlene Geschwindigkeit beachten
107,snow chains required,Schneeketten erforderlich
108,snow chains or tyres reqired,Winterreifen oder Schneeketten erforderlich
109,helicopter rescue in progress,Rettungshubschrauber im Einsatz
110,several accidents have taken place,es haben sich bereits mehrere Unfälle ereignet
111,drive with extreme caution,fahren Sie bitte besonders vorsichtig
112,approach with care,vorsichtig an das Stauende heranfahren
113,increase normal following distance,Sicherheitsabstand vergrößern
114,do not allow unnecessary gaps,keine unnötigen Lücken lassen
115,"follow the vehicle in front, smoothly",fahren Sie zügig an der Unfallstelle vorbei
116,do not slow down unneccessarily,nicht unnötig abbremsen
117,observe signs,auf Beschilderung achten
118,use hazard warning lights,Warnblinkanlage einschalten
119,no smoking,nicht rauchen
120,no naked flames,kein offenes Feuer
121,switch off mobile phones and two-way radios,Mobiltelefone und Funkgeräte ausschalten
122,allow emergency vehicles to pass,Rettungsfahrzeuge überholen lassen
123,clear a lane for emergency vehicles,Gasse für Rettungsfahrzeuge bilden
124,pull over to the edge of the roadway,an den Rand der Straße heranfahren
125,wait for escort vehicle,warten Sie auf Führungsfahrzeug
126,"in emergency, wait for police patrol",auf Lautsprecherdurchsagen der Polizei und der Rettungsdienste achten
128,stop at next safe place,an der nächsten sicheren Stelle halten
129,clear a lane for snowploughs and gritting vehicles,Gasse für Räum- und Streufahrzeuge frei halten
131,use right lane,benutzen Sie den rechten Fahrstreifen
132,use left lane,benutzen Sie den linken Fahrstreifen
133,heavy vehicles use right lane,LKW den rechten Fahrstreifen benutzen
134,heavy vehicles use left lane,LKW den linken Fahrstreifen benutzen
136,stop at next service area,nächsten Rast- oder Parkplatz anfahren
141,on the right,auf der rechten Seite
142,in the centre,in der Mitte
143,on the left,auf der linken Seite
144,in the bus lane,auf der Busspur
145,in the carpool lane,auf der Spur für Fahrgemeinschaften
146,on the hard shoulder,auf dem Standstreifen
147,in the emergency lane,auf der Notfallspur
148,on the opposite carriageway,auf der Gegenfahrbahn
149,in the heavy vehicle lane,auf der Schwerverkehrsspur
150,in the local lane,auf der Nahverkehrsspur
151,due to heat,wegen Hitze
152,due to frost,wegen Frost
153,for ferry service,für Fährbetrieb
154,for roads in,für Straßen in
155,in the through traffic lane,auf der Fernverkehrsspur
156,in the express lane,auf der Schnellspur
157,in the connecting carriageway,auf der Verbindungsfahrbahn
158,in the parallel carriageway,auf der Parallelfahrbahn
159,in the right-hand parallel carriageway,auf der rechten Parallelfahrbahn
160,in the left-hand parallel carriageway,auf der linken Parallelfahrbahn
161,in tunnels,in Tunnels
162,on slip roads,in Anschlussstellen
163,at high altitudes,in Höhenlagen
164,in low-lying areas,in tiefer gelegenen Gebieten
165,around a bend in the road,im Kurvenbereich
166,over the crest of a hill,hinter einer Kuppe
167,in the city centre,in der Innenstadt
168,in the inner city area,im Innenstadtbereich
169,in the slow vehicle lane,auf dem Langsamfahrstreifen
170,in the turning lane,auf der Wendespur
171,due to an earlier accident,wegen eines vorausgegangenen Unfalls
172,due to shear weight of traffic,wegen zu hoher Verkehrsbelastung
173,due to large numbers of visitors,wegen hoher Besucherzahlen
174,due to holiday traffic,wegen Urlaubsverkehrs
175,due to technical problems,wegen technischer Probleme
176,towards town,stadteinwärts
177,from town,stadtauswärts
178,on entry into the country,bei der Einreise
179,on leaving the country,bei der Ausreise
180,do not throw out any burning objects,nichts Brennendes aus dem Fahrzeug werfen
181,traffic wardens directing traffic,Verkehrshelfer regeln den Verkehr
185,due to falling ice,aufgrund von herabfallendem Eis
191,snow tyres recommended,Winterreifen empfohlen
192,snow tyres mandatory,Winterreifen vorgeschrieben
195,use through traffic lanes,benutzen Sie die Fernverkehrsspur
196,use local traffic lanes,benutzen Sie die Nahverkehrsspur
197,use left-hand parallel carriageway,benutzen Sie die linke Parallelfahrbahn
198,use right-hand parallel carriageway,benutzen Sie die rechte Parallelfahrbahn
199,use heavy vehicle lane,benutzen Sie die LKW-Spur
200,due to an earlier incident,wegen eines vorausgegangenen Vorfalls
201,why not ride share?,bilden Sie bitte Fahrgemeinschaften
202,is this your no-ride day?,Ist heute Ihr autofreier Tag?
203,due to an earlier event,wegen eines vorausgegangenen Ereignisses
204,please use rail service,bitte die Bahn benutzen
205,please use underground service,bitte die U-Bahn benutzen
206,please use tram service,bitte die Straßenbahn benutzen
207,please use bus service,bitte den Bus benutzen
208,for a limited time,vorübergehend
209,your parking ticket covers the return ride ,Fahrpreis für öffentliche Verkehrsmittel ist im Parkticket enthalten
210,avoid the rush hour,vermeiden Sie die Hauptverkehrszeiten
211,for holiday traffic,für Urlaubsverkehr
212,for residents,für Anwohner
213,several times,mehrfach
214,during the day time,am Tage
215,during off-peak periods,in verkehrsarmen Zeiten
216,during the night,in der Nacht
217,until further notice,bis auf weiteres
218,for arrivals,für Ankunft
219,for departures,für Abfahrt
220,access only,nur Zugang
221,only,nur
222,except,außer
223,for long distance traffic,für Fernverkehr
224,for local traffic,für Nahverkehr
225,for regional traffic,für Regionalverkehr
226,unconfirmed report,unbestätigter Bericht
227,on manual payment lanes,"auf Mautspuren mit
Schalterbetrieb"
231,sorry for any delay,entschuldigen Sie etwaige Verzögerungen
232,for roads leading towards,für Straßen nach
233,for roads from,für Straßen aus
234,we are grateful for your cooperation,wir danken Ihnen für Ihre Mitarbeit
235,Traffic queue length decreasing at an average rate of 10 km/hr,Staulänge sehr langsam abnehmend
236,Traffic queue length decreasing at an average rate of 20 km/hr,Staulänge langsam abnehmend
237,Traffic queue length decreasing at an average rate of 30 km/hr,Staulänge schnell abnehmend
238,Traffic queue length decreasing at an average rate of 40 km/hr,Staulänge sehr schnell abnehmend
239,leave your vehicle. Proceed to next save place,bitte das Fahrzeug verlassen und den nächsten sicheren Platz aufsuchen
240,for visitors,für Besucher
241,in the roadworks area,im Baustellenbereich
242,from,aus
243,to,nach
244,in,in
245,Traffic queue length increasing,Staulänge zunehmend
246,Traffic queue length increasing at an average rate of 10 km/hr,Staulänge sehr langsam zunehmend
247,Traffic queue length increasing at an average rate of 20 km/hr,Staulänge langsam zunehmend
248,Traffic queue length increasing at an average rate of 30 km/hr,Staulänge schnell zunehmend
249,Traffic queue length increasing at an average rate of 40 km/hr,Staulänge sehr schnell zunehmend
250,very frequent service,sehr kurzer Fahrtakt
251,frequent service,regelmäßiger Fahrtakt
252,fairly frequent service,recht kurzer Fahrtakt
253,regular service,fahrplanmäßiger Fahrtakt
255,Traffic queue length decreasing,Staulänge abnehmend
1 code text CEN english text german
2 1 heavy lorries are recommended to avoid the area LKW wird empfohlen, das Gebiet weiträumig zu umfahren
3 2 follow signs folgen Sie den Schildern
4 3 follow diversion signs der Umleitungsbeschilderung folgen
5 4 diversion in operation eine Umleitung ist eingerichtet
6 5 no suitable diversion available keine Umleitungsempfehlung
7 6 diversion is no longer recommended Umleitung wird nicht mehr empfohlen
8 7 for exceptional loads only für Großraum- und Schwertransporte
9 8 for heavy vehicles only für LKW
10 9 for cars and light vehicles only für PKW und leichte LKW
11 10 snowploughs in use Schneeräumfahrzeuge im Einsatz
12 11 gritting vehicles in use Streufahrzeuge im Einsatz
13 12 drive carefully bitte vorsichtig fahren
14 13 keep your distance Abstand halten
15 14 observe signals auf Signalregelung achten
16 15 overtake with care Vorsicht beim Überholen
17 16 cross junction with care Vorsicht an der Kreuzung
18 17 no overtaking Überholen verboten
19 18 use headlights Licht einschalten
20 19 use fog lights Nebelscheinwerfer einschalten
21 20 do not leave your vehicle bitte das Fahrzeug nicht verlassen
22 21 switch off engine Motor abstellen
23 22 close all windows. Turn off heater and vents Fenster schließen und Lüftung abstellen
24 23 test your brakes Bremsen überprüfen
25 24 winter equipment recommended Winterausrüstung empfohlen
26 25 snow chains recommended Schneeketten empfohlen
27 26 snow chains mandatory Schneekettenpflicht
28 27 keep to the left links fahren
29 28 keep to the right rechts fahren
30 29 use hard shoulder as lane Standstreifen mitbenutzen
31 30 do not drive on the hard shoulder Standstreifen nicht befahren
32 31 in the opposite direction in der Gegenrichtung
33 32 in the opposing lanes auf der Gegenfahrspur
34 33 in the overtaking lane auf dem Überholstreifen
35 34 in the crawler lane auf der Kriechspur
36 35 in the right lane auf dem rechten Fahrstreifen
37 36 in the middle lane auf dem mittleren Fahrstreifen
38 37 in the left lane auf dem linken Fahrstreifen
39 38 on the roadway auf der Fahrbahn
40 39 police directing traffic Polizei regelt den Verkehr
41 40 police in attendance Unfallaufnahme
42 41 extra police patrols in operation Polizei fährt verstärkt Streife
43 42 rescue and recovery work in progress wegen Bergungsarbeiten
44 43 look out for flagman auf Sicherungsposten achten
45 44 why not park-and-ride? P+R anfahren und öffentliche Verkehrsmittel benutzen
46 45 why not try public transport? nutzen Sie die öffentlichen Verkehrsmittel
47 46 only travel if absolutely necessary nur im Notfall fahren
48 47 increased risk of accident erhöhte Unfallgefahr
49 48 on bridges auf Brücken
50 49 in shaded areas in schattigen Bereichen
51 50 entering or leaving tunnels an Tunnelein- oder -ausgängen
52 51 winter closure Wintersperre
53 52 batch service in progress Blockabfertigung
54 53 the north in nördlicher Richtung
55 54 the north-east in nordöstlicher Richtung
56 55 the east in östlicher Richtung
57 56 the south-east in südöstlicher Richtung
58 57 the south in südlicher Richtung
59 58 the south-west in südwestlicher Richtung
60 59 the west in westlicher Richtung
61 60 the north-west in nordwestlicher Richtung
62 61 follow special diversion markers folgen Sie den Schildern mit den orangen Pfeilen
63 62 do not follow diversion signs nicht der Umleitungsbeschilderung folgen
64 63 follow local diversion eine örtliche Umleitung ist eingerichtet
65 64 compulsory diversion in operation obligatorische Umleitung eingerichtet
66 65 for petrol-engined vehicles only für Fahrzeuge mit Verbrennungsmotoren
67 66 for diesel-engined vehicles only für Fahrzeuge mit Dieselmotoren
68 67 for LPG vehicles only für Fahrzeuge mit Gasmotoren
69 68 local drivers are recommended to avoid the area ortskundige Autofahrer werden gebeten, das Gebiet weiträumig zu umfahren
70 69 for 4-wheel-drive with snow tyres or chains only für Allradfahrzeuge mit Winterreifen oder Schneeketten
71 70 in the median am Mittelstreifen
72 71 for cars only für PKW
73 72 for light vehicles only für leichte LKW
74 73 for vehicles with catalytic converters für Fahrzeuge mit Katalysatoren
75 74 for vehicles without catalytic converters für Fahrzeuge ohne Katalysatoren
76 75 for cars with trailers only für PKW mit Anhänger
77 76 for cars with caravans only für Fahrzeuge mit Wohnanhänger
78 77 for vehicles with trailers only für Fahrzeuge mit Anhänger
79 78 for heavy lorries only für Schwerlastverkehr
80 79 for buses only für Busse
81 80 for articulated vehicles only für Spezialfahrzeuge
82 81 for high-sided vehicles only für Fahrzeuge mit hohen Aufbauten
83 82 for hazardous loads only für Gefahrguttransporte
84 83 for abnormal loads only für Großraum-, Schwer- und Gefahrguttransporte
85 84 with even-numbered registration plates für KFZ mit geradzahligen Kennzeichen
86 85 with odd-numbered registration plates für KFZ mit ungeradzahligen Kennzeichen
87 86 for all vehicles für alle Fahrzeuge
88 88 for through traffic für Durchgangsverkehr
89 89 for rail services für Schienenverkehr
90 90 on the underground im U-Bahn-Verkehr
91 91 danger Gefahr
92 92 repairs in progress Reparaturarbeiten
93 93 pilot car in operation Lotsendienst im Einsatz
94 94 emergency vehicles at scene Rettungsfahrzeuge im Einsatz
95 95 traffic being directed around accident area Verkehr wird an der Unfallstelle vorbeigeführt
96 96 danger of explosion Explosionsgefahr
97 97 danger of fire Brandgefahr
98 98 radiation hazard Strahlungsgefahr
99 99 toxic leak Gasaustritt
100 100 firemen directing traffic Feuerwehr regelt den Verkehr
101 101 police speed checks in operation Geschwindigkeitskontrollen
102 102 mandatory speed limit in force die Geschwindigkeit ist begrenzt
103 103 speed limit in force for heavy vehicles Geschwindigkeitsbeschränkung für LKW
104 104 reduce your speed langsam fahren
105 105 observe speed limits auf Geschwindigkeitsbeschränkung achten
106 106 observe recommended speed die empfohlene Geschwindigkeit beachten
107 107 snow chains required Schneeketten erforderlich
108 108 snow chains or tyres reqired Winterreifen oder Schneeketten erforderlich
109 109 helicopter rescue in progress Rettungshubschrauber im Einsatz
110 110 several accidents have taken place es haben sich bereits mehrere Unfälle ereignet
111 111 drive with extreme caution fahren Sie bitte besonders vorsichtig
112 112 approach with care vorsichtig an das Stauende heranfahren
113 113 increase normal following distance Sicherheitsabstand vergrößern
114 114 do not allow unnecessary gaps keine unnötigen Lücken lassen
115 115 follow the vehicle in front, smoothly fahren Sie zügig an der Unfallstelle vorbei
116 116 do not slow down unneccessarily nicht unnötig abbremsen
117 117 observe signs auf Beschilderung achten
118 118 use hazard warning lights Warnblinkanlage einschalten
119 119 no smoking nicht rauchen
120 120 no naked flames kein offenes Feuer
121 121 switch off mobile phones and two-way radios Mobiltelefone und Funkgeräte ausschalten
122 122 allow emergency vehicles to pass Rettungsfahrzeuge überholen lassen
123 123 clear a lane for emergency vehicles Gasse für Rettungsfahrzeuge bilden
124 124 pull over to the edge of the roadway an den Rand der Straße heranfahren
125 125 wait for escort vehicle warten Sie auf Führungsfahrzeug
126 126 in emergency, wait for police patrol auf Lautsprecherdurchsagen der Polizei und der Rettungsdienste achten
127 128 stop at next safe place an der nächsten sicheren Stelle halten
128 129 clear a lane for snowploughs and gritting vehicles Gasse für Räum- und Streufahrzeuge frei halten
129 131 use right lane benutzen Sie den rechten Fahrstreifen
130 132 use left lane benutzen Sie den linken Fahrstreifen
131 133 heavy vehicles use right lane LKW den rechten Fahrstreifen benutzen
132 134 heavy vehicles use left lane LKW den linken Fahrstreifen benutzen
133 136 stop at next service area nächsten Rast- oder Parkplatz anfahren
134 141 on the right auf der rechten Seite
135 142 in the centre in der Mitte
136 143 on the left auf der linken Seite
137 144 in the bus lane auf der Busspur
138 145 in the carpool lane auf der Spur für Fahrgemeinschaften
139 146 on the hard shoulder auf dem Standstreifen
140 147 in the emergency lane auf der Notfallspur
141 148 on the opposite carriageway auf der Gegenfahrbahn
142 149 in the heavy vehicle lane auf der Schwerverkehrsspur
143 150 in the local lane auf der Nahverkehrsspur
144 151 due to heat wegen Hitze
145 152 due to frost wegen Frost
146 153 for ferry service für Fährbetrieb
147 154 for roads in für Straßen in
148 155 in the through traffic lane auf der Fernverkehrsspur
149 156 in the express lane auf der Schnellspur
150 157 in the connecting carriageway auf der Verbindungsfahrbahn
151 158 in the parallel carriageway auf der Parallelfahrbahn
152 159 in the right-hand parallel carriageway auf der rechten Parallelfahrbahn
153 160 in the left-hand parallel carriageway auf der linken Parallelfahrbahn
154 161 in tunnels in Tunnels
155 162 on slip roads in Anschlussstellen
156 163 at high altitudes in Höhenlagen
157 164 in low-lying areas in tiefer gelegenen Gebieten
158 165 around a bend in the road im Kurvenbereich
159 166 over the crest of a hill hinter einer Kuppe
160 167 in the city centre in der Innenstadt
161 168 in the inner city area im Innenstadtbereich
162 169 in the slow vehicle lane auf dem Langsamfahrstreifen
163 170 in the turning lane auf der Wendespur
164 171 due to an earlier accident wegen eines vorausgegangenen Unfalls
165 172 due to shear weight of traffic wegen zu hoher Verkehrsbelastung
166 173 due to large numbers of visitors wegen hoher Besucherzahlen
167 174 due to holiday traffic wegen Urlaubsverkehrs
168 175 due to technical problems wegen technischer Probleme
169 176 towards town stadteinwärts
170 177 from town stadtauswärts
171 178 on entry into the country bei der Einreise
172 179 on leaving the country bei der Ausreise
173 180 do not throw out any burning objects nichts Brennendes aus dem Fahrzeug werfen
174 181 traffic wardens directing traffic Verkehrshelfer regeln den Verkehr
175 185 due to falling ice aufgrund von herabfallendem Eis
176 191 snow tyres recommended Winterreifen empfohlen
177 192 snow tyres mandatory Winterreifen vorgeschrieben
178 195 use through traffic lanes benutzen Sie die Fernverkehrsspur
179 196 use local traffic lanes benutzen Sie die Nahverkehrsspur
180 197 use left-hand parallel carriageway benutzen Sie die linke Parallelfahrbahn
181 198 use right-hand parallel carriageway benutzen Sie die rechte Parallelfahrbahn
182 199 use heavy vehicle lane benutzen Sie die LKW-Spur
183 200 due to an earlier incident wegen eines vorausgegangenen Vorfalls
184 201 why not ride share? bilden Sie bitte Fahrgemeinschaften
185 202 is this your no-ride day? Ist heute Ihr autofreier Tag?
186 203 due to an earlier event wegen eines vorausgegangenen Ereignisses
187 204 please use rail service bitte die Bahn benutzen
188 205 please use underground service bitte die U-Bahn benutzen
189 206 please use tram service bitte die Straßenbahn benutzen
190 207 please use bus service bitte den Bus benutzen
191 208 for a limited time vorübergehend
192 209 your parking ticket covers the return ride Fahrpreis für öffentliche Verkehrsmittel ist im Parkticket enthalten
193 210 avoid the rush hour vermeiden Sie die Hauptverkehrszeiten
194 211 for holiday traffic für Urlaubsverkehr
195 212 for residents für Anwohner
196 213 several times mehrfach
197 214 during the day time am Tage
198 215 during off-peak periods in verkehrsarmen Zeiten
199 216 during the night in der Nacht
200 217 until further notice bis auf weiteres
201 218 for arrivals für Ankunft
202 219 for departures für Abfahrt
203 220 access only nur Zugang
204 221 only nur
205 222 except außer
206 223 for long distance traffic für Fernverkehr
207 224 for local traffic für Nahverkehr
208 225 for regional traffic für Regionalverkehr
209 226 unconfirmed report unbestätigter Bericht
210 227 on manual payment lanes auf Mautspuren mit Schalterbetrieb
211 231 sorry for any delay entschuldigen Sie etwaige Verzögerungen
212 232 for roads leading towards für Straßen nach
213 233 for roads from für Straßen aus
214 234 we are grateful for your cooperation wir danken Ihnen für Ihre Mitarbeit
215 235 Traffic queue length decreasing at an average rate of 10 km/hr Staulänge sehr langsam abnehmend
216 236 Traffic queue length decreasing at an average rate of 20 km/hr Staulänge langsam abnehmend
217 237 Traffic queue length decreasing at an average rate of 30 km/hr Staulänge schnell abnehmend
218 238 Traffic queue length decreasing at an average rate of 40 km/hr Staulänge sehr schnell abnehmend
219 239 leave your vehicle. Proceed to next save place bitte das Fahrzeug verlassen und den nächsten sicheren Platz aufsuchen
220 240 for visitors für Besucher
221 241 in the roadworks area im Baustellenbereich
222 242 from aus
223 243 to nach
224 244 in in
225 245 Traffic queue length increasing Staulänge zunehmend
226 246 Traffic queue length increasing at an average rate of 10 km/hr Staulänge sehr langsam zunehmend
227 247 Traffic queue length increasing at an average rate of 20 km/hr Staulänge langsam zunehmend
228 248 Traffic queue length increasing at an average rate of 30 km/hr Staulänge schnell zunehmend
229 249 Traffic queue length increasing at an average rate of 40 km/hr Staulänge sehr schnell zunehmend
230 250 very frequent service sehr kurzer Fahrtakt
231 251 frequent service regelmäßiger Fahrtakt
232 252 fairly frequent service recht kurzer Fahrtakt
233 253 regular service fahrplanmäßiger Fahrtakt
234 255 Traffic queue length decreasing Staulänge abnehmend

40
data/tmc_update_class_names.csv

@ -1,40 +0,0 @@
code(C),english,german
1,1. LEVEL OF SERVICE,Verkehrslage
2,2. EXPECTED LEVEL OF SERVICE,Erwartete Verkehrslage
3,3. ACCIDENTS,Unfälle
4,4. INCIDENTS,Vorfälle
5,5. CLOSURES AND LANE RESTRICTIONS,Straßen- und Fahrbahnsperrungen
6,6. CARRIAGEWAY RESTRICTIONS,Fahrbahnbeschränkungen
7,7. EXIT RESTRICTIONS,Beschränkungen der Ausfahrt
8,8. ENTRY RESTRICTIONS,Beschränkungen der Einfahrt
9,9. TRAFFIC RESTRICTIONS,Verkehrsbeschränkungen
10,10. CARPOOL INFORMATION,Informationen für Fahrgemeinschaften
11,11. ROADWORKS,Bauarbeiten
12,12. OBSTRUCTION HAZARDS,Behinderungen auf der Fahrbahn
13,13. DANGEROUS SITUATIONS,Gefährliche Situationen
14,14. ROAD CONDITIONS,Straßenzustand
15,15.TEMPERATURES,Temperaturen
16,16. PRECIPITATION AND VISIBILITY,Niederschlag und Sichtbehinderungen
17,17. WIND AND AIR QUALITY,Wind und Luftqualität
18,18. ACTIVITIES,Veranstaltungen
19,19. SECURITY ALERTS,Sicherheitsvorfälle
20,20. DELAYS,Zeitverluste
21,21. CANCELLATIONS,Ausfälle
22,22. TRAVEL TIME INFORMATION,Reiseinformationen
23,23. DANGEROUS VEHICLES,Gefährliche Fahrzeuge
24,24. EXCEPTIONAL LOADS/VEHICLES,Außergewöhnliche Ladungen und Fahrzeuge
25,25. TRAFFIC EQUIPMENT STATUS,Störungen an Lichtsignalanlagen und sonstigen Straßenausrüstungen
26,26. SIZE AND WEIGHT LIMITS,Beschränkung der Fahrzeugmaße und -gewichte
27,27. PARKING RESTRICTIONS,Parkregelungen
28,28. PARKING,Parken
29,29. REFERENCE TO AUDIO BROADCASTS,Information
30,30. SERVICE MESSAGES,Service Meldungen
31,31. SPECIAL MESSAGES,Spezielle Meldungen
32,32. LEVEL OF SERVICE FORECAST,Erwartete Verkehrslage
33,33. WEATHER FORECAST,Wettervorhersage
34,34. ROAD CONDITIONS FORECAST,Straßenzustandsvorhersage
35,35. ENVIRONMENT,Umwelt
36,36. WIND FORECAST,Windvorhersage
37,37. TEMPERATURE FORECAST,Temperaturvorhersage
38,38. DELAY FORECAST,Erwartete Zeitverluste
39,39. CANCELLATION FORECAST,Erwartete Streichungen
1 code(C) english german
2 1 1. LEVEL OF SERVICE Verkehrslage
3 2 2. EXPECTED LEVEL OF SERVICE Erwartete Verkehrslage
4 3 3. ACCIDENTS Unfälle
5 4 4. INCIDENTS Vorfälle
6 5 5. CLOSURES AND LANE RESTRICTIONS Straßen- und Fahrbahnsperrungen
7 6 6. CARRIAGEWAY RESTRICTIONS Fahrbahnbeschränkungen
8 7 7. EXIT RESTRICTIONS Beschränkungen der Ausfahrt
9 8 8. ENTRY RESTRICTIONS Beschränkungen der Einfahrt
10 9 9. TRAFFIC RESTRICTIONS Verkehrsbeschränkungen
11 10 10. CARPOOL INFORMATION Informationen für Fahrgemeinschaften
12 11 11. ROADWORKS Bauarbeiten
13 12 12. OBSTRUCTION HAZARDS Behinderungen auf der Fahrbahn
14 13 13. DANGEROUS SITUATIONS Gefährliche Situationen
15 14 14. ROAD CONDITIONS Straßenzustand
16 15 15.TEMPERATURES Temperaturen
17 16 16. PRECIPITATION AND VISIBILITY Niederschlag und Sichtbehinderungen
18 17 17. WIND AND AIR QUALITY Wind und Luftqualität
19 18 18. ACTIVITIES Veranstaltungen
20 19 19. SECURITY ALERTS Sicherheitsvorfälle
21 20 20. DELAYS Zeitverluste
22 21 21. CANCELLATIONS Ausfälle
23 22 22. TRAVEL TIME INFORMATION Reiseinformationen
24 23 23. DANGEROUS VEHICLES Gefährliche Fahrzeuge
25 24 24. EXCEPTIONAL LOADS/VEHICLES Außergewöhnliche Ladungen und Fahrzeuge
26 25 25. TRAFFIC EQUIPMENT STATUS Störungen an Lichtsignalanlagen und sonstigen Straßenausrüstungen
27 26 26. SIZE AND WEIGHT LIMITS Beschränkung der Fahrzeugmaße und -gewichte
28 27 27. PARKING RESTRICTIONS Parkregelungen
29 28 28. PARKING Parken
30 29 29. REFERENCE TO AUDIO BROADCASTS Information
31 30 30. SERVICE MESSAGES Service Meldungen
32 31 31. SPECIAL MESSAGES Spezielle Meldungen
33 32 32. LEVEL OF SERVICE FORECAST Erwartete Verkehrslage
34 33 33. WEATHER FORECAST Wettervorhersage
35 34 34. ROAD CONDITIONS FORECAST Straßenzustandsvorhersage
36 35 35. ENVIRONMENT Umwelt
37 36 36. WIND FORECAST Windvorhersage
38 37 37. TEMPERATURE FORECAST Temperaturvorhersage
39 38 38. DELAY FORECAST Erwartete Zeitverluste
40 39 39. CANCELLATION FORECAST Erwartete Streichungen

5
grc/CMakeLists.txt

@ -17,14 +17,15 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
install(FILES
multirds_multi_rds_printer.xml
multirds_rds_table_qt.xml
multirds_rds_parser_table_qt.xml
multirds_rds_decoder.xml
multirds_station_search.xml
multirds_max_freq.xml
multirds_stream_selector.xml
multirds_vector_cutter.xml
multirds_decoder_compare.xml
multirds_symbol_combiner.xml
multirds_sync_decim.xml
multirds_rds_decoder_redsea.xml
multirds_qtgui_range.xml
multirds_variable_setter.xml

6
grc/multirds_station_search.xml → grc/multirds_max_freq.xml

@ -1,10 +1,10 @@
<?xml version="1.0"?>
<block>
<name>station_search</name>
<key>multirds_station_search</key>
<name>max_freq</name>
<key>multirds_max_freq</key>
<category>[multirds]</category>
<import>import multirds</import>
<make>multirds.station_search($fft_len, $num_decoders, $center_freq, $samp_rate,$round_to,$debug)</make>
<make>multirds.max_freq($fft_len, $num_decoders, $center_freq, $samp_rate,$round_to,$debug)</make>
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes:
* name

38
grc/multirds_multi_rds_printer.xml

@ -0,0 +1,38 @@
<?xml version="1.0"?>
<block>
<name>Multi RDS Printer</name>
<key>multirds_multi_rds_printer</key>
<category>[multirds]</category>
<import>import multirds</import>
<make>multirds.multi_rds_printer($print_freq,$nPorts)</make>
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes:
* name
* key (makes the value accessible as $keyname, e.g. in the make node)
* type -->
<param>
<name>Print Frequency</name>
<key>print_freq</key>
<value>10</value>
<type>int</type>
</param>
<!-- Make one 'sink' node per input. Sub-nodes:
* name (an identifier for the GUI)
* type
* vlen
* optional (set to 1 for optional inputs) -->
<param>
<name>Number of Ports</name>
<key>nPorts</key>
<value>2</value>
<type>int</type>
<hide>part</hide>
</param>
<sink>
<name>in</name>
<type>message</type>
<nports>$nPorts</nports>
<!--<optional>1</optional>-->
</sink>
</block>

11
grc/multirds_symbol_combiner.xml → grc/multirds_sync_decim.xml

@ -1,10 +1,10 @@
<?xml version="1.0"?>
<block>
<name>symbol_combiner</name>
<key>multirds_symbol_combiner</key>
<name>sync_decim</name>
<key>multirds_sync_decim</key>
<category>[multirds]</category>
<import>import multirds</import>
<make>multirds.symbol_combiner($threshold, $min_diff, $log)</make>
<make>multirds.sync_decim($threshold, $min_diff, $log)</make>
<!-- Make one 'param' node for every Parameter you want settable from the GUI.
Sub-nodes:
* name
@ -58,11 +58,6 @@
* type
* vlen
* optional (set to 1 for optional inputs) -->
<source>
<name>ctrl</name>
<type>message</type>
<optional>1</optional>
</source>
<source>
<name>out</name>
<type>float</type>

2
include/multirds/CMakeLists.txt

@ -23,7 +23,7 @@
install(FILES
api.h
rds_decoder.h
symbol_combiner.h
sync_decim.h
rds_decoder_redsea.h
stream_router.h DESTINATION include/multirds
)

16
include/multirds/symbol_combiner.h → include/multirds/sync_decim.h

@ -19,8 +19,8 @@
*/
#ifndef INCLUDED_MULTIRDS_SYMBOL_COMBINER_H
#define INCLUDED_MULTIRDS_SYMBOL_COMBINER_H
#ifndef INCLUDED_MULTIRDS_SYNC_DECIM_H
#define INCLUDED_MULTIRDS_SYNC_DECIM_H
#include <multirds/api.h>
#include <gnuradio/sync_decimator.h>
@ -33,17 +33,17 @@ namespace gr {
* \ingroup multirds
*
*/
class MULTIRDS_API symbol_combiner : virtual public gr::sync_decimator
class MULTIRDS_API sync_decim : virtual public gr::sync_decimator
{
public:
typedef boost::shared_ptr<symbol_combiner> sptr;
typedef boost::shared_ptr<sync_decim> sptr;
/*!
* \brief Return a shared_ptr to a new instance of multirds::symbol_combiner.
* \brief Return a shared_ptr to a new instance of multirds::sync_decim.
*
* To avoid accidental use of raw pointers, multirds::symbol_combiner's
* To avoid accidental use of raw pointers, multirds::sync_decim's
* constructor is in a private implementation
* class. multirds::symbol_combiner::make is the public interface for
* class. multirds::sync_decim::make is the public interface for
* creating new instances.
*/
static sptr make(float threshold,float min_diff,bool log);
@ -52,5 +52,5 @@ namespace gr {
} // namespace multirds
} // namespace gr
#endif /* INCLUDED_MULTIRDS_SYMBOL_COMBINER_H */
#endif /* INCLUDED_MULTIRDS_SYNC_DECIM_H */

2
lib/CMakeLists.txt

@ -26,7 +26,7 @@ include_directories(${Boost_INCLUDE_DIR})
link_directories(${Boost_LIBRARY_DIRS})
list(APPEND multirds_sources
rds_decoder_impl.cc
symbol_combiner_impl.cc
sync_decim_impl.cc
rds_decoder_redsea_impl.cc
stream_router_impl.cc )

211
lib/rds_decoder_redsea_impl.cc

@ -30,7 +30,6 @@
#include "rds_decoder_redsea_impl.h"
#include <map>
#include <vector>
#include <bitset>
namespace gr {
namespace multirds {
@ -58,12 +57,16 @@ namespace gr {
dout << "constructing error lookup table"<<std::endl;
kErrorLookup = makeErrorLookupTable();
//dout<< kErrorLookup.count({(uint16_t)7, 'A'})<< std::endl;
//dout<< kErrorLookup.count({(uint16_t)7, 'B'})<< std::endl;
//dout<< kErrorLookup.count({(uint16_t)7, 'A'})<< std::endl;
//dout<< kErrorLookup.at({704, 'A'})<< std::endl;
// if (kErrorLookup.count({(uint16_t)14, (char)'A'}) > 0) {
// dout<<"found sy 14 offset A in table"<<std::endl;
// }
//dout<< "i am new"<< std::endl;
//~ if (kErrorLookup.count({(uint16_t)14, (char)'A'}) > 0) {
//~ dout<<"found sy 14 offset A in table"<<std::endl;
//~ }
dout<< "i am new"<< std::endl;
//dout<< kErrorLookup.at({704, 'A'})<< std::endl;
}
/*
@ -97,8 +100,6 @@ void rds_decoder_redsea_impl::enter_sync(uint16_t sync_block_number) {
block_bit_counter = 0;
block_number = (sync_block_number + 1) % 4;
group_assembly_started = false;
last_pi =0x0000;
group_corrected_blocks_counter =0;
d_state = SYNC;
}
/* see Annex B, page 64 of the standard */
@ -120,30 +121,6 @@ uint16_t rds_decoder_redsea_impl::calc_syndrome(uint32_t message,uint8_t mlen) {
}
//redsea stuff:
// Section B.1.1: '-- calculated by the modulo-two addition of all the rows of
// the -- matrix for which the corresponding coefficient in the -- vector is 1.'
uint32_t matrixMultiply(uint32_t vec, const std::vector<uint32_t>& matrix) {
uint32_t result = 0;
for (size_t k=0; k < matrix.size(); k++)
if ((vec >> k) & 0x01)
result ^= matrix[matrix.size() - 1 - k];
return result;
}
// Section B.2.1: 'The calculation of the syndromes -- can easily be done by
// multiplying each word with the parity matrix H.'
uint32_t calcSyndrome_vec(uint32_t vec) {
static const std::vector<uint32_t> parity_check_matrix({
0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004,
0x002, 0x001, 0x2dc, 0x16e, 0x0b7, 0x287, 0x39f, 0x313,
0x355, 0x376, 0x1bb, 0x201, 0x3dc,
0x1ee, 0x0f7, 0x2a7, 0x38f, 0x31b
});
return matrixMultiply(vec, parity_check_matrix);
}
const unsigned kBitmask16 = 0x000FFFF;
const unsigned kBitmask26 = 0x3FFFFFF;
const unsigned kBitmask28 = 0xFFFFFFF;
@ -153,25 +130,19 @@ std::map<std::pair<uint16_t, char>, uint32_t> rds_decoder_redsea_impl::makeError
static const unsigned int offset_word[5]={252,408,360,436,848};
static const unsigned int syndrome[5]={383,14,303,663,748};
static const char * const offset_name[]={"A","B","C","D","c"};*/
//const std::vector<uint16_t> offset_words ={0x0FC, 0x198, 0x168, 0x350, 0x1B4};
for (uint8_t offset_num=0;offset_num<5;offset_num++) {
//dout<<"name:" <<offset_name[offset_num];
//dout<<"\t word:" <<offset_word[offset_num]<< std::endl;
// "...the error-correction system should be enabled, but should be
// restricted by attempting to correct bursts of errors spanning one or two
// bits."
// Kopitz & Marks 1999: "RDS: The Radio Data System", p. 224
//for (uint32_t e=0x1;e <= 0x3;e+=0x2) {//for (uint32_t e : {0x1, 0x3}) {
//for (uint32_t e : {0x1, 0x3, 0x7,0x15,0x31}) {//fix up to 5 bit burst errors (as code should support)
for (uint32_t e : {0x1,0x3}) {//fix up to 2-bit burst errors (as book says)
for (uint32_t e : {0x1, 0x3}) {//fix up to 2 bit burst errors (as book says)
for (int shift=0; shift < 26; shift++) {
uint32_t errvec = ((e << shift) & kBitmask26);
uint32_t sy = calc_syndrome(errvec ^ offset_word[offset_num],26);//why uint32 and not uint16 as everywhere else???
//uint32_t sy = calcSyndrome_vec(errvec ^ offset_word[offset_num]);
uint16_t sy = calc_syndrome(errvec ^ offset_word[offset_num],26);
result.insert({{sy, offset_name[offset_num]}, errvec});
//dout << "adding sy:"<<sy<<"\t\toffset:"<<offset_name[offset_num]<<"\terrvec:"<<std::bitset<26>(errvec) <<std::endl;
//dout << "adding sy:"<<sy<<"\t\toffset:"<<offset_name[offset_num]<<"\terrvec:"<<std::bitset<32>(errvec) <<std::endl;
}
}
}
@ -179,17 +150,14 @@ static const char * const offset_name[]={"A","B","C","D","c"};*/
}
uint32_t rds_decoder_redsea_impl::correctBurstErrors(uint32_t block, char offset) {
uint32_t syndrome = calc_syndrome(block,26);
//uint32_t syndrome = calc_syndrome(block ^ offset_char_to_word(offset),26);
uint16_t syndrome = calc_syndrome(block,26);
uint32_t corrected_block = block;
//dout << "trying to correct sy:"<<syndrome<<"\t\toffset:"<<offset;//<<std::endl;
//dout << "\tcount:"<<kErrorLookup.count({(uint16_t)syndrome, (char)offset})<<std::endl;
if (kErrorLookup.count({syndrome, offset}) > 0) {
uint32_t err = kErrorLookup.at({syndrome, offset});
if (kErrorLookup.count({(uint16_t)syndrome, (char)offset}) > 0) {
uint32_t err = kErrorLookup.at({(uint16_t)syndrome, (char)offset});
//dout << "correcting"<<std::endl;
//err=0;//disables error correction
corrected_block ^= err;
}
return corrected_block;
}
@ -221,19 +189,6 @@ void rds_decoder_redsea_impl::decode_group(uint16_t *group) {
pmt::pmt_t pdu(pmt::cons(meta, data)); // make PDU: (metadata, data) pair
message_port_pub(pmt::mp("out"), pdu);
}
unsigned int rds_decoder_redsea_impl::offset_char_to_word(char offset_char){
// {'A','B','C','D','c'};
// {252,408,360,436,848};
switch(offset_char){
case 'A':return offset_word[0];
case 'B':return offset_word[1];
case 'C':return offset_word[2];
case 'D':return offset_word[3];
case 'c':return offset_word[4];
}
std::cout << "error converting offset char to word"<<std::endl;
return 0;//
}
//work function
int rds_decoder_redsea_impl::work (int noutput_items,
gr_vector_const_void_star &input_items,
@ -250,7 +205,7 @@ int rds_decoder_redsea_impl::work (int noutput_items,
uint16_t block_calculated_crc, block_received_crc, checkword,dataword;
uint16_t reg_syndrome;
uint8_t offset_char('x'); // x = error while decoding the word offset
uint8_t variant;
/* the synchronization process is described in Annex C, page 66 of the standard */
while (i<noutput_items) {
@ -286,90 +241,85 @@ int rds_decoder_redsea_impl::work (int noutput_items,
if (block_bit_counter<25) block_bit_counter++;
else {
good_block=false;
block_was_corrected=false;
dataword=(reg>>10) & 0xffff;//data part of received block (upper 16 bits)
block_calculated_crc=calc_syndrome(dataword,16);
checkword=reg & 0x3ff;//checkword part of received block (lower 10 bits)
/* manage special case of C or C' offset word */
if (block_number==2) {
if (variant == 2 ) dout << "error: 3rd block received before 2nd"<<std::endl;
else{
if (variant==0){//A
offset_char = 'C';
block_received_crc=checkword^offset_word[2];
}
else{//B
offset_char = 'c';
block_received_crc=checkword^offset_word[4];
//dout<<"B"<<std::endl;
}
if (block_received_crc==block_calculated_crc) {
if (variant==0){//A
offset_char = 'C';
block_received_crc=checkword^offset_word[2];
}
else{//B
offset_char = 'c';
block_received_crc=checkword^offset_word[4];
}
if (block_received_crc==block_calculated_crc) {
good_block=true;
}else{
//try correcting:
uint32_t corrected_block= correctBurstErrors(reg,offset_char);
if(corrected_block != reg){
good_block=true;
}else{
dataword=(corrected_block>>10) & 0xffff;
checkword=corrected_block & 0x3ff;
//dout << "corrected error"<<std::endl;
}else {
wrong_blocks_counter++;
good_block=false;
}
}
/*block_received_crc=checkword^offset_word[block_number];
if (block_received_crc==block_calculated_crc) {
good_block=true;
offset_char = 'C';
} else {
//try correcting:
uint32_t corrected_block= correctBurstErrors(reg,offset_char);
//uint32_t corrected_block= correctBurstErrors(reg,'C');
uint32_t corrected_block = reg;//2017-04-24 disabled correction for third block
//-> errors if corrected with wrong offset
if(corrected_block != reg){
good_block=true;
block_was_corrected=true;
group_corrected_blocks_counter++;
//wrong_blocks_counter++;
dataword=(corrected_block>>10) & 0xffff;
checkword=corrected_block & 0x3ff;
//dout << "corrected error"<<std::endl;
}else {
wrong_blocks_counter++;
good_block=false;
good_block=true;
dataword=(corrected_block>>10) & 0xffff;
checkword=corrected_block & 0x3ff;
offset_char = 'C';
//dout << "corrected error"<<std::endl;
}
}
}
else{
block_received_crc=checkword^offset_word[4];
if (block_received_crc==block_calculated_crc) {
good_block=true;
offset_char = 'c'; // C' (C-Tag)
} else {
wrong_blocks_counter++;
good_block=false;
}
}
}*/
}
else {
block_received_crc=checkword^offset_word[block_number];
if (block_received_crc==block_calculated_crc) {//valid block
if (block_received_crc==block_calculated_crc) {
good_block=true;
offset_char=expected_offset_char[block_number]; //expected_offset_char[]={'A','B','?','D'};
/*if (block_number==0) offset_char = 'A';
else if (block_number==1) offset_char = 'B';
else if (block_number==3) offset_char = 'D';*/
} else {
//detect clock slip
if (block_number==0 && last_pi!=0x000){//if PI was received earlier
uint16_t diff=dataword^(last_pi>>1);
uint16_t diff2=(dataword>>1)^(last_pi);
unsigned int num_diff_bits = std::bitset<16>(diff).count();
unsigned int num_diff_bits2 = std::bitset<16>(diff2).count();
if (num_diff_bits<2){
dout << "clockslip detection (forward,skipped one):"<<std::endl;
dout << "dataword:"<<std::bitset<16>(dataword)<<"\tlast_pi:"<<std::bitset<16>(last_pi)<<std::endl;
i--;
}
if (num_diff_bits2<2){
dout << "clockslip detection (backward,repeated one):"<<std::endl;
dout << "dataword:"<<std::bitset<16>(dataword)<<"\tlast_pi:"<<std::bitset<16>(last_pi)<<std::endl;
i++;
}
}
//try correcting:
uint32_t corrected_block= correctBurstErrors(reg,expected_offset_char[block_number]);
if(corrected_block != reg) {//syndrome found in table == correction worked
if(corrected_block != reg) {//syndrome found in table == correction worked
good_block=true;
block_was_corrected=true;
group_corrected_blocks_counter++;
//wrong_blocks_counter++;
dataword=(corrected_block>>10) & 0xffff;
checkword=corrected_block & 0x3ff;
dout << "corrected error:"<<std::endl;
dout << "old: rx:"<<block_received_crc<<"\tcalc:"<<block_calculated_crc<<std::endl;
block_received_crc=checkword^offset_word[block_number];
block_calculated_crc=calc_syndrome(dataword,16);
dout << "new: rx:"<<block_received_crc<<"\tcalc:"<<block_calculated_crc<<std::endl;
//dout << "corrected error"<<std::endl;
//dout << "old: rx:"<<block_received_crc<<"\tcalc:"<<block_calculated_crc<<std::endl;
//block_received_crc=checkword^offset_word[block_number];
//block_calculated_crc=calc_syndrome(dataword,16);
//dout << "new: rx:"<<block_received_crc<<"\tcalc:"<<block_calculated_crc<<std::endl;
offset_char=expected_offset_char[block_number];
}
else{
@ -381,25 +331,11 @@ int rds_decoder_redsea_impl::work (int noutput_items,
}
/* done checking CRC */
if (block_number==0 && good_block) {
last_pi=dataword;
group_assembly_started=true;
//group_corrected_blocks_counter=block_was_corrected;
group_corrected_blocks_counter=0;
group_good_blocks_counter=1;
variant=2;
}
if (block_number==1 && good_block) {//2nd block - > read group type variant
variant=(dataword>>11)& 0x1;
// uint8_t group=(dataword>>12)& 0xf;
// dout << "group:"<<std::setw(2)<< unsigned(group);
// //dout << "\tvariant:" << unsigned(variant);
// if (variant==0)
// dout << "A";
// else
// dout << "B";
// //dout << "\tvariant:" << unsigned(variant);
// dout << "\twas_corrected: "<<block_was_corrected<< std::endl;
variant=(dataword>>12)& 0x1;
}
if (group_assembly_started) {
if (!good_block) group_assembly_started=false;
@ -409,15 +345,14 @@ int rds_decoder_redsea_impl::work (int noutput_items,
group_good_blocks_counter++;
}
if (group_good_blocks_counter==5) decode_group(group);
//if (group_good_blocks_counter==5 and group_corrected_blocks_counter>0) decode_group(group);//test corrected blocks
}
block_bit_counter=0;
block_number=(block_number+1) % 4;
blocks_counter++;
/* 1187.5 bps / 104 bits = 11.4 groups/sec, or 45.7 blocks/sec */
if (blocks_counter==50) {//reduced from 50
if (blocks_counter==40) {//reduced from 50
last_wrong_blocks_counter=wrong_blocks_counter;
if (wrong_blocks_counter>35) {//reduced from 35
if (wrong_blocks_counter>28) {//reduced from 35
lout << "@@@@@ Lost Sync (Got " << wrong_blocks_counter
<< " bad blocks on " << blocks_counter
<< " total)" << std::endl;

7
lib/rds_decoder_redsea_impl.h

@ -55,12 +55,6 @@ private:
bool log;
bool presync;
bool good_block;
bool block_was_corrected;
uint8_t group_corrected_blocks_counter;
uint8_t variant;
uint16_t last_pi;
bool group_assembly_started;
uint8_t last_wrong_blocks_counter;
uint8_t lastseen_offset;
@ -76,7 +70,6 @@ private:
eOffset offsetForSyndrome(uint16_t syndrome);
eOffset nextOffsetFor(eOffset o);
uint32_t correctBurstErrors(uint32_t block, char offset);
unsigned int offset_char_to_word(char offset_char);
};

108
lib/symbol_combiner_impl.cc → lib/sync_decim_impl.cc

@ -23,27 +23,27 @@
#endif
#include <gnuradio/io_signature.h>
#include "symbol_combiner_impl.h"
#include "sync_decim_impl.h"
#define DECIM 2
#define lout log && std::cout
//#define SYNC_COUNTER_MAX 5//higher value -> slower sync, less cpu load
#define SYNC_COUNTER_MAX 200//higher value -> slower sync, less cpu load
#define SYNC_COUNTER_MAX 7//higher value -> slower sync, less cpu load
//#include <pmt.h>
namespace gr {
namespace multirds {
symbol_combiner::sptr
symbol_combiner::make(float threshold,float min_diff,bool log)
sync_decim::sptr
sync_decim::make(float threshold,float min_diff,bool log)
{
return gnuradio::get_initial_sptr
(new symbol_combiner_impl(threshold, min_diff, log));
(new sync_decim_impl(threshold, min_diff, log));
}
/*
* The private constructor
*/
symbol_combiner_impl::symbol_combiner_impl(float threshold,float min_diff,bool log)
: gr::sync_decimator("symbol_combiner",
sync_decim_impl::sync_decim_impl(float threshold,float min_diff,bool log)
: gr::sync_decimator("sync_decim",
gr::io_signature::make(1, 1, sizeof(float)),
gr::io_signature::make(1, 1, sizeof(float)), DECIM),
threshold(threshold),
@ -52,23 +52,20 @@ namespace gr {
{
message_port_register_in(pmt::mp("ctrl"));
set_msg_handler(pmt::mp("ctrl"), boost::bind(&symbol_combiner_impl::parse_ctrl_msg, this, _1));
message_port_register_out(pmt::mp("ctrl"));
set_msg_handler(pmt::mp("ctrl"), boost::bind(&sync_decim_impl::parse_ctrl_msg, this, _1));
//init persistant vars
last_input=0;
mode=COPY;
dosync_counter=0;
weakout_counter=0;
outbit_counter=0;
}
/*
* Our virtual destructor.
*/
symbol_combiner_impl::~symbol_combiner_impl()
sync_decim_impl::~sync_decim_impl()
{
}
void symbol_combiner_impl::parse_ctrl_msg(pmt::pmt_t pdu) {
void sync_decim_impl::parse_ctrl_msg(pmt::pmt_t pdu) {
if(!pmt::is_pair(pdu)) {
lout << "wrong input message (not a PDU)" << std::endl;
return;
@ -76,132 +73,83 @@ namespace gr {
pmt::pmt_t meta = pmt::car(pdu); // meta declares type 0:RDS, 1:sync/nosync
pmt::pmt_t sync = pmt::cdr(pdu);
if(1L==pmt::to_long(meta) && pmt::eqv(sync,pmt::PMT_F)){
/*if (mode != COPY){
pmt::pmt_t meta(pmt::from_long(4));
pmt::pmt_t data(pmt::from_long(COPY));
pmt::pmt_t pdu(pmt::cons(meta, data)); // make PDU: (metadata, data) pair
message_port_pub(pmt::mp("ctrl"), pdu);
lout<< "switched to copy"<<std::endl;
}
mode=COPY;*/
lout<< "entered nosync"<<std::endl;
lout<<"mode: "<<mode<<std::endl;
mode=COPY;
lout<<"mode: "<<mode<<std::endl;
}
}
int
symbol_combiner_impl::work(int noutput_items,
sync_decim_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
//if (noutput_items>8){
const float *in = (const float *) input_items[0];
float *out = (float *) output_items[0];
if(outbit_counter>2000){//2000 ^= ~every 2 seconds
lout<<"mode: "<<mode<<"\t";
lout<<"weakout_counter:"<<weakout_counter<<std::endl;
if(weakout_counter>1000){//switch to copy and resync if outputs low
mode=COPY;
pmt::pmt_t meta(pmt::from_long(4));
pmt::pmt_t data(pmt::from_long(COPY));
pmt::pmt_t pdu(pmt::cons(meta, data)); // make PDU: (metadata, data) pair
message_port_pub(pmt::mp("ctrl"), pdu);
lout<< "switched to copy"<<std::endl;
}
outbit_counter=0;
weakout_counter=0;
}
for (int i = 0; i < noutput_items; i++) {
if(mode==COPY){
out[i]=in[DECIM*i];
}
else if(mode==SKIP){//merges with left value
else if(mode==SKIP){
if(i==0){
out[i]=last_input-in[DECIM*i];}
else{
out[i]=in[DECIM*i-1]-in[DECIM*i];}
}
else if(mode==NOSKIP){//merges with right value
else if(mode==NOSKIP){
out[i]=in[DECIM*i]-in[DECIM*i+1];
}
//lout<<std::fixed << std::setprecision(3)<<out[i]<<".";
if(mode!=COPY and std::abs(out[i])<threshold){
weakout_counter++;
}
}
last_input=in[(noutput_items-1)*DECIM+1];//to use for next iteration of work
//lout<<noutput_items<<std::endl;
/*synchronize:*/
if(mode==COPY and dosync_counter>=SYNC_COUNTER_MAX){
//lout<<noutput_items<<std::endl;
if(mode==COPY and dosync_counter==SYNC_COUNTER_MAX){
dosync_counter=0;
float out_noskip;
float out_skip;
int skip_is_better_counter=0;
if (noutput_items>4)//min 4 comparisons TODO: what if there are never more than 4 outputs requested
if (noutput_items>8)//TODO: what if there are never more than 9 outputs requested
{
for (int i = 0; i < std::max(15,noutput_items); i++) {//max 15 comparisons -> cpu load
for (int i = 0; i < noutput_items; i++) {
if(i==0){
out_skip=last_input-in[DECIM*i];}
else{
out_skip=in[DECIM*i-1]-in[DECIM*i];}
out_noskip=in[DECIM*i]-in[DECIM*i+1];
/*if (std::abs(out_skip)>std::abs(out_noskip)){
if (std::abs(out_skip)>std::abs(out_noskip)){
skip_is_better_counter++;
}
else{
skip_is_better_counter--;
}*/
if (std::abs(out_skip)>threshold){
skip_is_better_counter++;
}
if (std::abs(out_noskip) >threshold){
skip_is_better_counter--;
}
//lout<<"state:"<< mode;
//lout<<"noutputs:"<<noutput_items;
//lout<<"in:"<<in[DECIM*i];
//lout<<"\t,out_noskip:"<<out_noskip;
//lout<<"\t,out_skip:"<<out_skip<<std::endl;
}
if (skip_is_better_counter>3){
pmt::pmt_t meta(pmt::from_long(4));
pmt::pmt_t data(pmt::from_long(SKIP));
pmt::pmt_t pdu(pmt::cons(meta, data)); // make PDU: (metadata, data) pair
message_port_pub(pmt::mp("ctrl"), pdu);
if (skip_is_better_counter>6){
mode=SKIP;
lout<<"switched to skip"<< std::endl;
}
else if (skip_is_better_counter<-3){
pmt::pmt_t meta(pmt::from_long(4));
pmt::pmt_t data(pmt::from_long(NOSKIP));
pmt::pmt_t pdu(pmt::cons(meta, data)); // make PDU: (metadata, data) pair
message_port_pub(pmt::mp("ctrl"), pdu);
else if (skip_is_better_counter<-6){
mode=NOSKIP;
lout<<"switched to noskip"<< std::endl;
}
}
else{//wait for longer input
dosync_counter=SYNC_COUNTER_MAX-2;
}
}
else if(mode==COPY){
else if(mode==COPY){
dosync_counter++;
}
}
// Tell runtime system how many output items we produced.
outbit_counter+=noutput_items;
return noutput_items;
/*}
else{return 0;}*/
}/*end of work*/
} /* namespace multirds */
} /* namespace gr */

16
lib/symbol_combiner_impl.h → lib/sync_decim_impl.h

@ -18,22 +18,22 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_MULTIRDS_SYMBOL_COMBINER_IMPL_H
#define INCLUDED_MULTIRDS_SYMBOL_COMBINER_IMPL_H
#ifndef INCLUDED_MULTIRDS_SYNC_DECIM_IMPL_H
#define INCLUDED_MULTIRDS_SYNC_DECIM_IMPL_H
#include <multirds/symbol_combiner.h>
#include <multirds/sync_decim.h>
namespace gr {
namespace multirds {
class symbol_combiner_impl : public symbol_combiner
class sync_decim_impl : public sync_decim
{
private:
// Nothing to declare in this block.
public:
symbol_combiner_impl(float threshold,float min_diff,bool log);
~symbol_combiner_impl();
sync_decim_impl(float threshold,float min_diff,bool log);
~sync_decim_impl();
// Where all the action really happens
int work(int noutput_items,
@ -47,12 +47,10 @@ namespace gr {
unsigned int skip;
void parse_ctrl_msg(pmt::pmt_t pdu);
int dosync_counter;
int weakout_counter;
int outbit_counter;
};
} // namespace multirds
} // namespace gr
#endif /* INCLUDED_MULTIRDS_SYMBOL_COMBINER_IMPL_H */
#endif /* INCLUDED_MULTIRDS_SYNC_DECIM_IMPL_H */

5
python/CMakeLists.txt

@ -31,9 +31,10 @@ endif()
GR_PYTHON_INSTALL(
FILES
__init__.py
multi_rds_printer.py
rds_table_qt.py
rds_parser_table_qt.py
station_search.py
max_freq.py
chart.py
stream_selector.py
vector_cutter.py
@ -52,5 +53,3 @@ include(GrTest)
set(GR_TEST_TARGET_DEPS gnuradio-multirds)
set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig)
GR_ADD_TEST(qa_rds_parser_table_qt ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_rds_parser_table_qt.py)
GR_ADD_TEST(qa_tmc_parser ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_tmc_parser.py)

219
python/RDS-decoder-instanciation.grc

@ -1,219 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<?grc format='1' created='3.7.11'?>
<flow_graph>
<timestamp>Thu Jun 8 13:29:17 2017</timestamp>
<block>
<key>options</key>
<param>
<key>author</key>
<value></value>
</param>
<param>
<key>window_size</key>
<value></value>
</param>
<param>
<key>category</key>
<value>[GRC Hier Blocks]</value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>description</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(8, 8)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>generate_options</key>
<value>qt_gui</value>
</param>
<param>
<key>hier_block_src_path</key>
<value>.:</value>
</param>
<param>
<key>id</key>
<value>top_block</value>
</param>
<param>
<key>max_nouts</key>
<value>0</value>
</param>
<param>
<key>qt_qss_theme</key>
<value></value>
</param>
<param>
<key>realtime_scheduling</key>
<value></value>
</param>
<param>
<key>run_command</key>
<value>{python} -u {filename}</value>
</param>
<param>
<key>run_options</key>
<value>prompt</value>
</param>
<param>
<key>run</key>
<value>True</value>
</param>
<param>
<key>thread_safe_setters</key>
<value></value>
</param>
<param>
<key>title</key>
<value></value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(8, 160)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>samp_rate</value>
</param>
<param>
<key>value</key>
<value>32000</value>
</param>
</block>
<block>
<key>blocks_null_source</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>bus_conns</key>
<value>[[0,],]</value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(471, 191)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blocks_null_source_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>num_outputs</key>
<value>1</value>
</param>
<param>
<key>type</key>
<value>byte</value>
</param>
<param>
<key>vlen</key>
<value>1</value>
</param>
</block>
<block>
<key>multirds_rds_decoder_redsea</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>debug</key>
<value>True</value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(662, 111)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>multirds_rds_decoder_redsea_0</value>
</param>
<param>
<key>log</key>
<value>False</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
</block>
<connection>
<source_block_id>blocks_null_source_0</source_block_id>
<sink_block_id>multirds_rds_decoder_redsea_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
</flow_graph>

4
python/__init__.py

@ -31,11 +31,11 @@ except ImportError:
pass
# import any pure python here
from multi_rds_printer import multi_rds_printer
from rds_table_qt import rds_table_qt
from rds_parser_table_qt import rds_parser_table_qt
from station_search import station_search
from max_freq import max_freq
from chart import Chart
from stream_selector import stream_selector

BIN
python/core

Binary file not shown.

186
python/station_search.py → python/max_freq.py

@ -21,15 +21,15 @@
import numpy as np
from gnuradio import gr
import code,math,pmt,time,threading
import code,math,pmt,time
class station_search(gr.sync_block):
class max_freq(gr.sync_block):
"""
docstring for block station_search
docstring for block max_freq
"""
def __init__(self, fft_len=1024,num_decoders=4,center_freq=0,samp_rate=0,round_to=100e3,debug=False):
gr.sync_block.__init__(self,
name="station_search",
name="max_freq",
in_sig=[(np.float32,fft_len)],
out_sig=None)
self.fft_len=fft_len
@ -39,13 +39,12 @@ class station_search(gr.sync_block):
self.snapto=round_to
self.debug=debug
self.last_station_indices=[0]*self.num_decoders
self.message_port_register_out(pmt.intern('out'))
self.timer=time.time()
self.message_port_register_in(pmt.intern('ctrl'))
self.set_msg_handler(pmt.intern('ctrl'), self.handle_ctrl_msg)
self.searchMode=True
self.index_fixed=[False]*self.num_decoders
self.search_thread=None
self.message_port_register_out(pmt.intern('out'))
self.timer=time.time()
self.message_port_register_in(pmt.intern('ctrl'))
self.set_msg_handler(pmt.intern('ctrl'), self.handle_ctrl_msg)
self.searchMode=True
self.index_fixed=[False]*self.num_decoders
def freq_to_index(self,freq):
startfreq=self.center_freq-self.samp_rate/2
#freq=self.samp_rate*index/self.fft_len+startfreq
@ -58,55 +57,55 @@ class station_search(gr.sync_block):
return freq
def handle_ctrl_msg(self,msg):
#if pmt.is_dict(msg):#check doesnt work, since pairs pass is_dict
try:
if pmt.is_dict():
m = pmt.pmt_to_python.pmt_to_dict(msg)
if m.has_key("cmd") and m["cmd"]=="set_audio_freq":
#print(m)
#print(self.last_station_indices)
freq_index=self.freq_to_index(m["freq"])
if m["chan"]=="left" and freq_index<self.fft_len-5:
if self.last_station_indices[0]==freq_index:
self.index_fixed[0]=False
print("decoder 0 free")
else:
self.last_station_indices[0]=freq_index
self.index_fixed[0]=True
print("decoder 0 fixed to %i"%m["freq"])
if m["chan"]=="right" and freq_index<self.fft_len-5:
if self.last_station_indices[1]==freq_index:
self.index_fixed[1]=False
print("decoder 1 free")
else:
self.last_station_indices[1]=freq_index
self.index_fixed[1]=True
print("decoder 1 fixed to %i"%m["freq"])
#print(self.last_station_indices)
if m.has_key("cmd") and m["cmd"]=="switch mode":
self.searchMode=not self.searchMode
print("searchMode: %s"%self.searchMode)
except RuntimeError:
pass#message was pair
#print(m)
#print(self.last_station_indices)
freq_index=self.freq_to_index(m["freq"])
if m["chan"]=="left" and freq_index<self.fft_len-5:
if self.last_station_indices[0]==freq_index:
self.index_fixed[0]=False
print("decoder 0 free")
else:
self.last_station_indices[0]=freq_index
self.index_fixed[0]=True
print("decoder 0 fixed to %i"%m["freq"])
if m["chan"]=="right" and freq_index<self.fft_len-5:
if self.last_station_indices[1]==freq_index:
self.index_fixed[1]=False
print("decoder 1 free")
else:
self.last_station_indices[1]=freq_index
self.index_fixed[1]=True
print("decoder 1 fixed to %i"%m["freq"])
#print(self.last_station_indices)
if m.has_key("cmd") and m["cmd"]=="switch mode":
self.searchMode=not self.searchMode
print("searchMode: %s"%self.searchMode)
def set_center_freq(self, freq=None):
self.index_fixed=[False]*self.num_decoders#free all decoders (freq wouldn't match anyways)
if freq is not None:
if isinstance(freq, float) or isinstance(freq, int):
self.center_freq=freq
else:
self.center_freq = int(freq)
def search(self,inputvector):
if isinstance(freq, float) or isinstance(freq, int):
self.center_freq=freq
else:
self.center_freq = int(freq)
def work(self, input_items, output_items):
if time.time()-self.timer<1:#every 1 seconds
return len(input_items[0])
elif self.searchMode:
#in0 = input_items[0]
#ii=input_items
carrier_width=2
carrier=self.fft_len/2
numbers=np.delete(inputvector[0],range(carrier-carrier_width,carrier+carrier_width+1))#read input and disregard center (hackrf LO)
numbers=np.delete(input_items[0][0],range(carrier-carrier_width,carrier+carrier_width+1))#read input and disregard center (hackrf LO)
#threshold=40# uni
#threshold=60#home
#threshold=np.mean(numbers)#2017-03-21 fft-multi-decoder
threshold=0.5*np.mean(numbers)#2017-05-18 fft-multi-decoder
threshold=np.mean(numbers)#2017-03-21 fft-multi-decoder
#minimum number of consecutive maximums (in fft domain) to consider signal as station:
#min_consec_max_threshold=1#uni
#min_consec_max_threshold=3#home
#min_consec_max_threshold=6#2017-03-21 fft-multi-decoder
min_consec_max_threshold=4#2017-05-18 fft-multi-decoder
min_consec_max_threshold=6#2017-03-21 fft-multi-decoder
fuzzyness=2#uni
#fuzzyness=10#home
@ -125,10 +124,10 @@ class station_search(gr.sync_block):
# max_indices[0].append(0)#to detect last station
max_indices=np.append(max_indices,0)#to detect last station
#try:
#max_indices.remove(self.fft_len/2)#suppress local oscillator of hackrf
#except ValueError:
#pass
#pass
for i in max_indices:
if abs(i-last_index) <= fuzzyness:
count+=i-last_index
@ -170,35 +169,32 @@ class station_search(gr.sync_block):
del station_indices_trunc[self.num_decoders:]#remove non decodable (too quiet) incidices
station_indices_tune=[0]*self.num_decoders
same_station_threshold=int(500000*self.fft_len/self.samp_rate)#0.5mhz
#same_station_threshold=3
new_stations=[]
#add fixed stations (currently unused):
#add fixed stations:
for i,old_freq in enumerate(self.last_station_indices):
if self.index_fixed[i]:
station_indices_tune[i]=old_freq
if self.index_fixed[i]:
station_indices_tune[i]=old_freq
#change existing/add new:
for new_freq in station_indices_trunc:
added=False
for i,old_freq in enumerate(self.last_station_indices):
if abs(old_freq-new_freq)<same_station_threshold:
station_indices_tune[i]=new_freq
added=True
if not added:
new_stations.append(new_freq)
#print("tune1:%s"%station_indices_tune)
if self.debug:
print("tunc:%s"%station_indices_trunc)
print("new_1:%s"%new_stations)
for i,tune_freq in enumerate(station_indices_tune):
if tune_freq == 0 and len(new_stations)>0:#add new stations to empty decoders
station_indices_tune[i]=new_stations.pop()
#print("tune2:%s"%station_indices_tune)
added=False
for i,old_freq in enumerate(self.last_station_indices):
if abs(old_freq-new_freq)<same_station_threshold:
station_indices_tune[i]=new_freq
added=True
if not added:
new_stations.append(new_freq)
#print("tune1:%s"%station_indices_tune)
#print("new_1 %s"%new_stations)
for i,tune_freq in enumerate(station_indices_tune):
if tune_freq == 0 and len(new_stations)>0:
station_indices_tune[i]=new_stations.pop()
#print("tune2:%s"%station_indices_tune)
#print("new_2 %s"%new_stations)
if self.debug:
print("new_2:%s"%new_stations)
print("last_index:%s"%self.last_station_indices)
print("tune_index:%s"%station_indices_tune)
self.last_station_indices=station_indices_tune#save current stations to compare againts next
station_strength=[]
@ -207,40 +203,24 @@ class station_search(gr.sync_block):
for index in station_indices_tune:
startfreq=self.center_freq-self.samp_rate/2
freq=self.samp_rate*index/self.fft_len+startfreq
#freq+=30000#add 30k because detected max often too low
freq+=30000#add 30k because detected max often too low
num_decimals=int(round(math.log(self.snapto,10)))
station_freqs.append(round(freq,-num_decimals))
station_strength.append(round(numbers[index],-2))
for i in range(0,min(self.num_decoders,len(station_freqs))):
msg_string=str(i+1)+" "+str(station_freqs[i])
send_pmt = pmt.string_to_symbol(msg_string)
self.message_port_pub(pmt.intern('out'), send_pmt)
if self.debug:
#print(max_indices)
#print(np.mean(numbers))
#print(len(max_indices))
#print(station_indices)
#print(station_indices_grouped)
#print(station_indices_sorted)
#print(station_indices_tune)
#print(station_strength)
print(station_freqs)
def work(self, input_items, output_items):
if time.time()-self.timer<2:#every 2 seconds
return len(input_items[0])
elif self.searchMode:
inputvector=input_items[0]
if self.search_thread == None or self.search_thread.is_alive()==False:
if self.debug:
print("starting thread")
self.search_thread = threading.Thread(target=self.search, args=[inputvector], kwargs={})
self.search_thread.start()
elif self.debug:
print("thread exists")
#in0 = input_items[0]
#ii=input_items
msg_string=str(i+1)+" "+str(station_freqs[i])
send_pmt = pmt.string_to_symbol(msg_string)
self.message_port_pub(pmt.intern('out'), send_pmt)
if self.debug:
#print(max_indices)
#print(np.mean(numbers))
#print(len(max_indices))
#print(station_indices)
#print(station_indices_grouped)
#print(station_indices_sorted)
#print(station_indices_tune)
#print(station_strength)
print(station_freqs)
return len(input_items[0])
else:

69
python/multi_rds_printer.py

@ -0,0 +1,69 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2016 <+YOU OR YOUR COMPANY+>.
#
# This 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 3, or (at your option)
# any later version.
#
# This software 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 this software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
import numpy,pmt,functools
from gnuradio import gr
class multi_rds_printer(gr.sync_block):
"""
docstring for block multi_rds_printer
"""
def __init__(self, print_freq,nPorts):
gr.sync_block.__init__(self,
name="multi_rds_printer",
in_sig=None,
out_sig=None)
self.PS="station name"
self.RT="radio text"
self.PI="C0FE"
self.stations = {}
self.print_freq = print_freq
self.print_count=print_freq
for i in range(0,nPorts):
self.message_port_register_in(pmt.intern('in%d'%i))
self.set_msg_handler(pmt.intern('in%d'%i), functools.partial(self.handle_msg, port=i))
def handle_msg(self, msg, port):
t = pmt.to_long(pmt.tuple_ref(msg, 0))
m = pmt.symbol_to_string(pmt.tuple_ref(msg, 1))
#code.interact(local=locals())
if(t==0):
self.PI=m
self.stations[str(port)+"PI"]=m
elif(t==1):
self.PS=m
self.stations[str(port)+"PS"]=m
elif(t==4):
self.RT=m
self.stations[str(port)+"RT"]=m
self.print_count -= 1
#print(self.stations)
if (self.print_count==0):
self.print_count=self.print_freq
print("########## stations ###########")
for key in sorted(self.stations):
print("%s: %s" % (key, self.stations[key]))
# def work(self, input_items, output_items):
# in0 = input_items[0]
# out = output_items[0]
# # <+signal processing here+>
# out[:] = in0
# return len(output_items[0])

44
python/qa_rds_parser_table_qt.py

@ -1,44 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2017 <+YOU OR YOUR COMPANY+>.
#
# This 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 3, or (at your option)
# any later version.
#
# This software 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 this software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
from gnuradio import gr, gr_unittest
from gnuradio import blocks
from multirds.rds_parser_table_qt import rds_parser_table_qt,rds_parser_table_qt_Signals
class qa_rds_parser_table_qt (gr_unittest.TestCase):
def setUp (self):
self.tb = gr.top_block ()
def tearDown (self):
self.tb = None
def test_001_instantiation(self):
self.signals=rds_parser_table_qt_Signals()
freq_tune=98.8e6
def set_freq_tune(self, freq_tune):
pass
self.parser_table = rds_parser_table_qt(self.signals,1,set_freq_tune,freq_tune,False, False,'../../data/',True)
# def test_001_t (self):
# set up fg
#self.tb.run ()
# check data
#self.assertEqual("a", "as")
if __name__ == '__main__':
gr_unittest.run(qa_rds_parser_table_qt, "qa_rds_parser_table_qt.xml")

45
python/qa_tmc_parser.py

@ -1,45 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2017 <+YOU OR YOUR COMPANY+>.
#
# This 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 3, or (at your option)
# any later version.
#
# This software 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 this software; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
from gnuradio import gr, gr_unittest
from gnuradio import blocks
from rds_parser_table_qt import rds_parser_table_qt
import multirds
class qa_tmc_parser (gr_unittest.TestCase):
def setUp (self):
self.tb = gr.top_block ()
def tearDown (self):
self.tb = None
def test_001_t (self):
# set up fg
self.tb.run ()
# check data
#self.assertEqual("a", "as")
#self.parser = multirds.tmc_parser("/home/clemens/forschungsarbeit/gr-multirds/data/", False, False, False,160)
#fails because tmc_parser tries to create gui object
if __name__ == '__main__':
gr_unittest.run(qa_tmc_parser, "qa_tmc_parser.xml")

9
python/qtgui_range.py

@ -75,13 +75,10 @@ class RangeWidget(QtGui.QWidget):
#print("update_gui called on widget %s"%self.label)
#print(value)
#self.d_widget.slider.setValue(value)
if self.range.min < value < self.range.max:
if self.style=="counter_slider":
self.d_widget.counter.setValue(value)
else:
self.d_widget.setValue(value)
if self.style=="counter_slider":
self.d_widget.counter.setValue(value)
else:
print("value %i not in range %i...%i"%(value,self.range.min,self.range.max))
self.d_widget.setValue(value)
#self.notifyChanged(self.rangeType(value))
def __init__(self, ranges, slot, label, style, rangeType=float):
""" Creates the QT Range widget """

262
python/rds_parser_table_qt.py

@ -18,19 +18,18 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
from __future__ import print_function#print without newline print('.', end="")
import numpy
from gnuradio import gr
import pmt,functools,csv,md5,collections,copy,sqlite3,atexit,time,re,sys
#old imports: folium
from datetime import datetime
from datetime import timedelta
import multirds.chart as chart
from multirds.tmc_classes import language#supported: de, en (both partially)
from multirds.tmc_classes import tmc_dict,tmc_message,language
from PyQt4 import Qt, QtCore, QtGui
import pprint,code
import pprint,code,pickle#for easier testing
pp = pprint.PrettyPrinter()
import cProfile, pstats, StringIO #for profiling
pr = cProfile.Profile()
@ -40,6 +39,7 @@ pr = cProfile.Profile()
from PyQt4.QtCore import QObject, pyqtSignal
from bitstring import BitArray
#language="de"#currently supported: de, en (both partially) #defined in tmc_classes.py
class rds_parser_table_qt_Signals(QObject):
@ -63,13 +63,11 @@ class rds_parser_table_qt(gr.sync_block):#START
out_sig=None)
if nPorts==1:
self.message_port_register_in(pmt.intern('in'))
self.set_msg_handler(pmt.intern('in'),
functools.partial(self.handle_msg, port=0))
self.set_msg_handler(pmt.intern('in'), functools.partial(self.handle_msg, port=0))
else:
for i in range(nPorts):
self.message_port_register_in(pmt.intern('in%d'%i))
self.set_msg_handler(pmt.intern('in%d'%i),
functools.partial(self.handle_msg, port=i))
self.set_msg_handler(pmt.intern('in%d'%i), functools.partial(self.handle_msg, port=i))
self.nPorts=nPorts
self.message_port_register_in(pmt.intern('freq'))
self.set_msg_handler(pmt.intern('freq'), self.set_freq)
@ -91,21 +89,19 @@ class rds_parser_table_qt(gr.sync_block):#START
self.decoder_frequencies={}
self.decoders=[]
for i in range(nPorts):
self.decoders.append({'synced':False,'freq':None,'PI':"",
'pilot_SNR':0,'decim_mode':0})
self.decoders.append({'synced':False,'freq':None,'PI':"",'pilot_SNR':0})
#self.decoder_synced={}
#self.colorder=['ID','freq','name','PTY','AF','time','text','quality','buttons']
self.colorder=['ID','freq','name','buttons','PTY','AF',
'time','text','quality','pilot_SNR','RT+']
self.colorder=['ID','freq','name','buttons','PTY','AF','time','text','quality','pilot_SNR','RT+']
self.workdir=workdir
self.PI_dict={}#contains PI:numpackets (string:integer)
self.tmc_messages=tmc_dict()
if self.writeDB:
#create new DB file
db_name=workdir+'RDS_data'+datetime.now().strftime("%Y%m%d_%H%M%S")+'.db'
db=sqlite3.connect(db_name, check_same_thread=False)
self.db=db
self.dbLock=QtCore.QSemaphore(1)
#create tables
try:
db.execute('''CREATE TABLE stations
@ -125,19 +121,20 @@ class rds_parser_table_qt(gr.sync_block):#START
#self.dbc.execute('''CREATE TABLE rtp
# (time text,PI text,rtp_string text)''')
reader = csv.reader(open(self.workdir+'RDS_ODA-AIDs_names_only.csv'),
delimiter=',', quotechar='"')
reader = csv.reader(open(self.workdir+'RDS_ODA-AIDs_names_only.csv'), delimiter=',', quotechar='"')
reader.next()#skip header
for row in reader:
self.ODA_application_names[int(row[0])]=row[1]
#read location code list:
reader = csv.reader(open(self.workdir+'LCL15.1.D-160122_utf8.csv'), delimiter=';', quotechar='"')
reader.next()#skip header
self.lcl_dict=dict((int(rows[0]),rows[1:]) for rows in reader)
#read RT+ class name list:
reader = csv.reader(open(self.workdir+'RTplus_classnames.csv'),
delimiter=',', quotechar='"')
reader = csv.reader(open(self.workdir+'RTplus_classnames.csv'), delimiter=',', quotechar='"')
reader.next()#skip header
self.rtp_classnames=dict((int(rows[0]),rows[1]) for rows in reader)
#read TMC-event list
reader = csv.reader(open(self.workdir+'event-list_with_forecast_sort.csv'),
delimiter=',', quotechar='"')
reader = csv.reader(open(self.workdir+'event-list_with_forecast_sort.csv'), delimiter=',', quotechar='"')
reader.next()#skip header
self.ecl_dict=dict((int(rows[0]),rows[1:]) for rows in reader)
#Code,Text CEN-English,Text (German),Text (German) kein Quantifier,Text (Quantifier = 1),Text (Quantifier >1),N,Q,T,D,U,C,R ,Comment
@ -149,31 +146,24 @@ class rds_parser_table_qt(gr.sync_block):#START
#C: update class:
#read update classes
reader = csv.reader(open(self.workdir+'tmc_update_class_names.csv'),
delimiter=',', quotechar='"')
reader = csv.reader(open(self.workdir+'tmc_update_class_names.csv'), delimiter=',', quotechar='"')
reader.next()#skip header, "code(C),english,german"
if language=="de":
self.tmc_update_class_names=dict((int(rows[0]),rows[2])
for rows in reader)#german names
self.tmc_update_class_names=dict((int(rows[0]),rows[2]) for rows in reader)#german names
else:
self.tmc_update_class_names=dict((int(rows[0]),rows[1])
for rows in reader)#english names
self.tmc_update_class_names=dict((int(rows[0]),rows[1]) for rows in reader)#english names
#read supplementary information code list
reader = csv.reader(open(self.workdir+'label6-supplementary-information-codes.csv'),
delimiter=',', quotechar='"')
reader = csv.reader(open(self.workdir+'label6-supplementary-information-codes.csv'), delimiter=',', quotechar='"')
reader.next()#skip header, "code,english,german"
if language=="de":
self.label6_suppl_info=dict((int(rows[0]),rows[2])
for rows in reader)#german
self.label6_suppl_info=dict((int(rows[0]),rows[2]) for rows in reader)#german
else:
self.label6_suppl_info=dict((int(rows[0]),rows[1])
for rows in reader)#english
self.label6_suppl_info=dict((int(rows[0]),rows[1]) for rows in reader)#english
#read PTY list
f=open(self.workdir+'pty-list.csv')
reader = csv.reader(f, delimiter=',', quotechar='"')
reader.next()#skip header
self.pty_dict=dict((int(rows[0]),unicode(rows[1],errors='ignore'))
for rows in reader)
self.pty_dict=dict((int(rows[0]),unicode(rows[1],errors='ignore')) for rows in reader)
f.close()
self.minute_count=0
self.minute_count_max=0
@ -187,31 +177,19 @@ class rds_parser_table_qt(gr.sync_block):#START
self.PI_dict[PI]-=1
#print(self.PI_dict)
if self.writeDB:
self.dbLock.acquire(1)
self.db.commit()
self.dbLock.release(1)
def update_freq(self):
# "&#9;" is a tab character
message_string="decoder frequencies:"
for num in self.decoder_frequencies:
freq=self.decoder_frequencies[num]
pilot_SNR=self.decoders[num]['pilot_SNR']
decim_mode=self.decoders[num]['decim_mode']
if decim_mode==0:#copy
underline=""
#underline="text-decoration-line: underline;text-decoration-style: wavy;text-decoration-color: red;"
elif decim_mode==1:#skip (merges with left value)
underline="text-decoration:overline"
elif decim_mode==2:#noskip (merges with right value)
underline="text-decoration:underline"
else:
underline=""
if self.decoders[num]['synced']:
message_string+="<span style='color:green;%s'>&emsp; %i:%0.1fM (%i dB)</span>"% (underline,num,freq/1e6,pilot_SNR)
message_string+="<span style='color:green'>&emsp; %i:%0.1fM (%i dB)</span>"% (num,freq/1e6,pilot_SNR)
#print("'color:green'>%i:%0.1fM</span>"% (num,freq/1e6))
else:#elif self.decoders[num]['synced']==False:
#print("'color:red'>%i:%0.1fM</span>"% (num,freq/1e6))
message_string+="<span style='color:red;%s'>&emsp; %i:%0.1fM (%i dB)</span>"% (underline,num,freq/1e6,pilot_SNR)
message_string+="<span style='color:red'>&emsp; %i:%0.1fM (%i dB)</span>"% (num,freq/1e6,pilot_SNR)
message_string+="<br>tuned frequency:%0.1fM"%(self.tuning_frequency/1e6)
self.signals.DataUpdateEvent.emit({'decoder_frequencies':message_string})
#print(message_string)
@ -265,7 +243,7 @@ class rds_parser_table_qt(gr.sync_block):#START
self.RDS_data[PI]["time"]={"timestring":"88:88","datestring":"00-00-0000","datetime":None}
self.RDS_data[PI]["wrong_block_ratio"]=1#100%
def handle_msg(self, msg, port):#port from 0 to 3
if pmt.to_long(pmt.car(msg))==1L:#sync/desync messages from RDS decoder
if pmt.to_long(pmt.car(msg))==1L:
synced=pmt.to_python(pmt.cdr(msg))
#print("port:%i, data: %s"%(port,data))
self.decoders[port]['synced']=synced
@ -276,7 +254,7 @@ class rds_parser_table_qt(gr.sync_block):#START
wrong_block_ratio=1#100%
self.RDS_data[PI]["wrong_block_ratio"]=wrong_block_ratio
self.signals.DataUpdateEvent.emit({'PI':PI,'wrong_block_ratio':wrong_block_ratio,'dots':dots})
elif pmt.to_long(pmt.car(msg))==2L:#wrong_block_ratio messages from RDS decoder
elif pmt.to_long(pmt.car(msg))==2L:
wrong_block_ratio=pmt.to_python(pmt.cdr(msg))
PI=self.decoders[port]['PI']
if self.RDS_data.has_key(PI):
@ -290,10 +268,6 @@ class rds_parser_table_qt(gr.sync_block):#START
PI=self.decoders[port]['PI']
if self.RDS_data.has_key(PI):
self.signals.DataUpdateEvent.emit({'PI':PI,'pilot_SNR':pilot_SNR})
elif pmt.to_long(pmt.car(msg))==4L:#mode messages from RDS sync_decim
mode=pmt.to_python(pmt.cdr(msg))
self.decoders[port]['decim_mode']=mode
self.update_freq()
else: #elif pmt.to_long(pmt.car(msg))==0L
array=pmt.to_python(msg)[1]
@ -311,7 +285,6 @@ class rds_parser_table_qt(gr.sync_block):#START
#self.signals.DataUpdateEvent.emit({'group_count':self.minute_count,'group_count_max':self.minute_count_max})
if self.writeDB:
#db=sqlite3.connect(self.db_name)
#self.dbLock.acquire(1)
db=self.db
@ -367,9 +340,7 @@ class rds_parser_table_qt(gr.sync_block):#START
self.RDS_data[PI]["TP"]=TP
self.RDS_data[PI]["PTY"]=self.pty_dict[PTY]
self.signals.DataUpdateEvent.emit({'PI':PI,'PTY':self.pty_dict[PTY],
'wrong_block_ratio':self.RDS_data[PI]["wrong_block_ratio"],
'TP':TP,'dots':dots})
self.signals.DataUpdateEvent.emit({'PI':PI,'PTY':self.pty_dict[PTY],'TP':TP,'wrong_block_ratio':self.RDS_data[PI]["wrong_block_ratio"],'dots':dots})
#self.signals.DataUpdateEvent.emit({'PI':PI,'PTY':self.pty_dict[PTY],'TP':TP})
@ -507,9 +478,9 @@ class rds_parser_table_qt(gr.sync_block):#START
PIN_valid= PIN_day in range(1,32) and PIN_hour in range(0,24) and PIN_minute in range(0,60)
if PIN_valid:
self.RDS_data[PI]["PIN"]=[PIN_day,PIN_hour,PIN_minute]
data_string="radio paging code:%i,LA:%i,variant:%i,SLC:%04X,PIN (valid):%s "%(radio_paging,LA,variant,SLC,str([PIN_day,PIN_hour,PIN_minute]))
data_string="variant:%i,SLC:%04X,PIN (valid):%s "%(variant,SLC,str([PIN_day,PIN_hour,PIN_minute]))
else:
data_string="radio paging code:%i,LA:%i,variant:%i,SLC:%04X,PIN:%04X "%(radio_paging,LA,variant,SLC,PIN)
data_string="variant:%i,SLC:%04X,PIN:%04X "%(variant,SLC,PIN)
#%02X%02X%02X%02X%02X
t=(str(datetime.now()),PI,self.RDS_data[PI]["PSN"],"PIN",data_string)
@ -531,7 +502,6 @@ class rds_parser_table_qt(gr.sync_block):#START
language_codes=SLC
if self.debug:
print("PI:%s PSN:%s,language_codes:%s"%(PI,self.RDS_data[PI]["PSN"],hex(language_codes)))
#variant 4 and 5 not assigned
elif variant==6:
#for use by broadcasters
if self.debug:
@ -543,6 +513,9 @@ class rds_parser_table_qt(gr.sync_block):#START
if(not self.RDS_data[PI].has_key("RT_0")):#initialize variables
self.RDS_data[PI]["RT_0"]={"RT":"_"*64,"RT_valid":[False]*64,"RT_all_valid":False}
self.RDS_data[PI]["RT_1"]={"RT":"_"*64,"RT_valid":[False]*64,"RT_all_valid":False}
#self.RDS_data[PI]["RT"]="_"*64
#self.RDS_data[PI]["RT_valid"]=[False]*64
#self.RDS_data[PI]["RT_all_valid"]=False
self.RDS_data[PI]["RT_last_ab_flag"]=2
adr= array[3]&0b00001111
@ -553,6 +526,7 @@ class rds_parser_table_qt(gr.sync_block):#START
#segment=self.decode_chars(chr(array[4])+chr(array[5])+chr(array[6])+chr(array[7]))
segment=chr(array[4])+chr(array[5])+chr(array[6])+chr(array[7])#EDIT:latedecode
#print("RT:adress: %d, segment:%s"%(adr,segment))
#self.signals.DataUpdateEvent.emit({'col':5,'row':port,'PI':PI,'groupType':groupType,'adress':adr,'segment':segment})
text_list=list(self.RDS_data[PI]["RT_"+str(ab_flag)]["RT"])
#determine text length:
@ -572,7 +546,7 @@ class rds_parser_table_qt(gr.sync_block):#START
text_list=['_']*64 #clear text
text_list[adr*4:adr*4+4]=segment
#reset stored text:
#self.RDS_data[PI]["RT_"+str(ab_flag)]["RT"]="_"*64 #done in text_list
self.RDS_data[PI]["RT_"+str(ab_flag)]["RT"]="_"*64
self.RDS_data[PI]["RT_"+str(ab_flag)]["RT_valid"]=[False]*64
#predict RT from last texts:
for rt in self.RDS_data[PI]["internals"]["RT_history"]:
@ -599,18 +573,12 @@ class rds_parser_table_qt(gr.sync_block):#START
if len(self.RDS_data[PI]["internals"]["RT_history"])>10:#only store last 10 RTs
self.RDS_data[PI]["internals"]["RT_history"].pop(0)
if self.writeDB:
t=(
str(datetime.now()),PI,self.RDS_data[PI]["PSN"],
"RT",self.decode_chars(rt)
)
t=(str(datetime.now()),PI,self.RDS_data[PI]["PSN"],"RT",self.decode_chars(rt))
db.execute("INSERT INTO data (time,PI,PSN,dataType,data) VALUES (?,?,?,?,?)",t)
self.RDS_data[PI]["internals"]["last_valid_rt"]=rt
try:#save rt+ if it exist
if self.writeDB:
t=(str(datetime.now()),PI,
self.RDS_data[PI]["PSN"],"RT+",
self.decode_chars(str(self.RDS_data[PI]["RT+"]))
)
t=(str(datetime.now()),PI,self.RDS_data[PI]["PSN"],"RT+",self.decode_chars(str(self.RDS_data[PI]["RT+"])))
db.execute("INSERT INTO data (time,PI,PSN,dataType,data) VALUES (?,?,?,?,?)",t)
except KeyError:
pass#no rt+ -> dont save
@ -667,7 +635,10 @@ class rds_parser_table_qt(gr.sync_block):#START
self.RDS_data[PI]["AID_list"][AID]["scope"]+="R"#regional
if (app_data>>0)&0x1==1:
self.RDS_data[PI]["AID_list"][AID]["scope"]+="U"#urban
#self.RDS_data[PI]["AID_list"][AID]["I"]=(app_data>>3)&0x1#international (EUROROAD)
#self.RDS_data[PI]["AID_list"][AID]["N"]=(app_data>>2)&0x1#national
#self.RDS_data[PI]["AID_list"][AID]["R"]=(app_data>>1)&0x1#regional
#self.RDS_data[PI]["AID_list"][AID]["U"]=(app_data>>0)&0x1#urban
elif variant==1:
self.RDS_data[PI]["AID_list"][AID]["SID"]=(app_data>>6)&0x3f#service identifier
#timing parameters (used to switch away from TMC station without missing messages):
@ -698,6 +669,10 @@ class rds_parser_table_qt(gr.sync_block):#START
if self.debug:
print("station:%s sent empty 4A group"%self.RDS_data[PI]["PSN"])
else:
#hours=((array[5] & 0x1) << 4) | ((array[6] >> 4) & 0x0f)
#minutes=((array[6] &0x0F)<<2)|((array[7] >>6)&0x3)
#offsetdir=(array[7]>>5)&0x1
#local_time_offset=0.5*((array[7])&0x1F)
if(offsetdir==1):
local_time_offset*=-1
try:
@ -736,8 +711,7 @@ class rds_parser_table_qt(gr.sync_block):#START
self.IH_data[PI][ih_data]["count"]+=1
self.IH_data[PI][ih_data]["last_time"]=str(datetime.now())
#TMC-alert-c (grouptype mostly 8A):
elif (self.RDS_data[PI]["AID_list"].has_key(52550)
and self.RDS_data[PI]["AID_list"][52550]["groupType"]==groupType):#TMC alert-C
elif self.RDS_data[PI]["AID_list"].has_key(52550) and self.RDS_data[PI]["AID_list"][52550]["groupType"]==groupType:#TMC alert-C
tmc_x=array[3]&0x1f #lower 5 bit of block2
tmc_y=(array[4]<<8)|(array[5]) #block3
tmc_z=(array[6]<<8)|(array[7])#block4
@ -769,7 +743,34 @@ class rds_parser_table_qt(gr.sync_block):#START
#~ ltn=1#assume germany TODO:add better error handling
#~ if self.log:
#~ print("no LTN (yet) for PI:%s"%PI)
#~ if tmc_T == 0:
#~ if tmc_F==1:#single group
#~ tmc_msg=tmc_message(PI,psn,ltn,tmc_x,tmc_y,tmc_z,datetime_received,self)
#~ self.print_tmc_msg(tmc_msg)
#~ elif tmc_F==0 and Y15==1:#1st group of multigroup
#~ ci=int(tmc_x&0x7)
#~ tmc_msg=tmc_message(PI,psn,ltn,tmc_x,tmc_y,tmc_z,datetime_received,self)
#~ #if self.RDS_data[PI]["internals"]["unfinished_TMC"].has_key(ci):
#~ #print("overwriting parital message")
#~ self.RDS_data[PI]["internals"]["unfinished_TMC"][ci]={"msg":tmc_msg,"time":time.time()}
#~ else:
#~ ci=int(tmc_x&0x7)
#~ if self.RDS_data[PI]["internals"]["unfinished_TMC"].has_key(ci):
#~ tmc_msg=self.RDS_data[PI]["internals"]["unfinished_TMC"][ci]["msg"]
#~ tmc_msg.add_group(tmc_y,tmc_z)
#~ age=time.time()-self.RDS_data[PI]["internals"]["unfinished_TMC"][ci]["time"]
#~ t=(time.time(),PI,age,ci,tmc_msg.is_complete)
#~ #print("%f: continuing message PI:%s,age:%f,ci:%i complete:%i"%t)
#~ self.RDS_data[PI]["internals"]["unfinished_TMC"][ci]["time"]=time.time()
#~ if tmc_msg.is_complete:
#~ self.print_tmc_msg(tmc_msg)#print and store message
#~ del self.RDS_data[PI]["internals"]["unfinished_TMC"][tmc_msg.ci]#delete finished message
#~ else:
#~ #if not ci==0:
#~ #print("ci %i not found, discarding"%ci)
#~ pass
#~ else:#alert plus or provider info
if tmc_T == 1:#rest done by tmc_parser
adr=tmc_x&0xf
@ -789,25 +790,16 @@ class rds_parser_table_qt(gr.sync_block):#START
seg_adr_start=(adr-4)*4#start of segment
text_list[seg_adr_start:seg_adr_start+4]=segment
self.RDS_data[PI]["AID_list"][52550]["provider name"]="".join(text_list)
if adr==6:
AF1_ON=tmc_y>>8
AF2_ON=tmc_y&0xff
PI_ON=tmc_z
if adr== 7:#freq of tuned an mapped station (not seen yet)
freq_TN=tmc_y>>8
freq_ON=tmc_y&0xff#mapped frequency
PI_ON=tmc_z
if self.debug:
print("TMC-info: TN:%i, station:%s"%(freq_TN,self.RDS_data[PI]["PSN"]))
self.RDS_data[PI]["TMC_TN"]=freq_TN
if adr== 9:
LTN_ON=(tmc_y>>10)
MGS_ON=(tmc_y>>6)&0xf
SID_ON=(tmc_y)&0x3f
PI_ON=tmc_z
else:
if self.log or self.debug or True:#not seen yet -> always print
print("alert plus on station %s (%s) , encrypted TMC?"%(PI,self.RDS_data[PI]["PSN"]))#(not seen yet)
if self.log or self.debug:
print("alert plus on station %s (%s)"%(PI,self.RDS_data[PI]["PSN"]))#(not seen yet)
#~ #self.tableobj.RDS_data["D301"]["AID_list"][52550]["provider name"]="test____"
#RadioText+ (grouptype mostly 12A):
@ -984,12 +976,10 @@ class rds_parser_table_qt(gr.sync_block):#START
elif (groupType == "8A"):
if self.debug:
print("8A without 3A on PI:%s"%PI)
elif self.log or self.log:#other group
print("group of type %s not decoded on station %s"% (groupType,PI))
#else:#other group
#print("group of type %s not decoded on station %s"% (groupType,PI))
pr.disable() #disabled-internal-profiling
#if self.writeDB:
# self.dbLock.release(1)
#end of handle_msg
def print_results(self):
s = StringIO.StringIO()
@ -1004,6 +994,18 @@ class rds_parser_table_qt(gr.sync_block):#START
#return(87.5e6+freq_raw*0.1e6)#returns float
else:
return(0)
def ref_locs(self,loc,name_string):
if(loc==34196):#europe
return(name_string)
else:
try:
locarray=self.lcl_dict[loc]
aref=int(locarray[6])
loc_name=locarray[4]
return(self.ref_locs(aref,name_string+","+loc_name))
#return(loc_name)
except KeyError:
return(name_string)
def decode_chars(self,charstring):
alphabet={
@ -1020,8 +1022,7 @@ class rds_parser_table_qt(gr.sync_block):#START
0b1100:u"ÁÀÉÈÍÌÓÒÚÙŘČŠŽĐĿ",
0b1101:u"ÂÄÊËÎÏÔÖÛÜřčšžđŀ",
0b1110:u"ÃÅÆŒŷÝÕØÞŊŔĆŚŹŦð",
0b1111:u"ãåæœŵýõøþŋŕćśźŧ "}#0xff should not occur (not in standard)
#(but occured 2017-03-04-9:18 , probably transmission error)
0b1111:u"ãåæœŵýõøþŋŕćśźŧ "}#0xff should not occur (not in standard) (but occured 2017-03-04-9:18 , probably transmission error)
#charlist=list(charstring)
return_string=u""
@ -1043,18 +1044,15 @@ class rds_parser_table_qt(gr.sync_block):#START
#return_string+=unichr(ord(char))#TODO: properly decide for UTF8 or EBU charset
except KeyError:
return_string+=u"?%02X?"%ord(char)#symbol not decoded
print("symbol not decoded: "+"?%02X?"%ord(char)+
"in string:"+return_string)
print("symbol not decoded: "+"?%02X?"%ord(char)+"in string:"+return_string)
pass
if not type(return_string)==unicode:
code.interact(local=locals())
return return_string
def color_text(self, text, start,end,textcolor,segmentcolor):
formatted_text=(
"<span style='font-family:Courier New;color:%s'>%s</span>"*3
)% (textcolor,text[:start],
segmentcolor,text[start:end],
textcolor,text[end:])
#formatted_text="<font face='Courier New' color='%s'>%s</font><font face='Courier New' color='%s'>%s</font><font face='Courier New' color='%s'>%s</font>"% (textcolor,text[:start],segmentcolor,text[start:end],textcolor,text[end:])
#formatted_text="<span style='background-color: yellow;color:%s'>%s</span><span style='color:%s'>%s</span><span style='color:%s'>%s</span>"% (textcolor,text[:start],segmentcolor,text[start:end],textcolor,text[end:])
formatted_text=("<span style='font-family:Courier New;color:%s'>%s</span>"*3)% (textcolor,text[:start],segmentcolor,text[start:end],textcolor,text[end:])
return formatted_text
class rds_parser_table_qt_Widget(QtGui.QWidget):
def __init__(self, signals,label,tableobj):
@ -1079,6 +1077,9 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
self.table.setColumnCount(len(self.colorder))
self.table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) #disallow editing
##button.clicked.connect(self.getDetails)
layout.addWidget(self.table)
self.table.setHorizontalHeaderLabels(self.colorder)
#self.table.setMaximumHeight(300)#TODO use dynamic value
@ -1096,23 +1097,23 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
print_button = QtGui.QPushButton("print profile")
print_button.clicked.connect(self.printProfile)
button_layout.addWidget(print_button)
mode_button = QtGui.QPushButton("searchMode")
mode_button = QtGui.QPushButton("mode")
mode_button.clicked.connect(self.switchMode)
button_layout.addWidget(mode_button)
layout.addLayout(button_layout)
label_layout = Qt.QHBoxLayout()
self.freq_label=QtGui.QLabel("decoder frequencies:")
self.freq_label.setWordWrap(True)
self.freq_label.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Ignored))#expand in horizontal direction and only wrap if window too small
self.freq_label.setTextFormat(QtCore.Qt.RichText)#instead of AutoText
self.freq_label.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Ignored))#expand in horizontal direction and only wrap if window too small
#self.freq_label.setTextFormat(QtCore.Qt.RichText)
#self.freq_label.setTextFormat(QtCore.Qt.PlainText)
self.count_label=QtGui.QLabel("count:")
self.count_label.setAlignment(QtCore.Qt.AlignRight)
label_layout.addWidget(self.freq_label)
label_layout.addWidget(self.count_label)
layout.addLayout(label_layout)
#self.setMinimumSize(Qt.QSize(500,40*self.tableobj.nPorts))
self.setMinimumSize(Qt.QSize(500,40*(4+self.tableobj.nPorts)))
#TODO set different minsize if TMC is shown
self.setMinimumSize(Qt.QSize(500,40*self.tableobj.nPorts))
self.lastResizeTime=0
self.clip = QtGui.QApplication.clipboard()
#self.cb.clear(mode=cb.Clipboard )
@ -1243,8 +1244,7 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
def showIHdata(self):
view=Qt.QDialog()
l=QtGui.QLabel("In House Data:\n%s"%pp.pformat(self.tableobj.IH_data))
l.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse |
QtCore.Qt.TextSelectableByKeyboard)
l.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse |QtCore.Qt.TextSelectableByKeyboard)
l.setWordWrap(True)
#self.IH_data
layout=Qt.QVBoxLayout()
@ -1257,12 +1257,10 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
PI=str(self.table.cellWidget(row,PIcol).text())
freq=int(self.tableobj.RDS_data[PI]['AF']['main'])
#print("setaudio row:%i, chan:%s, PI:%s,freq:%i"%(row,audio_channel,PI,freq))
send_pmt = pmt.pmt_to_python.pmt_from_dict({"cmd":"set_audio_freq",
"chan":audio_channel,"freq":freq})
send_pmt = pmt.pmt_to_python.pmt_from_dict({"cmd":"set_audio_freq","chan":audio_channel,"freq":freq})
self.tableobj.message_port_pub(pmt.intern('ctrl'), send_pmt)
#catch:
#print("no freq, cant set decoder")
#show notification? popup: too intrusive, log: maybe not visible, other possibility?
#print("no freq, cant set decoder")#show notification? popup: too intrusive, log: maybe not visible, other possibility?
#print("freq not in RX BW")#automatically shift freq-tune?
def setAudio2(self,row,audio_channel):
@ -1274,7 +1272,7 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
#self.tableobj.decoders[port]['PI']
inport=pmt.from_long(port)
outport=pmt.from_long(audio_channel)
#print("sending chan:%i"%audio_channel)
print("sending chan:%i"%audio_channel)
send_pmt=pmt.cons(inport, outport) #make PDU: (metadata, data) pair
self.tableobj.message_port_pub(pmt.intern('ctrl'), send_pmt)
@ -1282,15 +1280,13 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
PIcol=self.colorder.index('ID')
PI=str(self.table.cellWidget(row,PIcol).text())
view = chart.DialogViewer()
if self.tableobj.PI_dict.has_key(PI) and self.tableobj.PI_dict[PI]>3:
#dont print piechart if no packets received (detected via EON)
if self.tableobj.PI_dict.has_key(PI) and self.tableobj.PI_dict[PI]>3:#dont print piechart if no packets received (detected via EON)
table=chart.DataTable()
table.addColumn('groupType')
table.addColumn('numPackets')
blockcounts=copy.deepcopy(self.tableobj.RDS_data[PI]['blockcounts'])
del blockcounts['any']
#lambda function removes last character of PI string (A or B)
#and sorts based on integer valure of number in front
#lambda function removes last character of PI string (A or B) and sorts based on integer valure of number in front
for key in sorted(blockcounts,key=lambda elem: int(elem[0:-1])):
count=blockcounts[key]
table.addRow([key+": "+str(count),count])
@ -1304,14 +1300,11 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
del rds_data['PSN_valid']
del rds_data["RT_0"]['RT_valid']
del rds_data["RT_1"]['RT_valid']
rds_data['internals']['RT_history']=["".join(rt) for rt
in rds_data['internals']['RT_history']]
#combine char lists into strings (more compact)
rds_data['internals']['RT_history']=["".join(rt) for rt in rds_data['internals']['RT_history']]#combine char lists into strings (more compact)
except KeyError:
pass
l=QtGui.QLabel("Data:%s"%pp.pformat(rds_data))
l.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse |
QtCore.Qt.TextSelectableByKeyboard)
l.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse |QtCore.Qt.TextSelectableByKeyboard)
l.setWordWrap(True)
#l=QtGui.QLabel("Data:")
@ -1324,33 +1317,20 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
view.setWindowTitle(self.tableobj.RDS_data[PI]["PSN"])
view.exec_()
def onCLick(self):
from thread import start_new_thread
print("button clicked")
#code.interact(local=locals())
start_new_thread(self.interact,())
def interact(self):
code.interact(local=dict(globals(), **locals()))
code.interact(local=locals())
if __name__ == "__main__":
from PyQt4 import Qt
import sys
from thread import start_new_thread
class dummy:
def __init__(self):
self.colorder=['ID','freq','name','buttons','PTY','AF',
'time','text','quality','pilot_SNR','RT+']
self.nPorts=4
qapp = Qt.QApplication(sys.argv)
signals= rds_parser_table_qt_Signals()
mainobj=dummy()
widget = rds_parser_table_qt_Widget(signals,"TestLabel",mainobj)
app = Qt.QApplication(sys.argv)
mainobj= rds_parser_table_qt_Signals()
#mainobj=None
widget = rds_parser_table_qt_Widget(mainobj,"TestLabel")
widget.show()
widget.setWindowTitle("Test Qt gui")
widget.setGeometry(200,200,600,300)
def quitting():
print("quitting")
sys.exit()
qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting)
qapp.exec_()
#sys.exit(app.exec_())
sys.exit(app.exec_())
widget = None

1764
python/tmc_classes.py

File diff suppressed because it is too large Load Diff

169
python/tmc_parser.py

@ -18,7 +18,6 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
from __future__ import print_function#print without newline print('.', end="")
import numpy
from gnuradio import gr
@ -26,11 +25,10 @@ import pmt
from PyQt4 import Qt, QtCore, QtGui
import code,time,csv,sqlite3,atexit
from bitstring import BitArray
from multirds.tmc_classes import tmc_dict,tmc_message,language,lcl
from multirds.tmc_classes import tmc_dict,tmc_message,language
from datetime import datetime
from datetime import timedelta
class tmc_parser(gr.sync_block):
"""
docstring for block tmc_parser
@ -50,17 +48,14 @@ class tmc_parser(gr.sync_block):
self.tmc_meta={}
self.unfinished_messages={}
self.TMC_data={}
self.dataLock=QtCore.QSemaphore(1)
self.tmc_messages=tmc_dict()
atexit.register(self.goodbye)
self.save_data_timer=time.time()
self.lcl_obj=lcl(workdir+"LCL/")
self.save_data_timer=time.time()
if self.writeDB:
#create new DB file
db_name=workdir+'RDS_data'+datetime.now().strftime("%Y%m%d_%H%M%S")+'_TMC.db'
db=sqlite3.connect(db_name, check_same_thread=False)
self.db=db
self.dbLock=QtCore.QSemaphore(1)
#create tables
try:
@ -74,9 +69,9 @@ class tmc_parser(gr.sync_block):
except sqlite3.OperationalError as e:
print("ERROR: tables already exist")
print(e)
#reader = csv.reader(open(self.workdir+'LCL15.1.D-160122_utf8.csv'), delimiter=';', quotechar='"')
#reader.next()#skip header
#self.lcl_dict=dict((int(rows[0]),rows[1:]) for rows in reader)
reader = csv.reader(open(self.workdir+'LCL15.1.D-160122_utf8.csv'), delimiter=';', quotechar='"')
reader.next()#skip header
self.lcl_dict=dict((int(rows[0]),rows[1:]) for rows in reader)
#read TMC-event list
reader = csv.reader(open(self.workdir+'event-list_with_forecast_sort.csv'), delimiter=',', quotechar='"')
reader.next()#skip header
@ -99,62 +94,45 @@ class tmc_parser(gr.sync_block):
self.save_data()
print("closing tmc display")
def save_data(self):
print_dbg('saving data..', end="")
#self.dataLock.acquire(1) #disabled 2017-06-06 for performance
if self.writeDB:
self.dbLock.acquire(1)
self.db.commit()
self.dbLock.release(1)
f=open(self.workdir+'google_maps_markers.js', 'w')
markerstring=self.tmc_messages.getMarkerString()
#self.dataLock.release(1)
markerstring+='\n console.log("loaded "+markers.length+" markers")'
markerstring+='\n document.getElementById("errorid").innerHTML = "loaded "+markers.length+" markers";'
f.write(markerstring)
f.close()
print_dbg('saved')
def print_tmc_msg(self,tmc_msg):
print_dbg('parser:print', end="")
if self.writeDB and tmc_msg.event.is_cancellation == False:
try:
self.dataLock.acquire(1)
t=(int(tmc_msg.location.lcn),int(tmc_msg.event.updateClass),tmc_msg.PI,tmc_msg.tmc_hash,
tmc_msg.getTime(),int(tmc_msg.event.ecn),int(tmc_msg.is_single),
int(tmc_msg.tmc_DP),int(tmc_msg.tmc_D),int(tmc_msg.tmc_dir),int(tmc_msg.tmc_extent),
tmc_msg.location_text().decode("utf-8"),tmc_msg.events_string().decode("utf-8"),tmc_msg.info_str().decode("utf-8"),tmc_msg.multi_str().decode("utf-8"))
print_dbg('.', end="")
self.dbLock.acquire(1)
self.db.execute("REPLACE INTO TMC (lcn,updateclass,hash,PI,time,ecn,isSingle,DP,div,dir,extent,locstr,eventstr,infostr,multistr) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",t)
self.dbLock.release(1)
self.dataLock.release(1)
print_dbg('.', end="")
except Exception as e:
if self.log or self.debug:
print("error during db insert msg:%s"%tmc_msg.log_string())
print(e)
pass
print_dbg("db-done")
#self.dataLock.acquire(1)
self.qtwidget.print_tmc_msg(tmc_msg)
#self.dataLock.release(1)
print_dbg("parser:done")
#if self.debug:
#print("new tmc message %s"%tmc_msg)
if self.debug:
print("new tmc message %s"%tmc_msg)
def initialize_data_for_PI(self,PI):
self.unfinished_messages[PI]={}
def handle_msg(self,msg):
if time.time()-self.save_data_timer > 3:#every 3 seconds
self.save_data_timer=time.time()
self.save_data()
#self.save_data()
m=pmt.to_python(msg)
PI=m["PI"]
if not self.unfinished_messages.has_key(PI):
self.unfinished_messages[PI]={}
self.initialize_data_for_PI(PI)
if m["type"]=="3A_meta":
self.tmc_meta[PI]=m["data"]
elif m["type"]=="alert-c":
#self.qtwidget.updateui()
#print(m)
psn=m["PSN"]
try:
ltn=self.tmc_meta[PI]["LTN"]
@ -175,38 +153,27 @@ class tmc_parser(gr.sync_block):
if tmc_T == 0:
if tmc_F==1:#single group
tmc_msg=tmc_message(PI,psn,ltn,tmc_x,tmc_y,tmc_z,datetime_received,self)
self.dataLock.acquire(1)
print_message=self.tmc_messages.add(tmc_msg)
self.dataLock.release(1)
if print_message:#ignore duplicates
self.print_tmc_msg(tmc_msg)
self.tmc_messages.add(tmc_msg)
self.print_tmc_msg(tmc_msg)
elif tmc_F==0 and Y15==1:#1st group of multigroup
ci=int(tmc_x&0x7)
tmc_msg=tmc_message(PI,psn,ltn,tmc_x,tmc_y,tmc_z,datetime_received,self)
self.dataLock.acquire(1)
print_message=self.tmc_messages.add(tmc_msg)
self.dataLock.release(1)
self.tmc_messages.add(tmc_msg)
#if self.RDS_data[PI]["internals"]["unfinished_TMC"].has_key(ci):
#print("overwriting parital message")
if print_message:#save unfinished message only once (dont overwrite collected additional groups)
self.unfinished_messages[PI][ci]={"msg":tmc_msg,"time":time.time()}
self.unfinished_messages[PI][ci]={"msg":tmc_msg,"time":time.time()}
else:
ci=int(tmc_x&0x7)
if self.unfinished_messages[PI].has_key(ci):
tmc_msg=self.unfinished_messages[PI][ci]["msg"]
self.dataLock.acquire(1)
tmc_msg.add_group(tmc_y,tmc_z)
self.dataLock.release(1)
age=time.time()-self.unfinished_messages[PI][ci]["time"]
#t=(time.time(),PI,age,ci,tmc_msg.is_complete)
t=(time.time(),PI,age,ci,tmc_msg.is_complete)
#print("%f: continuing message PI:%s,age:%f,ci:%i complete:%i"%t)
self.unfinished_messages[PI]["time"]=time.time()
if tmc_msg.is_complete:
self.print_tmc_msg(tmc_msg)#print message
self.dataLock.acquire(1)#wait for print before delete
print_dbg("deleted finished (multi-group) message")
del self.unfinished_messages[PI][tmc_msg.ci]#delete finished message
self.dataLock.release(1)
else:
#if not ci==0:
#print("ci %i not found, discarding"%ci)
@ -225,25 +192,15 @@ class tmc_parser(gr.sync_block):
segment=self.decode_chars(chr(chr1)+chr(chr2)+chr(chr3)+chr(chr4))
if self.log:
print("TMC-info adr:%i (provider name), segment:%s, station:%s"%(adr,psn))
if adr==6:
AF1_ON=tmc_y>>8
AF2_ON=tmc_y&0xff
PI_ON=tmc_z
if adr== 7:#freq of tuned an mapped station (not seen yet)
freq_TN=tmc_y>>8
freq_ON=tmc_y&0xff#mapped frequency
PI_ON=tmc_z
if self.debug:
if self.log:
print("TMC-info: TN:%i, station:%s"%(freq_TN,psn))
if adr== 9:
LTN_ON=(tmc_y>>10)
MGS_ON=(tmc_y>>6)&0xf
SID_ON=(tmc_y)&0x3f
PI_ON=tmc_z
else:
if self.log or True:#not seen yet -> always print
if self.log:
print("alert plus on station %s (%s)"%(PI,psn))#(not seen yet)
#end of handle_msg
def getqtwidget(self):
return self.qtwidget
def decode_chars(self,charstring):
@ -286,84 +243,37 @@ class tmc_parser(gr.sync_block):
print("symbol not decoded: "+"?%02X?"%ord(char)+"in string:"+return_string)
pass
return return_string
def print_dbg(message,end="\n"):
dbg=False
if dbg:
print(message,end=end)
class tmc_parser_Widget(QtGui.QWidget):
def print_tmc_msg(self,tmc_msg):
self.parser.dataLock.acquire(1)
self.logMutex.acquire(1)
print_dbg("print:got mutex,",end="")
sb=self.logOutput.verticalScrollBar()
print_dbg(".",end="")
oldmax=sb.maximum()
print_dbg(".",end="")
auto_scroll= abs(oldmax-sb.value())<60#auto_scroll if scrollbar was at max
print_dbg(".",end="")
#print("%i %i %r"%(sb.maximum(),sb.value(),auto_scroll))
ef=unicode(self.event_filter.text().toUtf8(), encoding="UTF-8").lower()
lf=unicode(self.location_filter.text().toUtf8(), encoding="UTF-8").lower()
filters=[{"type":"location", "str":lf},{"type":"event", "str":ef}]
if tmc_dict.matchFilter(tmc_msg,self.showInvalid,filters):
print_dbg("a",end="")
logstr=Qt.QString.fromUtf8(tmc_msg.log_string())
print_dbg(".",end="")
self.logOutput.append(logstr)
print_dbg(".",end="")
QtGui.QApplication.processEvents()
print_dbg("a",end="")
multistr=Qt.QString.fromUtf8(tmc_msg.multi_str())
print_dbg(".",end="")
self.logOutput.append(multistr)
print_dbg(".",end="")
QtGui.QApplication.processEvents()
print_dbg("a",end="")
if self.parser.tmc_messages.matchFilter(tmc_msg,filters):
self.logOutput.append(Qt.QString.fromUtf8(tmc_msg.log_string()))
self.logOutput.append(Qt.QString.fromUtf8(tmc_msg.multi_str()))
#print("new message")
if auto_scroll:
#sb=self.logOutput.verticalScrollBar() #disabled 2017-04-28 might be cause of double free
sb=self.logOutput.verticalScrollBar()
new_max=sb.maximum()
print_dbg("s",end="")
sb.setValue(new_max)
print_dbg("s",end="")
self.logMutex.release(1)
self.parser.dataLock.release(1)
print_dbg("\tdone")
#print("scrolling %i %i %r"%(oldmax,new_max,sb.value()))
#code.interact(local=locals())
def updateui(self):
print("updating ui")
def filterChanged(self):
self.parser.dataLock.acquire(1)
self.logMutex.acquire(1)
print("filterChanged:got mutex,",end="")
ef=""
lf=""
try:
ef=unicode(self.event_filter.text().toUtf8(), encoding="UTF-8").lower()
lf=unicode(self.location_filter.text().toUtf8(), encoding="UTF-8").lower()
except Exception as e:
print(e)
print("error getting filter strings")
code.interact(local=locals())
print("read filters,",end="")
ef=unicode(self.event_filter.text().toUtf8(), encoding="UTF-8").lower()
lf=unicode(self.location_filter.text().toUtf8(), encoding="UTF-8").lower()
self.logOutput.clear()
QtGui.QApplication.processEvents()
print("cleared,",end="")
filters=[{"type":"location", "str":lf},{"type":"event", "str":ef}]
#print("getting logstring with filters:%s, showInvalid:%i"%(filters,self.showInvalid))
logstr=self.parser.tmc_messages.getLogString(self.showInvalid,filters)
print("got str,",end="")
self.logOutput.append(Qt.QString.fromUtf8(logstr))
QtGui.QApplication.processEvents()
self.logMutex.release(1)
print("appended,",end="")
self.parser.dataLock.release(1)
print("done")
def update_showInvalid(self):
self.showInvalid=self.GUI_showInvalid.isChecked()
self.logOutput.append(Qt.QString.fromUtf8(self.parser.tmc_messages.getLogString(filters)))
print("filter changed")
def __init__(self, parser,maxheight):
QtGui.QWidget.__init__(self)
layout = Qt.QVBoxLayout()
self.logMutex=QtCore.QSemaphore(1)
self.setLayout(layout)
self.parser=parser
self.tmc_message_label=QtGui.QLabel("TMC messages:")
@ -371,18 +281,13 @@ class tmc_parser_Widget(QtGui.QWidget):
self.location_filter=QtGui.QLineEdit(u"Baden-Württemberg")
self.event_filter.returnPressed.connect(self.filterChanged)
self.location_filter.returnPressed.connect(self.filterChanged)
self.showInvalid=False
self.GUI_showInvalid=QtGui.QCheckBox()
self.GUI_showInvalid.setChecked(self.showInvalid)
#self.showInvalid.stateChanged.connect(lambda:self.btnstate(self.b1))
self.GUI_showInvalid.stateChanged.connect(self.update_showInvalid)
filter_layout = Qt.QHBoxLayout()
filter_layout.addWidget(QtGui.QLabel("event filter:"))
filter_layout.addWidget(self.event_filter)
filter_layout.addWidget(QtGui.QLabel("location filter:"))
filter_layout.addWidget(self.location_filter)
filter_layout.addWidget(QtGui.QLabel("showInvalid:"))
filter_layout.addWidget(self.GUI_showInvalid)
layout.addLayout(filter_layout)
layout.addWidget(self.tmc_message_label)
self.logOutput = Qt.QTextEdit()
@ -394,4 +299,4 @@ class tmc_parser_Widget(QtGui.QWidget):
font.setFamily("Courier")
font.setPointSize(10)
layout.addWidget(self.logOutput)
QtGui.QApplication.processEvents()
self.clip = QtGui.QApplication.clipboard()

105
python/top_block.py

@ -1,105 +0,0 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
##################################################
# GNU Radio Python Flow Graph
# Title: Top Block
# Generated: Thu Jun 8 13:38:58 2017
##################################################
if __name__ == '__main__':
import ctypes
import sys
if sys.platform.startswith('linux'):
try:
x11 = ctypes.cdll.LoadLibrary('libX11.so')
x11.XInitThreads()
except:
print "Warning: failed to XInitThreads()"
from PyQt4 import Qt
from gnuradio import blocks
from gnuradio import eng_notation
from gnuradio import gr
from gnuradio.eng_option import eng_option
from gnuradio.filter import firdes
from optparse import OptionParser
import multirds
import sys
from gnuradio import qtgui
class top_block(gr.top_block, Qt.QWidget):
def __init__(self):
gr.top_block.__init__(self, "Top Block")
Qt.QWidget.__init__(self)
self.setWindowTitle("Top Block")
qtgui.util.check_set_qss()
try:
self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
except:
pass
self.top_scroll_layout = Qt.QVBoxLayout()
self.setLayout(self.top_scroll_layout)
self.top_scroll = Qt.QScrollArea()
self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
self.top_scroll_layout.addWidget(self.top_scroll)
self.top_scroll.setWidgetResizable(True)
self.top_widget = Qt.QWidget()
self.top_scroll.setWidget(self.top_widget)
self.top_layout = Qt.QVBoxLayout(self.top_widget)
self.top_grid_layout = Qt.QGridLayout()
self.top_layout.addLayout(self.top_grid_layout)
self.settings = Qt.QSettings("GNU Radio", "top_block")
self.restoreGeometry(self.settings.value("geometry").toByteArray())
##################################################
# Variables
##################################################
self.samp_rate = samp_rate = 32000
##################################################
# Blocks
##################################################
self.multirds_rds_decoder_redsea_0 = multirds.rds_decoder_redsea(False, True)
self.blocks_null_source_0 = blocks.null_source(gr.sizeof_char*1)
##################################################
# Connections
##################################################
self.connect((self.blocks_null_source_0, 0), (self.multirds_rds_decoder_redsea_0, 0))
def closeEvent(self, event):
self.settings = Qt.QSettings("GNU Radio", "top_block")
self.settings.setValue("geometry", self.saveGeometry())
event.accept()
def get_samp_rate(self):
return self.samp_rate
def set_samp_rate(self, samp_rate):
self.samp_rate = samp_rate
def main(top_block_cls=top_block, options=None):
from distutils.version import StrictVersion
if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"):
style = gr.prefs().get_string('qtgui', 'style', 'raster')
Qt.QApplication.setGraphicsSystem(style)
qapp = Qt.QApplication(sys.argv)
tb = top_block_cls()
tb.start()
tb.show()
def quitting():
tb.stop()
tb.wait()
qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting)
qapp.exec_()
if __name__ == '__main__':
main()

6
swig/multirds_swig.i

@ -9,7 +9,7 @@
%{
#include "multirds/rds_decoder.h"
#include "multirds/symbol_combiner.h"
#include "multirds/sync_decim.h"
#include "multirds/rds_decoder_redsea.h"
#include "multirds/stream_router.h"
%}
@ -17,8 +17,8 @@
%include "multirds/rds_decoder.h"
GR_SWIG_BLOCK_MAGIC2(multirds, rds_decoder);
%include "multirds/symbol_combiner.h"
GR_SWIG_BLOCK_MAGIC2(multirds, symbol_combiner);
%include "multirds/sync_decim.h"
GR_SWIG_BLOCK_MAGIC2(multirds, sync_decim);
%include "multirds/rds_decoder_redsea.h"
GR_SWIG_BLOCK_MAGIC2(multirds, rds_decoder_redsea);
%include "multirds/stream_router.h"

Loading…
Cancel
Save