@@ -231,7 +231,7 @@ class MultiFrameDecoder:
231
231
FIRST_FRAME: frame type reflecting the first frame in a multi frame response
232
232
CONSEQ_FRAME: frame type reflecting a consequtive frame in a multi frame response
233
233
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
235
235
res_id_list_hex: TP 'response CAN IDs' to process. For nmea/j1939, these are provided by default
236
236
237
237
"""
@@ -245,7 +245,7 @@ def __init__(self, tp_type=""):
245
245
"FIRST_FRAME" : 0x10 ,
246
246
"CONSEQ_FRAME" : 0x20 ,
247
247
"ff_payload_start" : 2 ,
248
- "bam_pgn_hex " : "" ,
248
+ "bam_pgn " : - 1 ,
249
249
"res_id_list_hex" : ["0x7E0" , "0x7E9" , "0x7EA" , "0x7EB" , "0x7EC" , "0x7ED" , "0x7EE" , "0x7EF" , "0x7EA" , "0x7BB" ],
250
250
}
251
251
@@ -257,7 +257,7 @@ def __init__(self, tp_type=""):
257
257
"FIRST_FRAME" : 0x20 ,
258
258
"CONSEQ_FRAME" : 0x00 ,
259
259
"ff_payload_start" : 8 ,
260
- "bam_pgn_hex " : "0xEC00" ,
260
+ "bam_pgn " : int ( "0xEC00" , 16 ) ,
261
261
"res_id_list_hex" : ["0xEB00" ],
262
262
}
263
263
@@ -269,7 +269,7 @@ def __init__(self, tp_type=""):
269
269
"FIRST_FRAME" : 0x00 ,
270
270
"CONSEQ_FRAME" : 0x00 ,
271
271
"ff_payload_start" : 2 ,
272
- "bam_pgn_hex " : "" ,
272
+ "bam_pgn " : - 1 ,
273
273
"res_id_list_hex" : [
274
274
"0xfed8" ,
275
275
"0x1f007" ,
@@ -350,99 +350,118 @@ def construct_new_tp_frame(self, base_frame, payload_concatenated, can_id):
350
350
def combine_tp_frames (self , df_raw ):
351
351
import pandas as pd
352
352
353
- bam_pgn_hex = self .frame_struct ["bam_pgn_hex " ]
353
+ bam_pgn = self .frame_struct ["bam_pgn " ]
354
354
res_id_list = [int (res_id , 16 ) for res_id in self .frame_struct ["res_id_list_hex" ]]
355
355
356
- df_raw_combined = pd . DataFrame ()
356
+ df_list_combined = []
357
357
358
- # use PGN matching for J1939 and NMEA
358
+ # use PGN matching for J1939 and NMEA and update res_id_list to relevant entries
359
359
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 ]
361
367
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 ]
362
372
df_raw_excl_tp = df_raw [~ df_raw ["ID" ].isin (res_id_list )]
363
373
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" )
365
376
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 )
373
378
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 ])]
416
385
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" ])
417
425
frame_list .append (new_frame .values .tolist ())
418
- frame_timestamp_list .append (frame_timestamp )
426
+ frame_timestamp_list .append (index )
419
427
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 )
424
434
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 )
430
437
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
432
442
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
435
448
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" ] :]:
441
452
payload_concatenated .append (byte )
442
453
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 )
445
463
464
+ df_raw_combined = pd .concat (df_list_combined )
446
465
df_raw_combined .index .name = "TimeStamp"
447
466
df_raw_combined = df_raw_combined .sort_index ()
448
467
0 commit comments