Browse Source

max_freq:mode switch, table:copy text, AFset,blockcounts updated fewer, text background: black-> default, ?ord(char)? for unknown symbols,arg-diff decoder (better if signal bad)

master
Clemens Richter 9 years ago
parent
commit
e993c192e9
  1. 2
      grc/crfa_rds_parser_table_qt.xml
  2. 65
      python/max_freq.py
  3. 172
      python/rds_parser_table_qt.py

2
grc/crfa_rds_parser_table_qt.xml

@ -82,7 +82,7 @@ $(gui_hint()($win))</make>
<name>in</name>
<type>message</type>
<nports>$nPorts</nports>
<!--<optional>1</optional>-->
<!-- <optional>1</optional> -->
</sink>
<sink>
<name>freq</name>

65
python/max_freq.py

@ -43,9 +43,13 @@ class max_freq(gr.sync_block):
self.counter=0
self.message_port_register_in(pmt.intern('ctrl'))
self.set_msg_handler(pmt.intern('ctrl'), self.handle_ctrl_msg)
self.searchMode=True
def handle_ctrl_msg(self,msg):
m = pmt.pmt_to_python.pmt_to_dict(msg)
print(m)
#print(m)
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):
if freq is not None:
if isinstance(freq, float) or isinstance(freq, int):
@ -56,7 +60,7 @@ class max_freq(gr.sync_block):
if self.counter<5:
self.counter+=1
return len(input_items[0])
else:
elif self.searchMode:
self.counter=0
#in0 = input_items[0]
#ii=input_items
@ -110,60 +114,6 @@ class max_freq(gr.sync_block):
station_indices_trunc=list(station_indices_sorted)#copy list
del station_indices_trunc[self.num_decoders:]#remove non decodable incidices
###############################
#comparelist=[]
#for freq in station_indices_trunc:
#comparelist.append({"freq":freq,"decoder":None,"new":True})#new detected-> no assigned decoder
#for decnum,freq in enumerate(self.last_station_indices):
#comparelist.append({"freq":freq,"decoder":decnum,"new":False})
##comparelist.sort()
#comparelist_sorted=sorted(comparelist, key=lambda k: k['freq'])
#print(comparelist_sorted)
#differences=[]
#station_indices_tune=[0]*4#TODO what if < 4 max freqs?
#last_elem=None
#same_station_threshold=2
#new_freqs=[]
##for elem in comparelist_sorted:
#while len(comparelist_sorted)>0:
#elem=comparelist_sorted.pop(0)#get and remove first
#freq=elem["freq"]
#if not last_elem==None and not elem["freq"]==0:
#fdiff=abs(freq-last_elem["freq"])
#differences.append(fdiff)
#if fdiff<same_station_threshold:#freq approx same-> use old decoder
#if elem["new"]:#if elem is new last_elem must be old
#decnum=last_elem["decoder"]
#freq=elem["freq"]#use new freq
#else:
#decnum=elem["decoder"]
#freq=last_elem["freq"]#use new freq
#station_indices_tune[decnum]=freq
#else:#stations different -> save last_elem and compare with next
#if last_elem["new"]:#save new
#new_freqs.append(last_elem["freq"])
#last_elem=elem
#if last_elem["new"]:#save new
#new_freqs.append(last_elem["freq"])
#station_indices_tune=list(set(station_indices_tune))#remove duplicates
#for i,freq in enumerate(station_indices_tune):
#if freq==0 and len(new_freqs)>0:#decoder unused
#station_indices_tune[i]=new_freqs.pop()#assign new freq
#print("diff %s"%differences)
#print("tune:%s"%station_indices_tune)
#print("nomatch:%s"%new_freqs)
###############################
#problems:
#very slow, sometimes switches
###############################
#station_indices_tune.sort()
###############################
#problems: swtiching
station_indices_tune=[0]*self.num_decoders
same_station_threshold=3
new_stations=[]
@ -192,6 +142,7 @@ class max_freq(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
num_decimals=int(round(math.log(self.snapto,10)))
station_freqs.append(round(freq,-num_decimals))
station_strength.append(round(numbers[index],-2))
@ -207,4 +158,6 @@ class max_freq(gr.sync_block):
print(station_freqs)
return len(input_items[0])
else:
return len(input_items[0])

172
python/rds_parser_table_qt.py

@ -21,15 +21,15 @@
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,folium
import pmt,functools,csv,md5,collections,copy,sqlite3,atexit,time,re,folium
from datetime import datetime
import crfa.chart as chart
from PyQt4 import Qt, QtCore, QtGui
import pprint,code,pickle#for easier testing
pp = pprint.PrettyPrinter()
import cProfile, pstats, StringIO #for profiling
pr = cProfile.Profile()
#import cProfile, pstats, StringIO #for profiling
#pr = cProfile.Profile()#disabled-internal-profiling
#from threading import Timer#to periodically save DB
@ -264,11 +264,11 @@ class tmc_message:
if self.count==gsi: #group in sequence
data1=int(tmc_y&0xfff)#data block 1
data2=int(tmc_z)#data block 2
#code.interact(local=locals())
self.data_arr.append("0x%03X"%data1)#3 hex characters
self.data_arr.append("0x%04X"%data2)#4 hex characters
#print(gsi)
#code.interact(local=locals())
if self.count==0:#last group
self.is_complete=True
self.debug_data=copy.deepcopy(self.data_arr)
@ -567,7 +567,7 @@ class rds_parser_table_qt(gr.sync_block):
self.RDS_data[PI]["AID_list"]={}
self.RDS_data[PI]["PSN"]="_"*8
self.RDS_data[PI]["PSN_valid"]=[False]*8
self.RDS_data[PI]["AF"]={}
self.RDS_data[PI]["AF"]={"set":set(),"rxset":set()}
self.RDS_data[PI]["TP"]=-1
self.RDS_data[PI]["TA"]=-1
self.RDS_data[PI]["PTY"]=""
@ -577,8 +577,10 @@ class rds_parser_table_qt(gr.sync_block):
if time.time()-self.save_data_timer > 10:#every 10 seconds
self.save_data_timer=time.time()
self.clean_data_and_commit_db()
pr.enable()
#code.interact(local=locals())
#pr.enable()#disabled-internal-profiling
#db=sqlite3.connect(self.db_name)
db=self.db
array=pmt.to_python(msg)[1]
groupNR=array[2]&0b11110000
groupVar=array[2]&0b00001000
@ -613,9 +615,15 @@ class rds_parser_table_qt(gr.sync_block):
freq_str="%i:%0.1fM"% (port,freq/1e6)
self.RDS_data[PI]["tuned_freq"]=freq
#self.signals.DataUpdateEvent.emit({'PI':PI,'freq':freq_str})
if self.RDS_data[PI]["blockcounts"].has_key(groupType):
self.RDS_data[PI]["blockcounts"][groupType] +=1 #increment
else:
self.RDS_data[PI]["blockcounts"][groupType] = 1 #initialize (1st group of this type)
self.RDS_data[PI]["blockcounts"]["any"]+=1
if self.RDS_data[PI]["blockcounts"]["any"]==5:
self.RDS_data[PI]["blockcounts"]["any"]=0
t=(str(PI),groupType,self.RDS_data[PI]["blockcounts"][groupType])#TODO only update DB every few seconds
db.execute("INSERT OR REPLACE INTO grouptypeCounts (PI,grouptype,count) VALUES (?,?,?)",t)
dots="."*self.RDS_data[PI]["blockcounts"]["any"]
self.RDS_data[PI]["TP"]=TP
self.RDS_data[PI]["PTY"]=self.pty_dict[PTY]
@ -623,22 +631,15 @@ class rds_parser_table_qt(gr.sync_block):
#save block to sqlite (commit at end of handle_msg)
#(time text,PI text,PSN text, grouptype text,content blob)
content="%02X%02X%02X%02X%02X" %(array[3]&0x1f,array[4],array[5],array[6],array[7])
#db=sqlite3.connect(self.db_name)
db=self.db
#t=(str(datetime.now()),PI,self.RDS_data[PI]["PSN"],groupType,content)
#db.execute("INSERT INTO groups VALUES (?,?,?,?,?)",t)
if self.RDS_data[PI]["blockcounts"].has_key(groupType):
self.RDS_data[PI]["blockcounts"][groupType] +=1 #increment
else:
self.RDS_data[PI]["blockcounts"][groupType] = 1 #initialize (1st group of this type)
#error 161213:
# db.execute("INSERT OR REPLACE INTO grouptypeCounts (PI,grouptype,count) VALUES (?,?,?)",t)
#InterfaceError: Error binding parameter 0 - probably unsupported type.
#fix?: added str() to PI, but it should already be a string
t=(str(PI),groupType,self.RDS_data[PI]["blockcounts"][groupType])#TODO only update DB every few seconds
db.execute("INSERT OR REPLACE INTO grouptypeCounts (PI,grouptype,count) VALUES (?,?,?)",t)
if (groupType == "0A"):#AF PSN
adr=array[3]&0b00000011
segment=self.decode_chars(chr(array[6])+chr(array[7]))
@ -677,13 +678,32 @@ class rds_parser_table_qt(gr.sync_block):
self.signals.DataUpdateEvent.emit({'PI':PI,'freq':freq_str})
t=(PI,self.RDS_data[PI]["PSN"],float(freq),self.RDS_data[PI]["PTY"],int(self.RDS_data[PI]["TP"]))
db.execute("INSERT INTO stations (PI,PSN,freq,PTY,TP) VALUES (?,?,?,?,?)",t)
if self.RDS_data[PI].has_key("tuned_freq") :#TODO add secondary freqs
freq=self.decode_AF_freq(array[4])
diff=abs(freq-self.RDS_data[PI]["tuned_freq"])
if diff<100000:
self.RDS_data[PI]["AF"]["rxset"].add(freq)
freq=self.decode_AF_freq(array[5])
diff=abs(freq-self.RDS_data[PI]["tuned_freq"])
if diff<100000:
self.RDS_data[PI]["AF"]["rxset"].add(freq)
if(array[4]>= 224 and array[4]<= 249):
#print("AF1 detected")
self.RDS_data[PI]["AF"]['number']=array[4]-224
#self.RDS_data[PI]["AF"]['main']=self.decode_AF_freq(array[5])
self.signals.DataUpdateEvent.emit({'row':port,'PI':PI,'AF':self.RDS_data[PI]["AF"]})
if(array[5]>= 224 and array[5]<= 249):
print("AF2 detected (shouldn't happen)")
print("AF2 detected (shouldn't happen) %s"%array[5])
#add frequencies to set
self.RDS_data[PI]["AF"]["set"].add(self.decode_AF_freq(array[4]))
self.RDS_data[PI]["AF"]["set"].add(self.decode_AF_freq(array[5]))
try:
self.RDS_data[PI]["AF"]["set"].remove(0)#remove control characters
except KeyError:
pass
name_list=list(self.RDS_data[PI]["PSN"])
if (name_list[adr*2:adr*2+2]==list(segment)):#segment already there
@ -706,7 +726,8 @@ class rds_parser_table_qt(gr.sync_block):
if (not self.RDS_data[PI]["PSN_valid"][i]):
valid = False
if(valid):
textcolor="black"
#textcolor="black"
textcolor=""#use default color (white if background is black)
if not self.RDS_data[PI]["internals"]["last_valid_psn"]==self.RDS_data[PI]["PSN"]:#ignore duplicates
t=(str(datetime.now()),PI,self.RDS_data[PI]["PSN"],"PSN_valid",self.RDS_data[PI]["PSN"])
db.execute("INSERT INTO data (time,PI,PSN,dataType,data) VALUES (?,?,?,?,?)",t)
@ -800,7 +821,8 @@ class rds_parser_table_qt(gr.sync_block):
if (not self.RDS_data[PI]["RT_valid"][i]):
self.RDS_data[PI]["RT_all_valid"] = False
if(self.RDS_data[PI]["RT_all_valid"]):
textcolor="black"
#textcolor="black"
textcolor=""#use default color (white if background is black)
l=list(self.RDS_data[PI]["RT"])
rt="".join(l[0:text_end])#remove underscores(default symbol) after line end marker
if not self.RDS_data[PI]["internals"]["last_valid_rt"]==rt:#ignore duplicates
@ -820,7 +842,7 @@ class rds_parser_table_qt(gr.sync_block):
rtcol=self.colorder.index('text')
self.signals.DataUpdateEvent.emit({'col':rtcol,'row':port,'PI':PI,'string':formatted_text})
#code.interact(local=locals())
elif (groupType == "3A"):#ODA announcements (contain application ID "AID")
AID=(array[6]<<8)|(array[7])#combine 2 bytes into 1 block
app_data=(array[4]<<8)|(array[5])#content defined by ODA-app
@ -1038,6 +1060,7 @@ class rds_parser_table_qt(gr.sync_block):
if not self.RDS_data.has_key(PI_ON):
self.init_data_for_PI(PI_ON)
self.RDS_data[PI_ON]["TP"]=TP_ON
self.PI_dict[PI_ON]=0#initialize dict, even if no packets received
if self.log:
print("found station %s via EON on station %s"%(PI_ON,PI))
if not self.RDS_data[PI]["EON"].has_key(PI_ON):
@ -1070,7 +1093,8 @@ class rds_parser_table_qt(gr.sync_block):
if (not self.RDS_data[PI_ON]["PSN_valid"][i]):
valid = False
if(valid):
textcolor="black"
#textcolor="black"
textcolor=""#use default color (white if background is black)
else:
textcolor="gray"
@ -1121,7 +1145,7 @@ class rds_parser_table_qt(gr.sync_block):
printdelay=500
self.printcounter+=0#printing disabled
if self.printcounter == printdelay and self.debug:
#code.interact(local=locals())
for key in self.RDS_data:
if self.RDS_data[key].has_key("PSN"):
psn=self.RDS_data[key]["PSN"]
@ -1137,7 +1161,7 @@ class rds_parser_table_qt(gr.sync_block):
#db.commit()
#db.close()
#pr.disable()
#pr.disable() #disabled-internal-profiling
#end of handle_msg
def print_tmc_msg(self,tmc_msg):
try:
@ -1174,13 +1198,13 @@ class rds_parser_table_qt(gr.sync_block):
marker_string=self.marker_template.format(lat=tmc_msg.location.ykoord,lon=tmc_msg.location.xkoord,text=map_tag)#without ID
self.map_markers.append(marker_string)
#code.interact(local=locals())
except Exception as e:
print(e)
raise
#print("line 1064")
#code.interact(local=locals())
except KeyError:
#print("location '%i' not found"%tmc_location)
pass
@ -1216,24 +1240,30 @@ class rds_parser_table_qt(gr.sync_block):
0b1001:u"âäêëîïôöûüñçş??ij",
0b1100:u"ÁÀÉÈÍÌÓÒÚÙŘČŠŽĐĿ",
0b1101:u"ÂÄÊËÎÏÔÖÛÜřčšžđŀ"}
charlist=list(charstring)
#charlist=list(charstring)
return_string=""
for i,char in enumerate(charstring):
#code.interact(local=locals())
if ord(char)<= 0b01111111:
charlist[i]=char #use ascii
#charlist[i]=char #use ascii
return_string+=char
else:
#split byte
alnr=(ord(char)&0xF0 )>>4 #upper 4 bit
index=ord(char)&0x0F #lower 4 bit
#code.interact(local=locals())
try:
charlist[i]=alphabet[alnr][index]
#charlist[i]=alphabet[alnr][index]
return_string+=alphabet[alnr][index]
except KeyError:
charlist[i]='?'#symbol not decoded #TODO
return_string+="?%02X?"%ord(char)
#charlist[i]='?'#symbol not decoded #TODO
pass
return "".join(charlist)
#return "".join(charlist)
return return_string
def color_text(self, text, start,end,textcolor,segmentcolor):
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="<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):
@ -1244,59 +1274,25 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
""" Creates the QT Range widget """
QtGui.QWidget.__init__(self)
layout = Qt.QVBoxLayout()
self.label = Qt.QLabel(label)
layout.addWidget(self.label)
#self.label = Qt.QLabel(label)
#layout.addWidget(self.label)#title of table disabled to save space
#layout.addWidget(self.label)
self.setLayout(layout)
#self.decoder_to_PI={}
self.PI_to_row={}
self.table=QtGui.QTableWidget(self)
rowcount=2
rowcount=0
self.table.setRowCount(rowcount)
self.table.setColumnCount(9)
self.table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) #disallow editing
#Data
empty_text32='________________________________'
empty_text64='________________________________________________________________'
#empty_text64='\xe4'*64
self.data = {'ID':[ QtGui.QLabel() for i in range(rowcount)],
'freq':[ QtGui.QLabel() for i in range(rowcount)],
'name':[ QtGui.QLabel() for i in range(rowcount)],
'PTY':[ QtGui.QLabel() for i in range(rowcount)],
'AF':[ QtGui.QLabel() for i in range(rowcount)],
'time':[ QtGui.QLabel() for i in range(rowcount)],
'text':[ QtGui.QLabel("_"*64) for i in range(rowcount)],
'quality':[ QtGui.QLabel() for i in range(rowcount)],
'buttons':[]}
#Enter data onto Table
self.colorder=['ID','freq','name','PTY','AF','time','text','quality','buttons']
horHeaders = []
for n, key in enumerate(self.colorder):
#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))
self.table.setItem(m, n, newitem)
elif isinstance(item,QtGui.QLabel):
self.table.setCellWidget(m,n,item)
else:
newitem = QtGui.QTableWidgetItem(item)
self.table.setItem(m, n, newitem)
for i in range(rowcount):#create buttons
button=QtGui.QPushButton("getDetails")
self.table.setCellWidget(i,self.table.columnCount()-1,button)
button.clicked.connect(functools.partial(self.getDetails, row=i))
#button.clicked.connect(self.getDetails)
#Add Header
layout.addWidget(self.label)
layout.addWidget(self.table)
##button.clicked.connect(self.getDetails)
self.table.setHorizontalHeaderLabels(horHeaders)
layout.addWidget(self.table)
self.table.setHorizontalHeaderLabels(self.colorder)
#self.table.setMaximumHeight(300)#TODO use dynamic value
button_layout = Qt.QHBoxLayout()
codebutton = QtGui.QPushButton("code.interact")
codebutton.clicked.connect(self.onCLick)
@ -1337,6 +1333,22 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
font.setPointSize(10)
self.lastResizeTime=0
layout.addWidget(self.logOutput)
self.clip = QtGui.QApplication.clipboard()
#self.cb.clear(mode=cb.Clipboard )
#self.cb.setText("Clipboard Text", mode=cb.Clipboard)
def keyPressEvent(self, e):
if (e.modifiers() & QtCore.Qt.ControlModifier):
selected = self.table.selectedRanges().pop()
selected.leftColumn()
selected.topRow()
if e.key() == QtCore.Qt.Key_C: #copy
try:
qs = self.table.cellWidget(selected.topRow(),selected.leftColumn()).text()#get QString from table
s=re.sub("<.*?>","", str(qs))#remove html tags
self.clip.setText(s)
except Exception as e:
print(e)
print("no text, cant copy")
def insert_empty_row(self):
rowPosition = self.table.rowCount()
self.table.insertRow(rowPosition)
@ -1441,7 +1453,7 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
layout=Qt.QVBoxLayout()
layout.addWidget(l)
view.setLayout(layout)
#code.interact(local=locals())
view.exec_()
def getDetails(self,row):
PIcol=self.colorder.index('ID')
@ -1474,7 +1486,7 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
l.setWordWrap(True)
#l=QtGui.QLabel("Data:")
view.layout().addWidget(l)
#code.interact(local=locals())
view.exec_()
def onCLick(self):
print("button clicked")
@ -1483,18 +1495,14 @@ 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

Loading…
Cancel
Save