From 707614b2c16fe76e2a5904078d403492c91a9b29 Mon Sep 17 00:00:00 2001 From: csrichter Date: Fri, 25 Nov 2016 22:53:35 +0100 Subject: [PATCH] donnerstag: enhanced colored text, freitag: TMC location code list (LCL), CT-decode, additional characters, cable->antenna --- grc/CMakeLists.txt | 3 +- grc/crfa_rds_parser_table_qt.xml | 46 +++++ python/CMakeLists.txt | 3 +- python/__init__.py | 1 + python/qtguitest.py | 2 +- python/rds_parser_table_qt.py | 281 +++++++++++++++++++++++++++++++ 6 files changed, 333 insertions(+), 3 deletions(-) create mode 100644 grc/crfa_rds_parser_table_qt.xml create mode 100644 python/rds_parser_table_qt.py diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 618533e..6fb7c98 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -20,5 +20,6 @@ install(FILES crfa_multi_rds_printer.xml crfa_qtguitest.xml - crfa_rds_table_qt.xml DESTINATION share/gnuradio/grc/blocks + crfa_rds_table_qt.xml + crfa_rds_parser_table_qt.xml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/crfa_rds_parser_table_qt.xml b/grc/crfa_rds_parser_table_qt.xml new file mode 100644 index 0000000..df29063 --- /dev/null +++ b/grc/crfa_rds_parser_table_qt.xml @@ -0,0 +1,46 @@ + + + RDS Parser Table (qt) + crfa_rds_parser_table_qt + [crfa] + import crfa + from crfa.rds_parser_table_qt import rds_parser_table_qt, rds_parser_table_qt_Widget,rds_parser_table_qt_Signals + self.$(id) = $(id) = $value + #set $win = 'self._%s_win'%$id + #set $signals = 'self._%s_signals'%$id +#if not $label() + #set $label = '"%s"'%$id +#end if +$(signals) = rds_parser_table_qt_Signals() +self.$(id) = crfa.rds_parser_table_qt($(signals),$nPorts) +$(win) = rds_parser_table_qt_Widget($signals, $label) +$(gui_hint()($win)) + + Label + label + + string + #if $label() then 'none' else 'part'# + + + GUI Hint + gui_hint + + gui_hint + part + + + Number of Ports + nPorts + 2 + int + part + + + in + message + $nPorts + + + + diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index ea30247..cea59ec 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -33,7 +33,8 @@ GR_PYTHON_INSTALL( __init__.py multi_rds_printer.py qtguitest.py - rds_table_qt.py DESTINATION ${GR_PYTHON_DIR}/crfa + rds_table_qt.py + rds_parser_table_qt.py DESTINATION ${GR_PYTHON_DIR}/crfa ) ######################################################################## diff --git a/python/__init__.py b/python/__init__.py index 098f147..3cff438 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -34,4 +34,5 @@ except ImportError: from multi_rds_printer import multi_rds_printer from qtguitest import qtguitest from rds_table_qt import rds_table_qt +from rds_parser_table_qt import rds_parser_table_qt # diff --git a/python/qtguitest.py b/python/qtguitest.py index 0f2e6f5..8182759 100644 --- a/python/qtguitest.py +++ b/python/qtguitest.py @@ -126,7 +126,7 @@ if __name__ == "__main__": widget.show() widget.setWindowTitle("Test Qt gui") widget.setGeometry(200,200,600,300) - #code.interact(local=locals()) + code.interact(local=locals()) sys.exit(app.exec_()) widget = None diff --git a/python/rds_parser_table_qt.py b/python/rds_parser_table_qt.py new file mode 100644 index 0000000..1e8ee77 --- /dev/null +++ b/python/rds_parser_table_qt.py @@ -0,0 +1,281 @@ +#!/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 +from gnuradio import gr +import code,pmt,functools +from PyQt4 import Qt, QtCore, QtGui +import pprint +pp = pprint.PrettyPrinter() + +from PyQt4.QtCore import QObject, pyqtSignal + +class rds_parser_table_qt_Signals(QObject): + DataUpdateEvent = QtCore.pyqtSignal(dict) + def __init__(self, parent=None): + super(QtCore.QObject, self).__init__() + +class rds_parser_table_qt(gr.sync_block): + """ + docstring for block qtguitest + """ + def __init__(self,signals,nPorts): + #QObject.__init__() + gr.sync_block.__init__(self, + name="RDS Table", + in_sig=None, + out_sig=None) + 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)) + + self.signals=signals + self.RTdict={} + self.RTvalid={} + self.PSNdict={} + self.PSNvalid={} + self.AFdata={} + def handle_msg(self, msg, port): + #code.interact(local=locals()) + array=pmt.to_python(msg)[1] + groupNR=array[2]&0b11110000 + groupVar=array[2]&0b00001000 + if (groupVar == 0): + groupType=str(groupNR >> 4)+"A" + else: + groupType=str(groupNR >> 4)+"B" + #print("raw:"+str(pmt.to_python(msg))+"\n") + PI="%02X%02X" %(array[0],array[1]) + #print("1st block:"+str(array[0])+","+str(array[1])+"= ID: %s" %PI) + #print("2st block:"+str(array[2])+","+str(array[3])+"= type:"+groupType) + #print("3st block:"+str(array[4])+","+str(array[5])) + #print("4st block:"+str(array[6])+","+str(array[7])) + if (groupType == "0A"):#AF PSN + adr=array[3]&0b00000011 + segment=chr(array[6])+chr(array[7]) + if(not self.PSNdict.has_key(PI)):#initialite dict + self.PSNdict[PI]="_"*8 + self.PSNvalid[PI]=[False]*8 + self.AFdata[PI]={} + #1110 0000 = no AF + #1110 0001 = 1AF + #1111 1001 = 25AF + + if(array[5]>= 224 and array[5]<= 249): + print("AF1 detected") + self.AFdata[PI]['number']=array[5]-224 + self.signals.DataUpdateEvent.emit({'row':port,'AF':self.AFdata[PI]}) + if(array[6]>= 224 and array[6]<= 249): + print("AF2 detected") + #determine if text is valid + valid=True + for i in range(0,8): + if (not self.PSNvalid[PI][i]): + valid = False + if(valid): + textcolor="black" + else: + textcolor="gray" + + name_list=list(self.PSNdict[PI]) + if (name_list[adr*2:adr*2+2]==list(segment)):#segment already there + segmentcolor="green" + elif(name_list[adr*2:adr*2+2]==['__']): #segment new + segmentcolor="orange" + name_list[adr*2:adr*2+2]=segment + else:#name changed (böse) + segmentcolor="red" + name_list[adr*2:adr*2+2]=segment + #reset stored text: + self.PSNdict[PI]="_"*8 + self.PSNvalid[PI]=[False]*8 + self.PSNvalid[PI][adr*2:adr*2+2]=[True] *2 + self.PSNdict[PI]="".join(name_list) + formatted_text=self.color_text(self.PSNdict[PI],adr*2,adr*2+2,textcolor,segmentcolor) + self.signals.DataUpdateEvent.emit({'col':5,'row':port,'PI':PI,'PSN':formatted_text}) + elif (groupType == "2A"):#RT radiotext + if(not self.RTdict.has_key(PI)):#initialite dict + self.RTdict[PI]="_"*64 + self.RTvalid[PI]=[False]*64 + else: + adr=array[3]&0b00001111 + segment=chr(array[4])+chr(array[5])+chr(array[6])+chr(array[7]) + #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.RTdict[PI]) + #determine text length: + try: + text_end=text_list.index('\r') + except ValueError: + text_end=64 #assume whole string is important + pass + #determine if text is valid + valid=True + for i in range(0,text_end): + if (not self.RTvalid[PI][i]): + valid = False + + + if (text_list[adr*4:adr*4+4]==list(segment)):#segment already there + segmentcolor="green" + elif (text_list[adr*4:adr*4+4]==['_']*4):#segment new + segmentcolor="orange" + text_list[adr*4:adr*4+4]=segment + else: + segmentcolor="red" + text_list[adr*4:adr*4+4]=segment + #reset stored text: + self.RTdict[PI]="_"*64 + self.RTvalid[PI]=[False]*64 + if(valid): + textcolor="black" + else: + textcolor="gray" + + #formatted_text="%s%s%s"% (textcolor,self.RTdict[PI][:adr*4],segmentcolor,self.RTdict[PI][adr*4:adr*4+4],textcolor,self.RTdict[PI][adr*4+4:]) + formatted_text=self.color_text(self.RTdict[PI],adr*4,adr*4+4,textcolor,segmentcolor) + #print(self.RTdict[PI]+" valid:"+str(valid)+"valarr:"+str(self.RTvalid[PI])) + self.RTvalid[PI][adr*4:adr*4+4]=[True] *4 + self.RTdict[PI]="".join(text_list) + + + + + + self.signals.DataUpdateEvent.emit({'col':5,'row':port,'PI':PI,'string':formatted_text}) + #code.interact(local=locals()) + else: + print("group of type %s not decoded on station %s"% (groupType,PI)) + + def color_text(self, text, start,end,textcolor,segmentcolor): + formatted_text="%s%s%s"% (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): + print("gui initializing") + self.signals = signals + self.signals.DataUpdateEvent.connect(self.display_data) + """ Creates the QT Range widget """ + QtGui.QWidget.__init__(self) + layout = Qt.QVBoxLayout() + self.label = Qt.QLabel(label) + layout.addWidget(self.label) + self.setLayout(layout) + self.table=QtGui.QTableWidget(self) + self.table.setRowCount(5) + self.table.setColumnCount(7) + self.table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) #disallow editing + #Data + empty_text32='________________________________' + empty_text64='________________________________________________________________' + self.data = {'ID':range(1,6), + 'freq':['','','',''], + 'name':[], + 'AF':['','','',''], + 'time':['','','',''], + 'text':[], + 'buttons':[]} + #Enter data onto Table + horHeaders = [] + for n, key in enumerate(['ID','freq','name','AF','time','text','buttons']): + #for n, key in enumerate(sorted(self.data.keys())): + horHeaders.append(key) + for m, item in enumerate(self.data[key]): + if type(item)==int:#convert ints to strings + newitem = QtGui.QTableWidgetItem(str(item)) + else: + newitem = QtGui.QTableWidgetItem(item) + self.table.setItem(m, n, newitem) + for i in range(0,4):#create buttons + button=QtGui.QPushButton("play") + self.table.setCellWidget(i,self.table.columnCount()-1,button) + button.clicked.connect(self.onCLick) + for i in range(0,4):#create text labels + label=QtGui.QLabel(empty_text64) + #label.setFont(QtGui.QFont("Courier New")) + self.table.setCellWidget(i,self.table.columnCount()-2,label) + for i in range(0,4):#create name labels + label=QtGui.QLabel("_"*8) + #label.setFont(QtGui.QFont("Courier New")) + self.table.setCellWidget(i,2,label) + #Add Header + self.table.setHorizontalHeaderLabels(horHeaders) + layout.addWidget(self.label) + layout.addWidget(self.table) + self.button = QtGui.QPushButton("i am a button") + layout.addWidget(self.button) + + def display_data(self, event): + #pp.pprint(event) + if type(event)==dict and event.has_key('row'): + if event.has_key('string'): + item=self.table.cellWidget(event['row'],event['col']) + item.setText(event['string']) + if event.has_key('PI'): + #setPI + PIcol=0 + self.table.item(event['row'],PIcol).setText(event['PI']) + if event.has_key('AF'): + #setAF + PIcol=3 + self.table.item(event['row'],PIcol).setText(event['AF']['number']) + if event.has_key('PSN'): + #setPSN + PSNcol=2 + item=self.table.cellWidget(event['row'],PSNcol) + item.setText(event['PSN']) + self.table.resizeColumnsToContents() + def reset_color(self): + for i in range(0,self.table.rowCount()): + for j in range(0,self.table.columnCount()): + item = self.table.item(i,j) + #code.interact(local=locals()) + #print(item.type()) + if item != '': + try: + item.setTextColor(QtCore.Qt.black) + except: + pass + #for item in self.table.items(): + #item.setTextColor(QtCore.Qt.black) + def onCLick(self): + print("button clicked") + self.reset_color() + #pp.pprint(event) +if __name__ == "__main__": + from PyQt4 import Qt + import sys + + # def valueChanged(frequency): + # print("Value updated - " + str(frequency)) + + app = Qt.QApplication(sys.argv) + # widget = RangeWidget(Range(0, 100, 10, 1, 100), valueChanged, "Test", "counter_slider", int) + 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) + #code.interact(local=locals()) + sys.exit(app.exec_()) + + widget = None