1
+ """
2
+ /**
3
+ * @file main.py
4
+ * @brief Script to parse CAN DBC files and log files, and plot specific CAN signal data over time.
5
+ *
6
+ * This script is designed to parse a DBC file to understand the structure of CAN messages and a log file
7
+ * to extract actual CAN message data. It then plots the specified signal data over time.
8
+ *
9
+ * The script uses the `cantools` library to parse the DBC file and understand the CAN message structure.
10
+ * The log file is parsed to extract individual CAN messages and their signals, which are then plotted using `matplotlib`.
11
+ *
12
+ *
13
+ * The script is designed to work with relative paths, making it easy to clone the repository and run the script without modifying paths.
14
+ *
15
+ * Author: Kiran Jojare
16
+ *
17
+ * Usage:
18
+ * python main.py <test|main> <signal_name> [start_time] [end_time]
19
+ *
20
+ * Arguments:
21
+ * mode: Mode to run the script in ('test' or 'main')
22
+ * signal: Signal name to plot
23
+ * start: (Optional) Start time for the plot
24
+ * end: (Optional) End time for the plot
25
+ */
26
+ """
27
+
1
28
import cantools
29
+ import os
2
30
import sys
3
31
import matplotlib .pyplot as plt
4
32
import argparse
5
33
6
34
def parse_dbc (file_path ):
35
+ """
36
+ @brief Parse the DBC file to get CAN message definitions.
37
+
38
+ @param file_path Path to the DBC file.
39
+ @return Parsed DBC database object.
40
+ """
7
41
try :
8
42
db = cantools .database .load_file (file_path )
9
43
print (f"Successfully parsed DBC file: { file_path } " )
@@ -13,21 +47,28 @@ def parse_dbc(file_path):
13
47
return None
14
48
15
49
def parse_log (db , log_file_path ):
50
+ """
51
+ @brief Parse the log file to extract CAN messages.
52
+
53
+ @param db Parsed DBC database object.
54
+ @param log_file_path Path to the log file.
55
+ @return List of parsed CAN messages.
56
+ """
16
57
try :
17
58
parsed_data = []
18
59
with open (log_file_path , 'r' ) as log_file :
19
60
current_message = None
20
61
for line in log_file :
21
- # print(f"Reading line: {line.strip()}") # Commented for clean output
62
+ # print(f"Reading line: {line.strip()}") # Debug print
22
63
if line .startswith ("CAN" ):
23
64
if current_message :
24
65
process_message (db , current_message , parsed_data )
25
66
current_message = [line .strip ()]
26
- # print("Detected start of a new message") # Commented for clean output
67
+ # print("Detected start of a new message") # Debug print
27
68
elif line .strip ().startswith ("->" ):
28
- # print("Detected start of line with ->")
69
+ # print("Detected start of line with ->") # Debug print
29
70
current_message .append (line .strip ())
30
- # print(f"Appending signal line: {line.strip()}") # Commented for clean output
71
+ # print(f"Appending signal line: {line.strip()}") # Debug print
31
72
if current_message :
32
73
process_message (db , current_message , parsed_data )
33
74
print_parsed_data (parsed_data )
@@ -37,21 +78,26 @@ def parse_log(db, log_file_path):
37
78
return None
38
79
39
80
def process_message (db , message_lines , parsed_data ):
81
+ """
82
+ @brief Process a single CAN message from the log file.
83
+
84
+ @param db Parsed DBC database object.
85
+ @param message_lines List of lines representing a single CAN message.
86
+ @param parsed_data List to append the parsed message data.
87
+ """
40
88
try :
41
- # print(f"Processing message lines: {message_lines}") # Commented for clean output
89
+ # print(f"Processing message lines: {message_lines}") # Debug print
42
90
main_line = message_lines [0 ].split ()
43
- # print(f"Main line parts: {main_line}") # Commented for clean output
91
+ # print(f"Main line parts: {main_line}") # Debug print
44
92
can_id = main_line [2 ]
45
- # if can_id in ["00000000", "0000040A"]:
46
- # return
47
93
ecu_name , message_name = main_line [6 ].split ('.' )
48
94
timestamp = main_line [7 ]
49
95
direction = main_line [8 ]
50
96
51
97
signals = []
52
98
53
99
for signal_line in message_lines [1 :]:
54
- # print("Signal Line ---- ", signal_line)
100
+ # print("Signal Line ---- ", signal_line) # Debug print
55
101
parts = signal_line .split ()
56
102
signal_name = parts [1 ]
57
103
signal_value = parts [2 ]
@@ -66,18 +112,30 @@ def process_message(db, message_lines, parsed_data):
66
112
})
67
113
68
114
except Exception as e :
69
- print (f"Error processing message: { e } , for CAN ID (Error Frames) : { can_id } " )
115
+ print (f"Error processing message: { e } , for CAN ID: { can_id } " )
70
116
return
71
117
72
118
def print_parsed_data (parsed_data ):
119
+ """
120
+ @brief Print parsed data for debugging purposes.
121
+
122
+ @param parsed_data List of parsed CAN messages.
123
+ """
73
124
for data in parsed_data :
74
125
#print(f"Message: {data['message_name']}, CAN ID: {data['can_id']}, Timestamp: {data['timestamp']}, Direction: {data['direction']}")
75
126
for signal in data ['signals' ]:
76
127
signal_name , signal_value , signal_timestamp = signal
77
128
#print(f" Signal: {signal_name}, Value: {signal_value}, Timestamp: {signal_timestamp}")
78
129
79
-
80
130
def plot_signals (parsed_data , signal_name , start_time , end_time ):
131
+ """
132
+ @brief Plot the signal data over time.
133
+
134
+ @param parsed_data List of parsed CAN messages.
135
+ @param signal_name Name of the signal to plot.
136
+ @param start_time Start time for the plot.
137
+ @param end_time End time for the plot.
138
+ """
81
139
timestamps = []
82
140
values = []
83
141
for data in parsed_data :
@@ -120,26 +178,28 @@ def plot_signals(parsed_data, signal_name, start_time, end_time):
120
178
121
179
args = parser .parse_args ()
122
180
123
- if args .mode == "test" :
124
- dbc_file = "C:\\ Github\\ CAN-Log-Parser\\ test\\ data\\ test.dbc"
125
- log_file = "C:\\ Github\\ CAN-Log-Parser\\ test\\ data\\ test_log.txt"
126
- elif args .mode == "main" :
127
- dbc_file = "C:\\ Github\\ CAN-Log-Parser\\ data\\ 1200G_CAN-DBC_v01.01.00.dbc"
128
- log_file = "C:\\ Github\\ CAN-Log-Parser\\ data\\ DMW_Message_Timeout_CAN_Log.txt"
181
+ # Determine the paths to the DBC and log files based on the mode
182
+ script_dir = os .path .dirname (os .path .abspath (__file__ ))
183
+ dbc_file = os .path .join (script_dir , ".." , "data" , "test.dbc" )
184
+ log_file = os .path .join (script_dir , ".." , "data" , "test_log.txt" )
129
185
186
+ # Parse the DBC file
130
187
db = parse_dbc (dbc_file )
131
188
if db :
189
+ # Parse the log file
132
190
parsed_data = parse_log (db , log_file )
133
191
if parsed_data :
192
+ # Determine start and end times for the plot if not provided
134
193
if args .start is None or args .end is None :
135
194
all_timestamps = [float (data ['timestamp' ]) / 1000 for data in parsed_data for signal in data ['signals' ]]
136
195
start_time = min (all_timestamps ) if args .start is None else args .start
137
196
end_time = max (all_timestamps ) if args .end is None else args .end
138
197
else :
139
198
start_time = args .start
140
199
end_time = args .end
200
+ # Plot the signals
141
201
plot_signals (parsed_data , args .signal , start_time , end_time )
142
202
else :
143
203
print ("Parsed data is empty or None." )
144
204
else :
145
- print ("DBC parsing failed." )
205
+ print ("DBC parsing failed." )
0 commit comments