Я пытаюсь создать конвертер журналов CAN из файлов .asc в файлы .csv (в удобочитаемой форме). Я несколько успешен. Мой код отлично работает практически с любой базой данных, кроме j1939.dbc.
Дело в том, что если я распечатаю сообщения, прочитанные из файла dbc, то я увижу, что сообщения из j1939.dbc считываются в базу данных. Но ему не удается найти ни одно из этих сообщений в обработанном файле журнала. В то же время я могу без проблем прочитать тот же файл с помощью Vector CANalyzer.
Интересно, почему это могло произойти и почему это влияет только на j1939.dbc, а не на другие.
Я подозреваю, что способ, которым я преобразовываю эти сообщения, может быть неверным, потому что они никогда не идут по строке if msg_id in database:
(и, как упоминалось выше, эти сообщения, безусловно, есть, потому что Vector CANalyzer отлично с ними работает).
РЕДАКТИРОВАТЬ: я понял, что, возможно, проблема не в cantools, а в пакете python-can, может быть, can.ASCReader()
не справляется с кадрами j1939 и опускает их? Я собираюсь исследовать себя, но я надеюсь, что кто-то, кто лучше разбирается в кодировании, поможет.
import pandas as pd
import can
import cantools
import time as t
from tqdm import tqdm
import re
import os
from binascii import unhexlify
dbcs = [filename.split('.')[0] for filename in os.listdir('./dbc/') if filename.endswith('.dbc')]
files = [filename.split('.')[0] for filename in os.listdir('./asc/') if filename.endswith('.asc')]
start = t.time()
db = cantools.database.Database()
for dbc in dbcs:
with open(f'./dbc/{dbc}.dbc', 'r') as f:
db.add_dbc(f)
f_num = 1
for fname in files:
print(f'[{f_num}/{len(files)}] Parsing data from file: {fname}')
log=can.ASCReader(f'./asc/{fname}.asc')
entries = []
all_msgs =[]
message = {'Time [s]': ''}
database = list(db._frame_id_to_message.keys())
print(database)
lines = sum(1 for line in open(f'./asc/{fname}.asc'))
msgs = iter(log)
try:
for msg, i in zip(msgs, tqdm(range(lines))):
msg = re.split("\\s+", str(msg))
timestamp = round(float(msg[1]), 0)
msg_id = int(msg[3], 16)
try:
data = unhexlify(''.join(msg[7:15]))
except:
continue
if msg_id in database:
if timestamp != message['Time [s]']:
entries.append(message.copy())
message.update({'Time [s]': timestamp})
message.update(db.decode_message(msg_id, data))
except ValueError:
print('ValueError')
df = pd.DataFrame(entries[1:])
duration = t.time() - start
df.to_csv(f'./csv/{fname}.csv', index=False)
print(f'DONE IN {int(round(duration, 2)//60)}min{round(duration % 60, 2)}s!\n{len(df.columns)} signals extracted!')
f_num += 1