mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2026-02-11 15:13:06 +01:00
some error handling and stats to sendN2K
This commit is contained in:
117
tools/sendN2K.py
117
tools/sendN2K.py
@@ -394,8 +394,10 @@ PGN_MODES={
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def logError(fmt,*args):
|
def logError(fmt,*args,keep=False):
|
||||||
print("ERROR:" +fmt%(args))
|
print("ERROR:" +fmt%(args),file=sys.stderr)
|
||||||
|
if not keep:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def dataToSep(data,maxbytes=None):
|
def dataToSep(data,maxbytes=None):
|
||||||
pd=None
|
pd=None
|
||||||
@@ -453,7 +455,7 @@ class CanFrame:
|
|||||||
'''(1658058069.867835) can0 09F80103#ACAF6C20B79AAC06'''
|
'''(1658058069.867835) can0 09F80103#ACAF6C20B79AAC06'''
|
||||||
match=cls.DUMP_PAT.search(line)
|
match=cls.DUMP_PAT.search(line)
|
||||||
if match is None:
|
if match is None:
|
||||||
logError("no dump pattern in line %s",line)
|
logError("no dump pattern in line %s",line,keep=True)
|
||||||
return
|
return
|
||||||
ts=match[1]
|
ts=match[1]
|
||||||
dt=datetime.datetime.fromtimestamp(float(ts),tz=datetime.UTC)
|
dt=datetime.datetime.fromtimestamp(float(ts),tz=datetime.UTC)
|
||||||
@@ -476,18 +478,16 @@ class CanFrame:
|
|||||||
pgn=(RDP << 16) + (PF << 8)+PS
|
pgn=(RDP << 16) + (PF << 8)+PS
|
||||||
return CanFrame(tstr,pgn,src=src,dst=dst,prio=prio,data=data)
|
return CanFrame(tstr,pgn,src=src,dst=dst,prio=prio,data=data)
|
||||||
|
|
||||||
class MultiFrame:
|
class MultiFrame(CanFrame):
|
||||||
def __init__(self,firstFrame: CanFrame):
|
def __init__(self,firstFrame: CanFrame):
|
||||||
|
super().__init__(firstFrame.ts,firstFrame.pgn,
|
||||||
|
src=firstFrame.src,dst=firstFrame.dst,prio=firstFrame.prio)
|
||||||
self.data=""
|
self.data=""
|
||||||
self.prio=firstFrame.prio
|
|
||||||
self.pgn=firstFrame.pgn
|
|
||||||
self.src=firstFrame.src
|
|
||||||
self.dst=firstFrame.dst
|
|
||||||
self.ts=firstFrame.ts
|
|
||||||
self.numFrames=firstFrame.getFPNum(bytes=False)
|
self.numFrames=firstFrame.getFPNum(bytes=False)
|
||||||
self.len=firstFrame.getFPNum(bytes=True)
|
self.len=firstFrame.getFPNum(bytes=True)
|
||||||
self.finished=False
|
self.finished=False
|
||||||
self.addFrame(firstFrame)
|
self.addFrame(firstFrame)
|
||||||
|
|
||||||
def addFrame(self,frame:CanFrame):
|
def addFrame(self,frame:CanFrame):
|
||||||
if self.finished:
|
if self.finished:
|
||||||
return False
|
return False
|
||||||
@@ -502,18 +502,27 @@ class MultiFrame:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.ts},{self.prio},{self.pgn},{self.src},{self.dst},{self.len},{dataToSep(self.data,self.numBytes)}"
|
return f"{self.ts},{self.prio},{self.pgn},{self.src},{self.dst},{self.len},{dataToSep(self.data,self.len)}"
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
print(f"usage: {sys.argv[0]} [-q] [-p pgn,pgn,...] [-w waitsec] [ -f plain|actisense] file")
|
print(f"usage: {sys.argv[0]} [-q] [-p pgn,pgn,...] [-w waitsec] [ -f plain|actisense] file")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
F_PLAIN=0
|
|
||||||
F_ACT=1
|
class Format:
|
||||||
FORMATS={
|
F_PLAIN=0
|
||||||
'plain':F_PLAIN,
|
N_PLAIN='plain'
|
||||||
'actisense':F_ACT
|
F_ACT=1
|
||||||
}
|
N_ACT='actisense'
|
||||||
|
def __init__(self,name,key,merge=True):
|
||||||
|
self.key=key
|
||||||
|
self.name=name
|
||||||
|
self.merge=merge
|
||||||
|
|
||||||
|
FORMATS=[
|
||||||
|
Format(Format.N_PLAIN,Format.F_PLAIN),
|
||||||
|
Format(Format.N_ACT,Format.F_ACT)
|
||||||
|
]
|
||||||
|
|
||||||
MAX_ACT=400
|
MAX_ACT=400
|
||||||
ACT_ESC=0x10
|
ACT_ESC=0x10
|
||||||
@@ -551,7 +560,7 @@ class ActBuffer:
|
|||||||
|
|
||||||
actBuffer=ActBuffer()
|
actBuffer=ActBuffer()
|
||||||
|
|
||||||
def send_act(frame_like,quiet):
|
def send_act(frame_like:CanFrame,quiet):
|
||||||
try:
|
try:
|
||||||
actBuffer.clear()
|
actBuffer.clear()
|
||||||
actBuffer.add(ACT_N2K)
|
actBuffer.add(ACT_N2K)
|
||||||
@@ -575,11 +584,59 @@ def send_act(frame_like,quiet):
|
|||||||
for i in range(0,frame_like.len*2,2):
|
for i in range(0,frame_like.len*2,2):
|
||||||
actBuffer.add(int(frame_like.data[i:i+2],16))
|
actBuffer.add(int(frame_like.data[i:i+2],16))
|
||||||
actBuffer.finalize()
|
actBuffer.finalize()
|
||||||
sys.stdout.buffer.write(memoryview(actBuffer.buf)[0:actBuffer.idx])
|
written=sys.stdout.buffer.write(memoryview(actBuffer.buf)[0:actBuffer.idx])
|
||||||
|
if (written != actBuffer.idx):
|
||||||
|
if not quiet:
|
||||||
|
logError(f"actisense not all bytes written {written}/{actBuffer.idx} for pgn={frame_like.pgn} ts={frame_like.ts}",keep=True)
|
||||||
sys.stdout.buffer.flush()
|
sys.stdout.buffer.flush()
|
||||||
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print(f"Error writing actisense for pgn {frame_like.pgn}, idx={actBuffer.idx}: {e}",file=sys.stderr)
|
print(f"Error writing actisense for pgn {frame_like.pgn}, idx={actBuffer.idx}: {e}",file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
class Counters:
|
||||||
|
C_OK=1
|
||||||
|
C_FAIL=2
|
||||||
|
C_FRAME=3
|
||||||
|
TITLES={
|
||||||
|
C_OK:'OK',
|
||||||
|
C_FAIL:'FAIL',
|
||||||
|
C_FRAME:'FRAMES'
|
||||||
|
}
|
||||||
|
def __init__(self):
|
||||||
|
self.counters={}
|
||||||
|
for i in self.TITLES.keys():
|
||||||
|
self.counters[i]=0
|
||||||
|
def add(self,idx:int):
|
||||||
|
if idx not in self.TITLES.keys():
|
||||||
|
return
|
||||||
|
self.counters[idx]+=1
|
||||||
|
def __str__(self):
|
||||||
|
rt=None
|
||||||
|
for i in self.TITLES.keys():
|
||||||
|
v=f"{self.TITLES[i]}:{self.counters[i]}"
|
||||||
|
if rt is None:
|
||||||
|
rt=v
|
||||||
|
else:
|
||||||
|
rt+=","+v
|
||||||
|
return rt
|
||||||
|
|
||||||
|
def writeOut(frame:CanFrame,format:Format,quiet:bool,counters:Counters):
|
||||||
|
rt=False
|
||||||
|
if format.key == Format.F_ACT:
|
||||||
|
rt= send_act(frame,quiet)
|
||||||
|
elif format.key == Format.F_PLAIN:
|
||||||
|
print(frame)
|
||||||
|
rt=True
|
||||||
|
counters.add(Counters.C_OK if rt else Counters.C_FAIL)
|
||||||
|
return rt
|
||||||
|
|
||||||
|
def findFormat(name:str)->Format:
|
||||||
|
for f in FORMATS:
|
||||||
|
if f.name == name:
|
||||||
|
return f
|
||||||
|
return None
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
@@ -589,7 +646,7 @@ if __name__ == '__main__':
|
|||||||
pgnlist=[]
|
pgnlist=[]
|
||||||
quiet=False
|
quiet=False
|
||||||
delay=0.0
|
delay=0.0
|
||||||
format=F_PLAIN
|
format=findFormat(Format.N_PLAIN)
|
||||||
for o,a in opts:
|
for o,a in opts:
|
||||||
if o == '-h':
|
if o == '-h':
|
||||||
usage()
|
usage()
|
||||||
@@ -601,14 +658,15 @@ if __name__ == '__main__':
|
|||||||
elif o == '-w':
|
elif o == '-w':
|
||||||
delay=float(a)
|
delay=float(a)
|
||||||
elif o == '-f':
|
elif o == '-f':
|
||||||
format=FORMATS.get(a)
|
format=findFormat(a)
|
||||||
if format is None:
|
if format is None:
|
||||||
logError(f"invalid format {a}, allowed {','.join(FORMATS.keys())}")
|
logError(f"invalid format {a}, allowed {','.join(x.name for x in FORMATS)}")
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
usage()
|
usage()
|
||||||
hasFilter=len(pgnlist) > 0
|
hasFilter=len(pgnlist) > 0
|
||||||
if not quiet and hasFilter:
|
if not quiet and hasFilter:
|
||||||
print(f"PGNs: {','.join(str(x) for x in pgnlist)}")
|
print(f"PGNs: {','.join(str(x) for x in pgnlist)}",file=sys.stderr)
|
||||||
|
counters=Counters()
|
||||||
with open (args[0],"r") as fh:
|
with open (args[0],"r") as fh:
|
||||||
buffer={}
|
buffer={}
|
||||||
lnr=0
|
lnr=0
|
||||||
@@ -617,11 +675,9 @@ if __name__ == '__main__':
|
|||||||
frame=CanFrame.fromDump(line)
|
frame=CanFrame.fromDump(line)
|
||||||
if hasFilter and not frame.pgn in pgnlist:
|
if hasFilter and not frame.pgn in pgnlist:
|
||||||
continue
|
continue
|
||||||
if frame.sequence is None:
|
counters.add(Counters.C_FRAME)
|
||||||
if format == F_PLAIN:
|
if frame.sequence is None or not format.merge:
|
||||||
print(frame)
|
writeOut(frame,format,quiet,counters=counters)
|
||||||
else:
|
|
||||||
send_act(frame,quiet)
|
|
||||||
if delay > 0:
|
if delay > 0:
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
else:
|
else:
|
||||||
@@ -640,12 +696,11 @@ if __name__ == '__main__':
|
|||||||
mf.addFrame(frame)
|
mf.addFrame(frame)
|
||||||
mustDelete=True
|
mustDelete=True
|
||||||
if mf.finished:
|
if mf.finished:
|
||||||
if format == F_PLAIN:
|
writeOut(mf,format,quiet,counters=counters)
|
||||||
print(mf)
|
|
||||||
else:
|
|
||||||
send_act(mf,quiet)
|
|
||||||
if mustDelete:
|
if mustDelete:
|
||||||
del buffer[key]
|
del buffer[key]
|
||||||
if delay > 0:
|
if delay > 0:
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
|
if not quiet:
|
||||||
|
print(f"STATISTICS: {counters}",file=sys.stderr)
|
||||||
|
|
||||||
Reference in New Issue
Block a user