Skip to content

Commit fed449f

Browse files
author
Martin
committed
Critical speed fix to MultiFrameDecoder
1 parent a0516fb commit fed449f

File tree

1 file changed

+97
-78
lines changed

1 file changed

+97
-78
lines changed

dashboard-writer/utils.py

+97-78
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ class MultiFrameDecoder:
231231
FIRST_FRAME: frame type reflecting the first frame in a multi frame response
232232
CONSEQ_FRAME: frame type reflecting a consequtive frame in a multi frame response
233233
ff_payload_start: the combined payload will start at this byte in the FIRST_FRAME
234-
bam_pgn_hex: this is used in J1939 and marks the initial BAM message ID in HEX
234+
bam_pgn: this is used in J1939 and marks the initial BAM message ID in DEC
235235
res_id_list_hex: TP 'response CAN IDs' to process. For nmea/j1939, these are provided by default
236236
237237
"""
@@ -245,7 +245,7 @@ def __init__(self, tp_type=""):
245245
"FIRST_FRAME": 0x10,
246246
"CONSEQ_FRAME": 0x20,
247247
"ff_payload_start": 2,
248-
"bam_pgn_hex": "",
248+
"bam_pgn": -1,
249249
"res_id_list_hex": ["0x7E0", "0x7E9", "0x7EA", "0x7EB", "0x7EC", "0x7ED", "0x7EE", "0x7EF", "0x7EA", "0x7BB"],
250250
}
251251

@@ -257,7 +257,7 @@ def __init__(self, tp_type=""):
257257
"FIRST_FRAME": 0x20,
258258
"CONSEQ_FRAME": 0x00,
259259
"ff_payload_start": 8,
260-
"bam_pgn_hex": "0xEC00",
260+
"bam_pgn": int("0xEC00", 16),
261261
"res_id_list_hex": ["0xEB00"],
262262
}
263263

@@ -269,7 +269,7 @@ def __init__(self, tp_type=""):
269269
"FIRST_FRAME": 0x00,
270270
"CONSEQ_FRAME": 0x00,
271271
"ff_payload_start": 2,
272-
"bam_pgn_hex": "",
272+
"bam_pgn": -1,
273273
"res_id_list_hex": [
274274
"0xfed8",
275275
"0x1f007",
@@ -350,99 +350,118 @@ def construct_new_tp_frame(self, base_frame, payload_concatenated, can_id):
350350
def combine_tp_frames(self, df_raw):
351351
import pandas as pd
352352

353-
bam_pgn_hex = self.frame_struct["bam_pgn_hex"]
353+
bam_pgn = self.frame_struct["bam_pgn"]
354354
res_id_list = [int(res_id, 16) for res_id in self.frame_struct["res_id_list_hex"]]
355355

356-
df_raw_combined = pd.DataFrame()
356+
df_list_combined = []
357357

358-
# use PGN matching for J1939 and NMEA
358+
# use PGN matching for J1939 and NMEA and update res_id_list to relevant entries
359359
if self.tp_type == "nmea" or self.tp_type == "j1939":
360-
df_raw_excl_tp = df_raw[~df_raw["ID"].apply(self.calculate_pgn).isin(res_id_list)]
360+
res_id_list_incl_bam = res_id_list
361+
res_id_list_incl_bam.append(bam_pgn)
362+
df_raw_match = df_raw["ID"].apply(self.calculate_pgn).isin(res_id_list_incl_bam)
363+
res_id_list = df_raw["ID"][df_raw_match].apply(self.calculate_pgn).drop_duplicates().values.tolist()
364+
365+
df_raw_tp = df_raw[df_raw_match]
366+
df_raw_excl_tp = df_raw[~df_raw_match]
361367
else:
368+
df_raw_match = df_raw["ID"].isin(res_id_list)
369+
res_id_list = df_raw["ID"][df_raw_match].drop_duplicates().values.tolist()
370+
371+
df_raw_tp = df_raw[df_raw_match]
362372
df_raw_excl_tp = df_raw[~df_raw["ID"].isin(res_id_list)]
363373

364-
df_raw_combined = df_raw_excl_tp
374+
if len(df_raw.index) - len(df_raw_tp.index) - len(df_raw_excl_tp.index):
375+
print("Warning - total rows does not equal sum of rows incl/excl transport protocol frames")
365376

366-
for channel, df_raw_channel in df_raw.groupby("BusChannel"):
367-
for res_id in res_id_list:
368-
# filter raw data for response ID and extract a 'base frame'
369-
if bam_pgn_hex == "":
370-
bam_pgn = 0
371-
else:
372-
bam_pgn = int(bam_pgn_hex, 16)
377+
df_list_combined.append(df_raw_excl_tp)
373378

374-
if self.tp_type == "nmea" or self.tp_type == "j1939":
375-
df_raw_filter = df_raw_channel[df_raw_channel["ID"].apply(self.calculate_pgn).isin([res_id, bam_pgn])]
376-
else:
377-
df_raw_filter = df_raw_channel[df_raw_channel["ID"].isin([res_id])]
378-
379-
if df_raw_filter.empty:
380-
continue
381-
382-
base_frame = df_raw_filter.iloc[0]
383-
384-
frame_list = []
385-
frame_timestamp_list = []
386-
payload_concatenated = []
387-
ff_length = 0xFFF
388-
can_id = None
389-
conseq_frame_prev = None
390-
391-
# iterate through rows in filtered dataframe
392-
for index, row in df_raw_filter.iterrows():
393-
payload = row["DataBytes"]
394-
first_byte = payload[0]
395-
row_id = row["ID"]
396-
row_pgn = self.calculate_pgn(row_id)
397-
398-
# check if first frame (either for UDS/NMEA or J1939 case)
399-
first_frame_test = (
400-
(first_byte & self.frame_struct["FIRST_FRAME_MASK"] == self.frame_struct["FIRST_FRAME"])
401-
& (bam_pgn_hex == "")
402-
) or (self.tp_type == "j1939" and bam_pgn == row_pgn)
403-
404-
# if single frame, save frame directly (excl. 1st byte)
405-
if first_byte & self.frame_struct["SINGLE_FRAME_MASK"] == self.frame_struct["SINGLE_FRAME"]:
406-
new_frame = self.construct_new_tp_frame(base_frame, payload, row_id)
407-
frame_list.append(new_frame.values.tolist())
408-
frame_timestamp_list.append(index)
409-
410-
# if first frame, save info from prior multi frame response sequence,
411-
# then initialize a new sequence incl. the first frame payload
412-
elif first_frame_test:
413-
# create a new frame using information from previous iterations
414-
if len(payload_concatenated) >= ff_length:
415-
new_frame = self.construct_new_tp_frame(base_frame, payload_concatenated, can_id)
379+
for res_id in res_id_list:
380+
# filter raw data for response ID and extract a 'base frame'
381+
if self.tp_type == "nmea" or self.tp_type == "j1939":
382+
df_raw_res_id = df_raw_tp[df_raw_tp["ID"].apply(self.calculate_pgn).isin([res_id, bam_pgn])]
383+
else:
384+
df_raw_res_id = df_raw_tp[df_raw_tp["ID"].isin([res_id])]
416385

386+
if df_raw_res_id.empty:
387+
continue
388+
389+
for channel, df_channel in df_raw_res_id.groupby("BusChannel"):
390+
391+
# if J1939, we can't group by CAN ID (as we need both bam_pgn and response)
392+
if self.tp_type == "j1939":
393+
group = "DataLength"
394+
else:
395+
group = "ID"
396+
397+
for identifier, df_raw_filter in df_channel.groupby(group):
398+
399+
base_frame = df_raw_filter.iloc[0]
400+
401+
frame_list = []
402+
frame_timestamp_list = []
403+
payload_concatenated = []
404+
ff_length = 0xFFF
405+
can_id = None
406+
conseq_frame_prev = None
407+
408+
# iterate through rows in filtered dataframe
409+
for index, row in df_raw_filter.iterrows():
410+
first_byte = row["DataBytes"][0]
411+
412+
# check if first frame (either for UDS/NMEA or J1939 case)
413+
if self.tp_type == "j1939" and bam_pgn == self.calculate_pgn(row["ID"]):
414+
first_frame_test = True
415+
elif (first_byte & self.frame_struct["FIRST_FRAME_MASK"]) == self.frame_struct["FIRST_FRAME"]:
416+
first_frame_test = True
417+
else:
418+
first_frame_test = False
419+
420+
# if single frame, save frame directly (excl. 1st byte)
421+
if self.tp_type != "nmea" and (
422+
first_byte & self.frame_struct["SINGLE_FRAME_MASK"] == self.frame_struct["SINGLE_FRAME"]
423+
):
424+
new_frame = self.construct_new_tp_frame(base_frame, row["DataBytes"], row["ID"])
417425
frame_list.append(new_frame.values.tolist())
418-
frame_timestamp_list.append(frame_timestamp)
426+
frame_timestamp_list.append(index)
419427

420-
# reset and start on next frame
421-
payload_concatenated = []
422-
conseq_frame_prev = None
423-
frame_timestamp = index
428+
# if first frame, save info from prior multi frame response sequence,
429+
# then initialize a new sequence incl. the first frame payload
430+
elif first_frame_test:
431+
# create a new frame using information from previous iterations
432+
if len(payload_concatenated) >= ff_length:
433+
new_frame = self.construct_new_tp_frame(base_frame, payload_concatenated, can_id)
424434

425-
# for J1939, extract PGN and convert to 29 bit CAN ID for use in baseframe
426-
if self.tp_type == "j1939":
427-
pgn_hex = "".join("{:02x}".format(x) for x in reversed(payload[5:8]))
428-
pgn = int(pgn_hex, 16)
429-
can_id = (6 << 26) | (pgn << 8) | 254
435+
frame_list.append(new_frame.values.tolist())
436+
frame_timestamp_list.append(frame_timestamp)
430437

431-
ff_length = (payload[0] & 0x0F) << 8 | payload[1]
438+
# reset and start on next frame
439+
payload_concatenated = []
440+
conseq_frame_prev = None
441+
frame_timestamp = index
432442

433-
for byte in payload[self.frame_struct["ff_payload_start"] :]:
434-
payload_concatenated.append(byte)
443+
# for J1939, extract PGN and convert to 29 bit CAN ID for use in baseframe
444+
if self.tp_type == "j1939":
445+
pgn_hex = "".join("{:02x}".format(x) for x in reversed(row["DataBytes"][5:8]))
446+
pgn = int(pgn_hex, 16)
447+
can_id = (6 << 26) | (pgn << 8) | 254
435448

436-
# if consequtive frame, extend payload with payload excl. 1st byte
437-
elif first_byte & self.frame_struct["CONSEQ_FRAME_MASK"] == self.frame_struct["CONSEQ_FRAME"]:
438-
if (conseq_frame_prev == None) or ((first_byte - conseq_frame_prev) == 1):
439-
conseq_frame_prev = first_byte
440-
for byte in payload[1:]:
449+
ff_length = (row["DataBytes"][0] & 0x0F) << 8 | row["DataBytes"][1]
450+
451+
for byte in row["DataBytes"][self.frame_struct["ff_payload_start"] :]:
441452
payload_concatenated.append(byte)
442453

443-
df_raw_tp = pd.DataFrame(frame_list, columns=base_frame.index, index=frame_timestamp_list)
444-
df_raw_combined = df_raw_combined.append(df_raw_tp)
454+
# if consequtive frame, extend payload with payload excl. 1st byte
455+
elif first_byte & self.frame_struct["CONSEQ_FRAME_MASK"] == self.frame_struct["CONSEQ_FRAME"]:
456+
if (conseq_frame_prev == None) or ((first_byte - conseq_frame_prev) == 1):
457+
conseq_frame_prev = first_byte
458+
for byte in row["DataBytes"][1:]:
459+
payload_concatenated.append(byte)
460+
461+
df_raw_res_id_new = pd.DataFrame(frame_list, columns=base_frame.index, index=frame_timestamp_list)
462+
df_list_combined.append(df_raw_res_id_new)
445463

464+
df_raw_combined = pd.concat(df_list_combined)
446465
df_raw_combined.index.name = "TimeStamp"
447466
df_raw_combined = df_raw_combined.sort_index()
448467

0 commit comments

Comments
 (0)