1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2026-02-11 07:03:07 +01:00

some error handling and stats to sendN2K

This commit is contained in:
wellenvogel
2025-09-24 18:10:06 +02:00
parent e5c4f0b179
commit e5968b8480

View File

@@ -394,8 +394,10 @@ PGN_MODES={
def logError(fmt,*args):
print("ERROR:" +fmt%(args))
def logError(fmt,*args,keep=False):
print("ERROR:" +fmt%(args),file=sys.stderr)
if not keep:
sys.exit(1)
def dataToSep(data,maxbytes=None):
pd=None
@@ -453,7 +455,7 @@ class CanFrame:
'''(1658058069.867835) can0 09F80103#ACAF6C20B79AAC06'''
match=cls.DUMP_PAT.search(line)
if match is None:
logError("no dump pattern in line %s",line)
logError("no dump pattern in line %s",line,keep=True)
return
ts=match[1]
dt=datetime.datetime.fromtimestamp(float(ts),tz=datetime.UTC)
@@ -476,18 +478,16 @@ class CanFrame:
pgn=(RDP << 16) + (PF << 8)+PS
return CanFrame(tstr,pgn,src=src,dst=dst,prio=prio,data=data)
class MultiFrame:
class MultiFrame(CanFrame):
def __init__(self,firstFrame: CanFrame):
super().__init__(firstFrame.ts,firstFrame.pgn,
src=firstFrame.src,dst=firstFrame.dst,prio=firstFrame.prio)
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.len=firstFrame.getFPNum(bytes=True)
self.finished=False
self.addFrame(firstFrame)
def addFrame(self,frame:CanFrame):
if self.finished:
return False
@@ -502,18 +502,27 @@ class MultiFrame:
return True
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():
print(f"usage: {sys.argv[0]} [-q] [-p pgn,pgn,...] [-w waitsec] [ -f plain|actisense] file")
sys.exit(1)
class Format:
F_PLAIN=0
N_PLAIN='plain'
F_ACT=1
FORMATS={
'plain':F_PLAIN,
'actisense':F_ACT
}
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
ACT_ESC=0x10
@@ -551,7 +560,7 @@ class ActBuffer:
actBuffer=ActBuffer()
def send_act(frame_like,quiet):
def send_act(frame_like:CanFrame,quiet):
try:
actBuffer.clear()
actBuffer.add(ACT_N2K)
@@ -575,11 +584,59 @@ def send_act(frame_like,quiet):
for i in range(0,frame_like.len*2,2):
actBuffer.add(int(frame_like.data[i:i+2],16))
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()
return True
except Exception as e:
if not quiet:
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__':
try:
@@ -589,7 +646,7 @@ if __name__ == '__main__':
pgnlist=[]
quiet=False
delay=0.0
format=F_PLAIN
format=findFormat(Format.N_PLAIN)
for o,a in opts:
if o == '-h':
usage()
@@ -601,14 +658,15 @@ if __name__ == '__main__':
elif o == '-w':
delay=float(a)
elif o == '-f':
format=FORMATS.get(a)
format=findFormat(a)
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:
usage()
hasFilter=len(pgnlist) > 0
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:
buffer={}
lnr=0
@@ -617,11 +675,9 @@ if __name__ == '__main__':
frame=CanFrame.fromDump(line)
if hasFilter and not frame.pgn in pgnlist:
continue
if frame.sequence is None:
if format == F_PLAIN:
print(frame)
else:
send_act(frame,quiet)
counters.add(Counters.C_FRAME)
if frame.sequence is None or not format.merge:
writeOut(frame,format,quiet,counters=counters)
if delay > 0:
time.sleep(delay)
else:
@@ -640,12 +696,11 @@ if __name__ == '__main__':
mf.addFrame(frame)
mustDelete=True
if mf.finished:
if format == F_PLAIN:
print(mf)
else:
send_act(mf,quiet)
writeOut(mf,format,quiet,counters=counters)
if mustDelete:
del buffer[key]
if delay > 0:
time.sleep(delay)
if not quiet:
print(f"STATISTICS: {counters}",file=sys.stderr)