From e096e99c4023ac5584c0263bcb07383a289a16ff Mon Sep 17 00:00:00 2001
From: csrichter
Date: Fri, 20 Jan 2017 17:24:49 +0100
Subject: [PATCH] handled MGM directionality change, improved map tags
(heading), improved location string templates (bei wenn extent==0), predict
RT
---
python/rds_parser_table_qt.py | 124 +++++++++++++++++++---------------
1 file changed, 69 insertions(+), 55 deletions(-)
diff --git a/python/rds_parser_table_qt.py b/python/rds_parser_table_qt.py
index 89c691f..a6172e4 100644
--- a/python/rds_parser_table_qt.py
+++ b/python/rds_parser_table_qt.py
@@ -77,7 +77,9 @@ class tmc_event:
self.is_cancellation = False
self.quantifierType=event_array[6]#Q:quantifier type: (0..12) or blank (no quantifier)
self.durationType=event_array[7]#T:duration type: D:dynamic, L:long lasting, in brackets or if time-of-day quantifier (no 7) is used in message -> no display, only for management
- self.direction=event_array[8]#D:direction: 1:unidirectional, 2:bidirectional
+ directionality=event_array[8]#D:directionality: 1:unidirectional, 2:bidirectional, cancellation messages dont have directionality
+ self.is_unidirectional=True if directionality=="1" else False
+ self.is_bidirectional=True if directionality=="2" else False
self.urgency=event_array[9]#U:urgency: blank: normal, X:extremely urgent, U:urgent
self.updateClass=int(event_array[10])#C: update class:
self.updateClassName=self.tableobj.tmc_update_class_names[self.updateClass]
@@ -89,6 +91,9 @@ class tmc_event:
except KeyError:
print("event '%i' not found"%ecn)
self.is_valid=False
+ def change_directionality(self):
+ self.is_unidirectional=not self.is_unidirectional
+ self.is_bidirectional=not self.is_bidirectional
def add_length(self,data):#from label2
self.length_str="%i km"%mgm_tag.length_to_km(data.uint)
#self.name=self.name.replace("(L)",self.length_str)
@@ -253,7 +258,7 @@ class tmc_location:
self.xkoord=int(loc_array[27])/100000.0
self.ykoord=int(loc_array[28])/100000.0
self.koord_str="%f,%f"%(self.ykoord,self.xkoord)
- #self.koord_str="%f° N, %f° E"%(self.ykoord,self.xkoord)
+ self.koord_str_google="{lat: %f, lng: %f}"%(self.ykoord,self.xkoord)
self.google_maps_link="https://www.google.de/maps/place/%f,%f"%(self.ykoord,self.xkoord)
self.has_koord=True
except ValueError:
@@ -267,8 +272,8 @@ class tmc_location:
##LOCATIONCODE;TYPE;SUBTYPE;ROADNUMBER;ROADNAME;FIRST_NAME;SECOND_NAME;AREA_REFERENCE;LINEAR_REFERENCE;NEGATIVE_OFFSET;POSITIVE_OFFSET;URBAN;INTERSECTIONCODE;INTERRUPTS_ROAD;IN_POSITIVE;OUT_POSITIVE;IN_NEGATIVE;OUT_NEGATIVE;PRESENT_POSITIVE;PRESENT_NEGATIVE;EXIT_NUMBER;DIVERSION_POSITIVE;DIVERSION_NEGATIVE;VERÄNDERT;TERN;NETZKNOTEN_NR;NETZKNOTEN2_NR;STATION;X_KOORD;Y_KOORD;POLDIR;ADMIN_County;ACTUALITY;ACTIVATED;TESTED;SPECIAL1;SPECIAL2;SPECIAL3;SPECIAL4;SPECIAL5;SPECIAL6;SPECIAL7;SPECIAL8;SPECIAL9;SPECIAL10
class tmc_dict:
- "dict of tmc messages sorted by location (LCN) and update class, automatically deletes/updates invalid items"
- marker_template="addMarker({{lat: {lat}, lng: {lon}}},'{text}')"
+ "dict of tmc messages sorted by location (LCN) and update class, automatically deletes/updates invalid(ated) items"
+ marker_template="addMarker({loc},'{text}',{endloc})"
def __init__(self):
self.messages=dict()
def add(self,message):
@@ -291,11 +296,9 @@ class tmc_dict:
def getMarkerString(self):
markerstring=""
for lcn in self.messages:
-
-
-
loc=None
- map_tag=""
+ endloc=None
+ map_tag='
'
for updateClass in self.messages[lcn]:
message=self.messages[lcn][updateClass]
if message.cancellation_time==None:
@@ -303,15 +306,22 @@ class tmc_dict:
else:
color="gray"
if message.location.has_koord:
+ if loc==None:#first message at this location
+ map_tag+='
'
+ map_tag+=message.location_text()
+ map_tag+='
'
+ if message.cancellation_time==None:
+ endloc=message.end_loc()#line displays length of 1st message (lowest class), that is not cancelled
loc=message.location
- #map_tag+=str(updateClass)+": "
map_tag+=''%color
map_tag+=message.map_string()
- map_tag+="
"
- map_tag+="
"
- map_tag+="
"
+ map_tag+='
'
+ map_tag+=''
+ map_tag+=''
if not loc==None:
- markerstring+=tmc_dict.marker_template.format(lat=loc.ykoord,lon=loc.xkoord,text=map_tag)
+ if endloc==None or not endloc.is_valid:
+ endloc=loc#creates line of 0 length (dot)
+ markerstring+=tmc_dict.marker_template.format(loc=loc.koord_str_google,text=map_tag,endloc=endloc.koord_str_google)
markerstring+="\n"
return markerstring
@@ -411,34 +421,38 @@ class tmc_message:
str_list=[str(elem) for elem in self.events]
return str(", ".join(str_list))
def log_string(self):
- #return str(self.event.updateClass)+": "+self.getTime()+": "+self.events_string()+"; "+str(self.location)+"; "+self.psn
- #code above gives unicode-decode error with character Ä (probably in location)
- #return "%s: %s: %s; %s; %s"%(str(self.event.updateClass),self.getTime(),self.events_string(),str(self.location),self.psn)
- #return str(self.event.updateClass)+": "+self.getTime()+": "+self.events_string()+"; "+str(self.location)+"; "+self.psn
- return str(self.event.updateClass)+": "+self.getTime()+": "+self.display_text()+"; "+self.psn
+ return str(self.event.updateClass)+": "+self.getTime()+": "+self.location_text()+": "+self.events_string()+"; "+self.psn
def db_string(self):
- return str(self.location)+": "+str(self.event.updateClass)+": "+self.display_text()
+ return str(self.location)+": "+str(self.event.updateClass)+": "+self.events_string()
def map_string(self):
- return str(self.event.updateClass)+": "+self.getTime()+": "+self.display_text()+"; "+self.multi_str()+"; "+self.psn
- #code above gives unicode-decode error with character Ä (probably in location)
- #return "%s: %s: %s; %s; %s"%(str(self.event.updateClass),self.getTime(),self.events_string(),self.multi_str(),self.psn)
- #return str(self.event.updateClass)+": "+self.getTime()+": "+self.events_string()+"; "+self.multi_str()+"; "+self.psn
- def display_text(self):
- text=self.events_string()+"; "+str(self.location)#use events_string if no display_text implemented
+ return str(self.event.updateClass)+": "+self.getTime()+": "+self.events_string()+"; "+self.multi_str()+"; "+self.psn
+ def end_loc(self):
+ return self.location.get_extent_location(self.location,self.tmc_extent,self.tmc_dir)
+ def location_text(self):
+ text=str(self.location)#use __str__ of location if no location_text implemented
#TODO add "dreieck" for P1.2 -> done in tmc_message.__str__
if not self.location.linRef==None:#test
- self.tmc_extent
- self.tmc_dir
- offset_loc=self.location.get_extent_location(self.location,self.tmc_extent,self.tmc_dir)
+ #self.tmc_extent and self.tmc_dir are ints
+ #offset_loc=self.location.get_extent_location(self.location,self.tmc_extent,self.tmc_dir)
+ offset_loc=self.end_loc()
if offset_loc.is_valid:
- offset_loc_name=str(offset_loc)
+ #offset_loc_name=str(offset_loc)
+ offset_loc_name=offset_loc.first_name
else:
print(offset_loc)
offset_loc_name="###INVALID###"
- templates={"de":"{A}, {B} in Richtung {C}, zwischen {D} und {E}, {F}"#codeing handbook: zwischen {D} und {E}, sprachdurchsagen: zwischen {E} und {D}
- ,"en":"{A}, {B} {C}, {F}, between {D} and {E}"}
- text=templates[language].format(A=self.location.linRef.roadnumber, B=self.location.linRef.second_name,C=self.location.linRef.first_name,D=str(self.location),E=offset_loc_name,F=self.events_string())
-
+ templates={"de_1":"{A}, {B} in Richtung {C}"#codeing handbook: zwischen {D} und {E}, sprachdurchsagen: zwischen {E} und {D}
+ ,"de_2a":", zwischen {D} und {E}"
+ ,"de_2b":", bei {D}"#extent==0
+ ,"en_1":"{A}, {B} {C}"
+ ,"en_2a":", between {D} and {E}"
+ ,"en_2b":", at {D}"}#extent==0
+ text=templates[language+"_1"].format(A=self.location.linRef.roadnumber, B=self.location.linRef.second_name,C=self.location.linRef.first_name)
+ if self.location.first_name==offset_loc_name:#similar to self.tmc_extent==0 (but some similar location have same same name)
+ text+=templates[language+"_2b"].format(D=self.location.first_name)
+ else:
+ text+=templates[language+"_2a"].format(D=self.location.first_name,E=offset_loc_name)
+
#LocCode: RefLine: RoadNr
#A
#LocCode:RefLine:Name2
@@ -492,7 +506,7 @@ class tmc_message:
self.is_complete=False
self._second_group_received=False
self.tmc_D=0
- self.tmc_DP=0
+ self.tmc_DP=0#default to duration of 0, can be changed with MGM
self.ci=int(tmc_x&0x7) #continuity index
self.data_arr=BitArray()
self.mgm_list=[]
@@ -541,8 +555,11 @@ class tmc_message:
del self.data_arr[0:fieldlen]
if not (label==0 and data.uint ==0):#ignore trailing zeros
self.mgm_list.append(mgm_tag(label,data,self.tableobj))
- if label==0:
+ if label==0:#duration/persistence
self.tmc_DP=data.uint
+ #label==1: control codes
+ elif label==1 and data.uint==2:
+ last_event.change_directionality#change directionality
elif label==1 and data.uint==5:
self.tmc_D=1#set diversion bit
elif label==1 and data.uint==6:
@@ -861,7 +878,7 @@ class rds_parser_table_qt(gr.sync_block):#START
self.RDS_data[PI]["TA"]=-1
self.RDS_data[PI]["PTY"]=""
self.RDS_data[PI]["DI"]=[2,2,2,2]
- self.RDS_data[PI]["internals"]={"last_rt_tooltip":"","unfinished_TMC":{},"last_valid_rt":"","last_valid_psn":""}
+ self.RDS_data[PI]["internals"]={"last_rt_tooltip":"","unfinished_TMC":{},"last_valid_rt":"","last_valid_psn":"","RT_history":[]}
self.RDS_data[PI]["time"]={"timestring":"88:88","datestring":"00-00-0000","datetime":None}
def handle_msg(self, msg, port):#port from 0 to 3
if time.time()-self.save_data_timer > 10:#every 10 seconds
@@ -1111,7 +1128,7 @@ class rds_parser_table_qt(gr.sync_block):#START
except ValueError:
text_end=64 #assume whole string is important
pass
-
+ predicted=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
@@ -1124,9 +1141,15 @@ class rds_parser_table_qt(gr.sync_block):#START
#reset stored text:
self.RDS_data[PI]["RT"]="_"*64
self.RDS_data[PI]["RT_valid"]=[False]*64
+ #predict RT from last texts:
+ for rt in self.RDS_data[PI]["internals"]["RT_history"]:
+ if rt[adr*4:adr*4+4]==list(segment):
+ self.RDS_data[PI]["RT"]="".join(rt)
+ predicted=True
self.RDS_data[PI]["RT_valid"][adr*4:adr*4+4]=[True] *4
- self.RDS_data[PI]["RT"]="".join(text_list)
+ if not predicted:
+ self.RDS_data[PI]["RT"]="".join(text_list)
#determine if (new) text is valid
self.RDS_data[PI]["RT_all_valid"]=True
@@ -1139,22 +1162,22 @@ class rds_parser_table_qt(gr.sync_block):#START
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
+ self.RDS_data[PI]["internals"]["RT_history"].append(l)
+ if len(self.RDS_data[PI]["internals"]["RT_history"])>10:#only store last 10 RTs
+ self.RDS_data[PI]["internals"]["RT_history"].pop(0)
t=(str(datetime.now()),PI,self.RDS_data[PI]["PSN"],"RT",rt)
if self.writeDB:
db.execute("INSERT INTO data (time,PI,PSN,dataType,data) VALUES (?,?,?,?,?)",t)
self.RDS_data[PI]["internals"]["last_valid_rt"]=rt
- try:#print rt+ if it exist
- t=(str(datetime.now()),PI,self.RDS_data[PI]["PSN"],"RT+",str(self.RDS_data[PI]["RT+"]))
+ try:#save rt+ if it exist
if self.writeDB:
+ t=(str(datetime.now()),PI,self.RDS_data[PI]["PSN"],"RT+",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
else:
textcolor="gray"
- #formatted_text="%s%s%s"% (textcolor,self.RDS_data[PI]["RT"][:adr*4],segmentcolor,self.RDS_data[PI]["RT"][adr*4:adr*4+4],textcolor,self.RDS_data[PI]["RT"][adr*4+4:])
formatted_text=self.color_text(self.RDS_data[PI]["RT"],adr*4,adr*4+4,textcolor,segmentcolor)
- #print(self.RDS_data[PI]["RT"]+" valid:"+str(valid)+"valarr:"+str(self.RDS_data[PI]["RT_valid"]))
-
rtcol=self.colorder.index('text')
self.signals.DataUpdateEvent.emit({'col':rtcol,'row':port,'PI':PI,'string':formatted_text})
@@ -1214,21 +1237,12 @@ class rds_parser_table_qt(gr.sync_block):#START
local_time_offset=0.5*((array[7])&0x1F)
if(offsetdir==1):
local_time_offset*=-1
- #year=int((datecode - 15078.2) / 365.25)
- #month=int((datecode - 14956.1 - int(year * 365.25)) / 30.6001)
- #day=datecode - 14956 - int(year * 365.25) - int(month * 30.6001)
- #if(month == 14 or month == 15):#no idea why -> annex g of RDS spec
- #year += 1;
- #month -= 13
- #year+=1900
- #month was off by one different rounding in c and python?
- #month-=1# 13.1.2017, month now not off by one
- #maybe the use of unsigned ints?
+
date=datetime(1858,11,17)+timedelta(days=int(datecode))#convert from MJD (modified julian date)
- #datestring="%02i.%02i.%4i, %02i:%02i (%+.1fh)" % (day,month,year,hours,minutes,local_time_offset)
timestring="%02i:%02i (%+.1fh)" % (hours,minutes,local_time_offset)
- datestring="%02i.%02i.%4i" % (date.day,date.month,date.year)
+ #datestring="%02i.%02i.%4i" % (date.day,date.month,date.year)
+ datestring=date.strftime("%d.%m.%Y")
ctcol=self.colorder.index('time')
self.signals.DataUpdateEvent.emit({'col':ctcol,'row':port,'PI':PI,'string':timestring,'tooltip':datestring})
t=(str(datetime.now()),PI,self.RDS_data[PI]["PSN"],"CT",datestring+" "+timestring+"; datecode(MJD):"+str(datecode))