EXE 변환 후 동작하여도 작동 작동 되도록 수정
@ -535,9 +535,24 @@ class MainView(QtWidgets.QMainWindow):
|
||||
channel_info = self.settings.get("channel_info", {}).get(os.path.basename(file_path), "CH0")
|
||||
try:
|
||||
shutil.copy(file_path, dbc_output_dir) # DBC 파일 복사
|
||||
subprocess.run(["python", "DBC_Converter_RX.py", file_path, rx_output_dir, json.dumps({os.path.basename(file_path): channel_info})], check=True)
|
||||
subprocess.run(["python", "DBC_Converter_TX.py", file_path, tx_output_dir, json.dumps({os.path.basename(file_path): channel_info})], check=True)
|
||||
subprocess.run(["python", "DBC_Converter_Common.py", file_path, common_output_dir, json.dumps({os.path.basename(file_path): channel_info})], check=True)
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
script_path = os.path.join(sys._MEIPASS, "DBC_Converter_RX.py")
|
||||
else:
|
||||
script_path = "DBC_Converter_RX.py"
|
||||
subprocess.run(["python", script_path, file_path, rx_output_dir, json.dumps({os.path.basename(file_path): channel_info})], check=True)
|
||||
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
script_path = os.path.join(sys._MEIPASS, "DBC_Converter_TX.py")
|
||||
else:
|
||||
script_path = "DBC_Converter_TX.py"
|
||||
subprocess.run(["python", script_path, file_path, tx_output_dir, json.dumps({os.path.basename(file_path): channel_info})], check=True)
|
||||
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
script_path = os.path.join(sys._MEIPASS, "DBC_Converter_Common.py")
|
||||
else:
|
||||
script_path = "DBC_Converter_Common.py"
|
||||
subprocess.run(["python", script_path, file_path, common_output_dir, json.dumps({os.path.basename(file_path): channel_info})], check=True)
|
||||
|
||||
self.updateAlertText(f"변환 성공", [file_path])
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.updateAlertText(f"변환 실패: {e}", [file_path])
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
added_files = [("./img/*", './img'),
|
||||
("./icon/*", '.icon'),
|
||||
("./icon.ico", '.')]
|
||||
("./icon/*", './icon'),
|
||||
("./icon.ico", '.'),
|
||||
("./*.py", '.')]
|
||||
|
||||
a = Analysis(['DBC_Converter.py'],
|
||||
a = Analysis(['DBC_Converter.py', 'DBC_Converter_Data_Parsing.py', 'DBC_Converter_Common.py', 'DBC_Converter_TX.py', 'DBC_Converter_RX.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=added_files,
|
||||
@ -20,7 +21,6 @@ a = Analysis(['DBC_Converter.py'],
|
||||
'PyQt5.QtWebEngineCore',
|
||||
'PyQt5.QtWebChannel',
|
||||
'PyQt5.QtWebSockets',
|
||||
'cantools',
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
|
||||
@ -54,31 +54,34 @@
|
||||
('pyiboot01_bootstrap',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_multiprocessing',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_inspect',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgres',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgres.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_setuptools',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_setuptools.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pyqt5',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pyqt5.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter_Data_Parsing',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter_Data_Parsing.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter_Common',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter_Common.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter_TX',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter_TX.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter_RX',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter_RX.py',
|
||||
'PYSOURCE')],
|
||||
[],
|
||||
False,
|
||||
False,
|
||||
1736326899,
|
||||
1740008983,
|
||||
[('runw.exe',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\runw.exe',
|
||||
'EXECUTABLE')],
|
||||
|
||||
@ -31,26 +31,29 @@
|
||||
('pyiboot01_bootstrap',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_multiprocessing',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_inspect',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgres',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgres.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_setuptools',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_setuptools.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pyqt5',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pyqt5.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Users\\MSI\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter_Data_Parsing',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter_Data_Parsing.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter_Common',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter_Common.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter_TX',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter_TX.py',
|
||||
'PYSOURCE'),
|
||||
('DBC_Converter_RX',
|
||||
'C:\\Users\\MSI\\Documents\\WorkSpace\\git\\DBC_Converter\\DBC_Converter_RX.py',
|
||||
'PYSOURCE')],
|
||||
'python313.dll',
|
||||
True,
|
||||
|
||||
@ -14,50 +14,14 @@ Types if import:
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named 'collections.abc' - imported by tracemalloc (top-level), traceback (top-level), inspect (top-level), logging (top-level), typing (top-level), selectors (top-level), cantools.tester (top-level), typing_extensions (top-level), configparser (top-level), can.exceptions (conditional), asyncio.base_events (top-level), http.client (top-level), asyncio.coroutines (top-level), sqlite3.dbapi2 (top-level), pkg_resources (top-level), setuptools (top-level), setuptools._vendor.jaraco.functools (top-level), setuptools._vendor.more_itertools.more (top-level), setuptools._vendor.more_itertools.recipes (top-level), setuptools._reqs (top-level), setuptools.discovery (top-level), setuptools.dist (top-level), setuptools._distutils.dist (top-level), setuptools.config.setupcfg (top-level), setuptools.config.expand (top-level), setuptools.config.pyprojecttoml (top-level), setuptools.config._apply_pyprojecttoml (top-level), tomllib._parser (top-level), setuptools._vendor.tomli._parser (top-level), setuptools.command.egg_info (top-level), setuptools.glob (top-level), setuptools.command._requirestxt (top-level), setuptools.command.bdist_wheel (top-level), wheel.cli.convert (top-level), wheel.cli.tags (top-level), setuptools._vendor.platformdirs.windows (conditional), diskcache.persistent (top-level), cantools.typechecking (top-level), cantools.database.utils (top-level), xml.etree.ElementTree (top-level), cantools.database.can.formats.sym (conditional), _pyrepl.types (top-level), _pyrepl.readline (top-level)
|
||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), setuptools._distutils.archive_util (optional), setuptools._vendor.backports.tarfile (optional)
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), setuptools._distutils.util (delayed, conditional, optional), setuptools._distutils.archive_util (optional), netrc (delayed, conditional), getpass (delayed, optional), setuptools._vendor.backports.tarfile (optional), http.server (delayed, optional)
|
||||
missing module named posix - imported by posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), os (conditional, optional), _pyrepl.unix_console (delayed, optional)
|
||||
missing module named pyimod02_importers - imported by C:\Users\MSI\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named 'collections.abc' - imported by traceback (top-level), inspect (top-level), logging (top-level), typing (top-level), selectors (top-level), tracemalloc (top-level)
|
||||
missing module named posix - imported by posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), os (conditional, optional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named termios - imported by getpass (optional), tty (top-level), _pyrepl.pager (delayed, optional), _pyrepl.unix_console (top-level), _pyrepl.fancy_termios (top-level), _pyrepl.unix_eventqueue (top-level)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named usercustomize - imported by site (delayed, optional)
|
||||
missing module named sitecustomize - imported by site (delayed, optional)
|
||||
missing module named _curses - imported by curses (top-level), curses.has_key (top-level), _pyrepl.curses (optional)
|
||||
missing module named fcntl - imported by subprocess (optional), _pyrepl.unix_console (top-level)
|
||||
missing module named readline - imported by cmd (delayed, conditional, optional), code (delayed, conditional, optional), rlcompleter (optional), pdb (delayed, optional), site (delayed, optional), sqlite3.__main__ (delayed, conditional, optional)
|
||||
missing module named '_typeshed.importlib' - imported by pkg_resources (conditional)
|
||||
missing module named _typeshed - imported by setuptools.glob (conditional), setuptools.compat.py311 (conditional), pkg_resources (conditional)
|
||||
missing module named jnius - imported by setuptools._vendor.platformdirs.android (delayed, conditional, optional)
|
||||
missing module named android - imported by setuptools._vendor.platformdirs.android (delayed, conditional, optional)
|
||||
missing module named importlib_resources - imported by setuptools._vendor.jaraco.text (optional)
|
||||
missing module named jaraco.text.yield_lines - imported by setuptools._vendor.jaraco.text (top-level), setuptools._entry_points (top-level), setuptools.command._requirestxt (top-level)
|
||||
missing module named _manylinux - imported by packaging._manylinux (delayed, optional), setuptools._vendor.packaging._manylinux (delayed, optional), wheel.vendored.packaging._manylinux (delayed, optional)
|
||||
missing module named trove_classifiers - imported by setuptools.config._validate_pyproject.formats (optional)
|
||||
missing module named pyimod02_importers - imported by C:\Users\MSI\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed), C:\Users\MSI\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgres.py (delayed)
|
||||
missing module named cantools.database.Database - imported by cantools.database (conditional), cantools.database.utils (conditional)
|
||||
missing module named cantools.database.Signal - imported by cantools.database (conditional), cantools.typechecking (conditional)
|
||||
missing module named cantools.database.Message - imported by cantools.database (conditional), cantools.typechecking (conditional)
|
||||
missing module named 'django.core' - imported by diskcache.djangocache (optional)
|
||||
missing module named django - imported by diskcache.djangocache (top-level)
|
||||
missing module named 'asammdf.mdf' - imported by can.io.mf4 (optional)
|
||||
missing module named 'asammdf.blocks' - imported by can.io.mf4 (optional)
|
||||
missing module named numpy - imported by can.io.mf4 (optional)
|
||||
missing module named asammdf - imported by can.io.mf4 (optional)
|
||||
missing module named win32event - imported by can.broadcastmanager (delayed)
|
||||
missing module named pywintypes - imported by can.broadcastmanager (delayed)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named _suggestions - imported by traceback (delayed, optional)
|
||||
missing module named _posixsubprocess - imported by subprocess (conditional)
|
||||
missing module named fcntl - imported by subprocess (optional)
|
||||
|
||||
BIN
dist/DBC Converter/DBC Converter.exe
vendored
635
dist/DBC Converter/_internal/DBC_Converter.py
vendored
Normal file
@ -0,0 +1,635 @@
|
||||
"""
|
||||
MainView 클래스는 PyQt5를 사용하여 DBC 파일을 C 파일로 변환하는 GUI 애플리케이션을 구현합니다.
|
||||
메서드:
|
||||
__init__(self):
|
||||
MainView 클래스의 초기화 메서드입니다. UI 설정 및 초기값을 설정합니다.
|
||||
loadSettings(self):
|
||||
설정 파일을 로드하고, 기본 저장 경로 및 마지막 열린 디렉토리를 설정합니다.
|
||||
saveSettings(self):
|
||||
현재 설정을 설정 파일에 저장합니다.
|
||||
setupUI(self):
|
||||
UI를 설정하고 메뉴, 툴바, 상태바, 파일 리스트 및 기타 위젯을 추가합니다.
|
||||
selectSavePath(self):
|
||||
저장 경로를 선택하는 파일 다이얼로그를 엽니다.
|
||||
openSavePath(self):
|
||||
현재 설정된 저장 경로를 엽니다.
|
||||
openCalculator(self):
|
||||
계산기를 엽니다.
|
||||
centerWindow(self):
|
||||
창을 화면 중앙에 위치시킵니다.
|
||||
centerDialog(self, dialog):
|
||||
다이얼로그를 부모 창의 중앙에 위치시킵니다.
|
||||
FilesOpen(self):
|
||||
파일 열기 다이얼로그를 열고 선택된 파일을 파일 리스트에 추가합니다.
|
||||
deleteSelectedFiles(self):
|
||||
선택된 파일을 파일 리스트에서 삭제합니다.
|
||||
deleteAllFiles(self):
|
||||
파일 리스트의 모든 파일을 삭제합니다.
|
||||
removeChannelInfo(self, file_path):
|
||||
설정 파일에서 특정 파일의 채널 정보를 제거합니다.
|
||||
clearAlerts(self):
|
||||
알림창의 내용을 지웁니다.
|
||||
showWarning(self, title, message):
|
||||
경고 메시지 박스를 표시합니다.
|
||||
showDuplicateFilesWarning(self, duplicate_files, new_files, new_files_names):
|
||||
중복 파일 경고 메시지 박스를 표시합니다.
|
||||
sortTreeView(self, col, reverse):
|
||||
파일 리스트를 특정 열을 기준으로 정렬합니다.
|
||||
selectAllFiles(self):
|
||||
파일 리스트의 모든 파일을 선택합니다.
|
||||
invertSelection(self):
|
||||
파일 리스트의 선택을 반전시킵니다.
|
||||
setWindowSize(self, size):
|
||||
창의 크기를 설정합니다.
|
||||
openSettings(self):
|
||||
설정 다이얼로그를 엽니다.
|
||||
openAbout(self):
|
||||
프로그램 정보 다이얼로그를 엽니다.
|
||||
populateTreeView(self, file_paths):
|
||||
파일 리스트에 파일을 추가하고 채널 정보를 업데이트합니다.
|
||||
updateAlertText(self, message, file_list):
|
||||
알림창에 메시지를 추가합니다.
|
||||
convertFiles(self):
|
||||
파일을 변환하고 변환 상태를 업데이트합니다.
|
||||
onHeaderClicked(self, logicalIndex):
|
||||
파일 리스트의 헤더를 클릭했을 때 정렬을 수행합니다.
|
||||
onItemDoubleClicked(self, item, column):
|
||||
파일 리스트의 항목을 더블클릭했을 때 파일을 열거나 경로를 엽니다.
|
||||
openChannelDialog(self, item):
|
||||
채널 선택 다이얼로그를 엽니다.
|
||||
applyChannelSelection(self, item, combo, dialog):
|
||||
선택된 채널을 파일 리스트에 적용하고 다이얼로그를 닫습니다.
|
||||
updateChannelInfo(self, directory, filename, channel):
|
||||
설정 파일에 채널 정보를 업데이트합니다.
|
||||
setupCloseEvent(self):
|
||||
프로그램 종료 이벤트를 설정합니다.
|
||||
onClose(self, event):
|
||||
프로그램 종료 시 설정을 초기화하고 저장합니다.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from datetime import datetime
|
||||
import json
|
||||
import subprocess
|
||||
import shutil # 파일 복사를 위해 shutil 모듈 추가
|
||||
|
||||
class MainView(QtWidgets.QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
base_path = sys._MEIPASS # 실행 파일 내에서 파일 경로 설정
|
||||
else:
|
||||
base_path = os.path.abspath(".") # 실행 파일이 아닌 경우 현재 디렉토리로 설정
|
||||
|
||||
icon_path = os.path.join(base_path, "icon/icon.png") # 아이콘 경로 설정
|
||||
self.setWindowIcon(QtGui.QIcon(icon_path)) # 프로그램 아이콘 설정
|
||||
self.version = "1.0.0" # 프로그램 버전 설정
|
||||
self.default_save_path = os.path.join(os.path.expanduser("~"), "Desktop") # 바탕화면 경로 설정
|
||||
self.file_paths = [] # 파일 경로 저장 리스트
|
||||
self.channel_info = {} # 채널 정보 초기화
|
||||
self.channel_options = ["CH0", "CH1", "CH2", "CH3", "CH4", "CH5"] # 채널 옵션 설정
|
||||
self.loadSettings() # 설정 로드
|
||||
self.setupUI(base_path) # UI 설정
|
||||
self.centerWindow() # 창을 화면 중앙에 위치
|
||||
self.sortTreeView(0, True) # 기본 파일명 오름차순 정렬
|
||||
self.setupCloseEvent() # 프로그램 종료 이벤트 설정
|
||||
self.tree.itemSelectionChanged.connect(self.onFileSelectionChanged)
|
||||
|
||||
def loadSettings(self):
|
||||
self.settings_file = "settings.json"
|
||||
if os.path.exists(self.settings_file):
|
||||
with open(self.settings_file, "r", encoding="utf-8") as file:
|
||||
self.settings = json.load(file) # 설정 파일 로드
|
||||
self.default_save_path = self.settings.get("default_save_path", os.path.join(os.path.expanduser("~"), "Desktop"))
|
||||
self.last_opened_dir = self.settings.get("last_opened_dir", os.path.expanduser("~"))
|
||||
# JSON 파일 내의 file_paths와 channel_info 정보 지우기
|
||||
self.settings["file_paths"] = []
|
||||
self.settings["channel_info"] = {}
|
||||
self.saveSettings()
|
||||
else:
|
||||
self.settings = {"theme": "light"} # 기본 설정
|
||||
self.default_save_path = os.path.join(os.path.expanduser("~"), "Desktop") # 바탕화면 경로 설정
|
||||
self.last_opened_dir = os.path.expanduser("~")
|
||||
|
||||
def saveSettings(self):
|
||||
self.settings["default_save_path"] = self.default_save_path
|
||||
self.settings["file_paths"] = self.file_paths
|
||||
self.settings["last_opened_dir"] = self.last_opened_dir
|
||||
with open(self.settings_file, "w", encoding="utf-8") as file:
|
||||
json.dump(self.settings, file, ensure_ascii=False, indent=4) # 설정 파일 저장
|
||||
|
||||
def setupUI(self, base_path):
|
||||
self.setWindowTitle("DBC Converter")
|
||||
self.setGeometry(100, 100, 1250, 600) # 창 크기 조정
|
||||
|
||||
# 메뉴바 추가
|
||||
self.menu_bar = self.menuBar()
|
||||
|
||||
file_menu = self.menu_bar.addMenu("파일")
|
||||
edit_menu = self.menu_bar.addMenu("편집")
|
||||
view_menu = self.menu_bar.addMenu("보기")
|
||||
tools_menu = self.menu_bar.addMenu("도구")
|
||||
|
||||
# 파일 메뉴 항목 추가
|
||||
add_file_action = QtWidgets.QAction("파일 추가", self)
|
||||
add_file_action.setShortcut('Ctrl+O')
|
||||
add_file_action.triggered.connect(self.FilesOpen)
|
||||
file_menu.addAction(add_file_action)
|
||||
|
||||
delete_selected_action = QtWidgets.QAction("선택 파일 삭제", self)
|
||||
delete_selected_action.setShortcut('Delete')
|
||||
delete_selected_action.triggered.connect(self.deleteSelectedFiles)
|
||||
file_menu.addAction(delete_selected_action)
|
||||
|
||||
delete_all_action = QtWidgets.QAction("모든 파일 삭제", self)
|
||||
delete_all_action.setShortcut('Ctrl+Shift+Delete')
|
||||
delete_all_action.triggered.connect(self.deleteAllFiles)
|
||||
file_menu.addAction(delete_all_action)
|
||||
|
||||
# 편집 메뉴 항목 추가
|
||||
select_all_action = QtWidgets.QAction("모두 선택", self)
|
||||
select_all_action.setShortcut('Ctrl+A')
|
||||
select_all_action.triggered.connect(self.selectAllFiles)
|
||||
edit_menu.addAction(select_all_action)
|
||||
|
||||
invert_selection_action = QtWidgets.QAction("선택 반전", self)
|
||||
invert_selection_action.setShortcut('Ctrl+I')
|
||||
invert_selection_action.triggered.connect(self.invertSelection)
|
||||
edit_menu.addAction(invert_selection_action)
|
||||
|
||||
# 보기 메뉴 항목 추가
|
||||
size_menu = view_menu.addMenu("창크기")
|
||||
size_menu.addAction("기본", lambda: self.setWindowSize("default")).setShortcut('Ctrl+0')
|
||||
size_menu.addAction("작게", lambda: self.setWindowSize("small")).setShortcut('Ctrl+1')
|
||||
size_menu.addAction("보통", lambda: self.setWindowSize("medium")).setShortcut('Ctrl+2')
|
||||
size_menu.addAction("크게", lambda: self.setWindowSize("large")).setShortcut('Ctrl+3')
|
||||
size_menu.addAction("자동", lambda: self.setWindowSize("auto")).setShortcut('Ctrl+4')
|
||||
|
||||
sort_menu = view_menu.addMenu("정렬")
|
||||
sort_menu.addAction("파일명 오름차순", lambda: self.sortTreeView(0, False)).setShortcut('Ctrl+Shift+N')
|
||||
sort_menu.addAction("파일명 내림차순", lambda: self.sortTreeView(0, True)).setShortcut('Ctrl+Shift+M')
|
||||
sort_menu.addAction("파일경로 오름차순", lambda: self.sortTreeView(1, False)).setShortcut('Ctrl+Shift+P')
|
||||
sort_menu.addAction("파일경로 내림차순", lambda: self.sortTreeView(1, True)).setShortcut('Ctrl+Shift+Q')
|
||||
sort_menu.addAction("파일크기 오름차순", lambda: self.sortTreeView(3, False)).setShortcut('Ctrl+Shift+S')
|
||||
sort_menu.addAction("파일크기 내림차순", lambda: self.sortTreeView(3, True)).setShortcut('Ctrl+Shift+T')
|
||||
|
||||
# 도구 메뉴 항목 추가
|
||||
settings_action = QtWidgets.QAction("설정", self)
|
||||
settings_action.setShortcut('Ctrl+P')
|
||||
settings_action.triggered.connect(self.openSettings)
|
||||
tools_menu.addAction(settings_action)
|
||||
|
||||
about_action = QtWidgets.QAction("프로그램 정보", self)
|
||||
about_action.setShortcut('Ctrl+I')
|
||||
about_action.triggered.connect(self.openAbout)
|
||||
tools_menu.addAction(about_action)
|
||||
|
||||
tools_menu.addSeparator() # 구분선 추가
|
||||
|
||||
calculator_action = QtWidgets.QAction("계산기", self)
|
||||
calculator_action.setShortcut('Ctrl+Shift+C')
|
||||
calculator_action.triggered.connect(self.openCalculator)
|
||||
tools_menu.addAction(calculator_action)
|
||||
|
||||
# 툴바 추가
|
||||
self.toolbar = self.addToolBar("Main Toolbar")
|
||||
|
||||
add_file_action_img_path = os.path.join(base_path, "img/add_file.png") # 파일 추가 아이콘 경로 설정
|
||||
add_file_action = QtWidgets.QAction(QtGui.QIcon(add_file_action_img_path), "파일 추가\n(Ctrl+O)", self)
|
||||
add_file_action.triggered.connect(self.FilesOpen)
|
||||
self.toolbar.addAction(add_file_action)
|
||||
|
||||
delete_file_action_img_path = os.path.join(base_path, "img/delete_file.png") # 파일 삭제 아이콘 경로 설정
|
||||
delete_file_action = QtWidgets.QAction(QtGui.QIcon(delete_file_action_img_path), "선택 파일 삭제\n(Delete)", self)
|
||||
delete_file_action.triggered.connect(self.deleteSelectedFiles)
|
||||
self.toolbar.addAction(delete_file_action)
|
||||
|
||||
delete_all_action_img_path = os.path.join(base_path, "img/delete_all.png") # 모든 파일 삭제 아이콘 경로 설정
|
||||
delete_all_action = QtWidgets.QAction(QtGui.QIcon(delete_all_action_img_path), "모든 파일 삭제\n(Ctrl+Shift+Delete)", self)
|
||||
delete_all_action.triggered.connect(self.deleteAllFiles)
|
||||
self.toolbar.addAction(delete_all_action)
|
||||
|
||||
delete_description_action_img_path = os.path.join(base_path, "img/delete_description.png") # 메시지 창 내용 삭제 아이콘 경로 설정
|
||||
delete_description_action = QtWidgets.QAction(QtGui.QIcon(delete_description_action_img_path), "메시지 창 내용 삭제\n(Ctrl+Shift+D)", self)
|
||||
delete_description_action.triggered.connect(self.clearAlerts)
|
||||
self.toolbar.addAction(delete_description_action)
|
||||
|
||||
convert_action_img_path = os.path.join(base_path, "img/convert.png") # 변환 아이콘 경로 설정
|
||||
convert_action = QtWidgets.QAction(QtGui.QIcon(convert_action_img_path), "변환\n(Ctrl+R)", self)
|
||||
convert_action.triggered.connect(self.convertFiles)
|
||||
self.toolbar.addAction(convert_action)
|
||||
|
||||
# 상태바 추가
|
||||
self.status_bar = self.statusBar()
|
||||
self.status_bar.showMessage("준비 완료")
|
||||
self.progress_bar = QtWidgets.QProgressBar()
|
||||
self.progress_bar.setMaximumWidth(200)
|
||||
self.status_bar.addPermanentWidget(self.progress_bar)
|
||||
self.progress_bar.setVisible(False)
|
||||
|
||||
# 메인 위젯 설정
|
||||
main_widget = QtWidgets.QWidget()
|
||||
self.setCentralWidget(main_widget)
|
||||
main_layout = QtWidgets.QHBoxLayout(main_widget)
|
||||
|
||||
# 파일 리스트 설정
|
||||
file_list_widget = QtWidgets.QWidget()
|
||||
file_list_layout = QtWidgets.QVBoxLayout(file_list_widget)
|
||||
self.tree = QtWidgets.QTreeWidget()
|
||||
self.tree.setColumnCount(4)
|
||||
self.tree.setHeaderLabels(['파일명', '파일경로', '채널', '파일크기'])
|
||||
self.tree.setColumnWidth(0, 400) # 파일명 너비 설정
|
||||
self.tree.setColumnWidth(1, 450) # 파일경로 너비 설정
|
||||
self.tree.setColumnWidth(2, 50) # 채널 너비 설정
|
||||
self.tree.setColumnWidth(3, 50) # 파일크기 너비 설정
|
||||
self.tree.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
self.tree.header().sectionClicked.connect(self.onHeaderClicked)
|
||||
self.tree.itemDoubleClicked.connect(self.onItemDoubleClicked)
|
||||
|
||||
# 헤더 라벨 가운데 정렬
|
||||
header = self.tree.header()
|
||||
for i in range(self.tree.columnCount()):
|
||||
header.setDefaultAlignment(QtCore.Qt.AlignCenter)
|
||||
|
||||
file_list_layout.addWidget(self.tree)
|
||||
|
||||
# 저장 경로 설정 위젯 추가
|
||||
path_layout = QtWidgets.QHBoxLayout()
|
||||
self.path_label = QtWidgets.QLabel("저장 경로:")
|
||||
self.path_edit = QtWidgets.QLineEdit(self.default_save_path)
|
||||
self.path_edit.setReadOnly(True) # 읽기 전용으로 설정
|
||||
self.path_button = QtWidgets.QPushButton("경로 선택")
|
||||
self.path_button.clicked.connect(self.selectSavePath)
|
||||
self.open_path_button = QtWidgets.QPushButton("경로 열기")
|
||||
self.open_path_button.clicked.connect(self.openSavePath)
|
||||
path_layout.addWidget(self.path_label)
|
||||
path_layout.addWidget(self.path_edit)
|
||||
path_layout.addWidget(self.path_button)
|
||||
path_layout.addWidget(self.open_path_button)
|
||||
file_list_layout.addLayout(path_layout)
|
||||
|
||||
# 알림창 설정
|
||||
self.alert_text = QtWidgets.QTextEdit()
|
||||
self.alert_text.setReadOnly(True)
|
||||
self.alert_text.setAcceptRichText(True)
|
||||
file_list_layout.addWidget(self.alert_text)
|
||||
|
||||
main_layout.addWidget(file_list_widget)
|
||||
|
||||
# 설정 창 추가
|
||||
self.settings_panel = self.createSettingsPanel()
|
||||
self.settings_panel.setFixedWidth(200) # 너비를 200으로 설정
|
||||
main_layout.addWidget(self.settings_panel, 0)
|
||||
|
||||
def createSettingsPanel(self):
|
||||
settings_panel = QtWidgets.QWidget()
|
||||
settings_layout = QtWidgets.QVBoxLayout(settings_panel)
|
||||
|
||||
settings_label = QtWidgets.QLabel("설정")
|
||||
settings_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||
settings_label.setStyleSheet("font-weight: bold; font-size: 14px;") # 글자를 굵게 하고 크기를 16px로 설정
|
||||
settings_layout.addWidget(settings_label)
|
||||
|
||||
# 설정 라벨과 채널 선택 라벨 사이에 작은 간격 추가
|
||||
settings_layout.addSpacing(20) # 10 픽셀 간격 추가
|
||||
|
||||
# 채널 선택 드롭다운 메뉴 추가
|
||||
channel_label = QtWidgets.QLabel("# 채널 선택")
|
||||
channel_label.setAlignment(QtCore.Qt.AlignLeft)
|
||||
settings_layout.addWidget(channel_label)
|
||||
|
||||
self.channel_combo = QtWidgets.QComboBox()
|
||||
self.channel_combo.addItems(self.channel_options)
|
||||
self.channel_combo.setEnabled(False) # 초기에는 비활성화
|
||||
self.channel_combo.currentIndexChanged.connect(self.onChannelChanged)
|
||||
settings_layout.addWidget(self.channel_combo)
|
||||
|
||||
# 상단 정렬을 위해 빈 공간 추가
|
||||
settings_layout.addStretch()
|
||||
|
||||
return settings_panel
|
||||
|
||||
def onFileSelectionChanged(self):
|
||||
selected_items = self.tree.selectedItems()
|
||||
if selected_items:
|
||||
self.channel_combo.setEnabled(True)
|
||||
current_channel = selected_items[0].text(2)
|
||||
self.channel_combo.setCurrentText(current_channel)
|
||||
else:
|
||||
self.channel_combo.setEnabled(False)
|
||||
|
||||
def onChannelChanged(self):
|
||||
selected_items = self.tree.selectedItems()
|
||||
if selected_items:
|
||||
new_channel = self.channel_combo.currentText()
|
||||
for item in selected_items:
|
||||
item.setText(2, new_channel)
|
||||
self.updateChannelInfo(item.text(1), item.text(0), new_channel)
|
||||
self.updateAlertText(f"채널 변경", [f"{item.text(0)}의 채널이 {new_channel}(으)로 변경되었습니다." for item in selected_items])
|
||||
|
||||
def selectSavePath(self):
|
||||
selected_path = QtWidgets.QFileDialog.getExistingDirectory(self, "저장 경로 선택", self.default_save_path)
|
||||
if selected_path:
|
||||
self.default_save_path = selected_path
|
||||
self.path_edit.setText(selected_path)
|
||||
|
||||
def openSavePath(self):
|
||||
if os.path.exists(self.default_save_path):
|
||||
os.startfile(self.default_save_path)
|
||||
else:
|
||||
self.showWarning("경고", "경로가 존재하지 않습니다")
|
||||
|
||||
def openCalculator(self):
|
||||
subprocess.Popen('calc.exe')
|
||||
|
||||
def centerWindow(self):
|
||||
frame_geometry = self.frameGeometry()
|
||||
screen_center = QtWidgets.QDesktopWidget().availableGeometry().center()
|
||||
frame_geometry.moveCenter(screen_center)
|
||||
self.move(frame_geometry.topLeft())
|
||||
|
||||
def centerDialog(self, dialog):
|
||||
dialog_geometry = dialog.frameGeometry()
|
||||
dialog_geometry.moveCenter(self.frameGeometry().center())
|
||||
dialog.move(dialog_geometry.topLeft())
|
||||
|
||||
def FilesOpen(self):
|
||||
file_paths, _ = QtWidgets.QFileDialog.getOpenFileNames(
|
||||
self, "파일 열기", self.last_opened_dir, "DBC 파일 (*.dbc);;모든 파일 (*.*)"
|
||||
)
|
||||
if file_paths:
|
||||
self.last_opened_dir = os.path.dirname(file_paths[0])
|
||||
self.file_paths = file_paths # 새로운 경로로 덮어쓰기
|
||||
existing_files = [self.tree.topLevelItem(i).text(0) for i in range(self.tree.topLevelItemCount())]
|
||||
duplicate_files = [os.path.split(file_path)[1] for file_path in file_paths if os.path.split(file_path)[1] in existing_files]
|
||||
new_files = [file_path for file_path in file_paths if os.path.split(file_path)[1] not in existing_files]
|
||||
|
||||
if duplicate_files:
|
||||
self.showDuplicateFilesWarning(duplicate_files, new_files, [os.path.split(file_path)[1] for file_path in new_files])
|
||||
self.updateAlertText(f"중복 파일 경고", duplicate_files)
|
||||
if new_files:
|
||||
self.populateTreeView(new_files)
|
||||
self.updateAlertText(f"파일 추가 완료", [os.path.split(file_path)[1] for file_path in new_files])
|
||||
self.saveSettings()
|
||||
|
||||
def deleteSelectedFiles(self):
|
||||
selected_items = self.tree.selectedItems()
|
||||
if not selected_items:
|
||||
self.showWarning("경고", "선택된 파일이 없습니다")
|
||||
self.updateAlertText("파일 삭제 실패", ["선택된 파일이 없습니다"])
|
||||
return
|
||||
deleted_files = [item.text(0) for item in selected_items]
|
||||
for item in selected_items:
|
||||
index = self.tree.indexOfTopLevelItem(item)
|
||||
file_path = os.path.join(item.text(1), item.text(0))
|
||||
self.removeChannelInfo(file_path) # 채널 정보 제거
|
||||
self.tree.takeTopLevelItem(index)
|
||||
self.file_paths = [self.tree.topLevelItem(i).text(1) + '/' + self.tree.topLevelItem(i).text(0) for i in range(self.tree.topLevelItemCount())]
|
||||
self.updateAlertText(f"파일 삭제 완료", deleted_files)
|
||||
self.saveSettings()
|
||||
|
||||
def deleteAllFiles(self):
|
||||
if self.tree.topLevelItemCount() == 0:
|
||||
self.showWarning("경고", "삭제할 파일이 없습니다")
|
||||
self.updateAlertText("모든 파일 삭제 실패", ["삭제할 파일이 없습니다"])
|
||||
return
|
||||
deleted_files = [self.tree.topLevelItem(i).text(0) for i in range(self.tree.topLevelItemCount())]
|
||||
for i in range(self.tree.topLevelItemCount()):
|
||||
item = self.tree.topLevelItem(i)
|
||||
file_path = os.path.join(item.text(1), item.text(0))
|
||||
self.removeChannelInfo(file_path) # 채널 정보 제거
|
||||
self.tree.clear()
|
||||
self.file_paths = []
|
||||
self.updateAlertText(f"모든 파일 삭제 완료", deleted_files)
|
||||
self.saveSettings()
|
||||
|
||||
def removeChannelInfo(self, file_path):
|
||||
if "channel_info" in self.settings and file_path in self.settings["channel_info"]:
|
||||
del self.settings["channel_info"][file_path]
|
||||
self.saveSettings()
|
||||
print(f"[INFO] Removed channel info for {file_path}")
|
||||
|
||||
def clearAlerts(self):
|
||||
self.alert_text.clear()
|
||||
|
||||
def showWarning(self, title, message):
|
||||
warning_box = QtWidgets.QMessageBox(self)
|
||||
warning_box.setIcon(QtWidgets.QMessageBox.Warning)
|
||||
warning_box.setWindowTitle(title)
|
||||
warning_box.setText(message)
|
||||
warning_box.exec_()
|
||||
|
||||
def showDuplicateFilesWarning(self, duplicate_files, new_files, new_files_names):
|
||||
duplicate_files_str = "\n".join(duplicate_files)
|
||||
new_files_str = "\n".join(new_files_names)
|
||||
if new_files:
|
||||
self.showWarning("중복 파일 경고", f"**중복 파일이 존재합니다**\n\n{duplicate_files_str}\n\n\n**중복 파일을 제외한 신규 파일을 추가합니다**\n\n{new_files_str}")
|
||||
else:
|
||||
self.showWarning("중복 파일 경고", f"**중복 파일이 존재합니다**\n\n{duplicate_files_str}")
|
||||
|
||||
def sortTreeView(self, col, reverse):
|
||||
items = []
|
||||
for i in range(self.tree.topLevelItemCount()):
|
||||
item = self.tree.takeTopLevelItem(0)
|
||||
items.append(item)
|
||||
if col == 3: # 파일크기 정렬
|
||||
items.sort(key=lambda x: float(x.text(col).replace(" KB", "")), reverse=reverse)
|
||||
else:
|
||||
items.sort(key=lambda x: x.text(col), reverse=reverse)
|
||||
for item in items:
|
||||
self.tree.addTopLevelItem(item)
|
||||
|
||||
def selectAllFiles(self):
|
||||
for i in range(self.tree.topLevelItemCount()):
|
||||
self.tree.topLevelItem(i).setSelected(True)
|
||||
|
||||
def invertSelection(self):
|
||||
for i in range(self.tree.topLevelItemCount()):
|
||||
item = self.tree.topLevelItem(i)
|
||||
item.setSelected(not item.isSelected())
|
||||
|
||||
def setWindowSize(self, size):
|
||||
if size == "small":
|
||||
self.resize(600, 400)
|
||||
elif size == "medium":
|
||||
self.resize(800, 600)
|
||||
elif size == "large":
|
||||
self.resize(1200, 1000)
|
||||
elif size == "default":
|
||||
self.resize(1250, 600)
|
||||
elif size == "auto":
|
||||
self.adjustSize()
|
||||
|
||||
def openSettings(self):
|
||||
settings_window = QtWidgets.QDialog(self)
|
||||
settings_window.setWindowTitle("설정")
|
||||
settings_window.setGeometry(100, 100, 400, 300)
|
||||
layout = QtWidgets.QVBoxLayout(settings_window)
|
||||
label = QtWidgets.QLabel("설정 창입니다.")
|
||||
label.setAlignment(QtCore.Qt.AlignCenter)
|
||||
layout.addWidget(label)
|
||||
self.centerDialog(settings_window)
|
||||
settings_window.exec_()
|
||||
|
||||
def openAbout(self):
|
||||
about_window = QtWidgets.QDialog(self)
|
||||
about_window.setWindowTitle("프로그램 정보")
|
||||
about_window.setGeometry(100, 100, 400, 300)
|
||||
layout = QtWidgets.QVBoxLayout(about_window)
|
||||
|
||||
label1 = QtWidgets.QLabel("이 프로그램은 DBC 파일을 C 파일로 변환합니다.")
|
||||
label1.setAlignment(QtCore.Qt.AlignCenter)
|
||||
|
||||
label3 = QtWidgets.QLabel(f"버전: {self.version}")
|
||||
label3.setAlignment(QtCore.Qt.AlignCenter)
|
||||
|
||||
layout.addWidget(label1)
|
||||
layout.addWidget(label3)
|
||||
self.centerDialog(about_window)
|
||||
about_window.exec_()
|
||||
|
||||
def populateTreeView(self, file_paths):
|
||||
def format_file_size(size_in_bytes):
|
||||
size_in_kb = size_in_bytes / 1024
|
||||
return f"{size_in_kb:.2f} KB"
|
||||
|
||||
for file_path in file_paths:
|
||||
directory, file = os.path.split(file_path)
|
||||
fsize = format_file_size(os.path.getsize(file_path))
|
||||
item = QtWidgets.QTreeWidgetItem([file, directory, self.channel_options[0], fsize])
|
||||
self.tree.addTopLevelItem(item)
|
||||
self.updateChannelInfo(directory, file, self.channel_options[0]) # 기본 채널을 0으로 설정
|
||||
self.file_paths = [self.tree.topLevelItem(i).text(1) + '/' + self.tree.topLevelItem(i).text(0) for i in range(self.tree.topLevelItemCount())]
|
||||
self.saveSettings()
|
||||
|
||||
def updateAlertText(self, message, file_list):
|
||||
current_time = QtCore.QDateTime.currentDateTime().toString("yy-MM-dd-ddd HH:mm:ss")
|
||||
self.alert_text.append(f"[{current_time}] {message}")
|
||||
for file in file_list:
|
||||
self.alert_text.append(f" - {file}")
|
||||
self.alert_text.append("") # 한 줄 띄우기
|
||||
|
||||
def convertFiles(self):
|
||||
if not self.file_paths:
|
||||
self.showWarning("경고", "변환할 파일이 없습니다")
|
||||
self.updateAlertText("변환 실패", ["변환할 파일이 없습니다"])
|
||||
return
|
||||
self.status_bar.showMessage("변환 중...")
|
||||
self.progress_bar.setVisible(True)
|
||||
self.progress_bar.setValue(0)
|
||||
total_files = len(self.file_paths)
|
||||
timestamp = datetime.now().strftime("%y-%m-%d-%a-%H-%M-%S") # 날짜 및 시간 형식 변경
|
||||
base_output_dir = os.path.join(self.default_save_path, "DBC 변환", timestamp)
|
||||
for index, file_path in enumerate(self.file_paths):
|
||||
file_name = os.path.splitext(os.path.basename(file_path))[0]
|
||||
rx_output_dir = os.path.join(base_output_dir, file_name, "RX")
|
||||
tx_output_dir = os.path.join(base_output_dir, file_name, "TX")
|
||||
common_output_dir = os.path.join(base_output_dir, file_name, "Common")
|
||||
dbc_output_dir = os.path.join(base_output_dir, "#DBC") # DBC 파일 저장 경로 설정
|
||||
os.makedirs(rx_output_dir, exist_ok=True)
|
||||
os.makedirs(tx_output_dir, exist_ok=True)
|
||||
os.makedirs(common_output_dir, exist_ok=True)
|
||||
os.makedirs(dbc_output_dir, exist_ok=True) # DBC 파일 저장 경로 생성
|
||||
channel_info = self.settings.get("channel_info", {}).get(os.path.basename(file_path), "CH0")
|
||||
try:
|
||||
shutil.copy(file_path, dbc_output_dir) # DBC 파일 복사
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
script_path = os.path.join(sys._MEIPASS, "DBC_Converter_RX.py")
|
||||
else:
|
||||
script_path = "DBC_Converter_RX.py"
|
||||
subprocess.run(["python", script_path, file_path, rx_output_dir, json.dumps({os.path.basename(file_path): channel_info})], check=True)
|
||||
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
script_path = os.path.join(sys._MEIPASS, "DBC_Converter_TX.py")
|
||||
else:
|
||||
script_path = "DBC_Converter_TX.py"
|
||||
subprocess.run(["python", script_path, file_path, tx_output_dir, json.dumps({os.path.basename(file_path): channel_info})], check=True)
|
||||
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
script_path = os.path.join(sys._MEIPASS, "DBC_Converter_Common.py")
|
||||
else:
|
||||
script_path = "DBC_Converter_Common.py"
|
||||
subprocess.run(["python", script_path, file_path, common_output_dir, json.dumps({os.path.basename(file_path): channel_info})], check=True)
|
||||
|
||||
self.updateAlertText(f"변환 성공", [file_path])
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.updateAlertText(f"변환 실패: {e}", [file_path])
|
||||
self.progress_bar.setValue(int((index + 1) / total_files * 100))
|
||||
self.status_bar.showMessage("변환 완료")
|
||||
self.progress_bar.setVisible(False)
|
||||
|
||||
def onHeaderClicked(self, logicalIndex):
|
||||
header = self.tree.headerItem()
|
||||
if header.text(logicalIndex).endswith("▲"):
|
||||
self.sortTreeView(logicalIndex, True)
|
||||
header.setText(logicalIndex, header.text(logicalIndex).replace("▲", "▼"))
|
||||
else:
|
||||
self.sortTreeView(logicalIndex, False)
|
||||
header.setText(logicalIndex, header.text(logicalIndex).replace("▼", "▲"))
|
||||
|
||||
def onItemDoubleClicked(self, item, column):
|
||||
if column == 0: # 파일명을 더블클릭한 경우
|
||||
file_path = os.path.join(item.text(1), item.text(0))
|
||||
os.startfile(file_path)
|
||||
elif column == 1: # 경로를 더블클릭한 경우
|
||||
os.startfile(item.text(1))
|
||||
elif column == 2: # 채널을 더블클릭한 경우
|
||||
self.openChannelDialog(item)
|
||||
|
||||
def openChannelDialog(self, item):
|
||||
channel_dialog = QtWidgets.QDialog(self)
|
||||
channel_dialog.setWindowTitle("채널 선택")
|
||||
channel_dialog.setGeometry(100, 100, 200, 100)
|
||||
layout = QtWidgets.QVBoxLayout(channel_dialog)
|
||||
|
||||
channel_combo = QtWidgets.QComboBox()
|
||||
channel_combo.addItems(self.channel_options)
|
||||
current_channel = item.text(2)
|
||||
channel_combo.setCurrentText(current_channel) # 현재 채널을 콤보박스에 설정
|
||||
layout.addWidget(channel_combo)
|
||||
|
||||
button_layout = QtWidgets.QHBoxLayout()
|
||||
apply_button = QtWidgets.QPushButton("확인")
|
||||
apply_button.clicked.connect(lambda: self.applyChannelSelection(item, channel_combo, channel_dialog))
|
||||
button_layout.addWidget(apply_button)
|
||||
|
||||
cancel_button = QtWidgets.QPushButton("취소")
|
||||
cancel_button.clicked.connect(channel_dialog.close)
|
||||
button_layout.addWidget(cancel_button)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
self.centerDialog(channel_dialog)
|
||||
channel_dialog.exec_()
|
||||
|
||||
def applyChannelSelection(self, item, combo, dialog):
|
||||
item.setText(2, combo.currentText())
|
||||
self.updateChannelInfo(item.text(1), item.text(0), combo.currentText()) # 채널 정보 업데이트
|
||||
dialog.close()
|
||||
|
||||
def updateChannelInfo(self, directory, filename, channel):
|
||||
file_path = os.path.join(directory, filename)
|
||||
file_name = os.path.basename(file_path)
|
||||
if "channel_info" not in self.settings:
|
||||
self.settings["channel_info"] = {}
|
||||
|
||||
self.settings["channel_info"][file_name] = channel
|
||||
self.saveSettings()
|
||||
print(f"[INFO] Updated channel info for {file_name} to {channel}")
|
||||
|
||||
def setupCloseEvent(self):
|
||||
self.closeEvent = self.onClose # 종료 이벤트 핸들러 설정
|
||||
|
||||
def onClose(self, event):
|
||||
self.file_paths = [] # 파일 경로 초기화
|
||||
self.settings["file_paths"] = [] # 설정 파일 경로 초기화
|
||||
self.settings["channel_info"] = {} # 채널 정보 초기화
|
||||
self.saveSettings() # 설정 저장
|
||||
event.accept() # 종료 이벤트 수락
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
main_view = MainView()
|
||||
main_view.show()
|
||||
sys.exit(app.exec_())
|
||||
77
dist/DBC Converter/_internal/DBC_Converter_Common.py
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
import os
|
||||
import sys
|
||||
from DBC_Converter_Data_Parsing import load_dbc_file
|
||||
|
||||
def generate_structs(signals, output_file):
|
||||
if not signals:
|
||||
print("[WARNING] No signals to generate structs for.")
|
||||
return
|
||||
|
||||
# Ensure the output directory exists
|
||||
output_dir = os.path.dirname(output_file)
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
f.write("#ifndef GENERATED_STRUCTS_H\n")
|
||||
f.write("#define GENERATED_STRUCTS_H\n\n")
|
||||
f.write("#include <stdint.h>\n\n")
|
||||
|
||||
tx_structs = {}
|
||||
rx_structs = {}
|
||||
|
||||
for message_name, message_info in signals.items():
|
||||
hex_id = message_info["ID"]
|
||||
|
||||
if message_info["TX ECU name"] == "VCU":
|
||||
struct_name = f"{message_name}_{hex_id}"
|
||||
tx_structs[struct_name] = []
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["Length"] <= 32:
|
||||
tx_structs[struct_name].append(f" uint32_t {signal['Signal name']} : {signal['Length']};")
|
||||
else:
|
||||
tx_structs[struct_name].append(f" float {signal['Signal name']};")
|
||||
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["RX ECU name"] == "VCU":
|
||||
struct_name = f"{message_name}_{hex_id}"
|
||||
if struct_name not in rx_structs:
|
||||
rx_structs[struct_name] = []
|
||||
if signal["Length"] <= 32:
|
||||
rx_structs[struct_name].append(f" uint32_t {signal['Signal name']} : {signal['Length']};")
|
||||
else:
|
||||
rx_structs[struct_name].append(f" float {signal['Signal name']};")
|
||||
|
||||
f.write("typedef struct {\n")
|
||||
f.write(" typedef struct {\n")
|
||||
for struct_name, fields in tx_structs.items():
|
||||
f.write(f" typedef struct {{\n")
|
||||
for field in fields:
|
||||
f.write(f" {field}\n")
|
||||
f.write(f" }} {struct_name};\n\n")
|
||||
f.write(" } TX;\n\n")
|
||||
|
||||
f.write(" typedef struct {\n")
|
||||
for struct_name, fields in rx_structs.items():
|
||||
f.write(f" typedef struct {{\n")
|
||||
for field in fields:
|
||||
f.write(f" {field}\n")
|
||||
f.write(f" }} {struct_name};\n\n")
|
||||
f.write(" } RX;\n")
|
||||
f.write("} VCU;\n\n")
|
||||
|
||||
f.write("#endif // GENERATED_STRUCTS_H\n")
|
||||
print(f"[INFO] Structs written to {output_file}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
dbc_file_path = sys.argv[1]
|
||||
output_dir = sys.argv[2]
|
||||
|
||||
output_structs_file = f"{output_dir}/generated_structs.h"
|
||||
|
||||
signals = load_dbc_file(dbc_file_path)
|
||||
if signals is None:
|
||||
print(f"[ERROR] Failed to load DBC file: {dbc_file_path}")
|
||||
sys.exit(1)
|
||||
|
||||
generate_structs(signals, output_structs_file)
|
||||
73
dist/DBC Converter/_internal/DBC_Converter_Data_Parsing.py
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
import re, sys
|
||||
|
||||
def load_dbc_file(file_path):
|
||||
try:
|
||||
with open(file_path, 'r') as file:
|
||||
content = file.read()
|
||||
# print(f"[INFO] Successfully loaded DBC file: {file_path}")
|
||||
|
||||
# 메시지와 시그널을 추출하는 정규 표현식
|
||||
message_pattern = re.compile(r'BO_\s+(\d+)\s+(\w+)\s*:\s*(\d+)\s+(\w+)')
|
||||
signal_pattern = re.compile(r'SG_\s+(\w+)\s*:\s*(\d+)\|(\d+)@(\d+)([+-])\s*\(([^,]+),\s*([^)]+)\)\s*\[[^\]]+\]\s*\"[^\"]*\"\s+(\w+)')
|
||||
|
||||
# 메시지와 시그널 매칭
|
||||
messages = {}
|
||||
current_message = None
|
||||
|
||||
for line in content.splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
current_message = None
|
||||
continue
|
||||
|
||||
message_match = message_pattern.match(line)
|
||||
if message_match:
|
||||
decimal_id = int(message_match.group(1))
|
||||
hex_id = f"0x{decimal_id:03X}"
|
||||
message_name = message_match.group(2)
|
||||
dlc = int(message_match.group(3))
|
||||
tx_ecu_name = message_match.group(4)
|
||||
current_message = message_name
|
||||
messages[current_message] = {
|
||||
"ID": hex_id,
|
||||
"DLC": dlc,
|
||||
"TX ECU name": tx_ecu_name,
|
||||
"Signals": []
|
||||
}
|
||||
elif current_message:
|
||||
signal_match = signal_pattern.match(line)
|
||||
if signal_match:
|
||||
signal_name = signal_match.group(1)
|
||||
msb = int(signal_match.group(2))
|
||||
length = int(signal_match.group(3))
|
||||
byte_order = int(signal_match.group(4))
|
||||
sign = signal_match.group(5)
|
||||
factor = float(signal_match.group(6))
|
||||
offset = float(signal_match.group(7))
|
||||
rx_ecu_name = signal_match.group(8)
|
||||
messages[current_message]["Signals"].append({
|
||||
"Signal name": signal_name,
|
||||
"msb": msb,
|
||||
"Length": length,
|
||||
"Byte order": byte_order,
|
||||
"Sign": sign,
|
||||
"Factor": factor,
|
||||
"Offset": offset,
|
||||
"RX ECU name": rx_ecu_name
|
||||
})
|
||||
|
||||
return messages
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to parse DBC file: {e}")
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
file_path = sys.argv[1]
|
||||
messages = load_dbc_file(file_path)
|
||||
|
||||
if messages:
|
||||
for message_name, message_info in messages.items():
|
||||
print(f"[INFO] Message: {message_name}, Info: {message_info['ID']}, {message_info['DLC']}, {message_info['TX ECU name']}")
|
||||
for signal in message_info['Signals']:
|
||||
print(f" └ Signal: {signal}")
|
||||
207
dist/DBC Converter/_internal/DBC_Converter_RX.py
vendored
Normal file
@ -0,0 +1,207 @@
|
||||
import sys
|
||||
from DBC_Converter_Data_Parsing import load_dbc_file
|
||||
|
||||
#============================== Generate Globals ==============================#
|
||||
def generate_globals(signals, C_file, header_file):
|
||||
if not signals:
|
||||
print("[WARNING] No signals to generate globals for.")
|
||||
return
|
||||
|
||||
with open(C_file, 'w') as f:
|
||||
f.write("#include <generated_RX_globals.h>\n")
|
||||
|
||||
for message_name, message_info in signals.items():
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["Length"] > 32:
|
||||
f.write(f"float GV_{signal['Signal name']} = 0.0f;\n")
|
||||
else:
|
||||
f.write(f"uint32_t GV_{signal['Signal name']} = 0;\n")
|
||||
|
||||
with open(header_file, 'w') as f:
|
||||
f.write("#ifndef GENERATED_GLOBALS_H\n")
|
||||
f.write("#define GENERATED_GLOBALS_H\n\n")
|
||||
f.write("#include <stdint.h>\n\n")
|
||||
for message_name, message_info in signals.items():
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["Length"] > 32:
|
||||
f.write(f"extern float GV_{signal['Signal name']};\n")
|
||||
else:
|
||||
f.write(f"extern uint32_t GV_{signal['Signal name']};\n")
|
||||
f.write("\n#endif // GENERATED_GLOBALS_H\n")
|
||||
print(f"[INFO] Globals and extern declarations written to {C_file} and {header_file}")
|
||||
|
||||
#============================== Generate VCU RX Function ==============================#
|
||||
def generate_vcu_rx_function_with_factors(signals, output_file):
|
||||
if not signals:
|
||||
print("[ERROR] No signals to generate VCU RX functions for.")
|
||||
return
|
||||
|
||||
# Initialize the header of the C file
|
||||
c_file_content = """
|
||||
#include "can.h"
|
||||
|
||||
// Declare Factors and Offsets for signals
|
||||
"""
|
||||
|
||||
# Collect unique Factors and Offsets
|
||||
factors_offsets = {}
|
||||
for message_name, message_info in signals.items():
|
||||
for signal in message_info["Signals"]:
|
||||
factor_name = f"Factor_{str(signal['Factor']).replace('.', '_')}"
|
||||
offset_name = f"Offset_m_{abs(signal['Offset']):.0f}"
|
||||
if signal['Factor'] != 1:
|
||||
factors_offsets[factor_name] = signal['Factor']
|
||||
if signal['Offset'] != 0:
|
||||
factors_offsets[offset_name] = signal['Offset']
|
||||
|
||||
# Add Factor and Offset variable declarations
|
||||
for name, value in factors_offsets.items():
|
||||
c_file_content += f"const float {name} = {value};\n"
|
||||
|
||||
# Add a newline for separation
|
||||
c_file_content += "\n"
|
||||
|
||||
# Iterate through all messages in the signals
|
||||
for message_name, message_info in signals.items():
|
||||
# Define the temporary struct
|
||||
temp_struct_name = f"{message_name}_temp"
|
||||
|
||||
# Check if any signal in the message has RX ECU name as VCU
|
||||
has_vcu_signal = any(signal["RX ECU name"] == "VCU" for signal in message_info["Signals"])
|
||||
if not has_vcu_signal:
|
||||
continue # Skip this message if no signal has RX ECU name as VCU
|
||||
|
||||
c_file_content += f"""
|
||||
void Receive_{message_name}_{message_info['ID']}(void)
|
||||
{{
|
||||
struct {{
|
||||
"""
|
||||
|
||||
# Add temporary variables to the struct
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["RX ECU name"] != "VCU":
|
||||
continue # RX ECU name이 VCU가 아닌 경우 건너뜁니다.
|
||||
if signal["Sign"] == "-":
|
||||
signal_type = "signed int"
|
||||
elif signal["Sign"] == "+":
|
||||
signal_type = "unsigned int"
|
||||
|
||||
c_file_content += f" {signal_type} {signal['Signal name']}_temp : {signal['Length']};\n"
|
||||
|
||||
c_file_content += f" }} {temp_struct_name};\n\n"
|
||||
|
||||
# Add temp assignments
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["RX ECU name"] != "VCU":
|
||||
continue # RX ECU name이 VCU가 아닌 경우 건너뜁니다.
|
||||
start_byte = signal["msb"] // 8
|
||||
start_bit = signal["msb"] % 8
|
||||
signal_length = signal["Length"]
|
||||
if signal["Byte order"] == 0: # Motorola (Big Endian)
|
||||
lsb = signal["msb"] + 8*(signal_length // 8) - (signal_length % 8 - 1)
|
||||
if signal_length > 8:
|
||||
# Handle multi-byte signals
|
||||
shift_expr = f"(CAN_ch[0].rx.buf[{start_byte}] << shift{7 - start_bit})"
|
||||
multi_byte_expr = []
|
||||
for i in range((signal_length + 7) // 8):
|
||||
byte_shift = (7 - start_bit) + (i * 8)
|
||||
if i == 0:
|
||||
multi_byte_expr.append(f"(CAN_ch[0].rx.buf[{start_byte + i}] << shift{7 - start_bit})")
|
||||
else:
|
||||
multi_byte_expr.append(f"(CAN_ch[0].rx.buf[{start_byte + i}] >> shift{byte_shift})")
|
||||
shift_expr = " | ".join(multi_byte_expr)
|
||||
else :
|
||||
shift_expr = f"(CAN_ch[0].rx.buf[{start_byte}] >> shift{lsb % 8})"
|
||||
else: # Intel (Little Endian)
|
||||
shift_expr = f"(CAN_ch[0].rx.buf[{start_byte}] >> shift{start_bit})"
|
||||
if signal_length > 8:
|
||||
# Handle multi-byte signals
|
||||
multi_byte_expr = []
|
||||
for i in range((signal_length + 7) // 8):
|
||||
byte_shift = i * 8
|
||||
if i == 0:
|
||||
multi_byte_expr.append(f"(CAN_ch[0].rx.buf[{start_byte + i}] >> shift{start_bit})")
|
||||
else:
|
||||
multi_byte_expr.append(f"(CAN_ch[0].rx.buf[{start_byte + i}] << shift{byte_shift})")
|
||||
shift_expr = " | ".join(multi_byte_expr)
|
||||
c_file_content += f" {temp_struct_name}.{signal['Signal name']}_temp = ({shift_expr}) & _{signal_length}bit;\n"
|
||||
|
||||
c_file_content += "\n"
|
||||
|
||||
# Assign to final ECU variables
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["RX ECU name"] != "VCU":
|
||||
continue # RX ECU name이 VCU가 아닌 경우 건너뜁니다.
|
||||
factor_name = f"Factor_{str(signal['Factor']).replace('.', '_')}"
|
||||
offset_name = f"Offset_m_{abs(signal['Offset']):.0f}"
|
||||
factor = f" * {factor_name}" if signal['Factor'] != 1 else ""
|
||||
offset = f" + {offset_name}" if signal['Offset'] != 0 else ""
|
||||
temp_var = f"{temp_struct_name}.{signal['Signal name']}_temp"
|
||||
c_file_content += f" VCU.RX.{message_name}_{message_info['ID']}.{signal['Signal name']} = ({temp_var}{factor}){offset};\n"
|
||||
|
||||
c_file_content += "}\n"
|
||||
|
||||
# Write the generated code to a single C file
|
||||
with open(output_file, "w") as c_file:
|
||||
c_file.write(c_file_content)
|
||||
print(f"Generated RX function C file with Factors and Offsets: {output_file}")
|
||||
|
||||
#============================== Generate Input Function ==============================#
|
||||
def generate_input_functions(signals, output_file):
|
||||
if not signals:
|
||||
print("[WARNING] No signals to generate Input functions for.")
|
||||
return
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
for message_name, message_info in signals.items():
|
||||
hex_id = message_info["ID"]
|
||||
function_name = f"void Input_Data_Set_{message_name}_CH0_{hex_id}(void)"
|
||||
f.write(f"{function_name}\n{{\n")
|
||||
for signal in message_info["Signals"]:
|
||||
f.write(f" GV_{signal['Signal name']} = VCU.RX.CH0_RX_{message_name}_{hex_id}.{signal['Signal name']};\n")
|
||||
f.write("}\n\n")
|
||||
print(f"[INFO] Input functions written to {output_file}")
|
||||
|
||||
#============================== Generate Initialization ==============================#
|
||||
def generate_initialization(signals, output_file):
|
||||
if not signals:
|
||||
print("[WARNING] No signals to generate initialization for.")
|
||||
return
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
f.write("void VCU_Data_Init(void)\n{\n")
|
||||
for message_name, message_info in signals.items():
|
||||
hex_id = message_info["ID"]
|
||||
struct_prefix = f"VCU.RX.CH0_RX_{message_name}_{hex_id}"
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["Offset"] != 0.0:
|
||||
if signal["Length"] <= 32:
|
||||
f.write(f" {struct_prefix}.{signal['Signal name']} = {signal['Offset']};\n")
|
||||
else:
|
||||
f.write(f" {struct_prefix}.{signal['Signal name']} = {signal['Offset']}f;\n")
|
||||
else:
|
||||
if signal["Length"] <= 32:
|
||||
f.write(f" {struct_prefix}.{signal['Signal name']} = 0;\n")
|
||||
else:
|
||||
f.write(f" {struct_prefix}.{signal['Signal name']} = 0.0f;\n")
|
||||
f.write("\n")
|
||||
f.write("}\n")
|
||||
print(f"[INFO] Initialization function written to {output_file}")
|
||||
|
||||
#============================== Main ==============================#
|
||||
if __name__ == "__main__":
|
||||
dbc_file_path = sys.argv[1]
|
||||
output_dir = sys.argv[2]
|
||||
|
||||
output_globals_C_file = f"{output_dir}/generated_RX_globals.c"
|
||||
output_globals_header_file = f"{output_dir}/generated_RX_globals.h"
|
||||
output_c_file = f"{output_dir}/generated_RX_receive.c"
|
||||
output_input_file = f"{output_dir}/generated_RX_input.c"
|
||||
output_initialization_file = f"{output_dir}/generated_RX_init.c"
|
||||
|
||||
signals = load_dbc_file(dbc_file_path)
|
||||
|
||||
generate_globals(signals, output_globals_C_file, output_globals_header_file)
|
||||
generate_vcu_rx_function_with_factors(signals, output_c_file)
|
||||
generate_input_functions(signals, output_input_file)
|
||||
generate_initialization(signals, output_initialization_file)
|
||||
192
dist/DBC Converter/_internal/DBC_Converter_TX.py
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
import sys
|
||||
from DBC_Converter_Data_Parsing import load_dbc_file
|
||||
|
||||
|
||||
|
||||
#============================== Generate TX Globals ==============================#
|
||||
def generate_tx_globals(signals, output_file, header_file):
|
||||
if not signals:
|
||||
print("[WARNING] No signals to generate TX globals for.")
|
||||
return
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
for message_name, message_info in signals.items():
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["Length"] > 32:
|
||||
f.write(f"float GV_{signal['Signal name']} = 0.0f;\n")
|
||||
else:
|
||||
f.write(f"uint32_t GV_{signal['Signal name']} = 0;\n")
|
||||
|
||||
with open(header_file, 'w') as f:
|
||||
f.write("#ifndef GENERATED_TX_GLOBALS_H\n")
|
||||
f.write("#define GENERATED_TX_GLOBALS_H\n\n")
|
||||
f.write("#include <stdint.h>\n\n")
|
||||
for message_name, message_info in signals.items():
|
||||
for signal in message_info["Signals"]:
|
||||
if signal["Length"] > 32:
|
||||
f.write(f"extern float GV_{signal['Signal name']};\n")
|
||||
else:
|
||||
f.write(f"extern uint32_t GV_{signal['Signal name']};\n")
|
||||
f.write("\n#endif // GENERATED_TX_GLOBALS_H\n")
|
||||
print(f"[INFO] TX globals written to {output_file} and {header_file}")
|
||||
|
||||
|
||||
#============================== Generate TX Functions ==============================#
|
||||
def generate_tx_functions(signals, output_file):
|
||||
if not signals:
|
||||
print("[WARNING] No signals to generate TX functions for.")
|
||||
return
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
for message_name, message_info in signals.items():
|
||||
hex_id = message_info["ID"]
|
||||
function_name = f"void Output_Data_Set_{message_name}_CH0_{hex_id}(void)"
|
||||
f.write(f"{function_name}\n{{\n")
|
||||
for signal in message_info["Signals"]:
|
||||
factor_str = f"/ {signal['Factor']}" if signal["Factor"] != 1.0 else ""
|
||||
offset_str = f"- {signal['Offset']}" if signal["Offset"] != 0.0 else ""
|
||||
mask = f"_{signal['Length']}bit"
|
||||
f.write(
|
||||
f" VCU.TX.CH0_{message_name}_{hex_id}.{signal['Signal name']} = "
|
||||
f"(int)((GV_{signal['Signal name']} {offset_str}) {factor_str}) & {mask};\n"
|
||||
)
|
||||
f.write("}\n\n")
|
||||
print(f"[INFO] TX functions written to {output_file}")
|
||||
|
||||
|
||||
#============================== Generate TX Initialization ==============================#
|
||||
def generate_tx_initialization(signals, output_file):
|
||||
if not signals:
|
||||
print("[WARNING] No TX signals found for initialization generation.")
|
||||
return
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
f.write("void Initialize_TX_Signals(void)\n{\n")
|
||||
for message_name, message_info in signals.items():
|
||||
hex_id = message_info["ID"]
|
||||
f.write(f" // {message_name} ({hex_id})\n")
|
||||
for signal in message_info["Signals"]:
|
||||
f.write(f" VCU.TX.CH0_{message_name}_{hex_id}.{signal['Signal name']} = 0;\n")
|
||||
f.write("\n")
|
||||
f.write("}\n")
|
||||
print(f"[INFO] TX initialization function written to {output_file}")
|
||||
|
||||
|
||||
#============================== Generate TX Enum ==============================#
|
||||
def generate_tx_enum(signals, output_file, cycle):
|
||||
if not signals:
|
||||
print("[WARNING] No TX messages found for enum generation.")
|
||||
return
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
f.write("typedef enum {\n")
|
||||
for idx, message_name in enumerate(signals.keys()):
|
||||
enum_name = f"VCU_CH0_TX_{message_name}_{cycle}"
|
||||
f.write(f" {enum_name} = {idx},\n")
|
||||
f.write(" NUMBER_OF_VCU_CH0_TX_MESSAGE,\n")
|
||||
f.write("} VCU_CH0_TX;\n")
|
||||
print(f"[INFO] TX enum written to {output_file}")
|
||||
|
||||
|
||||
#============================== Generate TX C File ==============================#
|
||||
def generate_vcu_can_transmit_single_c_file(signals, output_file):
|
||||
if not signals:
|
||||
print("[ERROR] No signals to generate VCU CAN transmit functions for.")
|
||||
return
|
||||
|
||||
# Initialize the header of the C file
|
||||
c_file_content = """
|
||||
#include "can.h"
|
||||
"""
|
||||
|
||||
# Iterate through all messages in the signals
|
||||
for message_name, message_info in signals.items():
|
||||
# Check if any signal in the message has RX ECU name as VCU
|
||||
has_vcu_signal = any(signal["RX ECU name"] != "VCU" for signal in message_info["Signals"])
|
||||
if not has_vcu_signal:
|
||||
continue # Skip this message if no signal has RX ECU name as VCU
|
||||
|
||||
# Add the function definition for the message
|
||||
c_file_content += f"""
|
||||
void Transmit_{message_name}_CH0_{message_info['ID']}(void)
|
||||
{{
|
||||
"""
|
||||
|
||||
# Iterate through signals and generate bit-packing logic
|
||||
buffer_assignments = [""] * message_info["DLC"]
|
||||
for signal in message_info["Signals"]:
|
||||
start_byte = signal["msb"] // 8
|
||||
start_bit = signal["msb"] % 8
|
||||
signal_length = signal["Length"]
|
||||
signal_name = f"VCU.TX.CH0_{message_name}_{message_info['ID']}.{signal['Signal name']}"
|
||||
|
||||
# Handle 8-bit chunks
|
||||
while signal_length > 0:
|
||||
bits_in_byte = min(8 - start_bit, signal_length)
|
||||
shift_amount = (signal["Length"] - signal_length)
|
||||
if signal["Byte order"] == 0: # Motorola (Big Endian)
|
||||
if bits_in_byte == 8:
|
||||
shift_expr = f"({signal_name} >> shift{shift_amount})"
|
||||
else:
|
||||
shift_expr = f"({signal_name} << shift{start_bit})" if start_bit > 0 else f"({signal_name} >> shift{shift_amount})"
|
||||
else: # Intel (Little Endian)
|
||||
shift_expr = f"({signal_name} >> shift{shift_amount}) << shift{start_bit}" if start_bit > 0 else f"({signal_name} >> shift{shift_amount})"
|
||||
buffer_index = start_byte
|
||||
|
||||
# Ensure buffer_index is within the range of buffer_assignments
|
||||
if buffer_index >= len(buffer_assignments):
|
||||
print(f"[ERROR] Buffer index {buffer_index} out of range for message {message_name}")
|
||||
break
|
||||
|
||||
# Add to the buffer assignments
|
||||
if buffer_assignments[buffer_index]:
|
||||
buffer_assignments[buffer_index] += f"\n | {shift_expr}"
|
||||
else:
|
||||
buffer_assignments[buffer_index] = f"{shift_expr}"
|
||||
|
||||
# Update pointers
|
||||
signal_length -= bits_in_byte
|
||||
start_byte += 1
|
||||
start_bit = 0
|
||||
|
||||
# Write buffer assignments to the function
|
||||
for i, assignment in enumerate(buffer_assignments):
|
||||
if assignment:
|
||||
c_file_content += f" CAN_ch[0].tx.buf[{i}] = ({assignment}) & _8bit;\n"
|
||||
|
||||
# Add the send function call
|
||||
c_file_content += f"""
|
||||
can_send_config(CAN_INST_0, g_messageObjectConf_VCU_0ch_TX[VCU_CH0_TX_{message_name}_10ms]);
|
||||
}}
|
||||
"""
|
||||
|
||||
# Write the generated code to a single C file
|
||||
with open(output_file, "w") as c_file:
|
||||
c_file.write(c_file_content)
|
||||
print(f"Generated C file with all VCU messages: {output_file}")
|
||||
|
||||
|
||||
#============================== Main ==============================#
|
||||
if __name__ == "__main__":
|
||||
dbc_file_path = sys.argv[1]
|
||||
output_dir = sys.argv[2]
|
||||
|
||||
output_structs_file = f"{output_dir}/generated_TX_structs.h"
|
||||
output_globals_file = f"{output_dir}/generated_TX_globals.c"
|
||||
output_globals_header = f"{output_dir}/generated_TX_globals.h"
|
||||
output_tx_functions_file = f"{output_dir}/generated_TX_output.c"
|
||||
output_tx_initialization = f"{output_dir}/generated_TX_init.c"
|
||||
output_enum_file = f"{output_dir}/generated_TX_enum.h"
|
||||
output_c_file = f"{output_dir}/generated_TX_transmit.c" # Replace with your desired output file name
|
||||
cycle_time = "10ms"
|
||||
|
||||
signals = load_dbc_file(dbc_file_path)
|
||||
if signals is None:
|
||||
print(f"[ERROR] Failed to load DBC file: {dbc_file_path}")
|
||||
sys.exit(1)
|
||||
|
||||
generate_tx_globals(signals, output_globals_file, output_globals_header)
|
||||
generate_tx_functions(signals, output_tx_functions_file)
|
||||
generate_tx_initialization(signals, output_tx_initialization)
|
||||
generate_tx_enum(signals, output_enum_file, cycle_time)
|
||||
generate_vcu_can_transmit_single_c_file(signals, output_c_file)
|
||||
BIN
dist/DBC Converter/_internal/_asyncio.pyd
vendored
BIN
dist/DBC Converter/_internal/_ctypes.pyd
vendored
BIN
dist/DBC Converter/_internal/_elementtree.pyd
vendored
BIN
dist/DBC Converter/_internal/_multiprocessing.pyd
vendored
BIN
dist/DBC Converter/_internal/_overlapped.pyd
vendored
BIN
dist/DBC Converter/_internal/_queue.pyd
vendored
BIN
dist/DBC Converter/_internal/_sqlite3.pyd
vendored
BIN
dist/DBC Converter/_internal/_ssl.pyd
vendored
BIN
dist/DBC Converter/_internal/_wmi.pyd
vendored
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2019 Erik Moqvist
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@ -1,509 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: cantools
|
||||
Version: 40.0.0
|
||||
Summary: CAN BUS tools.
|
||||
Author-email: Erik Moqvist <erik.moqvist@gmail.com>
|
||||
License: MIT
|
||||
Project-URL: homepage, https://github.com/cantools/cantools
|
||||
Project-URL: documentation, https://cantools.readthedocs.io/
|
||||
Project-URL: repository, https://github.com/cantools/cantools
|
||||
Keywords: can,can bus,arxml,dbc,kcd,automotive
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Requires-Python: >=3.9
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
Requires-Dist: bitstruct>=8.16.1
|
||||
Requires-Dist: python-can>=3.3.4
|
||||
Requires-Dist: textparser>=0.21.1
|
||||
Requires-Dist: diskcache
|
||||
Requires-Dist: argparse_addons
|
||||
Requires-Dist: crccheck
|
||||
Provides-Extra: dev
|
||||
Requires-Dist: mypy; extra == "dev"
|
||||
Requires-Dist: pipx; extra == "dev"
|
||||
Requires-Dist: ruff; extra == "dev"
|
||||
Requires-Dist: tox; extra == "dev"
|
||||
Provides-Extra: plot
|
||||
Requires-Dist: matplotlib; extra == "plot"
|
||||
Provides-Extra: windows-all
|
||||
Requires-Dist: windows-curses; (platform_system == "Windows" and platform_python_implementation == "CPython") and extra == "windows-all"
|
||||
|
||||
|github-actions| |coverage|
|
||||
|
||||
About
|
||||
=====
|
||||
|
||||
CAN BUS tools in Python 3.
|
||||
|
||||
- `DBC`_, `KCD`_, SYM, ARXML 3&4 and CDD file parsing.
|
||||
|
||||
- CAN message encoding and decoding.
|
||||
|
||||
- Simple and extended signal multiplexing.
|
||||
|
||||
- Diagnostic DID encoding and decoding.
|
||||
|
||||
- ``candump`` output decoder.
|
||||
|
||||
- Node `tester`_.
|
||||
|
||||
- `C` source code generator.
|
||||
|
||||
- CAN bus monitor.
|
||||
|
||||
- Graphical plots of signals.
|
||||
|
||||
Project homepage: https://github.com/cantools/cantools
|
||||
|
||||
Documentation: https://cantools.readthedocs.io
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python3 -m pip install cantools
|
||||
|
||||
Example usage
|
||||
=============
|
||||
|
||||
Scripting
|
||||
---------
|
||||
|
||||
The example starts by parsing a `small DBC-file`_ and printing its
|
||||
messages and signals.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import cantools
|
||||
>>> from pprint import pprint
|
||||
>>> db = cantools.database.load_file('tests/files/dbc/motohawk.dbc')
|
||||
>>> db.messages
|
||||
[message('ExampleMessage', 0x1f0, False, 8, 'Example message used as template in MotoHawk models.')]
|
||||
>>> example_message = db.get_message_by_name('ExampleMessage')
|
||||
>>> pprint(example_message.signals)
|
||||
[signal('Enable', 7, 1, 'big_endian', False, 1.0, 0, 0.0, 0.0, '-', False, None, {0: 'Disabled', 1: 'Enabled'}, None),
|
||||
signal('AverageRadius', 6, 6, 'big_endian', False, 0.1, 0, 0.0, 5.0, 'm', False, None, None, ''),
|
||||
signal('Temperature', 0, 12, 'big_endian', True, 0.01, 250, 229.53, 270.47, 'degK', False, None, None, None)]
|
||||
|
||||
The example continues `encoding`_ a message and sending it on a CAN
|
||||
bus using the `python-can`_ package.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import can
|
||||
>>> can_bus = can.interface.Bus('vcan0', bustype='socketcan')
|
||||
>>> data = example_message.encode({'Temperature': 250.1, 'AverageRadius': 3.2, 'Enable': 1})
|
||||
>>> message = can.Message(arbitration_id=example_message.frame_id, data=data)
|
||||
>>> can_bus.send(message)
|
||||
|
||||
Alternatively, a message can be encoded using the `encode_message()`_
|
||||
method on the database object.
|
||||
|
||||
The last part of the example receives and `decodes`_ a CAN message.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> message = can_bus.recv()
|
||||
>>> db.decode_message(message.arbitration_id, message.data)
|
||||
{'AverageRadius': 3.2, 'Enable': 'Enabled', 'Temperature': 250.09}
|
||||
|
||||
See `examples`_ for additional examples.
|
||||
|
||||
Command line tool
|
||||
-----------------
|
||||
|
||||
The decode subcommand
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Decode CAN frames captured with the Linux program ``candump``.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ candump vcan0 | python3 -m cantools decode tests/files/dbc/motohawk.dbc
|
||||
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 ::
|
||||
ExampleMessage(
|
||||
Enable: 'Enabled' -,
|
||||
AverageRadius: 0.0 m,
|
||||
Temperature: 255.92 degK
|
||||
)
|
||||
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 ::
|
||||
ExampleMessage(
|
||||
Enable: 'Enabled' -,
|
||||
AverageRadius: 0.0 m,
|
||||
Temperature: 255.92 degK
|
||||
)
|
||||
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 ::
|
||||
ExampleMessage(
|
||||
Enable: 'Enabled' -,
|
||||
AverageRadius: 0.0 m,
|
||||
Temperature: 255.92 degK
|
||||
)
|
||||
|
||||
Alternatively, the decoded message can be printed on a single line:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ candump vcan0 | python3 -m cantools decode --single-line tests/files/dbc/motohawk.dbc
|
||||
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 :: ExampleMessage(Enable: 'Enabled' -, AverageRadius: 0.0 m, Temperature: 255.92 degK)
|
||||
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 :: ExampleMessage(Enable: 'Enabled' -, AverageRadius: 0.0 m, Temperature: 255.92 degK)
|
||||
vcan0 1F0 [8] 80 4A 0F 00 00 00 00 00 :: ExampleMessage(Enable: 'Enabled' -, AverageRadius: 0.0 m, Temperature: 255.92 degK)
|
||||
|
||||
The plot subcommand
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The plot subcommand is similar to the decode subcommand but messages are visualized using `matplotlib`_ instead of being printed to stdout.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ candump -l vcan0
|
||||
$ cat candump-2021-01-04_180521.log
|
||||
(1609779922.655421) vcan0 00000343#B204B9049C049C04
|
||||
(1609779922.655735) vcan0 0000024A#120527052E051905
|
||||
(1609779923.657524) vcan0 00000343#C404C404CB04C404
|
||||
(1609779923.658086) vcan0 0000024A#8B058B058B059205
|
||||
(1609779924.659912) vcan0 00000343#5C04790479045504
|
||||
(1609779924.660471) vcan0 0000024A#44064B0659064406
|
||||
(1609779925.662277) vcan0 00000343#15040704F203F203
|
||||
(1609779925.662837) vcan0 0000024A#8B069906A706A706
|
||||
(1609779926.664191) vcan0 00000343#BC03B503A703BC03
|
||||
(1609779926.664751) vcan0 0000024A#A006A706C406C406
|
||||
|
||||
$ cat candump-2021-01-04_180521.log | python3 -m cantools plot tests/files/dbc/abs.dbc
|
||||
|
||||
.. image:: https://github.com/cantools/cantools/raw/master/docs/plot-1.png
|
||||
|
||||
If you don't want to show all signals you can select the desired signals with command line arguments.
|
||||
A ``*`` can stand for any number of any character, a ``?`` for exactly one arbitrary character.
|
||||
Signals separated by a ``-`` are displayed in separate subplots.
|
||||
Optionally a format can be specified after a signal, separated by a colon.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cat candump-2021-01-04_180521.log | python3 -m cantools plot tests/files/dbc/abs.dbc '*33.*fl:-<' '*33.*fr:->' - '*33.*rl:-<' '*33.*rr:->'
|
||||
|
||||
.. image:: https://github.com/cantools/cantools/raw/master/docs/plot-2-subplots.png
|
||||
|
||||
Signals with a different range of values can be displayed in the same subplot on different vertical axes by separating them with a comma.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cat candump-2021-01-04_180521.log | cantools plot --auto-color tests/files/dbc/abs.dbc -- \
|
||||
--ylabel 'Bremse 33' '*_33.*fl*:-<' '*_33.*fr*:>' '*_33.*rl*:3' '*_33.*rr*:4' , \
|
||||
--ylabel 'Bremse 2' '*_2.*fl*:-<' '*_2.*fr*:>' '*_2.*rl*:3' '*_2.*rr*:4'
|
||||
|
||||
.. image:: https://github.com/cantools/cantools/raw/master/docs/plot-2-axes.png
|
||||
|
||||
Matplotlib comes with different preinstalled styles that you can use:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cat candump-2021-01-04_180521.log | cantools plot tests/files/dbc/abs.dbc --style seaborn
|
||||
|
||||
.. image:: https://github.com/cantools/cantools/raw/master/docs/plot-seaborn.png
|
||||
|
||||
You can try all available styles with
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cantools plot --list-styles . | sed -n '/^- /s/^- //p' | while IFS= read -r style; do
|
||||
cat candump-2021-01-04_180521.log | cantools plot tests/files/dbc/abs.dbc --style "$style" --title "--style '$style'"
|
||||
done
|
||||
|
||||
For more information see
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 -m cantools plot --help
|
||||
|
||||
Note that by default matplotlib is not installed with cantools. But it can be by specifying an extra
|
||||
at installation:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 -m pip install cantools[plot]
|
||||
|
||||
The dump subcommand
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Dump given database in a human readable format:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python3 -m cantools dump tests/files/dbc/motohawk.dbc
|
||||
================================= Messages =================================
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Name: ExampleMessage
|
||||
Id: 0x1f0
|
||||
Length: 8 bytes
|
||||
Cycle time: - ms
|
||||
Senders: PCM1
|
||||
Layout:
|
||||
|
||||
Bit
|
||||
|
||||
7 6 5 4 3 2 1 0
|
||||
+---+---+---+---+---+---+---+---+
|
||||
0 |<-x|<---------------------x|<--|
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| +-- AverageRadius
|
||||
+-- Enable
|
||||
+---+---+---+---+---+---+---+---+
|
||||
1 |-------------------------------|
|
||||
+---+---+---+---+---+---+---+---+
|
||||
2 |----------x| | | | | |
|
||||
B +---+---+---+---+---+---+---+---+
|
||||
y +-- Temperature
|
||||
t +---+---+---+---+---+---+---+---+
|
||||
e 3 | | | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
4 | | | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
5 | | | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
6 | | | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
7 | | | | | | | | |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
Signal tree:
|
||||
|
||||
-- {root}
|
||||
+-- Enable
|
||||
+-- AverageRadius
|
||||
+-- Temperature
|
||||
|
||||
Signal choices:
|
||||
|
||||
Enable
|
||||
0 Disabled
|
||||
1 Enabled
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
The list subcommand
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Print all information of a given database in a human readable
|
||||
format. This is very similar to the "dump" subcommand, but the output
|
||||
is less pretty, slightly more comprehensive and easier to parse by
|
||||
shell scripts:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 -m cantools list -a tests/files/dbc/motohawk.dbc
|
||||
ExampleMessage:
|
||||
Comment[None]: Example message used as template in MotoHawk models.
|
||||
Frame ID: 0x1f0 (496)
|
||||
Size: 8 bytes
|
||||
Is extended frame: False
|
||||
Signals:
|
||||
Enable:
|
||||
Type: Integer
|
||||
Start bit: 7
|
||||
Length: 1 bits
|
||||
Unit: -
|
||||
Is signed: False
|
||||
Named values:
|
||||
0: Disabled
|
||||
|
||||
The generate C source subcommand
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Generate `C` source code from given database.
|
||||
|
||||
The generated code contains:
|
||||
|
||||
- Message `structs`_.
|
||||
|
||||
- Message `pack`_ and `unpack`_ functions.
|
||||
|
||||
- Signal `encode`_ and `decode`_ functions.
|
||||
|
||||
- Frame id, length, type, cycle time and signal choices `defines`_.
|
||||
|
||||
Known limitations:
|
||||
|
||||
- The maximum signal size is 64 bits, which in practice is never
|
||||
exceeded.
|
||||
|
||||
Below is an example of how to generate C source code from a
|
||||
database. The database is ``tests/files/dbc/motohawk.dbc``.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python3 -m cantools generate_c_source tests/files/dbc/motohawk.dbc
|
||||
Successfully generated motohawk.h and motohawk.c.
|
||||
|
||||
See `motohawk.h`_ and `motohawk.c`_ for the contents of the generated
|
||||
files.
|
||||
|
||||
In this example we use ``--use-float`` so floating point numbers in the generated
|
||||
code are single precision (``float``) instead of double precision (``double``).
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python3 -m cantools generate_c_source --use-float tests/files/dbc/motohawk.dbc
|
||||
Successfully generated motohawk.h and motohawk.c.
|
||||
|
||||
In the next example we use ``--database-name`` to set a custom
|
||||
namespace for all generated types, defines and functions. The output
|
||||
file names are also changed by this option.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python3 -m cantools generate_c_source --database-name my_database_name tests/files/dbc/motohawk.dbc
|
||||
Successfully generated my_database_name.h and my_database_name.c.
|
||||
|
||||
See `my_database_name.h`_ and `my_database_name.c`_ for the contents
|
||||
of the generated files.
|
||||
|
||||
In the next example we use ``--no-floating-point-numbers`` to generate
|
||||
code without floating point types, i.e. ``float`` and ``double``.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python3 -m cantools generate_c_source --no-floating-point-numbers tests/files/dbc/motohawk.dbc
|
||||
Successfully generated motohawk.h and motohawk.c.
|
||||
|
||||
See `motohawk_no_floating_point_numbers.h`_ and
|
||||
`motohawk_no_floating_point_numbers.c`_ for the contents of the
|
||||
generated files.
|
||||
|
||||
In the last example ``--node`` is used to generate
|
||||
message pack functions only for messages sent by the specified node and unpack
|
||||
functions only for messages with its signal receivers belonging to that node.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ cantools generate_c_source tests/files/dbc/motohawk.dbc --node PCM1
|
||||
Successfully generated motohawk.h and motohawk.c.
|
||||
|
||||
See `motohawk_sender_node.h`_ and
|
||||
`motohawk_sender_node.c`_ for the contents of the
|
||||
generated files.
|
||||
|
||||
Other C code generators:
|
||||
|
||||
- http://www.coderdbc.com
|
||||
|
||||
- https://github.com/howerj/dbcc
|
||||
|
||||
- https://github.com/lonkamikaze/hsk-libs/blob/master/scripts/dbc2c.awk
|
||||
|
||||
- https://sourceforge.net/projects/comframe/
|
||||
|
||||
The monitor subcommand
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Monitor CAN bus traffic in a text based user interface.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ python3 -m cantools monitor tests/files/dbc/motohawk.dbc
|
||||
|
||||
.. image:: https://github.com/cantools/cantools/raw/master/docs/monitor.png
|
||||
|
||||
The menu at the bottom of the monitor shows the available commands.
|
||||
|
||||
- Quit: Quit the monitor. Ctrl-C can be used as well.
|
||||
|
||||
- Filter: Only display messages matching given regular
|
||||
expression. Press <Enter> to return to the menu from the filter
|
||||
input line.
|
||||
|
||||
- Play/Pause: Toggle between playing and paused (or running and freezed).
|
||||
|
||||
- Reset: Reset the monitor to its initial state.
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
#. Fork the repository.
|
||||
|
||||
#. Install prerequisites.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
python3 -m pip install -e .[dev]
|
||||
|
||||
#. Implement the new feature or bug fix.
|
||||
|
||||
#. Implement test case(s) to ensure that future changes do not break
|
||||
legacy.
|
||||
|
||||
#. Run the linters
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
ruff check src
|
||||
mypy src
|
||||
|
||||
#. Run the tests.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
tox -e py
|
||||
|
||||
#. Create a pull request.
|
||||
|
||||
.. |github-actions| image:: https://github.com/cantools/cantools/actions/workflows/pythonpackage.yml/badge.svg?branch=master
|
||||
:target: https://github.com/cantools/cantools/actions/workflows/pythonpackage.yml
|
||||
:alt: Github Actions workflow status
|
||||
|
||||
.. |coverage| image:: https://coveralls.io/repos/github/cantools/cantools/badge.svg?branch=master
|
||||
:target: https://coveralls.io/github/cantoolscantools?branch=master
|
||||
:alt: Test coverage reports on Coveralls.io
|
||||
|
||||
|
||||
.. _small DBC-file: https://github.com/cantools/cantools/blob/master/tests/files/dbc/motohawk.dbc
|
||||
|
||||
.. _motohawk.dbc: https://github.com/cantools/cantools/blob/master/tests/files/dbc/motohawk.dbc
|
||||
|
||||
.. _python-can: https://python-can.readthedocs.io/en/master/
|
||||
|
||||
.. _DBC: http://www.socialledge.com/sjsu/index.php?title=DBC_Format
|
||||
|
||||
.. _KCD: https://github.com/julietkilo/kcd
|
||||
|
||||
.. _tester: http://cantools.readthedocs.io/en/latest/#cantools.tester.Tester
|
||||
|
||||
.. _encoding: http://cantools.readthedocs.io/en/latest/#cantools.database.can.Message.encode
|
||||
|
||||
.. _encode_message(): http://cantools.readthedocs.io/en/latest/#cantools.database.can.Database.encode_message
|
||||
|
||||
.. _decodes: http://cantools.readthedocs.io/en/latest/#cantools.database.can.Database.decode_message
|
||||
|
||||
.. _examples: https://github.com/cantools/cantools/blob/master/examples
|
||||
|
||||
.. _structs: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L58
|
||||
|
||||
.. _pack: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L88
|
||||
|
||||
.. _unpack: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L102
|
||||
|
||||
.. _encode: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L116
|
||||
|
||||
.. _decode: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L125
|
||||
|
||||
.. _defines: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h#L42
|
||||
|
||||
.. _motohawk.h: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.h
|
||||
|
||||
.. _motohawk.c: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk.c
|
||||
|
||||
.. _my_database_name.h: https://github.com/cantools/cantools/blob/master/tests/files/c_source/my_database_name.h
|
||||
|
||||
.. _my_database_name.c: https://github.com/cantools/cantools/blob/master/tests/files/c_source/my_database_name.c
|
||||
|
||||
.. _motohawk_no_floating_point_numbers.h: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk_no_floating_point_numbers.h
|
||||
|
||||
.. _motohawk_no_floating_point_numbers.c: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk_no_floating_point_numbers.c
|
||||
|
||||
.. _motohawk_sender_node.h: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk_sender_node.h
|
||||
|
||||
.. _motohawk_sender_node.c: https://github.com/cantools/cantools/blob/master/tests/files/c_source/motohawk_sender_node.c
|
||||
|
||||
.. _matplotlib: https://matplotlib.org/
|
||||
@ -1,132 +0,0 @@
|
||||
../../Scripts/cantools.exe,sha256=Sb1EuGixzTWJ0RcO3RGGevfvMH5KLodtAH0Lg-EIiF4,108417
|
||||
cantools-40.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
cantools-40.0.0.dist-info/LICENSE,sha256=7T2TtOL_oh75b3QyWjeJu-6qMOQpJXmIW0hddxJ1L-k,1085
|
||||
cantools-40.0.0.dist-info/METADATA,sha256=eaorpFjqlfQ_y2BQEUWOkVRxVEyGn7NS0ihugoG98tc,16805
|
||||
cantools-40.0.0.dist-info/RECORD,,
|
||||
cantools-40.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
cantools-40.0.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
||||
cantools-40.0.0.dist-info/entry_points.txt,sha256=p5cKpHKEUgX0e8zmetd96BEVi4WNq1wn_dIciA2Dx50,53
|
||||
cantools-40.0.0.dist-info/top_level.txt,sha256=Tl_rJpBXgVrhgmBrKozbrcQrKnOIX89JqFF7aF_4EbA,9
|
||||
cantools/__init__.py,sha256=dShD_0LbGClNr5kVJq87hHForHdbzRWimfeHFF-MFW0,3199
|
||||
cantools/__main__.py,sha256=V5nadWmxSTd8D7vRUsqjlHBswGCFUy3EX7yGNSsqBuM,71
|
||||
cantools/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/__pycache__/__main__.cpython-313.pyc,,
|
||||
cantools/__pycache__/errors.cpython-313.pyc,,
|
||||
cantools/__pycache__/j1939.cpython-313.pyc,,
|
||||
cantools/__pycache__/logreader.cpython-313.pyc,,
|
||||
cantools/__pycache__/tester.cpython-313.pyc,,
|
||||
cantools/__pycache__/typechecking.cpython-313.pyc,,
|
||||
cantools/autosar/__init__.py,sha256=KwuJfKbaKOyBXmCbj_b3l3JSyCd6B-9jm7vBInPGLuU,125
|
||||
cantools/autosar/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/autosar/__pycache__/end_to_end.cpython-313.pyc,,
|
||||
cantools/autosar/__pycache__/secoc.cpython-313.pyc,,
|
||||
cantools/autosar/__pycache__/snakeauth.cpython-313.pyc,,
|
||||
cantools/autosar/end_to_end.py,sha256=Wgoi_YbKGW_NDZjFrgRafR-JYi0v7zDiu0ulUiX0nMM,5679
|
||||
cantools/autosar/secoc.py,sha256=zaSISt45oFBIbFe2cj7x6sac54nrLg0Tk2dv1RKtuYA,3771
|
||||
cantools/autosar/snakeauth.py,sha256=Fv-IjzXdBF2M7rIpEB7So-i238e_MyuhGnYYQe0bDVg,1204
|
||||
cantools/database/__init__.py,sha256=MjqwEd8a0qwA3N5xtwvad9Su38UrpdqTqI7fyEJTNHI,13980
|
||||
cantools/database/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/database/__pycache__/conversion.cpython-313.pyc,,
|
||||
cantools/database/__pycache__/errors.cpython-313.pyc,,
|
||||
cantools/database/__pycache__/namedsignalvalue.cpython-313.pyc,,
|
||||
cantools/database/__pycache__/utils.cpython-313.pyc,,
|
||||
cantools/database/can/__init__.py,sha256=1qeDi4SCYQ350zImodvQ52GKRRo3fRMoLxQ8pkVOnvI,157
|
||||
cantools/database/can/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/attribute.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/attribute_definition.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/bus.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/c_source.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/database.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/environment_variable.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/internal_database.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/message.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/node.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/signal.cpython-313.pyc,,
|
||||
cantools/database/can/__pycache__/signal_group.cpython-313.pyc,,
|
||||
cantools/database/can/attribute.py,sha256=VAKQU3jGcxv4gLByEd7UDkiOPkKdmyBurM2RBQ8EUts,775
|
||||
cantools/database/can/attribute_definition.py,sha256=jh5OAR2wBOBeOA8cWKQt84FtVGMhGw0Tyh8a3tnNnvw,2190
|
||||
cantools/database/can/bus.py,sha256=2E6AS0JeXycYH9MkRPIGrvi9cVLa8lUasJYbYFfHYbQ,2496
|
||||
cantools/database/can/c_source.py,sha256=a2vHyAM9OBDcL13WMcvAiKzFuYCnm3UONN-vfezU2Ts,59837
|
||||
cantools/database/can/database.py,sha256=JQPgn-se8857z9QkE9yEnEinMRpOlhcDydwpqkqfAIM,21416
|
||||
cantools/database/can/environment_variable.py,sha256=lzr7ipETkSe-4MBJgiDHghZJNXmiQUzUyZH2c5bGM7I,3342
|
||||
cantools/database/can/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
cantools/database/can/formats/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/database/can/formats/__pycache__/dbc.cpython-313.pyc,,
|
||||
cantools/database/can/formats/__pycache__/dbc_specifics.cpython-313.pyc,,
|
||||
cantools/database/can/formats/__pycache__/kcd.cpython-313.pyc,,
|
||||
cantools/database/can/formats/__pycache__/sym.cpython-313.pyc,,
|
||||
cantools/database/can/formats/__pycache__/utils.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__init__.py,sha256=QIrXBHtivZk38P6VPwdOFYobByLABe-W7zw6rvwJUKc,2658
|
||||
cantools/database/can/formats/arxml/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__pycache__/bus_specifics.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__pycache__/database_specifics.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__pycache__/ecu_extract_loader.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__pycache__/end_to_end_properties.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__pycache__/message_specifics.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__pycache__/node_specifics.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__pycache__/secoc_properties.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__pycache__/system_loader.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/__pycache__/utils.cpython-313.pyc,,
|
||||
cantools/database/can/formats/arxml/bus_specifics.py,sha256=RsfMykp-KeyBvwqQCRxqU6Ll9Yj-spAYeBn-E3AC9Og,146
|
||||
cantools/database/can/formats/arxml/database_specifics.py,sha256=pqhu-npNpduae3LRwxbjE51TkVNYTAvCE_n6qnKNswM,455
|
||||
cantools/database/can/formats/arxml/ecu_extract_loader.py,sha256=1EpMAkpn1-H2Df1Yd19YyDa2_3-_Zr17hj6aoy_YPX4,12913
|
||||
cantools/database/can/formats/arxml/end_to_end_properties.py,sha256=uXcO3HvMyIn7jJ20ulkd6COl6VTg9a2zkUcjcxVUq_g,1427
|
||||
cantools/database/can/formats/arxml/message_specifics.py,sha256=zpRxcsD7Nxx5RjYQNHHHKLVmmVKag_RPz2H2dGdoXHU,2087
|
||||
cantools/database/can/formats/arxml/node_specifics.py,sha256=ctWaS90gfXVqM-14_6Y1o39uRhWYpliROtO9udwXP-c,224
|
||||
cantools/database/can/formats/arxml/secoc_properties.py,sha256=tQkA3L2h_2IR1I-Cq3DIVbiebwNpOH5MxAfgz4kalqc,3282
|
||||
cantools/database/can/formats/arxml/system_loader.py,sha256=5hmobxU_-L_RO-1Egp7TYlZJUfE1UEEVrJ2eKqzBS4w,97943
|
||||
cantools/database/can/formats/arxml/utils.py,sha256=8KPdCXqiabNY6pkJVu0i4NNDGlW4dDb4EaYD7GngCmA,2624
|
||||
cantools/database/can/formats/dbc.py,sha256=9UmBZLaGdUaRCDB95l8ebDPOl_dNGrN5UXPh7fTJN8Q,67680
|
||||
cantools/database/can/formats/dbc_specifics.py,sha256=d_ucv7Bu2zuHx_SLUIFN9NtZJcT7qXtjd188stNqcM8,2453
|
||||
cantools/database/can/formats/kcd.py,sha256=Dwu4n6QMaG5ftz-8mCLogvmnfDZcnz6al3AZVhaVliw,15247
|
||||
cantools/database/can/formats/sym.py,sha256=puVKeHI6GLqId9T32ynjnYAieDThjGDyFrCqhiuPwD0,35269
|
||||
cantools/database/can/formats/utils.py,sha256=1w1z3N18cEpD-EDCAWA9d3zKMQZx8WPM049arLDoPBU,355
|
||||
cantools/database/can/internal_database.py,sha256=JR-y8sItyu09HP8qahW_l3woFto55VSVYOZ3KSAnh60,826
|
||||
cantools/database/can/message.py,sha256=FFLeeFwxEb0beP8kmh_LnCPdHPPpbxvjXw5kxg-KMNg,49085
|
||||
cantools/database/can/node.py,sha256=Gj2TDAxgDqlyPE1zmfLMr9kGAdu0g_UMhY81pMgeIDo,2980
|
||||
cantools/database/can/signal.py,sha256=XWinJCBPfeS1H7BcaKhlVe75cFUZVSDGwc0Wbh8TE6k,10792
|
||||
cantools/database/can/signal_group.py,sha256=CkbHppcrCP6ESvu8x4qIbULIyb4s2jNc2GtCZOLl7eY,1293
|
||||
cantools/database/conversion.py,sha256=2CoykOApx8UtfXlk4pAXDCTUetohb2fqDPWsdlH_9Sc,9842
|
||||
cantools/database/diagnostics/__init__.py,sha256=vqZ2N40Vpr37GlcIwnONuVFRenVh5Scmfc40KTReFJE,75
|
||||
cantools/database/diagnostics/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/database/diagnostics/__pycache__/data.cpython-313.pyc,,
|
||||
cantools/database/diagnostics/__pycache__/database.cpython-313.pyc,,
|
||||
cantools/database/diagnostics/__pycache__/did.cpython-313.pyc,,
|
||||
cantools/database/diagnostics/__pycache__/internal_database.cpython-313.pyc,,
|
||||
cantools/database/diagnostics/data.py,sha256=AAF2fSwS_24j-_pk1bAyQm29StqXfAuxPtilxUPbOt8,5195
|
||||
cantools/database/diagnostics/database.py,sha256=3MCSskJpDirWRnNK3tryWbKxq-O6vIAAxCrNJkn5IZA,3170
|
||||
cantools/database/diagnostics/did.py,sha256=WO1kkqqWtG_ygtH9Lk3lvuAsm06DVz36RC6tiS9y59E,3352
|
||||
cantools/database/diagnostics/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
cantools/database/diagnostics/formats/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/database/diagnostics/formats/__pycache__/cdd.cpython-313.pyc,,
|
||||
cantools/database/diagnostics/formats/cdd.py,sha256=OGgHeL4hg_gbWG8orEbdi88kCMS8vRCorn1gX5BJPew,6754
|
||||
cantools/database/diagnostics/internal_database.py,sha256=E90ThC42YoB0okiQ3zOjMSMISAdbel6UKkE_5cv0KqM,161
|
||||
cantools/database/errors.py,sha256=F-y-Oagw39fYnLWTV-Vu-ysNPVFH4QWd4KnE8L5i4jY,179
|
||||
cantools/database/namedsignalvalue.py,sha256=2-McjdG9--gq3sv4ctbc54TOlqThAZorqFaF1VY3_g8,1593
|
||||
cantools/database/utils.py,sha256=xrN4g8CsGAL4V8zAcVWzdPlXQ0f0cdqU61vhkeEQKhQ,15980
|
||||
cantools/errors.py,sha256=0AdPszq7kkayF5OtHciuT3B1FQRHxM8C1mcKgJVyfwE,89
|
||||
cantools/j1939.py,sha256=_3uWp8p9uf3GdZDYHtMBCPeOSkqDw3bWIVGCFekaRBs,4484
|
||||
cantools/logreader.py,sha256=_MgDs-MoPX_W0HX3TJ5N5mwZWqsekREvc2f5LxOAja4,14963
|
||||
cantools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
cantools/subparsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
cantools/subparsers/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/subparsers/__pycache__/__utils__.cpython-313.pyc,,
|
||||
cantools/subparsers/__pycache__/convert.cpython-313.pyc,,
|
||||
cantools/subparsers/__pycache__/decode.cpython-313.pyc,,
|
||||
cantools/subparsers/__pycache__/generate_c_source.cpython-313.pyc,,
|
||||
cantools/subparsers/__pycache__/list.cpython-313.pyc,,
|
||||
cantools/subparsers/__pycache__/monitor.cpython-313.pyc,,
|
||||
cantools/subparsers/__pycache__/plot.cpython-313.pyc,,
|
||||
cantools/subparsers/__utils__.py,sha256=7hV150FTaiPegd_WDMyJPC9pl5XsbzN0XTyBCmvwdxE,8780
|
||||
cantools/subparsers/convert.py,sha256=ajxpdvl3DLxwBfoSx_XaIA_V2dLjzfv-4ySuSyKxigQ,1493
|
||||
cantools/subparsers/decode.py,sha256=vuxOBS3E0XcMFogr9OMNLqnvD1qecjOiUooGGXfmIKI,2947
|
||||
cantools/subparsers/dump/__init__.py,sha256=fJTBEqjq29K9Wt39gP6_ZgnXbG6p7SJScmlJvR8qvgU,5816
|
||||
cantools/subparsers/dump/__pycache__/__init__.cpython-313.pyc,,
|
||||
cantools/subparsers/dump/__pycache__/formatting.cpython-313.pyc,,
|
||||
cantools/subparsers/dump/formatting.py,sha256=ljROsdSrsxgJtckZi0SvhRmd__L31A4SS3eoJ6BJofQ,11841
|
||||
cantools/subparsers/generate_c_source.py,sha256=ifB44lGD_HnVaDvunz0caS6zrJ8LcnUHVbN5Aj9fXvw,4091
|
||||
cantools/subparsers/list.py,sha256=SDnjwC1_RKm02jqwVEuqofCfNZl_rNJwUE3xYYHxVng,14391
|
||||
cantools/subparsers/monitor.py,sha256=at_ggsrV0bZqL6On_3C-4D3J1yTX0w_4XxvUNAe478M,20071
|
||||
cantools/subparsers/plot.py,sha256=OpNzyEN5cynBBPDAJgbu_Kzr6-n7--iORvlpuqaT7ow,34633
|
||||
cantools/tester.py,sha256=1Vll_TKqzApfZ-nXBesqancawrIZ3ub5MksYTPPqaRQ,15370
|
||||
cantools/typechecking.py,sha256=U1B-6NV-IGx9vtozvOJZ2BMREv-BdWbpcKWrH9LHa2o,1957
|
||||
@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (75.6.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
[console_scripts]
|
||||
cantools = cantools.__init__:_main
|
||||
@ -1 +0,0 @@
|
||||
cantools
|
||||
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
BIN
dist/DBC Converter/_internal/img/0.Main.png
vendored
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
dist/DBC Converter/_internal/img/1.Main(no).png
vendored
Normal file
|
After Width: | Height: | Size: 389 KiB |
BIN
dist/DBC Converter/_internal/img/2.AddFiile.png
vendored
Normal file
|
After Width: | Height: | Size: 536 KiB |
BIN
dist/DBC Converter/_internal/img/3.DeleteFile.png
vendored
Normal file
|
After Width: | Height: | Size: 441 KiB |
BIN
dist/DBC Converter/_internal/img/4.RepositorySelection.png
vendored
Normal file
|
After Width: | Height: | Size: 536 KiB |
BIN
dist/DBC Converter/_internal/img/5.ChannelSelection.png
vendored
Normal file
|
After Width: | Height: | Size: 590 KiB |
BIN
dist/DBC Converter/_internal/img/6.Convert.png
vendored
Normal file
|
After Width: | Height: | Size: 620 KiB |
BIN
dist/DBC Converter/_internal/img/7.Complete.png
vendored
Normal file
|
After Width: | Height: | Size: 618 KiB |
BIN
dist/DBC Converter/_internal/img/main.pptx
vendored
Normal file
BIN
dist/DBC Converter/_internal/libffi-8.dll
vendored
BIN
dist/DBC Converter/_internal/libssl-3.dll
vendored
BIN
dist/DBC Converter/_internal/pyexpat.pyd
vendored
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,165 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@ -1,218 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: python-can
|
||||
Version: 4.5.0
|
||||
Summary: Controller Area Network interface module for Python
|
||||
Author: python-can contributors
|
||||
License: LGPL v3
|
||||
Project-URL: homepage, https://github.com/hardbyte/python-can
|
||||
Project-URL: documentation, https://python-can.readthedocs.io
|
||||
Project-URL: repository, https://github.com/hardbyte/python-can
|
||||
Project-URL: changelog, https://github.com/hardbyte/python-can/blob/develop/CHANGELOG.md
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Education
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: Manufacturing
|
||||
Classifier: Intended Audience :: Telecommunications Industry
|
||||
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: MacOS
|
||||
Classifier: Operating System :: Microsoft :: Windows
|
||||
Classifier: Operating System :: POSIX :: Linux
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Topic :: Software Development :: Embedded Systems
|
||||
Classifier: Topic :: Software Development :: Embedded Systems :: Controller Area Network (CAN)
|
||||
Classifier: Topic :: System :: Hardware :: Hardware Drivers
|
||||
Classifier: Topic :: System :: Logging
|
||||
Classifier: Topic :: System :: Monitoring
|
||||
Classifier: Topic :: System :: Networking
|
||||
Classifier: Topic :: Utilities
|
||||
Requires-Python: >=3.8
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE.txt
|
||||
Requires-Dist: wrapt~=1.10
|
||||
Requires-Dist: packaging>=23.1
|
||||
Requires-Dist: typing_extensions>=3.10.0.0
|
||||
Requires-Dist: msgpack~=1.1.0; platform_system != "Windows"
|
||||
Provides-Extra: lint
|
||||
Requires-Dist: pylint==3.2.*; extra == "lint"
|
||||
Requires-Dist: ruff==0.7.0; extra == "lint"
|
||||
Requires-Dist: black==24.10.*; extra == "lint"
|
||||
Requires-Dist: mypy==1.12.*; extra == "lint"
|
||||
Provides-Extra: pywin32
|
||||
Requires-Dist: pywin32>=305; extra == "pywin32"
|
||||
Provides-Extra: seeedstudio
|
||||
Requires-Dist: pyserial>=3.0; extra == "seeedstudio"
|
||||
Provides-Extra: serial
|
||||
Requires-Dist: pyserial~=3.0; extra == "serial"
|
||||
Provides-Extra: neovi
|
||||
Requires-Dist: filelock; extra == "neovi"
|
||||
Requires-Dist: python-ics>=2.12; extra == "neovi"
|
||||
Provides-Extra: canalystii
|
||||
Requires-Dist: canalystii>=0.1.0; extra == "canalystii"
|
||||
Provides-Extra: cantact
|
||||
Requires-Dist: cantact>=0.0.7; extra == "cantact"
|
||||
Provides-Extra: cvector
|
||||
Requires-Dist: python-can-cvector; extra == "cvector"
|
||||
Provides-Extra: gs-usb
|
||||
Requires-Dist: gs_usb>=0.2.1; extra == "gs-usb"
|
||||
Provides-Extra: nixnet
|
||||
Requires-Dist: nixnet>=0.3.2; extra == "nixnet"
|
||||
Provides-Extra: pcan
|
||||
Requires-Dist: uptime~=3.0.1; extra == "pcan"
|
||||
Provides-Extra: remote
|
||||
Requires-Dist: python-can-remote; extra == "remote"
|
||||
Provides-Extra: sontheim
|
||||
Requires-Dist: python-can-sontheim>=0.1.2; extra == "sontheim"
|
||||
Provides-Extra: canine
|
||||
Requires-Dist: python-can-canine>=0.2.2; extra == "canine"
|
||||
Provides-Extra: zlgcan
|
||||
Requires-Dist: zlgcan-driver-py; extra == "zlgcan"
|
||||
Provides-Extra: viewer
|
||||
Requires-Dist: windows-curses; (platform_system == "Windows" and platform_python_implementation == "CPython") and extra == "viewer"
|
||||
Provides-Extra: mf4
|
||||
Requires-Dist: asammdf>=6.0.0; extra == "mf4"
|
||||
|
||||
python-can
|
||||
==========
|
||||
|
||||
|pypi| |conda| |python_implementation| |downloads| |downloads_monthly|
|
||||
|
||||
|docs| |github-actions| |coverage| |mergify| |formatter|
|
||||
|
||||
.. |pypi| image:: https://img.shields.io/pypi/v/python-can.svg
|
||||
:target: https://pypi.python.org/pypi/python-can/
|
||||
:alt: Latest Version on PyPi
|
||||
|
||||
.. |conda| image:: https://img.shields.io/conda/v/conda-forge/python-can
|
||||
:target: https://github.com/conda-forge/python-can-feedstock
|
||||
:alt: Latest Version on conda-forge
|
||||
|
||||
.. |python_implementation| image:: https://img.shields.io/pypi/implementation/python-can
|
||||
:target: https://pypi.python.org/pypi/python-can/
|
||||
:alt: Supported Python implementations
|
||||
|
||||
.. |downloads| image:: https://static.pepy.tech/badge/python-can
|
||||
:target: https://pepy.tech/project/python-can
|
||||
:alt: Downloads on PePy
|
||||
|
||||
.. |downloads_monthly| image:: https://static.pepy.tech/badge/python-can/month
|
||||
:target: https://pepy.tech/project/python-can
|
||||
:alt: Monthly downloads on PePy
|
||||
|
||||
.. |formatter| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/python/black
|
||||
:alt: This project uses the black formatter.
|
||||
|
||||
.. |docs| image:: https://readthedocs.org/projects/python-can/badge/?version=stable
|
||||
:target: https://python-can.readthedocs.io/en/stable/
|
||||
:alt: Documentation
|
||||
|
||||
.. |github-actions| image:: https://github.com/hardbyte/python-can/actions/workflows/ci.yml/badge.svg
|
||||
:target: https://github.com/hardbyte/python-can/actions/workflows/ci.yml
|
||||
:alt: Github Actions workflow status
|
||||
|
||||
.. |coverage| image:: https://coveralls.io/repos/github/hardbyte/python-can/badge.svg?branch=develop
|
||||
:target: https://coveralls.io/github/hardbyte/python-can?branch=develop
|
||||
:alt: Test coverage reports on Coveralls.io
|
||||
|
||||
.. |mergify| image:: https://img.shields.io/endpoint.svg?url=https://api.mergify.com/v1/badges/hardbyte/python-can&style=flat
|
||||
:target: https://mergify.io
|
||||
:alt: Mergify Status
|
||||
|
||||
The **C**\ ontroller **A**\ rea **N**\ etwork is a bus standard designed
|
||||
to allow microcontrollers and devices to communicate with each other. It
|
||||
has priority based bus arbitration and reliable deterministic
|
||||
communication. It is used in cars, trucks, boats, wheelchairs and more.
|
||||
|
||||
The ``can`` package provides controller area network support for
|
||||
Python developers; providing common abstractions to
|
||||
different hardware devices, and a suite of utilities for sending and receiving
|
||||
messages on a can bus.
|
||||
|
||||
The library currently supports CPython as well as PyPy and runs on Mac, Linux and Windows.
|
||||
|
||||
============================== ===========
|
||||
Library Version Python
|
||||
------------------------------ -----------
|
||||
2.x 2.6+, 3.4+
|
||||
3.x 2.7+, 3.5+
|
||||
4.0+ 3.7+
|
||||
4.3+ 3.8+
|
||||
============================== ===========
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- common abstractions for CAN communication
|
||||
- support for many different backends (see the `docs <https://python-can.readthedocs.io/en/stable/interfaces.html>`__)
|
||||
- receiving, sending, and periodically sending messages
|
||||
- normal and extended arbitration IDs
|
||||
- `CAN FD <https://en.wikipedia.org/wiki/CAN_FD>`__ support
|
||||
- many different loggers and readers supporting playback: ASC (CANalyzer format), BLF (Binary Logging Format by Vector), MF4 (Measurement Data Format v4 by ASAM), TRC, CSV, SQLite, and Canutils log
|
||||
- efficient in-kernel or in-hardware filtering of messages on supported interfaces
|
||||
- bus configuration reading from a file or from environment variables
|
||||
- command line tools for working with CAN buses (see the `docs <https://python-can.readthedocs.io/en/stable/scripts.html>`__)
|
||||
- more
|
||||
|
||||
|
||||
Example usage
|
||||
-------------
|
||||
|
||||
``pip install python-can``
|
||||
|
||||
.. code:: python
|
||||
|
||||
# import the library
|
||||
import can
|
||||
|
||||
# create a bus instance using 'with' statement,
|
||||
# this will cause bus.shutdown() to be called on the block exit;
|
||||
# many other interfaces are supported as well (see documentation)
|
||||
with can.Bus(interface='socketcan',
|
||||
channel='vcan0',
|
||||
receive_own_messages=True) as bus:
|
||||
|
||||
# send a message
|
||||
message = can.Message(arbitration_id=123, is_extended_id=True,
|
||||
data=[0x11, 0x22, 0x33])
|
||||
bus.send(message, timeout=0.2)
|
||||
|
||||
# iterate over received messages
|
||||
for msg in bus:
|
||||
print(f"{msg.arbitration_id:X}: {msg.data}")
|
||||
|
||||
# or use an asynchronous notifier
|
||||
notifier = can.Notifier(bus, [can.Logger("recorded.log"), can.Printer()])
|
||||
|
||||
You can find more information in the documentation, online at
|
||||
`python-can.readthedocs.org <https://python-can.readthedocs.org/en/stable/>`__.
|
||||
|
||||
|
||||
Discussion
|
||||
----------
|
||||
|
||||
If you run into bugs, you can file them in our
|
||||
`issue tracker <https://github.com/hardbyte/python-can/issues>`__ on GitHub.
|
||||
|
||||
`Stackoverflow <https://stackoverflow.com/questions/tagged/can+python>`__ has several
|
||||
questions and answers tagged with ``python+can``.
|
||||
|
||||
Wherever we interact, we strive to follow the
|
||||
`Python Community Code of Conduct <https://www.python.org/psf/codeofconduct/>`__.
|
||||
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
See `doc/development.rst <doc/development.rst>`__ for getting started.
|
||||
@ -1,190 +0,0 @@
|
||||
../../Scripts/can_logconvert.exe,sha256=4OLlyHsi4OUi_soiBmhtaUC_seuJ1e3Alu-yqLLLnqE,108412
|
||||
../../Scripts/can_logger.exe,sha256=ybhXzwGvkCnwJcWCHzKa6qSxHVTi80X9sPsNeiC1PAI,108408
|
||||
../../Scripts/can_player.exe,sha256=kSsqUd_DlQ6S15yAgSvUc7a_eI4ZCUAzS1gM3z-V-UA,108408
|
||||
../../Scripts/can_viewer.exe,sha256=sUX1h5GPslijbiSwAAuDSpomM2Zt9DvxXaXvLygv0pE,108408
|
||||
can/__init__.py,sha256=R0FbX-rk4vfp1reupjJcYGAYhu1OO_0Rsarymtx-H1A,2957
|
||||
can/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/__pycache__/_entry_points.cpython-313.pyc,,
|
||||
can/__pycache__/bit_timing.cpython-313.pyc,,
|
||||
can/__pycache__/broadcastmanager.cpython-313.pyc,,
|
||||
can/__pycache__/bus.cpython-313.pyc,,
|
||||
can/__pycache__/ctypesutil.cpython-313.pyc,,
|
||||
can/__pycache__/exceptions.cpython-313.pyc,,
|
||||
can/__pycache__/interface.cpython-313.pyc,,
|
||||
can/__pycache__/listener.cpython-313.pyc,,
|
||||
can/__pycache__/logconvert.cpython-313.pyc,,
|
||||
can/__pycache__/logger.cpython-313.pyc,,
|
||||
can/__pycache__/message.cpython-313.pyc,,
|
||||
can/__pycache__/notifier.cpython-313.pyc,,
|
||||
can/__pycache__/player.cpython-313.pyc,,
|
||||
can/__pycache__/thread_safe_bus.cpython-313.pyc,,
|
||||
can/__pycache__/typechecking.cpython-313.pyc,,
|
||||
can/__pycache__/util.cpython-313.pyc,,
|
||||
can/__pycache__/viewer.cpython-313.pyc,,
|
||||
can/_entry_points.py,sha256=h3NcPDarBMlHFggGVlcHYSY80nutagzkbd7zvkBVVq0,883
|
||||
can/bit_timing.py,sha256=pWjJw0Vd52XBJ7qsdgDg4ZRYpXhi-vfwaK1T22wMtZ0,42518
|
||||
can/broadcastmanager.py,sha256=F-9NF_twn7xdwd0wE0F7XuHExoPzgojbDlrOFGwVkYI,13234
|
||||
can/bus.py,sha256=UyhNzcAw0y1MY2Gj1OjSVF2Bt5z3isXIvBVllnmiUSc,19552
|
||||
can/ctypesutil.py,sha256=6mUNOW2tbzA92e8lR7gZ3j_Lin0sBT5zs6ivnMA-Vyw,2463
|
||||
can/exceptions.py,sha256=b-iOjhfOEGGJ3XRokdUfMQ5u7mCs3CW2nvqrKnDmnq0,4097
|
||||
can/interface.py,sha256=rp_DEk34gcz5oifBZ631p0mULVFLNcnGCBMMd-7JxPc,6911
|
||||
can/interfaces/__init__.py,sha256=oUH47iDy8dD5PwsZTf5_TEcZaijOeidtmRHXQofjyA0,2190
|
||||
can/interfaces/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/__pycache__/canalystii.cpython-313.pyc,,
|
||||
can/interfaces/__pycache__/cantact.cpython-313.pyc,,
|
||||
can/interfaces/__pycache__/gs_usb.cpython-313.pyc,,
|
||||
can/interfaces/__pycache__/iscan.cpython-313.pyc,,
|
||||
can/interfaces/__pycache__/nican.cpython-313.pyc,,
|
||||
can/interfaces/__pycache__/nixnet.cpython-313.pyc,,
|
||||
can/interfaces/__pycache__/robotell.cpython-313.pyc,,
|
||||
can/interfaces/__pycache__/slcan.cpython-313.pyc,,
|
||||
can/interfaces/__pycache__/virtual.cpython-313.pyc,,
|
||||
can/interfaces/canalystii.py,sha256=GedKF34FG7zuXvtNPqEDkBlZjEi0K9fjYB8X6HbBtW0,8065
|
||||
can/interfaces/cantact.py,sha256=b1HIeTnXkL3REzmSWJSw3XbavqTMJTZvYVsn3GrEb-g,5972
|
||||
can/interfaces/etas/__init__.py,sha256=yzYQ_j00VX4if_WzGsM6EdDTJbrfuqhVwoF0X0fFfh0,12093
|
||||
can/interfaces/etas/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/etas/__pycache__/boa.cpython-313.pyc,,
|
||||
can/interfaces/etas/boa.py,sha256=d0P66wr-vC5HxTg4_lGFdoasIfyUdo6GrnVL7HPJxOs,20644
|
||||
can/interfaces/gs_usb.py,sha256=c4AIipb_yYsNsY-zew2OSSzzFaXZ5QxvoRQ0LlkThHQ,6112
|
||||
can/interfaces/ics_neovi/__init__.py,sha256=ZrIW0OnnhdUSSotJ2NQpTPGsNyXLVMFQh33Nm4oQYNE,219
|
||||
can/interfaces/ics_neovi/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/ics_neovi/__pycache__/neovi_bus.cpython-313.pyc,,
|
||||
can/interfaces/ics_neovi/neovi_bus.py,sha256=bKIb8HhvijjCaAr8zjWOun6YLawxJDe64HR-4-_5n5s,17873
|
||||
can/interfaces/iscan.py,sha256=5rah_TybSfibuVX8AxcOR3CFbA7Py_-4yU7Kk1gS644,6348
|
||||
can/interfaces/ixxat/__init__.py,sha256=xRymShxicj--2CzuAFkTKUEHZKRfX1KFsniWGAWl_SQ,508
|
||||
can/interfaces/ixxat/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/ixxat/__pycache__/canlib.cpython-313.pyc,,
|
||||
can/interfaces/ixxat/__pycache__/canlib_vcinpl.cpython-313.pyc,,
|
||||
can/interfaces/ixxat/__pycache__/canlib_vcinpl2.cpython-313.pyc,,
|
||||
can/interfaces/ixxat/__pycache__/constants.cpython-313.pyc,,
|
||||
can/interfaces/ixxat/__pycache__/exceptions.cpython-313.pyc,,
|
||||
can/interfaces/ixxat/__pycache__/structures.cpython-313.pyc,,
|
||||
can/interfaces/ixxat/canlib.py,sha256=6mhDGO1_uOV3IVedVujS0jXe6DGNqSsXt4gmFmZdl5U,5844
|
||||
can/interfaces/ixxat/canlib_vcinpl.py,sha256=SbpTlW1GEY5ESMq1kbpuF1cy-nkzpM6CGvyg3G9ZkDQ,38085
|
||||
can/interfaces/ixxat/canlib_vcinpl2.py,sha256=c99Se3NBQH3jJPJwiB_xdo2KiR2ESKYp17quI5QnMR0,39652
|
||||
can/interfaces/ixxat/constants.py,sha256=N-YrqhKmezwBnygBI4BQk-9_BQyyLVo3CFg_SZmKIdg,9102
|
||||
can/interfaces/ixxat/exceptions.py,sha256=DLtBDPG522pcNbaxemwUwKNHmozgYQGfSCfXDOqefpQ,978
|
||||
can/interfaces/ixxat/structures.py,sha256=WjA2pgenCAmclQqfVlRShL7nrnQl62PjEkt5oN0PSYM,10540
|
||||
can/interfaces/kvaser/__init__.py,sha256=v8tcm4xo73lCZ6z2hfMUv73jb5bW7Y3OB6XrNm37-z0,218
|
||||
can/interfaces/kvaser/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/kvaser/__pycache__/canlib.cpython-313.pyc,,
|
||||
can/interfaces/kvaser/__pycache__/constants.cpython-313.pyc,,
|
||||
can/interfaces/kvaser/__pycache__/structures.cpython-313.pyc,,
|
||||
can/interfaces/kvaser/canlib.py,sha256=csAl9rMb0KiXztpnF-21pLu-QWG74tekF782er8MCvo,28087
|
||||
can/interfaces/kvaser/constants.py,sha256=_iFCp9ppS8X0byvk_lWm3YnSWaZXU-xYupetDoy1FnI,6965
|
||||
can/interfaces/kvaser/structures.py,sha256=0rdDBApNDl_wpG8MDJ0xW3XU4bGn-XRoHuyOL_VYYq0,1971
|
||||
can/interfaces/neousys/__init__.py,sha256=fVs-zoPY6J44kvYa8yH-GI-uzBH6j9yDxcC7ErW-GAM,134
|
||||
can/interfaces/neousys/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/neousys/__pycache__/neousys.cpython-313.pyc,,
|
||||
can/interfaces/neousys/neousys.py,sha256=nOSLeSLQVpF_COQ-L3eFM4Jk9OGAXxZgTkYMlTT8Cwc,7693
|
||||
can/interfaces/nican.py,sha256=1bsV3h1pc_UxvGU6Kv4KgTE00nWzwuwK3DMaK73WaUU,11552
|
||||
can/interfaces/nixnet.py,sha256=fMtFQT7fvhqzCeqOc-v4zrXNG8nOqSU4G9yZx57h7pw,13179
|
||||
can/interfaces/pcan/__init__.py,sha256=D0sfeL2tk2xVKLtxkAUvJjXddwP3y0n4vC1PDoa8i-Y,137
|
||||
can/interfaces/pcan/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/pcan/__pycache__/basic.cpython-313.pyc,,
|
||||
can/interfaces/pcan/__pycache__/pcan.cpython-313.pyc,,
|
||||
can/interfaces/pcan/basic.py,sha256=Iv_pNzkHWw9Qq8JZ95I1o5dnrktaPbtrrQOQrJL53sQ,41286
|
||||
can/interfaces/pcan/pcan.py,sha256=JRTw6lxanH7WU4ZJze7SwM4gBOomh-qWfTjc_yDX56g,28445
|
||||
can/interfaces/robotell.py,sha256=OlLqvnuWKDu7cnRCP0n36WnQAmTLJzZ97eHhBdIzD_0,15756
|
||||
can/interfaces/seeedstudio/__init__.py,sha256=hRTBWKIPxob_nPLZq4quPDu6YwZO_AZmZpthjBROjkE,119
|
||||
can/interfaces/seeedstudio/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/seeedstudio/__pycache__/seeedstudio.cpython-313.pyc,,
|
||||
can/interfaces/seeedstudio/seeedstudio.py,sha256=Pl8LHeghz-Jk8ukdS1CkrSCZKW0sL9UmKYFMlC-hgKc,9610
|
||||
can/interfaces/serial/__init__.py,sha256=rpPrM68xhR0D6eIol1oyEvyw__CBCtBUAiZnfgL3k60,114
|
||||
can/interfaces/serial/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/serial/__pycache__/serial_can.cpython-313.pyc,,
|
||||
can/interfaces/serial/serial_can.py,sha256=dyQexSnUC0DrHvlw_lkHsFKLioiVo5pRFLUilu38aqI,7384
|
||||
can/interfaces/slcan.py,sha256=fGJgOdoMgGetSL2toYAn-TbGYpS4GeXzdpFfjO-7Lt0,11976
|
||||
can/interfaces/socketcan/__init__.py,sha256=VV3-1FlheR-Km27B2r7nTtlEIli07aYGN188bcrUfK0,286
|
||||
can/interfaces/socketcan/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/socketcan/__pycache__/constants.cpython-313.pyc,,
|
||||
can/interfaces/socketcan/__pycache__/socketcan.cpython-313.pyc,,
|
||||
can/interfaces/socketcan/__pycache__/utils.cpython-313.pyc,,
|
||||
can/interfaces/socketcan/constants.py,sha256=7DfAcYCokY9np63SyH39W7iP9wAUktxyH_1PKN3Wu2s,1130
|
||||
can/interfaces/socketcan/socketcan.py,sha256=jQ8XHHCrDSDbWa8Zka5U3dOivYkk2-DJE3OJeI3mraA,32431
|
||||
can/interfaces/socketcan/utils.py,sha256=I7tyAM_GqjQbvf36XIyruUdOkhm3NdKf7gqba7KoFFw,2833
|
||||
can/interfaces/socketcand/__init__.py,sha256=4rUdnZlPmSmdfIpF8rvLxjHZ5w-xfLTiHL5XMCyg4c0,275
|
||||
can/interfaces/socketcand/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/socketcand/__pycache__/socketcand.cpython-313.pyc,,
|
||||
can/interfaces/socketcand/socketcand.py,sha256=EFGWConsRpnPp1mViqw-GcA1XZU4UwgwRhPwXEa5Jaw,12912
|
||||
can/interfaces/systec/__init__.py,sha256=omi-SgqBEAOKne1SrmNLj1p1BMPBCHbJOhQ9QOKlgms,160
|
||||
can/interfaces/systec/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/systec/__pycache__/constants.cpython-313.pyc,,
|
||||
can/interfaces/systec/__pycache__/exceptions.cpython-313.pyc,,
|
||||
can/interfaces/systec/__pycache__/structures.cpython-313.pyc,,
|
||||
can/interfaces/systec/__pycache__/ucan.cpython-313.pyc,,
|
||||
can/interfaces/systec/__pycache__/ucanbus.cpython-313.pyc,,
|
||||
can/interfaces/systec/constants.py,sha256=1AupgsozCjoN8ENyx4B2LNNYtAj9YPEUeZgS9rJmBhg,22700
|
||||
can/interfaces/systec/exceptions.py,sha256=jG-XitcteyN-db4AMWlIUNeSih0Lp6TXaQN-DBGyKYc,4839
|
||||
can/interfaces/systec/structures.py,sha256=gj1doSJuOBIAsjGI8i2vVub7Zv5Ot-26PSGY7jeQAAk,12986
|
||||
can/interfaces/systec/ucan.py,sha256=eFfhItZWkYb0ZnI_dQNJBDMLjorV_c3GZCggzP0Xmo8,46738
|
||||
can/interfaces/systec/ucanbus.py,sha256=ysQDywiVMkgUhVGAFPAzCzb5VzekoXWtbJJ93whyr7w,11354
|
||||
can/interfaces/udp_multicast/__init__.py,sha256=aGLFDeB2Mr0qjFHGpvvWiod-gwr8r6HWgc6HQJc326Y,157
|
||||
can/interfaces/udp_multicast/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/udp_multicast/__pycache__/bus.cpython-313.pyc,,
|
||||
can/interfaces/udp_multicast/__pycache__/utils.cpython-313.pyc,,
|
||||
can/interfaces/udp_multicast/bus.py,sha256=pSXCf4CvRFPaE1daQltg94eS7RxUainHG_y-8gQRSiM,17199
|
||||
can/interfaces/udp_multicast/utils.py,sha256=s9rnXmk-MtMk-m2Iu-jn4qKcd6tAvMAykDPgPLr-LXc,2161
|
||||
can/interfaces/usb2can/__init__.py,sha256=5Nz3w5APrNDpVmRNTjHuSJzeq9QfesdoJVNkgHtAzyI,253
|
||||
can/interfaces/usb2can/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/usb2can/__pycache__/serial_selector.cpython-313.pyc,,
|
||||
can/interfaces/usb2can/__pycache__/usb2canInterface.cpython-313.pyc,,
|
||||
can/interfaces/usb2can/__pycache__/usb2canabstractionlayer.cpython-313.pyc,,
|
||||
can/interfaces/usb2can/serial_selector.py,sha256=FqVnUsPsfcX2o9CecXCEO14v_cK29AVNGUyqQLx8drU,1669
|
||||
can/interfaces/usb2can/usb2canInterface.py,sha256=UFBttq2yefCMhA850DQaVQysDCKPRB6AAi24hr6A2wA,6648
|
||||
can/interfaces/usb2can/usb2canabstractionlayer.py,sha256=tx1xnRvFIJ2A0P_GvRLfaxWamkAPHE83asm5KHgx6xQ,6100
|
||||
can/interfaces/vector/__init__.py,sha256=c1CPg3ra6Dx33w9-w57FORMgKpvS5QCTlNEPbqtvhMs,564
|
||||
can/interfaces/vector/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/interfaces/vector/__pycache__/canlib.cpython-313.pyc,,
|
||||
can/interfaces/vector/__pycache__/exceptions.cpython-313.pyc,,
|
||||
can/interfaces/vector/__pycache__/xlclass.cpython-313.pyc,,
|
||||
can/interfaces/vector/__pycache__/xldefine.cpython-313.pyc,,
|
||||
can/interfaces/vector/__pycache__/xldriver.cpython-313.pyc,,
|
||||
can/interfaces/vector/canlib.py,sha256=AnAHpc1Jk9cngKaa-RQ_rdlcxAcIj_FfBFYA0nnFLU0,49407
|
||||
can/interfaces/vector/exceptions.py,sha256=_4ThvHUUuSymWTnrGaiikoFevpxXlDl4j_86LvtuWEU,926
|
||||
can/interfaces/vector/xlclass.py,sha256=vPoptlI7c8fAXmsFNya7MoH7E03OA8ZK2kCLWEhOxZk,8461
|
||||
can/interfaces/vector/xldefine.py,sha256=XgAgUQ20vxn0bgI9FmLpBtJocQSB0GEN99zblc_j-K8,9572
|
||||
can/interfaces/vector/xldriver.py,sha256=dhwldW1QtwpO9mk_OgPCbEyPR969wp7R6wsXuGExOuQ,9893
|
||||
can/interfaces/virtual.py,sha256=ifFu38lt6ivI66_1mcculOntQbb4TafQHZxIIReMqjQ,7229
|
||||
can/io/__init__.py,sha256=w60ODfi9bPYF6ckFloPuixKweSusDbOii5X8r1BqBTg,1243
|
||||
can/io/__pycache__/__init__.cpython-313.pyc,,
|
||||
can/io/__pycache__/asc.cpython-313.pyc,,
|
||||
can/io/__pycache__/blf.cpython-313.pyc,,
|
||||
can/io/__pycache__/canutils.cpython-313.pyc,,
|
||||
can/io/__pycache__/csv.cpython-313.pyc,,
|
||||
can/io/__pycache__/generic.cpython-313.pyc,,
|
||||
can/io/__pycache__/logger.cpython-313.pyc,,
|
||||
can/io/__pycache__/mf4.cpython-313.pyc,,
|
||||
can/io/__pycache__/player.cpython-313.pyc,,
|
||||
can/io/__pycache__/printer.cpython-313.pyc,,
|
||||
can/io/__pycache__/sqlite.cpython-313.pyc,,
|
||||
can/io/__pycache__/trc.cpython-313.pyc,,
|
||||
can/io/asc.py,sha256=b4cQDbpznyllzNKd3dEYj-_FywOS9IdbUyYc1rN1Om4,17475
|
||||
can/io/blf.py,sha256=jL3y6PHMTjBVUsTTKaRWVG_n-7GRkyJRkKDBHibvI0Q,21933
|
||||
can/io/canutils.py,sha256=mKs-CxnlcMhfA8qYKMc7v1t6m2TyQulh8roKuRBQUDw,6313
|
||||
can/io/csv.py,sha256=VhP0i8SmpAQpJgcTWGhUfoR3O7pZeBaEIIcmBjSRdUQ,4384
|
||||
can/io/generic.py,sha256=3_YecJlNXMlSGKhrSjJGVHExd-IZGCrp0-DTvJrfpdw,3738
|
||||
can/io/logger.py,sha256=jSe_YBIE3Et3lALP0n9ebB_3mV_c4NwQ5nl0FCd3nxA,13648
|
||||
can/io/mf4.py,sha256=uwAWxixN9XrAiS9gzM1BUDXfTzMnSuHYW-G8-9C9SYw,20574
|
||||
can/io/player.py,sha256=mrWV2fOb2hkFGg3XeiJFTH_u18-gqkZi-wAB4l7LY_E,6067
|
||||
can/io/printer.py,sha256=RaztAPdrDzBuA0st8xaduB5m83jeXbQstjJ38eeaDxA,1810
|
||||
can/io/sqlite.py,sha256=mgExkCe3dg7EIjlWaHwdP7zfgbPuYPHyoVYlS8xNzPY,9124
|
||||
can/io/trc.py,sha256=vNXrjstRTY-AY7mUaKeVDr7Al35XSTFrvKcB3TsAn-Q,16142
|
||||
can/listener.py,sha256=u4OhBB85cfGOExSpJh4_woAcTxabyzvbnJDn2fdZx5Q,5533
|
||||
can/logconvert.py,sha256=r-mUzbaz0bouSzSV2rOBCuaRy0sI288N68QNHSOF_bQ,1541
|
||||
can/logger.py,sha256=Bh3iTj37cTYrJgkG8ik6w2wHSMfZAsvxQULk-o5Deu8,10422
|
||||
can/message.py,sha256=L8X6hbL5rRyPz3gIRKc0imanfjuuUAL1NPUUkZJETaE,12061
|
||||
can/notifier.py,sha256=NTtbGeOg6NoiL57de8JLGT5Qd-rK-q3_sAUOKjtWKGw,6609
|
||||
can/player.py,sha256=wTtnlbq--fNbTCDs4xwPvQte0Lf7LYoa32A0VmHkB18,2966
|
||||
can/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
can/thread_safe_bus.py,sha256=mA2ZUS11AWlmfDG62H9LycYItkX3BBsACYH7GrHdZFg,3113
|
||||
can/typechecking.py,sha256=w_-IWbaYcIIaZ2z2HxIJcu8ZTHDlbuQK-qY5T_ylhmo,2031
|
||||
can/util.py,sha256=gVHFdDdGyT_dHKB-ox3ixQYhRRItfeOoh3Z9_nh_0QY,16394
|
||||
can/viewer.py,sha256=kIuEiTSoBiPOnE7nclc2O98qJaqFSYqRclSPjAdN8BE,22300
|
||||
python_can-4.5.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
python_can-4.5.0.dist-info/LICENSE.txt,sha256=2n6rt7r999OuXp8iOqW9we7ORaxWncIbOwN1ILRGR2g,7651
|
||||
python_can-4.5.0.dist-info/METADATA,sha256=0Ndae35X7mV4kUP88bSjWklqXyPhQRzxwXVXwNOZMFU,8884
|
||||
python_can-4.5.0.dist-info/RECORD,,
|
||||
python_can-4.5.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
||||
python_can-4.5.0.dist-info/entry_points.txt,sha256=k0xFGWlRv838DScY-7B604jlqkQ2SEbPSNGYoCTmTJI,142
|
||||
python_can-4.5.0.dist-info/top_level.txt,sha256=D3m3layW1dpiXBpZ6ESNxVgsfJEBWPE9VTefMMmI1HY,4
|
||||
@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (75.6.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
[console_scripts]
|
||||
can_logconvert = can.logconvert:main
|
||||
can_logger = can.logger:main
|
||||
can_player = can.player:main
|
||||
can_viewer = can.viewer:main
|
||||
@ -1 +0,0 @@
|
||||
can
|
||||
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@ -1,129 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: importlib_metadata
|
||||
Version: 8.0.0
|
||||
Summary: Read metadata from Python packages
|
||||
Author-email: "Jason R. Coombs" <jaraco@jaraco.com>
|
||||
Project-URL: Source, https://github.com/python/importlib_metadata
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: Apache Software License
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Requires-Python: >=3.8
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
Requires-Dist: zipp >=0.5
|
||||
Requires-Dist: typing-extensions >=3.6.4 ; python_version < "3.8"
|
||||
Provides-Extra: doc
|
||||
Requires-Dist: sphinx >=3.5 ; extra == 'doc'
|
||||
Requires-Dist: jaraco.packaging >=9.3 ; extra == 'doc'
|
||||
Requires-Dist: rst.linker >=1.9 ; extra == 'doc'
|
||||
Requires-Dist: furo ; extra == 'doc'
|
||||
Requires-Dist: sphinx-lint ; extra == 'doc'
|
||||
Requires-Dist: jaraco.tidelift >=1.4 ; extra == 'doc'
|
||||
Provides-Extra: perf
|
||||
Requires-Dist: ipython ; extra == 'perf'
|
||||
Provides-Extra: test
|
||||
Requires-Dist: pytest !=8.1.*,>=6 ; extra == 'test'
|
||||
Requires-Dist: pytest-checkdocs >=2.4 ; extra == 'test'
|
||||
Requires-Dist: pytest-cov ; extra == 'test'
|
||||
Requires-Dist: pytest-mypy ; extra == 'test'
|
||||
Requires-Dist: pytest-enabler >=2.2 ; extra == 'test'
|
||||
Requires-Dist: pytest-ruff >=0.2.1 ; extra == 'test'
|
||||
Requires-Dist: packaging ; extra == 'test'
|
||||
Requires-Dist: pyfakefs ; extra == 'test'
|
||||
Requires-Dist: flufl.flake8 ; extra == 'test'
|
||||
Requires-Dist: pytest-perf >=0.9.2 ; extra == 'test'
|
||||
Requires-Dist: jaraco.test >=5.4 ; extra == 'test'
|
||||
Requires-Dist: importlib-resources >=1.3 ; (python_version < "3.9") and extra == 'test'
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg
|
||||
:target: https://pypi.org/project/importlib_metadata
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg
|
||||
|
||||
.. image:: https://github.com/python/importlib_metadata/actions/workflows/main.yml/badge.svg
|
||||
:target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22
|
||||
:alt: tests
|
||||
|
||||
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json
|
||||
:target: https://github.com/astral-sh/ruff
|
||||
:alt: Ruff
|
||||
|
||||
.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest
|
||||
:target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest
|
||||
|
||||
.. image:: https://img.shields.io/badge/skeleton-2024-informational
|
||||
:target: https://blog.jaraco.com/skeleton
|
||||
|
||||
.. image:: https://tidelift.com/badges/package/pypi/importlib-metadata
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme
|
||||
|
||||
Library to access the metadata for a Python package.
|
||||
|
||||
This package supplies third-party access to the functionality of
|
||||
`importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`_
|
||||
including improvements added to subsequent Python versions.
|
||||
|
||||
|
||||
Compatibility
|
||||
=============
|
||||
|
||||
New features are introduced in this third-party library and later merged
|
||||
into CPython. The following table indicates which versions of this library
|
||||
were contributed to different versions in the standard library:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - importlib_metadata
|
||||
- stdlib
|
||||
* - 7.0
|
||||
- 3.13
|
||||
* - 6.5
|
||||
- 3.12
|
||||
* - 4.13
|
||||
- 3.11
|
||||
* - 4.6
|
||||
- 3.10
|
||||
* - 1.4
|
||||
- 3.8
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
See the `online documentation <https://importlib-metadata.readthedocs.io/>`_
|
||||
for usage details.
|
||||
|
||||
`Finder authors
|
||||
<https://docs.python.org/3/reference/import.html#finders-and-loaders>`_ can
|
||||
also add support for custom package installers. See the above documentation
|
||||
for details.
|
||||
|
||||
|
||||
Caveats
|
||||
=======
|
||||
|
||||
This project primarily supports third-party packages installed by PyPA
|
||||
tools (or other conforming packages). It does not support:
|
||||
|
||||
- Packages in the stdlib.
|
||||
- Packages installed without metadata.
|
||||
|
||||
Project details
|
||||
===============
|
||||
|
||||
* Project home: https://github.com/python/importlib_metadata
|
||||
* Report bugs at: https://github.com/python/importlib_metadata/issues
|
||||
* Code hosting: https://github.com/python/importlib_metadata
|
||||
* Documentation: https://importlib-metadata.readthedocs.io/
|
||||
|
||||
For Enterprise
|
||||
==============
|
||||
|
||||
Available as part of the Tidelift Subscription.
|
||||
|
||||
This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.
|
||||
|
||||
`Learn more <https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=referral&utm_campaign=github>`_.
|
||||
@ -1,32 +0,0 @@
|
||||
importlib_metadata-8.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
importlib_metadata-8.0.0.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
||||
importlib_metadata-8.0.0.dist-info/METADATA,sha256=anuQ7_7h4J1bSEzfcjIBakPi2cyVQ7y7jklLHsBeH1k,4648
|
||||
importlib_metadata-8.0.0.dist-info/RECORD,,
|
||||
importlib_metadata-8.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
importlib_metadata-8.0.0.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
|
||||
importlib_metadata-8.0.0.dist-info/top_level.txt,sha256=CO3fD9yylANiXkrMo4qHLV_mqXL2sC5JFKgt1yWAT-A,19
|
||||
importlib_metadata/__init__.py,sha256=tZNB-23h8Bixi9uCrQqj9Yf0aeC--Josdy3IZRIQeB0,33798
|
||||
importlib_metadata/__pycache__/__init__.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_adapters.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_collections.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_compat.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_functools.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_itertools.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_meta.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/_text.cpython-312.pyc,,
|
||||
importlib_metadata/__pycache__/diagnose.cpython-312.pyc,,
|
||||
importlib_metadata/_adapters.py,sha256=rIhWTwBvYA1bV7i-5FfVX38qEXDTXFeS5cb5xJtP3ks,2317
|
||||
importlib_metadata/_collections.py,sha256=CJ0OTCHIjWA0ZIVS4voORAsn2R4R2cQBEtPsZEJpASY,743
|
||||
importlib_metadata/_compat.py,sha256=73QKrN9KNoaZzhbX5yPCCZa-FaALwXe8TPlDR72JgBU,1314
|
||||
importlib_metadata/_functools.py,sha256=PsY2-4rrKX4RVeRC1oGp1lB1pmC9eKN88_f-bD9uOoA,2895
|
||||
importlib_metadata/_itertools.py,sha256=cvr_2v8BRbxcIl5x5ldfqdHjhI8Yi8s8yk50G_nm6jQ,2068
|
||||
importlib_metadata/_meta.py,sha256=nxZ7C8GVlcBFAKWyVOn_dn7ot_twBcbm1NmvjIetBHI,1801
|
||||
importlib_metadata/_text.py,sha256=HCsFksZpJLeTP3NEk_ngrAeXVRRtTrtyh9eOABoRP4A,2166
|
||||
importlib_metadata/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
importlib_metadata/compat/__pycache__/__init__.cpython-312.pyc,,
|
||||
importlib_metadata/compat/__pycache__/py311.cpython-312.pyc,,
|
||||
importlib_metadata/compat/__pycache__/py39.cpython-312.pyc,,
|
||||
importlib_metadata/compat/py311.py,sha256=uqm-K-uohyj1042TH4a9Er_I5o7667DvulcD-gC_fSA,608
|
||||
importlib_metadata/compat/py39.py,sha256=cPkMv6-0ilK-0Jw_Tkn0xYbOKJZc4WJKQHow0c2T44w,1102
|
||||
importlib_metadata/diagnose.py,sha256=nkSRMiowlmkhLYhKhvCg9glmt_11Cox-EmLzEbqYTa8,379
|
||||
importlib_metadata/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (70.1.1)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -1 +0,0 @@
|
||||
importlib_metadata
|
||||
@ -1,2 +0,0 @@
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est euismod turpis, id tincidunt sapien risus a quam. Maecenas fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, feugiat in, orci. In hac habitasse platea dictumst.
|
||||
BIN
dist/DBC Converter/_internal/sqlite3.dll
vendored
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2012 Daniel Holth <dholth@fastmail.fm> and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
@ -1,66 +0,0 @@
|
||||
Metadata-Version: 2.3
|
||||
Name: wheel
|
||||
Version: 0.45.1
|
||||
Summary: A built-package format for Python
|
||||
Keywords: wheel,packaging
|
||||
Author-email: Daniel Holth <dholth@fastmail.fm>
|
||||
Maintainer-email: Alex Grönholm <alex.gronholm@nextday.fi>
|
||||
Requires-Python: >=3.8
|
||||
Description-Content-Type: text/x-rst
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Topic :: System :: Archiving :: Packaging
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Requires-Dist: pytest >= 6.0.0 ; extra == "test"
|
||||
Requires-Dist: setuptools >= 65 ; extra == "test"
|
||||
Project-URL: Changelog, https://wheel.readthedocs.io/en/stable/news.html
|
||||
Project-URL: Documentation, https://wheel.readthedocs.io/
|
||||
Project-URL: Issue Tracker, https://github.com/pypa/wheel/issues
|
||||
Project-URL: Source, https://github.com/pypa/wheel
|
||||
Provides-Extra: test
|
||||
|
||||
wheel
|
||||
=====
|
||||
|
||||
This is a command line tool for manipulating Python wheel files, as defined in
|
||||
`PEP 427`_. It contains the following functionality:
|
||||
|
||||
* Convert ``.egg`` archives into ``.whl``
|
||||
* Unpack wheel archives
|
||||
* Repack wheel archives
|
||||
* Add or remove tags in existing wheel archives
|
||||
|
||||
.. _PEP 427: https://www.python.org/dev/peps/pep-0427/
|
||||
|
||||
Historical note
|
||||
---------------
|
||||
|
||||
This project used to contain the implementation of the setuptools_ ``bdist_wheel``
|
||||
command, but as of setuptools v70.1, it no longer needs ``wheel`` installed for that to
|
||||
work. Thus, you should install this **only** if you intend to use the ``wheel`` command
|
||||
line tool!
|
||||
|
||||
.. _setuptools: https://pypi.org/project/setuptools/
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
The documentation_ can be found on Read The Docs.
|
||||
|
||||
.. _documentation: https://wheel.readthedocs.io/
|
||||
|
||||
Code of Conduct
|
||||
---------------
|
||||
|
||||
Everyone interacting in the wheel project's codebases, issue trackers, chat
|
||||
rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.
|
||||
|
||||
.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
../../Scripts/wheel.exe,sha256=-G3ngeOxk4bN2s9A8LHzAP3dH0v2YTzKotxQTcY-36M,108407
|
||||
wheel-0.45.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
wheel-0.45.1.dist-info/LICENSE.txt,sha256=MMI2GGeRCPPo6h0qZYx8pBe9_IkcmO8aifpP8MmChlQ,1107
|
||||
wheel-0.45.1.dist-info/METADATA,sha256=mKz84H7m7jsxJyzeIcTVORiTb0NPMV39KvOIYhGgmjA,2313
|
||||
wheel-0.45.1.dist-info/RECORD,,
|
||||
wheel-0.45.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
wheel-0.45.1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
|
||||
wheel-0.45.1.dist-info/entry_points.txt,sha256=rTY1BbkPHhkGMm4Q3F0pIzJBzW2kMxoG1oriffvGdA0,104
|
||||
wheel/__init__.py,sha256=mrxMnvdXACur_LWegbUfh5g5ysWZrd63UJn890wvGNk,59
|
||||
wheel/__main__.py,sha256=NkMUnuTCGcOkgY0IBLgBCVC_BGGcWORx2K8jYGS12UE,455
|
||||
wheel/__pycache__/__init__.cpython-313.pyc,,
|
||||
wheel/__pycache__/__main__.cpython-313.pyc,,
|
||||
wheel/__pycache__/_bdist_wheel.cpython-313.pyc,,
|
||||
wheel/__pycache__/_setuptools_logging.cpython-313.pyc,,
|
||||
wheel/__pycache__/bdist_wheel.cpython-313.pyc,,
|
||||
wheel/__pycache__/macosx_libfile.cpython-313.pyc,,
|
||||
wheel/__pycache__/metadata.cpython-313.pyc,,
|
||||
wheel/__pycache__/util.cpython-313.pyc,,
|
||||
wheel/__pycache__/wheelfile.cpython-313.pyc,,
|
||||
wheel/_bdist_wheel.py,sha256=UghCQjSH_pVfcZh6oRjzSw_TQhcf3anSx1OkiLSL82M,21694
|
||||
wheel/_setuptools_logging.py,sha256=-5KC-lne0ilOUWIDfOkqapUWGMFZhuKYDIavIZiB5kM,781
|
||||
wheel/bdist_wheel.py,sha256=tpf9WufiSO1RuEMg5oPhIfSG8DMziCZ_4muCKF69Cqo,1107
|
||||
wheel/cli/__init__.py,sha256=Npq6_jKi03dhIcRnmbuFhwviVJxwO0tYEnEhWMv9cJo,4402
|
||||
wheel/cli/__pycache__/__init__.cpython-313.pyc,,
|
||||
wheel/cli/__pycache__/convert.cpython-313.pyc,,
|
||||
wheel/cli/__pycache__/pack.cpython-313.pyc,,
|
||||
wheel/cli/__pycache__/tags.cpython-313.pyc,,
|
||||
wheel/cli/__pycache__/unpack.cpython-313.pyc,,
|
||||
wheel/cli/convert.py,sha256=Bi0ntEXb9nTllCxWeTRQ4j-nPs3szWSEKipG_GgnMkQ,12634
|
||||
wheel/cli/pack.py,sha256=CAFcHdBVulvsHYJlndKVO7KMI9JqBTZz5ii0PKxxCOs,3103
|
||||
wheel/cli/tags.py,sha256=lHw-LaWrkS5Jy_qWcw-6pSjeNM6yAjDnqKI3E5JTTCU,4760
|
||||
wheel/cli/unpack.py,sha256=Y_J7ynxPSoFFTT7H0fMgbBlVErwyDGcObgme5MBuz58,1021
|
||||
wheel/macosx_libfile.py,sha256=k1x7CE3LPtOVGqj6NXQ1nTGYVPaeRrhVzUG_KPq3zDs,16572
|
||||
wheel/metadata.py,sha256=JC4p7jlQZu2bUTAQ2fevkqLjg_X6gnNyRhLn6OUO1tc,6171
|
||||
wheel/util.py,sha256=aL7aibHwYUgfc8WlolL5tXdkV4DatbJxZHb1kwHFJAU,423
|
||||
wheel/vendored/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
wheel/vendored/__pycache__/__init__.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/LICENSE,sha256=ytHvW9NA1z4HS6YU0m996spceUDD2MNIUuZcSQlobEg,197
|
||||
wheel/vendored/packaging/LICENSE.APACHE,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174
|
||||
wheel/vendored/packaging/LICENSE.BSD,sha256=tw5-m3QvHMb5SLNMFqo5_-zpQZY2S8iP8NIYDwAo-sU,1344
|
||||
wheel/vendored/packaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
wheel/vendored/packaging/__pycache__/__init__.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/_elffile.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/_manylinux.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/_musllinux.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/_parser.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/_structures.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/_tokenizer.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/markers.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/requirements.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/specifiers.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/tags.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/utils.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/__pycache__/version.cpython-313.pyc,,
|
||||
wheel/vendored/packaging/_elffile.py,sha256=hbmK8OD6Z7fY6hwinHEUcD1by7czkGiNYu7ShnFEk2k,3266
|
||||
wheel/vendored/packaging/_manylinux.py,sha256=P7sdR5_7XBY09LVYYPhHmydMJIIwPXWsh4olk74Uuj4,9588
|
||||
wheel/vendored/packaging/_musllinux.py,sha256=z1s8To2hQ0vpn_d-O2i5qxGwEK8WmGlLt3d_26V7NeY,2674
|
||||
wheel/vendored/packaging/_parser.py,sha256=4tT4emSl2qTaU7VTQE1Xa9o1jMPCsBezsYBxyNMUN-s,10347
|
||||
wheel/vendored/packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431
|
||||
wheel/vendored/packaging/_tokenizer.py,sha256=alCtbwXhOFAmFGZ6BQ-wCTSFoRAJ2z-ysIf7__MTJ_k,5292
|
||||
wheel/vendored/packaging/markers.py,sha256=_TSPI1BhJYO7Bp9AzTmHQxIqHEVXaTjmDh9G-w8qzPA,8232
|
||||
wheel/vendored/packaging/requirements.py,sha256=dgoBeVprPu2YE6Q8nGfwOPTjATHbRa_ZGLyXhFEln6Q,2933
|
||||
wheel/vendored/packaging/specifiers.py,sha256=IWSt0SrLSP72heWhAC8UL0eGvas7XIQHjqiViVfmPKE,39778
|
||||
wheel/vendored/packaging/tags.py,sha256=fedHXiOHkBxNZTXotXv8uXPmMFU9ae-TKBujgYHigcA,18950
|
||||
wheel/vendored/packaging/utils.py,sha256=XgdmP3yx9-wQEFjO7OvMj9RjEf5JlR5HFFR69v7SQ9E,5268
|
||||
wheel/vendored/packaging/version.py,sha256=PFJaYZDxBgyxkfYhH3SQw4qfE9ICCWrTmitvq14y3bs,16234
|
||||
wheel/vendored/vendor.txt,sha256=Z2ENjB1i5prfez8CdM1Sdr3c6Zxv2rRRolMpLmBncAE,16
|
||||
wheel/wheelfile.py,sha256=USCttNlJwafxt51YYFFKG7jnxz8dfhbyqAZL6jMTA9s,8411
|
||||
@ -1,4 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: flit 3.10.1
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
@ -1,6 +0,0 @@
|
||||
[console_scripts]
|
||||
wheel=wheel.cli:main
|
||||
|
||||
[distutils.commands]
|
||||
bdist_wheel=wheel.bdist_wheel:bdist_wheel
|
||||
|
||||
@ -2,6 +2,6 @@
|
||||
"theme": "light",
|
||||
"default_save_path": "C:/Users/MSI/Desktop",
|
||||
"file_paths": [],
|
||||
"last_opened_dir": "C:/Users/MSI/Desktop/python/motorola_tx",
|
||||
"last_opened_dir": "C:/Users/MSI/SynologyDrive/3min_be/한자연/!과제/초안전/#Debug/DBC",
|
||||
"channel_info": {}
|
||||
}
|
||||