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))