From 9b2f1b13c3f2dfadedb2e06e1e2f71b3b0c25422 Mon Sep 17 00:00:00 2001 From: Godpp <tzj0429@163.com> Date: Mon, 17 Feb 2020 22:01:39 +0800 Subject: [PATCH] 123 --- Pipfile.lock | 436 +++++++++ widgets/diagnostic_trouble_code_widget.py | 455 +++++++++ .gitignore | 148 +++ config.ini | 3 widgets/flash_bootloader_widget.py | 504 ++++++++++ abc.ico | 0 Pipfile | 21 build.sh | 5 README.md | 26 widgets/data_identifier_widget.py | 794 ++++++++++++++++ ControlCAN.dll | 0 widgets/main_widget.py | 56 + build.bat | 3 main.py | 24 uds/client.py | 345 +++++++ 15 files changed, 2,820 insertions(+), 0 deletions(-) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ccd249 --- /dev/null +++ b/.gitignore @@ -0,0 +1,148 @@ +# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig + +# Created by https://www.gitignore.io/api/visualstudiocode,python +# Edit at https://www.gitignore.io/?templates=visualstudiocode,python + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +# End of https://www.gitignore.io/api/visualstudiocode,python + +# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) +.vscode/* +files/* +.idea/* diff --git a/ControlCAN.dll b/ControlCAN.dll new file mode 100644 index 0000000..06137ec --- /dev/null +++ b/ControlCAN.dll Binary files differ diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..e6229fe --- /dev/null +++ b/Pipfile @@ -0,0 +1,21 @@ +[[source]] +name = "pypi" +url = "https://mirrors.aliyun.com/pypi/simple/" +verify_ssl = false + +[dev-packages] +autopep8 = "==1.4.4" +pylint = "==2.3.1" + +[packages] +aioisotp = "==0.1.1" +udsoncan = "==1.8" +pyqt5 = "==5.12.2" +asyncqt = "==0.7.0" +autopep8 = "==1.4.4" +pylint = "==2.3.1" +pyinstaller = "==3.5" +pywin32-ctypes ="==0.2.0" + +[requires] +python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..e6e02e6 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,436 @@ +{ + "_meta": { + "hash": { + "sha256": "52208087d2a67939bdd327679176e1be6ac48f123bc907ac01736becd16fe1f5" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://mirrors.aliyun.com/pypi/simple/", + "verify_ssl": false + } + ] + }, + "default": { + "aenum": { + "hashes": [ + "sha256:284ddb976413d97239a932d7e5202ba58d66e5dbd81531bf3033ebb36ec30b23", + "sha256:a4334cabf47c167d44ab5a6198837b80deec5d5bad1b5cf70c966c3a330260e8", + "sha256:d2bb6ea7586aaae889d3a5c332eafa851eeffe6e7068807c79b6c86c4326b938" + ], + "version": "==2.2.3" + }, + "aioisotp": { + "hashes": [ + "sha256:27bcffe39835e937e7be2f3374e613399d2c95631b324d292caf1f5a18f829bd", + "sha256:f998284978a7a41a5b527fdcf1555fe7996fd98e80b48dbe95c005df1ddf1b4a" + ], + "index": "pypi", + "version": "==0.1.1" + }, + "altgraph": { + "hashes": [ + "sha256:1f05a47122542f97028caf78775a095fbe6a2699b5089de8477eb583167d69aa", + "sha256:c623e5f3408ca61d4016f23a681b9adb100802ca3e3da5e718915a9e4052cebe" + ], + "version": "==0.17" + }, + "astroid": { + "hashes": [ + "sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a", + "sha256:840947ebfa8b58f318d42301cf8c0a20fd794a33b61cc4638e28e9e61ba32f42" + ], + "version": "==2.3.3" + }, + "asyncqt": { + "hashes": [ + "sha256:8b1507c968c85cf0b7eee5d2a887162d38af15fb8c5b1ec25beed6025d7383ac", + "sha256:e0f51a0c27d7276b50ef2a4539e0d56bbcf5e837854caba40b41741dbe36ffb3" + ], + "index": "pypi", + "version": "==0.7.0" + }, + "autopep8": { + "hashes": [ + "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" + ], + "index": "pypi", + "version": "==1.4.4" + }, + "colorama": { + "hashes": [ + "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff", + "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.4.3" + }, + "future": { + "hashes": [ + "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d" + ], + "version": "==0.18.2" + }, + "isort": { + "hashes": [ + "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", + "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + ], + "version": "==4.3.21" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d", + "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449", + "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08", + "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a", + "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50", + "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd", + "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239", + "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb", + "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea", + "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e", + "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156", + "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142", + "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442", + "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62", + "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db", + "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531", + "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383", + "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a", + "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357", + "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4", + "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0" + ], + "version": "==1.4.3" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "packaging": { + "hashes": [ + "sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73", + "sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334" + ], + "version": "==20.1" + }, + "pefile": { + "hashes": [ + "sha256:a5d6e8305c6b210849b47a6174ddf9c452b2888340b8177874b862ba6c207645" + ], + "version": "==2019.4.18" + }, + "pycodestyle": { + "hashes": [ + "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", + "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" + ], + "version": "==2.5.0" + }, + "pyinstaller": { + "hashes": [ + "sha256:ee7504022d1332a3324250faf2135ea56ac71fdb6309cff8cd235de26b1d0a96" + ], + "index": "pypi", + "version": "==3.5" + }, + "pylint": { + "hashes": [ + "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", + "sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1" + ], + "index": "pypi", + "version": "==2.3.1" + }, + "pyparsing": { + "hashes": [ + "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f", + "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec" + ], + "version": "==2.4.6" + }, + "pyqt5": { + "hashes": [ + "sha256:06cb9a1ea1289ca2b2d81f9a2da44a05029d5b4d36fa47b6a0c0b9027ff03fef", + "sha256:44b263f395045eb5bba34f4df2d269e07b1e073fd359645b022943dd1accadfd", + "sha256:bb4ec5583baa18f741ec6c229489dc1910290d4ce4d6756a2ea062f7bf6456e6", + "sha256:c168a8883bbe7877809c3239c5dcfb9e8de5fe7e8e828c8add7e4f77cc8fc02a" + ], + "index": "pypi", + "version": "==5.12.2" + }, + "pyqt5-sip": { + "hashes": [ + "sha256:1115728644bbadcde5fc8a16e7918bd31915a42dd6fb36b10d4afb78c582753e", + "sha256:1f4289276d355b6521dc2cc956189315da6f13adfb6bbab8f25ebd15e3bce1d4", + "sha256:288c6dc18a8d6a20981c07b715b5695d9b66880778565f3792bc6e38f14f20fb", + "sha256:3f665376d9e52faa9855c3736a66ce6d825f85c86d7774d3c393f09da23f4f86", + "sha256:6b4860c4305980db509415d0af802f111d15f92016c9422eb753bc8883463456", + "sha256:7ffa39763097f64de129cf5cc770a651c3f65d2466b4fe05bef2bd2efbaa38e6", + "sha256:8a18e6f45d482ddfe381789979d09ee13aa6450caa3a0476503891bccb3ac709", + "sha256:8da842d3d7bf8931d1093105fb92702276b6dbb7e801abbaaa869405d616171a", + "sha256:b42021229424aa44e99b3b49520b799fd64ff6ae8b53f79f903bbd85719a28e4", + "sha256:b5b4906445fe980aee76f20400116b6904bf5f30d0767489c13370e42a764020", + "sha256:c1e730a9eb2ec3869ed5d81b0f99f6e2460fb4d77750444c0ec183b771d798f7", + "sha256:cbeeae6b45234a1654657f79943f8bccd3d14b4e7496746c62cf6fbce69442c7", + "sha256:d46b0f8effc554de52a1466b1bd80e5cb4bce635a75ac4e7ad6247c965dec5b9", + "sha256:e28c3abc9b62a1b7e796891648b9f14f8167b31c8e7990fae79654777252bb4d", + "sha256:e6078f5ee7d31c102910d0c277a110e1c2a20a3fc88cd017a39e170120586d3f", + "sha256:ee1a12f09d5af2304273bfd2f6b43835c1467d5ed501a6c95f5405637fa7750a", + "sha256:f314f31f5fd39b06897f013f425137e511d45967150eb4e424a363d8138521c6" + ], + "version": "==12.7.1" + }, + "python-can": { + "hashes": [ + "sha256:5fefb5c1e7e7f07faefc02c6eac79f9b58376f007048a04d8e7f325d48ec6b2e" + ], + "version": "==3.3.2" + }, + "pywin32": { + "hashes": [ + "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be", + "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511", + "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0", + "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507", + "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116", + "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e", + "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc", + "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2", + "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4", + "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295", + "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c", + "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa" + ], + "index": "pypi", + "version": "==227" + }, + "pywin32-ctypes": { + "hashes": [ + "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942", + "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98" + ], + "version": "==0.2.0" + }, + "sip": { + "hashes": [ + "sha256:066654acad02685cbdc84c3741e56b45845505426e9fc3c193fd3fe09afc0738", + "sha256:1b4c78e57b5876b9848c7634dbde5f9a1eff21cc13d0c589d461b5d4370b8b09", + "sha256:3b600dd1c8293bb7cf002a20dbbc736010c6a5e161241d73b16685744ffe57c2", + "sha256:42f7d43379e8f9bb50997870e94bdd691eadfe61ca2dfd679f821144afb50f24", + "sha256:4fe6f7e1a1f1bf38cbc6cbc5f0888934d8fc101d1478b0514477a7b44f3d41c0", + "sha256:62df2afa4c872bcac15746d8082de0ff14cfff6a487d5e25c6568bff5298cb88", + "sha256:9193914b685d02cd9a3d562d0132ab2297bc7b518a591a4ef39a1ca59da31fdd", + "sha256:9f331f61250df2427a92acabf18dfb2383e6ca74407fc5ff05c1cb037b03b62f", + "sha256:b2fda76ecb78df121fc165104050890c23ac41fa91e2a7d1b9a37aa22b212550", + "sha256:ba4a8a75bde2e58ee5bf28cf7c1aa3e90d2f51e9386ab812b0220786d684b340", + "sha256:bc9e061b16e6b3836621d4f6e6e8af0db3f2715643d54b975359ddb754896439", + "sha256:d08f9566f9a869d390f0c70e8e514eb4f650c56e5f1bd894fbceb793b598b9f0", + "sha256:de370fc4048684123c78f2f6e261d9ac53b51dc005f727f362e4e671322cdbd5", + "sha256:e896200e4a05bc8bf2ad5da3a9f733ca56f313bf0c6366a71677b39fd6a2ec2f", + "sha256:eeba96ca1d1bbf8de9b262df500176a689bdfc338d0f418eca7ff432731839a4", + "sha256:f287bb196e3453365032bc0931b61419e0a61631729f7ffa2df1aba5c49514d7", + "sha256:fbf8f71a26a94f7e32eb780bea0e55856dbb99dbcf33a99529565ed5cd060259" + ], + "index": "pypi", + "version": "==5.1.1" + }, + "six": { + "hashes": [ + "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", + "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" + ], + "version": "==1.14.0" + }, + "toml": { + "hashes": [ + "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", + "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e" + ], + "version": "==0.10.0" + }, + "typed-ast": { + "hashes": [ + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" + ], + "markers": "implementation_name == 'cpython' and python_version < '3.8'", + "version": "==1.4.1" + }, + "udsoncan": { + "hashes": [ + "sha256:beb34bf11c229131c2e87fd0e0263b91787913e79d8462408e8cb04666351e8b", + "sha256:c71195d3a8fa10f0b17fb13d705c0dd2a37c1100855d95e6c3fede3e8fef3c3b" + ], + "index": "pypi", + "version": "==1.8" + }, + "windows-curses": { + "hashes": [ + "sha256:261fde5680d1ce4ce116908996b9a3cfb0ffb03ea68d42240f62b56a9fa6af2c", + "sha256:66034dc9a705d87308cc9ea90836f4ee60008a1d5e2c1d34ace627f60268158b", + "sha256:669caad3ae16faf2d201d7ab3b8af418a2fd074d8a39d60ca26f3acb34b6afe5", + "sha256:73bd3eebccfda55330783f165151de115bfa238d1332f0b2e224b550d6187840", + "sha256:89a6d973f88cfe49b41ea80164dcbec209d296e0cec34a02002578b0bf464a64", + "sha256:8ba7c000d7ffa5452bbd0966b96e69261e4f117ebe510aeb8771a9650197b7f0", + "sha256:97084c6b37b1534f6a28a514d521dfae402f77dcbad42b14ee32e8d5bdc13648", + "sha256:9e474a181f96d60429a4766145628264e60b72e7715876f9135aeb2e842f9433", + "sha256:cfe64c30807c146ef8d094412f90f2a2c81ad6aefff3ebfe8e37aabe2f801303", + "sha256:ff8c67f74b88944d99fa9d22971c05c335bc74f149120f0a69340c2c3a595497" + ], + "version": "==2.1.0" + }, + "wrapt": { + "hashes": [ + "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" + ], + "version": "==1.11.2" + } + }, + "develop": { + "astroid": { + "hashes": [ + "sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a", + "sha256:840947ebfa8b58f318d42301cf8c0a20fd794a33b61cc4638e28e9e61ba32f42" + ], + "version": "==2.3.3" + }, + "autopep8": { + "hashes": [ + "sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" + ], + "index": "pypi", + "version": "==1.4.4" + }, + "colorama": { + "hashes": [ + "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff", + "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1" + ], + "markers": "sys_platform == 'win32'", + "version": "==0.4.3" + }, + "isort": { + "hashes": [ + "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", + "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + ], + "version": "==4.3.21" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d", + "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449", + "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08", + "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a", + "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50", + "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd", + "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239", + "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb", + "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea", + "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e", + "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156", + "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142", + "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442", + "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62", + "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db", + "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531", + "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383", + "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a", + "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357", + "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4", + "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0" + ], + "version": "==1.4.3" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", + "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c" + ], + "version": "==2.5.0" + }, + "pylint": { + "hashes": [ + "sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", + "sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1" + ], + "index": "pypi", + "version": "==2.3.1" + }, + "six": { + "hashes": [ + "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", + "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c" + ], + "version": "==1.14.0" + }, + "typed-ast": { + "hashes": [ + "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355", + "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919", + "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa", + "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652", + "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75", + "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01", + "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d", + "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1", + "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907", + "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c", + "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3", + "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b", + "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614", + "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb", + "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b", + "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41", + "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6", + "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34", + "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe", + "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4", + "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7" + ], + "markers": "implementation_name == 'cpython' and python_version < '3.8'", + "version": "==1.4.1" + }, + "wrapt": { + "hashes": [ + "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" + ], + "version": "==1.11.2" + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..92e6fe5 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# 修改的第三方库源码 +```py +# 注释 udsoncan.services.ReadDataByIdentifier 107-108行 +if len(response.data) < offset+len(codec): + raise InvalidResponseException(response, "Value for data identifier 0x%04x was incomplete according to definition in configuration" % did) +# logger.error 添加异常抛出 can.interfaces.canalystii +# 105行 +logger.error("VCI_OpenDevice Error") +raise Exception('VCI_OpenDevice Error') +# 110行 +logger.error("VCI_InitCAN Error") +self.shutdown() +raise Exception('VCI_InitCAN Error') +# 116行 +logger.error("VCI_StartCAN Error") +self.shutdown() +raise Exception('VCI_StartCAN Error') +``` + +# 打包为exe后,复制或创建config.ini到exe目录 +# config.ini示例 +```ini +[CAN_ID] +tx_id = 0x692 +rx_id = 0x693 +``` diff --git a/abc.ico b/abc.ico new file mode 100644 index 0000000..404a2c7 --- /dev/null +++ b/abc.ico Binary files differ diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..684a632 --- /dev/null +++ b/build.bat @@ -0,0 +1,3 @@ +REM Before running this, make sure all PIP dependencies are installed. + +pyinstaller --clean -i abc.ico -F -w --add-binary "ControlCAN.dll;." main.py diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..8e819f8 --- /dev/null +++ b/build.sh @@ -0,0 +1,5 @@ +#/bin/bash + +# Before running this, make sure all PIP dependencies are installed. + +pyinstaller --clean -F -w --add-binary "ControlCAN.dll:." main.py diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..3d9ef9e --- /dev/null +++ b/config.ini @@ -0,0 +1,3 @@ +[CAN_ID] +tx_id = 0x692 +rx_id = 0x693 diff --git a/main.py b/main.py new file mode 100644 index 0000000..1ba63cb --- /dev/null +++ b/main.py @@ -0,0 +1,24 @@ +import sys +import asyncio +from PyQt5.QtWidgets import QApplication +from asyncqt import QEventLoop +from widgets.flash_bootloader_widget import FlashBootloaderWidget +# from widgets.data_identifier_widget import DataIdentifierWidget +# from widgets.diagnostic_trouble_code_widget import DiagnosticTroubleCodeWidget +# from widgets.main_widget import MainWidget + +if __name__ == '__main__': + + app = QApplication(sys.argv) + loop = QEventLoop(app) + asyncio.set_event_loop(loop) + + # w = MainWidget() + w = FlashBootloaderWidget() + # w = DataIdentifierWidget() + # w = DiagnosticTroubleCodeWidget() + w.show() + + with loop: + sys.exit(loop.run_forever()) + #Successfully installed altgraph-0.17 future-0.18.2 pefile-2019.4.18 pyinstaller-3.5 pywin32-ctypes-0.2.0 diff --git a/uds/client.py b/uds/client.py new file mode 100644 index 0000000..1b72f78 --- /dev/null +++ b/uds/client.py @@ -0,0 +1,345 @@ +import asyncio + +from udsoncan import Response, Request, Dtc, MemoryLocation, services +from udsoncan.exceptions import NegativeResponseException, UnexpectedResponseException, ConfigError +from udsoncan.configs import default_client_config + + +class Client(object): + + def __init__(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter, config=default_client_config): + self.reader = reader + self.writer = writer + self.config = dict(config) + + async def send_request(self, request: Request, suppress_positive_response=None, timeout=None): + if timeout is None: + timeout = self.config['request_timeout'] + + payload = request.get_payload(suppress_positive_response) + self.writer.write(payload) + + if suppress_positive_response is None: + payload = await asyncio.wait_for(self.reader.read(4095), timeout) + response = Response.from_payload(payload) + + if not response.positive: + raise NegativeResponseException(response) + + return response + + async def change_session(self, newsession, suppress_positive_response=None, timeout=None): + request = services.DiagnosticSessionControl.make_request(newsession) + + response = await self.send_request(request, suppress_positive_response, timeout) + + if response is None: + return + + services.DiagnosticSessionControl.interpret_response(response) + + if newsession != response.service_data.session_echo: + raise UnexpectedResponseException(response, 'Response subfunction received from server (0x%02x) does not match the requested subfunction (0x%02x)' % ( + response.service_data.session_echo, newsession)) + + return response + + async def request_seed(self, level): + request = services.SecurityAccess.make_request( + level, mode=services.SecurityAccess.Mode.RequestSeed) + + response = await self.send_request(request) + + if response is None: + return + + services.SecurityAccess.interpret_response( + response, mode=services.SecurityAccess.Mode.RequestSeed) + + expected_level = services.SecurityAccess.normalize_level( + mode=services.SecurityAccess.Mode.RequestSeed, level=level) + received_level = response.service_data.security_level_echo + + if expected_level != received_level: + raise UnexpectedResponseException( + response, 'Response subfunction received from server (0x%02x) does not match the requested subfunction (0x%02x)' % (received_level, expected_level)) + + return response + + async def send_key(self, level, key): + request = services.SecurityAccess.make_request( + level, mode=services.SecurityAccess.Mode.SendKey, key=key) + + response = await self.send_request(request) + + if response is None: + return + + services.SecurityAccess.interpret_response( + response, mode=services.SecurityAccess.Mode.SendKey) + + expected_level = services.SecurityAccess.normalize_level( + mode=services.SecurityAccess.Mode.SendKey, level=level) + received_level = response.service_data.security_level_echo + + if expected_level != received_level: + raise UnexpectedResponseException( + response, 'Response subfunction received from server (0x%02x) does not match the requested subfunction (0x%02x)' % (received_level, expected_level)) + + return response + + async def tester_present(self, suppress_positive_response=None, timeout=None): + request = services.TesterPresent.make_request() + + response = await self.send_request(request, suppress_positive_response, timeout) + + if response is None: + return + + services.TesterPresent.interpret_response(response) + + if request.subfunction != response.service_data.subfunction_echo: + raise UnexpectedResponseException(response, 'Response subfunction received from server (0x%02x) does not match the requested subfunction (0x%02x)' % ( + response.service_data.subfunction_echo, request.subfunction)) + + return response + + async def read_data_by_identifier_first(self, didlist): + didlist = services.ReadDataByIdentifier.validate_didlist_input(didlist) + response = await self.read_data_by_identifier(didlist) + values = response.service_data.values + if len(values) > 0 and len(didlist) > 0: + return values[didlist[0]] + + async def read_data_by_identifier(self, didlist): + didlist = services.ReadDataByIdentifier.validate_didlist_input(didlist) + + request = services.ReadDataByIdentifier.make_request( + didlist=didlist, didconfig=self.config['data_identifiers']) + + if 'data_identifiers' not in self.config or not isinstance(self.config['data_identifiers'], dict): + raise AttributeError( + 'Configuration does not contains a valid data identifier description.') + + response = await self.send_request(request) + + if response is None: + return + + params = { + 'didlist': didlist, + 'didconfig': self.config['data_identifiers'], + 'tolerate_zero_padding': self.config['tolerate_zero_padding'] + } + + try: + services.ReadDataByIdentifier.interpret_response( + response, **params) + except ConfigError as e: + if e.key in didlist: + raise + else: + raise UnexpectedResponseException( + response, "Server returned values for data identifier 0x%04x that was not requested and no Codec was defined for it. Parsing must be stopped." % (e.key)) + + set_request_didlist = set(didlist) + set_response_didlist = set(response.service_data.values.keys()) + extra_did = set_response_didlist - set_request_didlist + missing_did = set_request_didlist - set_response_didlist + + if len(extra_did) > 0: + raise UnexpectedResponseException( + response, "Server returned values for %d data identifier that were not requested. Dids are : %s" % (len(extra_did), extra_did)) + + if len(missing_did) > 0: + raise UnexpectedResponseException( + response, "%d data identifier values are missing from server response. Dids are : %s" % (len(missing_did), missing_did)) + + return response + + async def write_data_by_identifier(self, did, value): + request = services.WriteDataByIdentifier.make_request( + did, value, didconfig=self.config['data_identifiers']) + + response = await self.send_request(request) + + if response is None: + return + + services.WriteDataByIdentifier.interpret_response(response) + + if response.service_data.did_echo != did: + raise UnexpectedResponseException(response, 'Server returned a response for data identifier 0x%04x while client requested for did 0x%04x' % ( + response.service_data.did_echo, did)) + + return response + + async def ecu_reset(self, reset_type, suppress_positive_response=None, timeout=None): + request = services.ECUReset.make_request(reset_type) + + response = await self.send_request(request, suppress_positive_response, timeout) + + if response is None: + return + + services.ECUReset.interpret_response(response) + + if response.service_data.reset_type_echo != reset_type: + raise UnexpectedResponseException(response, 'Response subfunction received from server (0x%02x) does not match the requested subfunction (0x%02x)' % ( + response.service_data.reset_type_echo, reset_type)) + + return response + + async def clear_dtc(self, group=0xFFFFFF): + request = services.ClearDiagnosticInformation.make_request(group) + + response = await self.send_request(request) + + if response is None: + return + + services.ClearDiagnosticInformation.interpret_response(response) + + return response + + async def start_routine(self, routine_id, data=None): + response = await self.routine_control(routine_id, services.RoutineControl.ControlType.startRoutine, data) + return response + + async def stop_routine(self, routine_id, data=None): + response = await self.routine_control(routine_id, services.RoutineControl.ControlType.stopRoutine, data) + return response + + async def routine_control(self, routine_id, control_type, data=None): + request = services.RoutineControl.make_request( + routine_id, control_type, data=data) + + response = await self.send_request(request) + + if response is None: + return + + services.RoutineControl.interpret_response(response) + + if control_type != response.service_data.control_type_echo: + raise UnexpectedResponseException(response, 'Control type of response (0x%02x) does not match request control type (0x%02x)' % ( + response.service_data.control_type_echo, control_type)) + + if routine_id != response.service_data.routine_id_echo: + raise UnexpectedResponseException(response, 'Response received from server (ID = 0x%04x) does not match the requested routine ID (0x%04x)' % ( + response.service_data.routine_id_echo, routine_id)) + + return response + + async def communication_control(self, control_type, communication_type, suppress_positive_response=None, timeout=None): + request = services.CommunicationControl.make_request( + control_type, communication_type) + + response = await self.send_request(request, suppress_positive_response, timeout) + + if response is None: + return + + services.CommunicationControl.interpret_response(response) + + if control_type != response.service_data.control_type_echo: + raise UnexpectedResponseException(response, 'Control type of response (0x%02x) does not match request control type (0x%02x)' % ( + response.service_data.control_type_echo, control_type)) + + return response + + async def request_download(self, memory_location, dfi=None): + response = await self.request_upload_download(services.RequestDownload, memory_location, dfi) + return response + + async def request_upload(self, memory_location, dfi=None): + response = await self.request_upload_download(services.RequestUpload, memory_location, dfi) + return response + + async def request_upload_download(self, service_cls, memory_location, dfi=None): + dfi = service_cls.normalize_data_format_identifier(dfi) + + if service_cls not in [services.RequestDownload, services.RequestUpload]: + raise ValueError( + 'Service must either be RequestDownload or RequestUpload') + + if not isinstance(memory_location, MemoryLocation): + raise ValueError( + 'memory_location must be an instance of MemoryLocation') + + if 'server_address_format' in self.config: + memory_location.set_format_if_none( + address_format=self.config['server_address_format']) + + if 'server_memorysize_format' in self.config: + memory_location.set_format_if_none( + memorysize_format=self.config['server_memorysize_format']) + + request = service_cls.make_request( + memory_location=memory_location, dfi=dfi) + + response = await self.send_request(request) + + if response is None: + return + + service_cls.interpret_response(response) + + return response + + async def transfer_data(self, sequence_number, data=None): + request = services.TransferData.make_request(sequence_number, data) + + response = await self.send_request(request) + + if response is None: + return + + services.TransferData.interpret_response(response) + + if sequence_number != response.service_data.sequence_number_echo: + raise UnexpectedResponseException(response, 'Block sequence number of response (0x%02x) does not match request block sequence number (0x%02x)' % ( + response.service_data.sequence_number_echo, sequence_number)) + + return response + + async def request_transfer_exit(self, data=None): + request = services.RequestTransferExit.make_request(data) + + response = await self.send_request(request) + + if response is None: + return + + services.RequestTransferExit.interpret_response(response) + + return response + + async def control_dtc_setting(self, setting_type, data=None, suppress_positive_response=None, timeout=None): + request = services.ControlDTCSetting.make_request( + setting_type, data=data) + + response = await self.send_request(request, suppress_positive_response, timeout) + + if response is None: + return + + services.ControlDTCSetting.interpret_response(response) + + if response.service_data.setting_type_echo != setting_type: + raise UnexpectedResponseException(response, 'Setting type of response (0x%02x) does not match request control type (0x%02x)' % ( + response.service_data.setting_type_echo, setting_type)) + + return response + + async def get_dtc_by_status_mask(self, status_mask): + pass + + async def get_number_of_dtc_by_status_mask(self, status_mask): + pass + + async def get_supported_dtc(self): + pass + + async def read_dtc_information(self, subfunction, status_mask=None, severity_mask=None, dtc=None, snapshot_record_number=None, extended_data_record_number=None, extended_data_size=None): + pass diff --git a/widgets/data_identifier_widget.py b/widgets/data_identifier_widget.py new file mode 100644 index 0000000..c21a183 --- /dev/null +++ b/widgets/data_identifier_widget.py @@ -0,0 +1,794 @@ +from PyQt5 import QtWidgets, QtCore, QtGui +from can.interfaces.canalystii import CANalystIIBus, TIMING_DICT +from can.interfaces.vector import VectorBus +from can.bus import BusABC +import asyncio +import time +import aioisotp +from uds.client import Client +from udsoncan import DidCodec +from udsoncan import DataIdentifier +from udsoncan.configs import default_client_config +import struct +import configparser + + +class AsciiCodec(DidCodec): + + def __init__(self, string_len=None): + if string_len is None: + raise ValueError( + "You must provide a length to the AsciiCodec") + self.string_len = string_len + + def encode(self, string_ascii): + if len(string_ascii) > self.string_len: + string_ascii = string_ascii[0:self.string_len] + + elif len(string_ascii) < self.string_len: + for i in range(self.string_len - len(string_ascii)): + string_ascii += ' ' + + return string_ascii.encode('ascii') + + def decode(self, string_bin): + string_ascii = string_bin.decode('ascii') + if len(string_ascii) > self.string_len: + string_ascii = string_ascii[0:self.string_len] + + return string_ascii.strip() + + def __len__(self): + return self.string_len + + +class PartNumberCodec(DidCodec): + def __init__(self, byte_len=None): + if byte_len is None: + raise ValueError( + "You must provide a length to the PartNumberCodec") + self.byte_len = byte_len + + def encode(self, string_ascii): + if self.byte_len == 1: + data = struct.pack('>B', int(string_ascii)) + elif self.byte_len == 2: + data = struct.pack('>H', int(string_ascii)) + elif self.byte_len == 4: + data = struct.pack('>L', int(string_ascii)) + elif self.byte_len == 8: + data = struct.pack('>Q', int(string_ascii)) + + if len(data) > self.byte_len: + data = data[0:self.byte_len] + + return data + + def decode(self, byte_data): + data = 0 + for i in byte_data: + data = data << 8 | i + return str(data) + + def __len__(self): + return self.byte_len + + +class PartNumberVersionCodec(DidCodec): + def __init__(self, byte_len=None): + if byte_len is None: + raise ValueError( + "You must provide a length to the PartNumberCodec") + self.byte_len = byte_len + + def encode(self, string_ascii): + if self.byte_len == 1: + data = struct.pack('>B', int(string_ascii)) + elif self.byte_len == 2: + data = struct.pack('>H', int(string_ascii)) + elif self.byte_len == 4: + data = struct.pack('>L', int(string_ascii)) + elif self.byte_len == 8: + data = struct.pack('>Q', int(string_ascii)) + + if len(data) > self.byte_len: + data = data[0:self.byte_len] + + return data + + def decode(self, byte_data): + ret = '' + for i in byte_data: + ret += '%.1x' % i + return ret + + def __len__(self): + return self.byte_len + + +class BCDCodec(DidCodec): + + def __init__(self, byte_len=None): + self.byte_len = byte_len + + def encode(self, string_ascii): + string_ascii = string_ascii.strip() + + if len(string_ascii) > self.byte_len * 2: + string_ascii = string_ascii[0:self.byte_len * 2] + elif len(string_ascii) < self.byte_len * 2: + for i in range(self.byte_len * 2 - len(string_ascii)): + string_ascii += '0' + + data = bytearray() + for i in range(self.byte_len): + part = string_ascii[2 * i: 2 * i + 2] + data.append(int(part, 16)) + + return data + + def decode(self, byte_data): + ret = '' + for i in byte_data: + ret += '%.2x' % i + + return ret + + def __len__(self): + return self.byte_len + + +class DataIdentifierWidget(QtWidgets.QWidget): + + def __init__(self, parent=None, flags=QtCore.Qt.WindowFlags()): + super().__init__(parent=parent, flags=flags) + self.initUI() + self.client: Client = None + self.opened_flag = False + self.did_config = { + 0xF190: AsciiCodec(17), + 0xF1B1: AsciiCodec(9), + 0xF1B2: AsciiCodec(16), + + 0xF1D0: PartNumberCodec(4), + 0xF1D1: PartNumberVersionCodec(2), + 0xF1D2: PartNumberCodec(4), + 0xF1D3: PartNumberVersionCodec(2), + 0xF0DF: PartNumberVersionCodec(1), + + 0xF187: AsciiCodec(21), + 0xF195: AsciiCodec(16), + 0xF198: BCDCodec(8), + 0xF199: BCDCodec(4), + } + + try: + config = configparser.ConfigParser() + config.read('config.ini') + self.tx_id = int(config['CAN_ID']['tx_id'], 16) + self.rx_id = int(config['CAN_ID']['rx_id'], 16) + self.append_text_to_log_display('read config.ini success') + except Exception as e: + self.append_text_to_log_display( + 'read config.ini error, use 0x692 and 0x693 for default tx_id and rx_id', '#ff0000') + self.tx_id = 0x692 + self.rx_id = 0x693 + + def initUI(self): + + self.setWindowTitle('Data Identifier') + self.setFont(QtGui.QFont('Segoe UI')) + + cb_interface_type = QtWidgets.QComboBox(self) + cb_interface_type.addItems(['vector', 'canalystii']) + cb_interface_type.setObjectName('cb_interface_type') + + cb_baudrate = QtWidgets.QComboBox(self) + cb_baudrate.addItems([('%dK' % (i/1000)) for i in TIMING_DICT.keys()]) + cb_baudrate.setCurrentIndex(14) + cb_baudrate.setObjectName('cb_baudrate') + + cb_can_channel = QtWidgets.QComboBox(self) + cb_can_channel.addItems(['CH1/3', 'CH2/4']) + cb_can_channel.setObjectName('cb_can_channel') + + btn_open = QtWidgets.QPushButton(self) + btn_open.setText('open') + btn_open.setObjectName('btn_open') + btn_close = QtWidgets.QPushButton(self) + btn_close.setText('close') + btn_close.setObjectName('btn_close') + + hb0 = QtWidgets.QHBoxLayout() + hb0.addWidget(cb_interface_type) + hb0.addWidget(cb_baudrate) + hb0.addWidget(cb_can_channel) + hb0.addWidget(btn_open) + hb0.addWidget(btn_close) + + # 0xF190 + lb_0xf190 = QtWidgets.QLabel(self) + lb_0xf190.setText('Vehicle Identification Number') + le_0xf190 = QtWidgets.QLineEdit(self) + le_0xf190.setObjectName('le_0xf190') + btn_read_0xf190 = QtWidgets.QPushButton(self) + btn_read_0xf190.setText('read') + btn_read_0xf190.setObjectName('btn_read_0xf190') + btn_write_0xf190 = QtWidgets.QPushButton(self) + btn_write_0xf190.setText('write') + btn_write_0xf190.setObjectName('btn_write_0xf190') + + # 0xF1B1 + lb_0xf1b1 = QtWidgets.QLabel(self) + lb_0xf1b1.setText('Data Universal Numbering System') + le_0xf1b1 = QtWidgets.QLineEdit(self) + le_0xf1b1.setObjectName('le_0xf1b1') + btn_read_0xf1b1 = QtWidgets.QPushButton(self) + btn_read_0xf1b1.setText('read') + btn_read_0xf1b1.setObjectName('btn_read_0xf1b1') + + # 0xF1B2 + lb_0xf1b2 = QtWidgets.QLabel(self) + lb_0xf1b2.setText('Manufacturing Traceability Characters') + le_0xf1b2 = QtWidgets.QLineEdit(self) + le_0xf1b2.setObjectName('le_0xf1b2') + btn_read_0xf1b2 = QtWidgets.QPushButton(self) + btn_read_0xf1b2.setText('read') + btn_read_0xf1b2.setObjectName('btn_read_0xf1b2') + btn_write_0xf1b2 = QtWidgets.QPushButton(self) + btn_write_0xf1b2.setText('write') + btn_write_0xf1b2.setObjectName('btn_write_0xf1b2') + + # 0xF1D0 + lb_0xf1d0 = QtWidgets.QLabel(self) + lb_0xf1d0.setText('Base Model Part Number') + le_0xf1d0 = QtWidgets.QLineEdit(self) + le_0xf1d0.setObjectName('le_0xf1d0') + btn_read_0xf1d0 = QtWidgets.QPushButton(self) + btn_read_0xf1d0.setText('read') + btn_read_0xf1d0.setObjectName('btn_read_0xf1d0') + + # 0xF1D1 + lb_0xf1d1 = QtWidgets.QLabel(self) + lb_0xf1d1.setText('Base Model Part Number Version Code') + le_0xf1d1 = QtWidgets.QLineEdit(self) + le_0xf1d1.setObjectName('le_0xf1d1') + btn_read_0xf1d1 = QtWidgets.QPushButton(self) + btn_read_0xf1d1.setText('read') + btn_read_0xf1d1.setObjectName('btn_read_0xf1d1') + + # 0xF1D2 + lb_0xf1d2 = QtWidgets.QLabel(self) + lb_0xf1d2.setText('End Model Part Number') + le_0xf1d2 = QtWidgets.QLineEdit(self) + le_0xf1d2.setObjectName('le_0xf1d2') + btn_read_0xf1d2 = QtWidgets.QPushButton(self) + btn_read_0xf1d2.setText('read') + btn_read_0xf1d2.setObjectName('btn_read_0xf1d2') + + # 0xF1D3 + lb_0xf1d3 = QtWidgets.QLabel(self) + lb_0xf1d3.setText('End Model Part Number Version Code') + le_0xf1d3 = QtWidgets.QLineEdit(self) + le_0xf1d3.setObjectName('le_0xf1d3') + btn_read_0xf1d3 = QtWidgets.QPushButton(self) + btn_read_0xf1d3.setText('read') + btn_read_0xf1d3.setObjectName('btn_read_0xf1d3') + + # 0xF0DF + lb_0xf0df = QtWidgets.QLabel(self) + lb_0xf0df.setText('Manufacturers Mode Flag') + cb_0xf0df = QtWidgets.QComboBox(self) + cb_0xf0df.setObjectName('cb_0xf0df') + cb_0xf0df.addItem('NonFactoryModel', 0) + cb_0xf0df.addItem('FactoryMode', 1) + btn_read_0xf0df = QtWidgets.QPushButton(self) + btn_read_0xf0df.setText('read') + btn_read_0xf0df.setObjectName('btn_read_0xf0df') + btn_write_0xf0df = QtWidgets.QPushButton(self) + btn_write_0xf0df.setText('write') + btn_write_0xf0df.setObjectName('btn_write_0xf0df') + + # 0xF187 + lb_0xf187 = QtWidgets.QLabel(self) + lb_0xf187.setText('ECU Part Number') + le_0xf187 = QtWidgets.QLineEdit(self) + le_0xf187.setObjectName('le_0xf187') + btn_read_0xf187 = QtWidgets.QPushButton(self) + btn_read_0xf187.setText('read') + btn_read_0xf187.setObjectName('btn_read_0xf187') + + # 0xF195 + lb_0xf195 = QtWidgets.QLabel(self) + lb_0xf195.setText('Supplier ECU Software Version Number') + le_0xf195 = QtWidgets.QLineEdit(self) + le_0xf195.setObjectName('le_0xf195') + btn_read_0xf195 = QtWidgets.QPushButton(self) + btn_read_0xf195.setText('read') + btn_read_0xf195.setObjectName('btn_read_0xf195') + + # 0xF198 + lb_0xf198 = QtWidgets.QLabel(self) + lb_0xf198.setText('Repair Shop Code') + le_0xf198 = QtWidgets.QLineEdit(self) + le_0xf198.setObjectName('le_0xf198') + btn_read_0xf198 = QtWidgets.QPushButton(self) + btn_read_0xf198.setText('read') + btn_read_0xf198.setObjectName('btn_read_0xf198') + btn_write_0xf198 = QtWidgets.QPushButton(self) + btn_write_0xf198.setText('write') + btn_write_0xf198.setObjectName('btn_write_0xf198') + + # 0xF199 + lb_0xf199 = QtWidgets.QLabel(self) + lb_0xf199.setText('Programming Date') + le_0xf199 = QtWidgets.QLineEdit(self) + le_0xf199.setObjectName('le_0xf199') + btn_read_0xf199 = QtWidgets.QPushButton(self) + btn_read_0xf199.setText('read') + btn_read_0xf199.setObjectName('btn_read_0xf199') + btn_write_0xf199 = QtWidgets.QPushButton(self) + btn_write_0xf199.setText('write') + btn_write_0xf199.setObjectName('btn_write_0xf199') + + gl0 = QtWidgets.QGridLayout() + + gl0.addWidget(lb_0xf190, 0, 0, 1, 1) + gl0.addWidget(le_0xf190, 0, 1, 1, 1) + gl0.addWidget(btn_read_0xf190, 0, 2, 1, 1) + gl0.addWidget(btn_write_0xf190, 0, 3, 1, 1) + + gl0.addWidget(lb_0xf1b1, 1, 0, 1, 1) + gl0.addWidget(le_0xf1b1, 1, 1, 1, 1) + gl0.addWidget(btn_read_0xf1b1, 1, 2, 1, 1) + + gl0.addWidget(lb_0xf1b2, 2, 0, 1, 1) + gl0.addWidget(le_0xf1b2, 2, 1, 1, 1) + gl0.addWidget(btn_read_0xf1b2, 2, 2, 1, 1) + gl0.addWidget(btn_write_0xf1b2, 2, 3, 1, 1) + + gl0.addWidget(lb_0xf1d0, 3, 0, 1, 1) + gl0.addWidget(le_0xf1d0, 3, 1, 1, 1) + gl0.addWidget(btn_read_0xf1d0, 3, 2, 1, 1) + + gl0.addWidget(lb_0xf1d1, 4, 0, 1, 1) + gl0.addWidget(le_0xf1d1, 4, 1, 1, 1) + gl0.addWidget(btn_read_0xf1d1, 4, 2, 1, 1) + + gl0.addWidget(lb_0xf1d2, 5, 0, 1, 1) + gl0.addWidget(le_0xf1d2, 5, 1, 1, 1) + gl0.addWidget(btn_read_0xf1d2, 5, 2, 1, 1) + + gl0.addWidget(lb_0xf1d3, 6, 0, 1, 1) + gl0.addWidget(le_0xf1d3, 6, 1, 1, 1) + gl0.addWidget(btn_read_0xf1d3, 6, 2, 1, 1) + + gl0.addWidget(lb_0xf0df, 7, 0, 1, 1) + gl0.addWidget(cb_0xf0df, 7, 1, 1, 1) + gl0.addWidget(btn_read_0xf0df, 7, 2, 1, 1) + gl0.addWidget(btn_write_0xf0df, 7, 3, 1, 1) + + gl0.addWidget(lb_0xf187, 8, 0, 1, 1) + gl0.addWidget(le_0xf187, 8, 1, 1, 1) + gl0.addWidget(btn_read_0xf187, 8, 2, 1, 1) + + gl0.addWidget(lb_0xf195, 9, 0, 1, 1) + gl0.addWidget(le_0xf195, 9, 1, 1, 1) + gl0.addWidget(btn_read_0xf195, 9, 2, 1, 1) + + gl0.addWidget(lb_0xf198, 10, 0, 1, 1) + gl0.addWidget(le_0xf198, 10, 1, 1, 1) + gl0.addWidget(btn_read_0xf198, 10, 2, 1, 1) + gl0.addWidget(btn_write_0xf198, 10, 3, 1, 1) + + gl0.addWidget(lb_0xf199, 11, 0, 1, 1) + gl0.addWidget(le_0xf199, 11, 1, 1, 1) + gl0.addWidget(btn_read_0xf199, 11, 2, 1, 1) + gl0.addWidget(btn_write_0xf199, 11, 3, 1, 1) + + tb_log_display = QtWidgets.QTextBrowser(self) + tb_log_display.setObjectName('tb_log_display') + + hb1 = QtWidgets.QHBoxLayout() + hb1.addWidget(tb_log_display) + + vb = QtWidgets.QVBoxLayout() + vb.addLayout(hb0) + vb.addLayout(gl0) + vb.addLayout(hb1) + + self.setLayout(vb) + + QtCore.QMetaObject.connectSlotsByName(self) + + @QtCore.pyqtSlot(str) + def on_cb_interface_type_currentIndexChanged(self, text): + + if text == 'vector': + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(0, 'CH1/3') + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(1, 'CH2/4') + elif text == 'canalystii': + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(0, 'CAN1') + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(1, 'CAN2') + + @QtCore.pyqtSlot() + def on_btn_open_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.open_device_task()) + + @QtCore.pyqtSlot() + def on_btn_close_clicked(self): + self.opened_flag = False + self.client = None + self.append_text_to_log_display('close device success') + + @QtCore.pyqtSlot() + def on_btn_read_0xf190_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf190_task()) + + @QtCore.pyqtSlot() + def on_btn_write_0xf190_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.write_0xf190_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf1b1_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf1b1_task()) + + @QtCore.pyqtSlot() + def on_btn_write_0xf1b1_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.write_0xf1b1_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf1b2_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf1b2_task()) + + @QtCore.pyqtSlot() + def on_btn_write_0xf1b2_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.write_0xf1b2_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf1d0_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf1d0_task()) + + @QtCore.pyqtSlot() + def on_btn_write_0xf1d0_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.write_0xf1d0_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf1d1_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf1d1_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf1d2_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf1d2_task()) + + @QtCore.pyqtSlot() + def on_btn_write_0xf1d2_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.write_0xf1d2_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf1d3_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf1d3_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf0df_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf0df_task()) + + @QtCore.pyqtSlot() + def on_btn_write_0xf0df_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.write_0xf0df_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf187_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf187_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf195_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf195_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf198_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf198_task()) + + @QtCore.pyqtSlot() + def on_btn_write_0xf198_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.write_0xf198_task()) + + @QtCore.pyqtSlot() + def on_btn_read_0xf199_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.read_0xf199_task()) + + @QtCore.pyqtSlot() + def on_btn_write_0xf199_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.write_0xf199_task()) + + @QtCore.pyqtSlot() + def on_btn_write_0xf199_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.write_0xf199_task()) + + def append_text_to_log_display(self, text, color='#000000'): + + text = '<font color="%s">%s</font>' % (color, text) + self.findChild(QtWidgets.QTextEdit, 'tb_log_display').append(text) + + def clear_log_display(self): + + self.findChild(QtWidgets.QTextEdit, 'tb_log_display').clear() + + async def open_device_task(self): + + if self.opened_flag is True: + self.append_text_to_log_display('already opened', '#ff0000') + return + + interface_type_index = self.findChild( + QtWidgets.QComboBox, 'cb_interface_type').currentIndex() + + baudrate_index = self.findChild( + QtWidgets.QComboBox, 'cb_baudrate').currentIndex() + + can_channel_index = self.findChild( + QtWidgets.QComboBox, 'cb_can_channel').currentIndex() + + # bus = VectorBus(channel=1, bitrate=500000, can_filters=can_filters) + # bus = CANalystIIBus(channel=0, baud=500000, can_filters=can_filters) + + self.clear_log_display() + + can_filters = [ + {'can_id': self.rx_id, 'can_mask': 0xFFFFFFFF} + ] + + bitrate = list(TIMING_DICT.keys())[baudrate_index] + + try: + bus: BusABC = None + if interface_type_index == 0: + bus = VectorBus(channel=can_channel_index, + bitrate=bitrate, can_filters=can_filters) + + elif interface_type_index == 1: + bus = CANalystIIBus(channel=can_channel_index, + baud=bitrate, can_filters=can_filters) + + network = aioisotp.ISOTPNetwork(bus=bus) + + with network.open(): + reader, writer = await network.open_connection(self.rx_id, self.tx_id) + client = Client(reader, writer) + client.config['data_identifiers'] = self.did_config + + self.client = client + + try: + response = await client.tester_present(timeout=0.3) + except asyncio.TimeoutError: + pass + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + await client.change_session(3) + await client.request_seed(1) + await client.send_key(1, bytes([0x6d, 0xfb, 0x53, 0x20])) + + self.append_text_to_log_display('open device success') + self.opened_flag = True + + while self.opened_flag: + await client.tester_present(True) + await asyncio.sleep(1) + # print('tester present') + except asyncio.TimeoutError: + self.append_text_to_log_display('open device failed', '#ff0000') + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf190_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf190) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf190').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def write_0xf190_task(self): + try: + client = self.client + value = self.findChild(QtWidgets.QLineEdit, 'le_0xf190').text() + await client.write_data_by_identifier(0xf190, value) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf1b1_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf1b1) + data = response.strip() + self.findChild(QtWidgets.QLineEdit, + 'le_0xf1b1').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def write_0xf1b1_task(self): + try: + client = self.client + value = self.findChild(QtWidgets.QLineEdit, 'le_0xf1b1').text() + await client.write_data_by_identifier(0xf1b1, value) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf1b2_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf1b2) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf1b2').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def write_0xf1b2_task(self): + try: + client = self.client + value = self.findChild(QtWidgets.QLineEdit, 'le_0xf1b2').text() + await client.write_data_by_identifier(0xf1b2, value) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf1d0_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf1d0) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf1d0').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def write_0xf1d0_task(self): + try: + client = self.client + value = self.findChild(QtWidgets.QLineEdit, 'le_0xf1d0').text() + await client.write_data_by_identifier(0xf1d0, value) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf1d1_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf1d1) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf1d1').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf1d2_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf1d2) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf1d2').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def write_0xf1d2_task(self): + try: + client = self.client + value = self.findChild(QtWidgets.QLineEdit, 'le_0xf1d2').text() + await client.write_data_by_identifier(0xf1d2, value) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf1d3_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf1d3) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf1d3').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf0df_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf0df) + data = response + self.findChild(QtWidgets.QComboBox, + 'cb_0xf0df').setCurrentIndex(int(data)) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def write_0xf0df_task(self): + try: + client = self.client + value = self.findChild(QtWidgets.QComboBox, + 'cb_0xf0df').currentIndex() + await client.write_data_by_identifier(0xf0df, value) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf187_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf187) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf187').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf195_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf195) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf195').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf198_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf198) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf198').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def write_0xf198_task(self): + try: + client = self.client + value = self.findChild(QtWidgets.QLineEdit, 'le_0xf198').text() + await client.write_data_by_identifier(0xf198, value) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def read_0xf199_task(self): + try: + client = self.client + response = await client.read_data_by_identifier_first(0xf199) + data = response + self.findChild(QtWidgets.QLineEdit, + 'le_0xf199').setText(data) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def write_0xf199_task(self): + try: + client = self.client + value = self.findChild(QtWidgets.QLineEdit, 'le_0xf199').text() + await client.write_data_by_identifier(0xf199, value) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') diff --git a/widgets/diagnostic_trouble_code_widget.py b/widgets/diagnostic_trouble_code_widget.py new file mode 100644 index 0000000..d93394e --- /dev/null +++ b/widgets/diagnostic_trouble_code_widget.py @@ -0,0 +1,455 @@ +from PyQt5 import QtWidgets, QtCore, QtGui +from can.interfaces.canalystii import CANalystIIBus, TIMING_DICT +from can.interfaces.vector import VectorBus +from can.bus import BusABC +import asyncio +import time +import aioisotp +from uds.client import Client +from udsoncan import MemoryLocation +import configparser + + +dtc_describe = { + 0x550122: 'P按键信号不正常', + 0x550271: '马达动作故障', + 0x550329: 'HOME侧传感器异常', + 0x550429: 'M侧传感器故障', + 0xD10017: '超过正常诊断电压', + 0xD10116: '低于正常诊断电压', + 0xC00188: 'BUS OFF', + 0xC29187: '丢失TCU信号', + 0xC14687: '丢失GW信号', +} + + +class DiagnosticTroubleCodeWidget(QtWidgets.QWidget): + + def __init__(self, parent=None, flags=QtCore.Qt.WindowFlags()): + super().__init__(parent=parent, flags=flags) + self.initUI() + self.client: Client = None + self.opened_flag = False + self.dtc_mask = 0 + + try: + config = configparser.ConfigParser() + config.read('config.ini') + self.tx_id = int(config['CAN_ID']['tx_id'], 16) + self.rx_id = int(config['CAN_ID']['rx_id'], 16) + self.append_text_to_log_display('read config.ini success') + except Exception as e: + self.append_text_to_log_display( + 'read config.ini error, use 0x692 and 0x693 for default tx_id and rx_id', '#ff0000') + self.tx_id = 0x692 + self.rx_id = 0x693 + + def initUI(self): + + self.setWindowTitle('Diagnostic Trouble Code') + self.setFont(QtGui.QFont('Segoe UI')) + + cb_interface_type = QtWidgets.QComboBox(self) + cb_interface_type.addItems(['vector', 'canalystii']) + cb_interface_type.setObjectName('cb_interface_type') + + cb_baudrate = QtWidgets.QComboBox(self) + cb_baudrate.addItems([('%dK' % (i/1000)) for i in TIMING_DICT.keys()]) + cb_baudrate.setCurrentIndex(14) + cb_baudrate.setObjectName('cb_baudrate') + + cb_can_channel = QtWidgets.QComboBox(self) + cb_can_channel.addItems(['CH1/3', 'CH2/4']) + cb_can_channel.setObjectName('cb_can_channel') + + btn_open = QtWidgets.QPushButton(self) + btn_open.setText('open') + btn_open.setObjectName('btn_open') + btn_close = QtWidgets.QPushButton(self) + btn_close.setText('close') + btn_close.setObjectName('btn_close') + + hb0 = QtWidgets.QHBoxLayout() + hb0.addWidget(cb_interface_type) + hb0.addWidget(cb_baudrate) + hb0.addWidget(cb_can_channel) + hb0.addWidget(btn_open) + hb0.addWidget(btn_close) + + btn_dtc_on = QtWidgets.QPushButton('DTC On', self) + btn_dtc_on.setObjectName('btn_dtc_on') + btn_dtc_off = QtWidgets.QPushButton('DTC Off', self) + btn_dtc_off.setObjectName('btn_dtc_off') + btn_clear_dtc = QtWidgets.QPushButton('Clear DTC', self) + btn_clear_dtc.setObjectName('btn_clear_dtc') + + hb1 = QtWidgets.QHBoxLayout() + hb1.addWidget(btn_dtc_on) + hb1.addWidget(btn_dtc_off) + hb1.addWidget(btn_clear_dtc) + + btn_get_number_of_dtc_by_status_mask = QtWidgets.QPushButton(self) + btn_get_number_of_dtc_by_status_mask.setText( + 'get number of dtc by status_mask') + btn_get_number_of_dtc_by_status_mask.setObjectName( + 'btn_get_number_of_dtc_by_status_mask') + + btn_get_dtc_by_status_mask = QtWidgets.QPushButton(self) + btn_get_dtc_by_status_mask.setText('get dtc by status mask') + btn_get_dtc_by_status_mask.setObjectName('btn_get_dtc_by_status_mask') + + btn_get_supported_dtc = QtWidgets.QPushButton(self) + btn_get_supported_dtc.setText('get supported dtc') + btn_get_supported_dtc.setObjectName('btn_get_supported_dtc') + + hb2 = QtWidgets.QHBoxLayout() + hb2.addWidget(btn_get_number_of_dtc_by_status_mask) + hb2.addWidget(btn_get_dtc_by_status_mask) + hb2.addWidget(btn_get_supported_dtc) + + cb_bit0 = QtWidgets.QCheckBox(self) + cb_bit0.setText('bit0 : testFailed') + cb_bit0.setObjectName('cb_bit0') + cb_bit1 = QtWidgets.QCheckBox(self) + cb_bit1.setText('bit1 : testFailedThisOperationCycle') + cb_bit1.setObjectName('cb_bit1') + cb_bit2 = QtWidgets.QCheckBox(self) + cb_bit2.setText('bit2 : pendingDTC') + cb_bit2.setObjectName('cb_bit2') + cb_bit3 = QtWidgets.QCheckBox(self) + cb_bit3.setText('bit3 : confirmedDTC') + cb_bit3.setObjectName('cb_bit3') + + cb_bit4 = QtWidgets.QCheckBox(self) + cb_bit4.setText('bit4 : testNotCompletedSinceLastClear') + cb_bit4.setObjectName('cb_bit4') + cb_bit5 = QtWidgets.QCheckBox(self) + cb_bit5.setText('bit5 : testFailedSinceLastClear') + cb_bit5.setObjectName('cb_bit5') + cb_bit6 = QtWidgets.QCheckBox(self) + cb_bit6.setText('bit6 : testNotCompletedThisOperationCycle') + cb_bit6.setObjectName('cb_bit6') + cb_bit7 = QtWidgets.QCheckBox(self) + cb_bit7.setText('bit7 : warningIndicatorRequested') + cb_bit7.setObjectName('cb_bit7') + + gl0 = QtWidgets.QGridLayout() + + gl0.addWidget(cb_bit0, 0, 0, 1, 1) + gl0.addWidget(cb_bit1, 0, 1, 1, 1) + gl0.addWidget(cb_bit2, 0, 2, 1, 1) + gl0.addWidget(cb_bit3, 0, 3, 1, 1) + gl0.addWidget(cb_bit4, 1, 0, 1, 1) + gl0.addWidget(cb_bit5, 1, 1, 1, 1) + gl0.addWidget(cb_bit6, 1, 2, 1, 1) + gl0.addWidget(cb_bit7, 1, 3, 1, 1) + + gb_dtc_bits = QtWidgets.QGroupBox('dtc mask bits', self) + gb_dtc_bits.setLayout(gl0) + + hb3 = QtWidgets.QHBoxLayout() + hb3.addWidget(gb_dtc_bits) + + tb_log_display = QtWidgets.QTextBrowser(self) + tb_log_display.setObjectName('tb_log_display') + + hb4 = QtWidgets.QHBoxLayout() + hb4.addWidget(tb_log_display) + + vb = QtWidgets.QVBoxLayout() + vb.addLayout(hb0) + vb.addLayout(hb1) + vb.addLayout(hb2) + vb.addLayout(hb3) + vb.addLayout(hb4) + + self.setLayout(vb) + + QtCore.QMetaObject.connectSlotsByName(self) + + @QtCore.pyqtSlot(str) + def on_cb_interface_type_currentIndexChanged(self, text): + + if text == 'vector': + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(0, 'CH1/3') + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(1, 'CH2/4') + elif text == 'canalystii': + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(0, 'CAN1') + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(1, 'CAN2') + + @QtCore.pyqtSlot() + def on_btn_open_clicked(self): + loop = asyncio.get_event_loop() + loop.create_task(self.open_device_task()) + + @QtCore.pyqtSlot() + def on_btn_close_clicked(self): + self.opened_flag = False + self.client = None + self.append_text_to_log_display('close device success') + + @QtCore.pyqtSlot() + def on_btn_dtc_on_clicked(self): + if self.opened_flag: + loop = asyncio.get_event_loop() + loop.create_task(self.control_dtc_task(1)) + else: + self.append_text_to_log_display( + 'please open the device', '#ff0000') + + @QtCore.pyqtSlot() + def on_btn_dtc_off_clicked(self): + if self.opened_flag: + loop = asyncio.get_event_loop() + loop.create_task(self.control_dtc_task(2)) + else: + self.append_text_to_log_display( + 'please open the device', '#ff0000') + + @QtCore.pyqtSlot() + def on_btn_clear_dtc_clicked(self): + if self.opened_flag: + loop = asyncio.get_event_loop() + loop.create_task(self.clear_dtc_task()) + else: + self.append_text_to_log_display( + 'please open the device', '#ff0000') + + @QtCore.pyqtSlot() + def on_btn_get_number_of_dtc_by_status_mask_clicked(self): + if self.opened_flag: + loop = asyncio.get_event_loop() + loop.create_task(self.get_number_of_dtc_by_status_mask_task()) + else: + self.append_text_to_log_display( + 'please open the device', '#ff0000') + + @QtCore.pyqtSlot() + def on_btn_get_dtc_by_status_mask_clicked(self): + if self.opened_flag: + loop = asyncio.get_event_loop() + loop.create_task(self.get_dtc_by_status_mask_task()) + else: + self.append_text_to_log_display( + 'please open the device', '#ff0000') + + @QtCore.pyqtSlot() + def on_btn_get_supported_dtc_clicked(self): + if self.opened_flag: + loop = asyncio.get_event_loop() + loop.create_task(self.get_supported_dtc_task()) + else: + self.append_text_to_log_display( + 'please open the device', '#ff0000') + + @QtCore.pyqtSlot(int) + def on_cb_bit0_stateChanged(self, state): + if state == 0: + self.dtc_mask &= ~(1 << 0) + else: + self.dtc_mask |= 1 << 0 + + @QtCore.pyqtSlot(int) + def on_cb_bit1_stateChanged(self, state): + if state == 0: + self.dtc_mask &= ~(1 << 1) + else: + self.dtc_mask |= 1 << 1 + + @QtCore.pyqtSlot(int) + def on_cb_bit2_stateChanged(self, state): + if state == 0: + self.dtc_mask &= ~(1 << 2) + else: + self.dtc_mask |= 1 << 2 + + @QtCore.pyqtSlot(int) + def on_cb_bit3_stateChanged(self, state): + if state == 0: + self.dtc_mask &= ~(1 << 3) + else: + self.dtc_mask |= 1 << 3 + + @QtCore.pyqtSlot(int) + def on_cb_bit4_stateChanged(self, state): + if state == 0: + self.dtc_mask &= ~(1 << 4) + else: + self.dtc_mask |= 1 << 4 + + @QtCore.pyqtSlot(int) + def on_cb_bit5_stateChanged(self, state): + if state == 0: + self.dtc_mask &= ~(1 << 5) + else: + self.dtc_mask |= 1 << 5 + + @QtCore.pyqtSlot(int) + def on_cb_bit6_stateChanged(self, state): + if state == 0: + self.dtc_mask &= ~(1 << 6) + else: + self.dtc_mask |= 1 << 6 + + @QtCore.pyqtSlot(int) + def on_cb_bit7_stateChanged(self, state): + if state == 0: + self.dtc_mask &= ~(1 << 7) + else: + self.dtc_mask |= 1 << 7 + + def append_text_to_log_display(self, text, color='#000000'): + + text = '<font color="%s">%s</font>' % (color, text) + self.findChild(QtWidgets.QTextEdit, 'tb_log_display').append(text) + + def clear_log_display(self): + + self.findChild(QtWidgets.QTextEdit, 'tb_log_display').clear() + + async def open_device_task(self): + + if self.opened_flag is True: + self.append_text_to_log_display('already opened', '#ff0000') + return + + interface_type_index = self.findChild( + QtWidgets.QComboBox, 'cb_interface_type').currentIndex() + + baudrate_index = self.findChild( + QtWidgets.QComboBox, 'cb_baudrate').currentIndex() + + can_channel_index = self.findChild( + QtWidgets.QComboBox, 'cb_can_channel').currentIndex() + + # bus = VectorBus(channel=1, bitrate=500000, can_filters=can_filters) + # bus = CANalystIIBus(channel=0, baud=500000, can_filters=can_filters) + + self.clear_log_display() + + can_filters = [ + {'can_id': self.rx_id, 'can_mask': 0xFFFFFFFF} + ] + + bitrate = list(TIMING_DICT.keys())[baudrate_index] + + try: + bus: BusABC = None + if interface_type_index == 0: + bus = VectorBus(channel=can_channel_index, + bitrate=bitrate, can_filters=can_filters) + + elif interface_type_index == 1: + bus = CANalystIIBus(channel=can_channel_index, + baud=bitrate, can_filters=can_filters) + + network = aioisotp.ISOTPNetwork(bus=bus) + + with network.open(): + reader, writer = await network.open_connection(self.rx_id, self.tx_id) + client = Client(reader, writer) + + self.client = client + + try: + response = await client.tester_present(timeout=0.3) + except asyncio.TimeoutError: + pass + except Exception as e: + print(e) + + await client.change_session(3) + await client.request_seed(1) + await client.send_key(1, bytes([0x6d, 0xfb, 0x53, 0x20])) + + self.append_text_to_log_display('open device success') + self.opened_flag = True + + while self.opened_flag: + await client.tester_present(True) + await asyncio.sleep(1) + # print('tester present') + except asyncio.TimeoutError: + self.append_text_to_log_display('open device failed', '#ff0000') + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def control_dtc_task(self, setting_type): + try: + response = await self.client.control_dtc_setting(setting_type) + # print(response) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def clear_dtc_task(self, group=0xffffff): + try: + response = await self.client.clear_dtc(group) + # print(response) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def get_number_of_dtc_by_status_mask_task(self): + + if self.dtc_mask == 0: + self.append_text_to_log_display('dtc mask is empty', '#ff0000') + return + + try: + self.client.writer.write(bytes([0x19, 0x01, self.dtc_mask])) + payload = await asyncio.wait_for(self.client.reader.read(4095), 1) + self.append_text_to_log_display( + '>>> 0x1901 get_number_of_dtc_by_status_mask') + self.append_text_to_log_display('Status Mask:0x%.2x DTC Format:0x%.2x DTC Count:%d' % ( + payload[2], payload[3], payload[4] << 8 | payload[5])) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def get_dtc_by_status_mask_task(self): + + if self.dtc_mask == 0: + self.append_text_to_log_display('dtc mask is empty', '#ff0000') + return + + try: + self.client.writer.write(bytes([0x19, 0x02, self.dtc_mask])) + payload = await asyncio.wait_for(self.client.reader.read(4095), 1) + self.append_text_to_log_display( + '>>> 0x1902 get_dtc_by_status_mask') + for i in range(len(payload[3:]) // 4): + a = i * 4 + 3 + b = i * 4 + 4 + c = i * 4 + 5 + d = i * 4 + 6 + dtc_hex = payload[a] << 16 | payload[b] << 8 | payload[c] << 0 + log = 'DTC:0x%.2x%.2x%.2x Status:0x%.2x %s ' % ( + payload[a], payload[b], payload[c], payload[d], dtc_describe[dtc_hex]) + for j in range(8): + if payload[d] >> j & 0x1: + log += 'bit%d ' % j + self.append_text_to_log_display(log) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + async def get_supported_dtc_task(self): + try: + self.client.writer.write(bytes([0x19, 0x0a])) + payload = await asyncio.wait_for(self.client.reader.read(4095), 1) + self.append_text_to_log_display('>>> 0x190a get_supported_dtc') + for i in range(len(payload[3:]) // 4): + a = i * 4 + 3 + b = i * 4 + 4 + c = i * 4 + 5 + d = i * 4 + 6 + dtc_hex = payload[a] << 16 | payload[b] << 8 | payload[c] << 0 + log = 'DTC:0x%.2x%.2x%.2x Status:0x%.2x %s ' % ( + payload[a], payload[b], payload[c], payload[d], dtc_describe[dtc_hex]) + for j in range(8): + if payload[d] >> j & 0x1: + log += 'bit%d ' % j + self.append_text_to_log_display(log) + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') diff --git a/widgets/flash_bootloader_widget.py b/widgets/flash_bootloader_widget.py new file mode 100644 index 0000000..855d4d3 --- /dev/null +++ b/widgets/flash_bootloader_widget.py @@ -0,0 +1,504 @@ +from PyQt5 import QtWidgets, QtCore, QtGui +from can.interfaces.canalystii import CANalystIIBus, TIMING_DICT +from can.interfaces.vector import VectorBus +from can.bus import BusABC +import asyncio +import time +import aioisotp +from uds.client import Client +from udsoncan import MemoryLocation +import configparser + + +class FlashBootloaderWidget(QtWidgets.QWidget): + + def __init__(self, parent=None, flags=QtCore.Qt.WindowFlags()): + super().__init__(parent=parent, flags=flags) + self.initUI() + self.in_programming = False + self.bus: BusABC = None + self.drv_data: bytes = None + self.app_data: bytes = None + + try: + config = configparser.ConfigParser() + config.read('config.ini') + self.tx_id = int(config['CAN_ID']['tx_id'], 16) + self.rx_id = int(config['CAN_ID']['rx_id'], 16) + self.append_text_to_log_display('read config.ini success') + except Exception as e: + self.append_text_to_log_display( + 'read config.ini error, use 0x692 and 0x693 for default tx_id and rx_id', '#ff0000') + self.tx_id = 0x692 + self.rx_id = 0x693 + + def initUI(self): + + self.setWindowTitle('Flash Bootloader') + self.setFont(QtGui.QFont('Segoe UI')) + + le_drv = QtWidgets.QLineEdit(self) + le_drv.setReadOnly(True) + le_drv.setObjectName('le_drv') + btn_drv = QtWidgets.QPushButton(self) + btn_drv.setText('driver') + btn_drv.setObjectName('btn_drv') + + le_app = QtWidgets.QLineEdit(self) + le_app.setReadOnly(True) + le_app.setObjectName('le_app') + btn_app = QtWidgets.QPushButton(self) + btn_app.setText('app') + btn_app.setObjectName('btn_app') + + gl0 = QtWidgets.QGridLayout() + gl0.addWidget(le_drv, 0, 0, 1, 1) + gl0.addWidget(btn_drv, 0, 1, 1, 1) + gl0.addWidget(le_app, 1, 0, 1, 1) + gl0.addWidget(btn_app, 1, 1, 1, 1) + + cb_interface_type = QtWidgets.QComboBox(self) + cb_interface_type.addItems(['vector', 'canalystii']) + cb_interface_type.setObjectName('cb_interface_type') + + cb_baudrate = QtWidgets.QComboBox(self) + cb_baudrate.addItems([('%dK' % (i/1000)) for i in TIMING_DICT.keys()]) + cb_baudrate.setCurrentIndex(14) + cb_baudrate.setObjectName('cb_baudrate') + + cb_can_channel = QtWidgets.QComboBox(self) + cb_can_channel.addItems(['CH1/3', 'CH2/4']) + cb_can_channel.setObjectName('cb_can_channel') + + btn_open = QtWidgets.QPushButton(self) + btn_open.setText('open') + btn_open.setObjectName('btn_open') + + hb0 = QtWidgets.QHBoxLayout() + hb0.addWidget(cb_interface_type) + hb0.addWidget(cb_baudrate) + hb0.addWidget(cb_can_channel) + hb0.addWidget(btn_open) + + cb_only_main = QtWidgets.QCheckBox(self) + cb_only_main.setText('only programming step') + + btn_start = QtWidgets.QPushButton(self) + btn_start.setText('start programming') + btn_start.setObjectName('btn_start') + btn_start.setDisabled(True) + + hb1 = QtWidgets.QHBoxLayout() + hb1.addWidget(cb_only_main) + hb1.addWidget(btn_start) + + progress_bar = QtWidgets.QProgressBar() + progress_bar.setObjectName('progress_bar') + + hb2 = QtWidgets.QHBoxLayout() + hb2.addWidget(progress_bar) + + checkbox1 = QtWidgets.QCheckBox(self) + checkbox2 = QtWidgets.QCheckBox(self) + checkbox3 = QtWidgets.QCheckBox(self) + checkbox4 = QtWidgets.QCheckBox(self) + checkbox5 = QtWidgets.QCheckBox(self) + checkbox6 = QtWidgets.QCheckBox(self) + checkbox7 = QtWidgets.QCheckBox(self) + checkbox8 = QtWidgets.QCheckBox(self) + checkbox9 = QtWidgets.QCheckBox(self) + checkbox10 = QtWidgets.QCheckBox(self) + checkbox11 = QtWidgets.QCheckBox(self) + + # https://blog.csdn.net/jianfengxia/article/details/86623321 + + checkbox1.setText('Enter extended session') + checkbox2.setText('Stop setting of DTCs') + checkbox3.setText('Disable non-diagnostic communication') + vb_pre = QtWidgets.QVBoxLayout() + vb_pre.setAlignment(QtCore.Qt.AlignTop) + vb_pre.addWidget(checkbox1) + vb_pre.addWidget(checkbox2) + vb_pre.addWidget(checkbox3) + gb_pre = QtWidgets.QGroupBox(self) + gb_pre.setTitle('pre-programming') + gb_pre.setLayout(vb_pre) + + checkbox4.setText('Enter programming session') + checkbox5.setText('Request seed') + checkbox6.setText('Send key') + checkbox7.setText('Write Programming Date') + checkbox8.setText('Erase Application Software Memory') + checkbox9.setText('Download Application Software') + checkbox10.setText( + 'Check Programming Application Software Dependencie') + + vb_main = QtWidgets.QVBoxLayout() + vb_main.setAlignment(QtCore.Qt.AlignTop) + vb_main.addWidget(checkbox4) + vb_main.addWidget(checkbox5) + vb_main.addWidget(checkbox6) + vb_main.addWidget(checkbox7) + vb_main.addWidget(checkbox8) + vb_main.addWidget(checkbox9) + vb_main.addWidget(checkbox10) + gb_main = QtWidgets.QGroupBox(self) + gb_main.setTitle('programming') + gb_main.setLayout(vb_main) + + checkbox11.setText('ECUReset') + vb_post = QtWidgets.QVBoxLayout() + vb_post.setAlignment(QtCore.Qt.AlignTop) + vb_post.addWidget(checkbox11) + gb_post = QtWidgets.QGroupBox(self) + gb_post.setTitle('post-programming') + gb_post.setLayout(vb_post) + + hb3 = QtWidgets.QHBoxLayout() + hb3.addWidget(gb_pre) + hb3.addWidget(gb_main) + hb3.addWidget(gb_post) + + tb_log_display = QtWidgets.QTextBrowser(self) + tb_log_display.setObjectName('tb_log_display') + + hb4 = QtWidgets.QHBoxLayout() + hb4.addWidget(tb_log_display) + + vb = QtWidgets.QVBoxLayout() + vb.addLayout(gl0) + vb.addLayout(hb0) + vb.addLayout(hb1) + vb.addLayout(hb2) + vb.addLayout(hb3) + vb.addLayout(hb4) + + self.setLayout(vb) + + QtCore.QMetaObject.connectSlotsByName(self) + + async def pre_programming(self, client: Client): + + self.append_text_to_log_display('# 预编程步骤') + + # 进入extended session + self.append_text_to_log_display('>>> 进入extended session') + response = await client.change_session(3) + # print(response) + + # 检查编程条件 + self.append_text_to_log_display('>>> 检查编程条件') + response = await client.start_routine(0xff02) + # print(response) + + # 关闭DTC的存储 + self.append_text_to_log_display('>>> 关闭DTC的存储') + response = await client.control_dtc_setting(2) + # print(response) + + # 关闭与诊断无关的报文 + self.append_text_to_log_display('>>> 关闭与诊断无关的报文') + response = await client.communication_control(0x03, 0x01) + # print(response) + + async def programming(self, client: Client): + + self.append_text_to_log_display('# 主编程步骤') + + # 进入programming session + self.append_text_to_log_display('>>> 进入programming session') + response = await client.change_session(2) + # print(response) + + # 请求种子 + self.append_text_to_log_display('>>> 请求种子') + response = await client.request_seed(1) + # print(response) + + # 发送密钥 + self.append_text_to_log_display('>>> 发送密钥') + response = await client.send_key(1, bytes([0xb3, 0x42])) + # print(response) + + # 发送driver文件 + self.append_text_to_log_display('>>> 发送driver文件') + drv_file = self.drv_data + address = drv_file[16] << 24 | drv_file[17] << 16 | drv_file[18] << 8 | drv_file[19] << 0 + memorysize = drv_file[20] << 24 | drv_file[21] << 16 | drv_file[22] << 8 | drv_file[23] << 0 + memory_location = MemoryLocation(address, memorysize, 32, 32) + response = await client.request_download(memory_location) + # print(response) + + max_length = response.service_data.max_length + + # 有效数据长度, 去除sid和sequence两个字节 + payload_length = max_length - 2 + + count = (len(drv_file) + payload_length - 1) // payload_length + + base = self.get_progressbar_pos() + for i in range(count): + start = i * payload_length + end = start + payload_length + response = await client.transfer_data((i + 1) % 256, drv_file[start:end]) + self.set_progressbar_pos(base + end) + # print(response) + + response = await client.request_transfer_exit() + # print(response) + + # driver文件完整性检验 + self.append_text_to_log_display('>>> driver文件完整性检验') + response = await client.start_routine(0xf001, drv_file[0:4]) + # print(response) + + app_file = self.app_data + address = app_file[16] << 24 | app_file[17] << 16 | app_file[18] << 8 | app_file[19] << 0 + memorysize = app_file[20] << 24 | app_file[21] << 16 | app_file[22] << 8 | app_file[23] << 0 + memory_location = MemoryLocation(address, memorysize, 32, 32) + + # 删除app存储空间 + self.append_text_to_log_display('>>> 删除app存储空间') + data = b'' + data += memory_location.alfid.get_byte() + data += memory_location.get_address_bytes() + data += memory_location.get_memorysize_bytes() + response = await client.start_routine(0xff00, data) + # print(response) + + # 发送app文件 + self.append_text_to_log_display('>>> 发送app文件') + response = await client.request_download(memory_location) + # print(response) + + max_length = response.service_data.max_length + + # 有效数据长度, 去除sid和sequence两个字节 + payload_length = max_length - 2 + + count = (len(app_file) + payload_length - 1) // payload_length + + base = self.get_progressbar_pos() + for i in range(count): + start = i * payload_length + end = start + payload_length + response = await client.transfer_data((i + 1) % 256, app_file[start:end]) + self.set_progressbar_pos(base + end) + # print(response) + + response = await client.request_transfer_exit() + # print(response) + + # app文件完整性检验 + self.append_text_to_log_display('>>> app文件完整性检验') + response = await client.start_routine(0xf001, app_file[0:4]) + # print(response) + + async def post_programming(self, client: Client): + + self.append_text_to_log_display('# 后编程步骤') + + # 回到default session + self.append_text_to_log_display('>>> 回到default session') + response = await client.change_session(1, True) + # print(response) + + async def start_programming(self): + + network = aioisotp.ISOTPNetwork(bus=self.bus) + + with network.open(): + + reader, writer = await network.open_connection(self.rx_id, self.tx_id) + + client = Client(reader, writer) + + try: + await client.tester_present(timeout=0.3) + except asyncio.TimeoutError: + # canalystii 第一条请求无效 + # timeout >= 0.3 + if isinstance(self.bus, CANalystIIBus): + pass + elif isinstance(self.bus, VectorBus): + self.append_text_to_log_display('查看是否选错CAN通道', '#ff0000') + + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + self.set_progressbar_pos(0) + + t1 = time.time() + + try: + + await self.pre_programming(client) + await self.programming(client) + await self.post_programming(client) + + except asyncio.TimeoutError: + + self.append_text_to_log_display('request timeout', '#ff0000') + + except Exception as e: + + self.append_text_to_log_display('%s' % e, '#ff0000') + + t2 = time.time() + + self.append_text_to_log_display('finished in %.2f sec' % (t2 - t1)) + self.in_programming = False + self.findChild(QtWidgets.QPushButton, + 'btn_start').setDisabled(True) + + def set_progressbar_pos(self, pos): + + drv_data_len = len( + self.drv_data) if self.drv_data is not None else 0 + app_data_len = len( + self.app_data) if self.app_data is not None else 0 + total_len = drv_data_len + app_data_len + if pos > total_len: + pos = total_len + elif pos < 0: + pos = 0 + + self.findChild(QtWidgets.QProgressBar, 'progress_bar').setValue(pos) + + def get_progressbar_pos(self): + + return self.findChild(QtWidgets.QProgressBar, 'progress_bar').value() + + def append_text_to_log_display(self, text, color='#000000'): + + text = '<font color="%s">%s</font>' % (color, text) + self.findChild(QtWidgets.QTextBrowser, 'tb_log_display').append(text) + + def clear_log_display(self): + + self.findChild(QtWidgets.QTextBrowser, 'tb_log_display').clear() + + @QtCore.pyqtSlot() + def on_btn_drv_clicked(self): + + if self.in_programming: + self.append_text_to_log_display('## 正在编程中') + return + + fileName, _ = QtWidgets.QFileDialog.getOpenFileName( + self, 'load driver file', '.', 'All Files (*);;Bin Files (*.bin)') + + if fileName != '': + self.findChild(QtWidgets.QLineEdit, 'le_drv').setText(fileName) + with open(fileName, 'rb') as fd: + self.drv_data = fd.read() + drv_data_len = len( + self.drv_data) if self.drv_data is not None else 0 + app_data_len = len( + self.app_data) if self.app_data is not None else 0 + total_len = drv_data_len + app_data_len + self.findChild(QtWidgets.QProgressBar, + 'progress_bar').setRange(0, total_len) + + @QtCore.pyqtSlot() + def on_btn_app_clicked(self): + + if self.in_programming: + self.append_text_to_log_display('## 正在编程中') + return + + fileName, _ = QtWidgets.QFileDialog.getOpenFileName( + self, 'load app file', '.', 'All Files (*);;Bin Files (*.bin)') + + if fileName != '': + self.findChild(QtWidgets.QLineEdit, 'le_app').setText(fileName) + with open(fileName, 'rb') as fd: + self.app_data = fd.read() + drv_data_len = len( + self.drv_data) if self.drv_data is not None else 0 + app_data_len = len( + self.app_data) if self.app_data is not None else 0 + total_len = drv_data_len + app_data_len + self.findChild(QtWidgets.QProgressBar, + 'progress_bar').setRange(0, total_len) + + @QtCore.pyqtSlot() + def on_btn_start_clicked(self): + + if self.drv_data is None or self.app_data is None: + self.append_text_to_log_display('请加载driver文件和app文件') + return + + if self.bus is None: + self.append_text_to_log_display('请打开设备') + return + + if self.in_programming: + self.append_text_to_log_display('## 正在编程中') + return + + self.in_programming = True + loop = asyncio.get_event_loop() + loop.create_task(self.start_programming()) + + @QtCore.pyqtSlot() + def on_btn_open_clicked(self): + + if self.in_programming: + self.append_text_to_log_display('## 正在编程中') + return + + interface_type_index = self.findChild( + QtWidgets.QComboBox, 'cb_interface_type').currentIndex() + + baudrate_index = self.findChild( + QtWidgets.QComboBox, 'cb_baudrate').currentIndex() + + can_channel_index = self.findChild( + QtWidgets.QComboBox, 'cb_can_channel').currentIndex() + + # bus = VectorBus(channel=1, bitrate=500000, can_filters=can_filters) + # bus = CANalystIIBus(channel=0, baud=500000, can_filters=can_filters) + + self.clear_log_display() + + can_filters = [ + {'can_id': self.rx_id, 'can_mask': 0xFFFFFFFF} + ] + + bitrate = list(TIMING_DICT.keys())[baudrate_index] + + try: + + if interface_type_index == 0: + self.bus = VectorBus(channel=can_channel_index, + bitrate=bitrate, can_filters=can_filters) + + elif interface_type_index == 1: + self.bus = CANalystIIBus(channel=can_channel_index, + baud=bitrate, can_filters=can_filters) + + self.append_text_to_log_display('open device success') + self.findChild(QtWidgets.QPushButton, + 'btn_start').setDisabled(False) + + except Exception as e: + self.append_text_to_log_display('%s' % e, '#ff0000') + + @QtCore.pyqtSlot(str) + def on_cb_interface_type_currentIndexChanged(self, text): + + if text == 'vector': + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(0, 'CH1/3') + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(1, 'CH2/4') + elif text == 'canalystii': + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(0, 'CAN1') + self.findChild(QtWidgets.QComboBox, + 'cb_can_channel').setItemText(1, 'CAN2') + +# @PyQt5.QtCore.pyqtSlot(参数) +# def on_发送者对象名称_发射信号名称(self, 参数): +# pass diff --git a/widgets/main_widget.py b/widgets/main_widget.py new file mode 100644 index 0000000..68eead9 --- /dev/null +++ b/widgets/main_widget.py @@ -0,0 +1,56 @@ +from PyQt5 import QtWidgets, QtGui, QtCore + +from widgets.flash_bootloader_widget import FlashBootloaderWidget +from widgets.data_identifier_widget import DataIdentifierWidget +from widgets.diagnostic_trouble_code_widget import DiagnosticTroubleCodeWidget + + +class MainWidget(QtWidgets.QWidget): + + def __init__(self): + super().__init__() + self.initUI() + # self.move_center() + + def initUI(self): + + self.setFont(QtGui.QFont('Segoe UI')) + self.setWindowTitle('Flash Bootloader') + + flash_bootloader_widget = FlashBootloaderWidget(self) + data_identifier_widget = DataIdentifierWidget(self) + diagnostic_trouble_code_widget = DiagnosticTroubleCodeWidget(self) + + tab_widget = QtWidgets.QTabWidget(self) + tab_widget.setObjectName('tab_widget') + tab_widget.addTab(flash_bootloader_widget, 'Flash Bootloader') + tab_widget.addTab(data_identifier_widget, 'Data Identifier') + tab_widget.addTab(diagnostic_trouble_code_widget, + 'Diagnostic Trouble Code') + + hb0 = QtWidgets.QHBoxLayout() + hb0.addWidget(tab_widget) + + vb = QtWidgets.QVBoxLayout() + vb.addLayout(hb0) + + self.setLayout(vb) + + QtCore.QMetaObject.connectSlotsByName(self) + + def move_center(self): + + w = QtWidgets.QApplication.desktop().width() + h = QtWidgets.QApplication.desktop().height() + ww = self.width() + hh = self.height() + self.move((w - ww) / 2, (h - hh) / 2) + + @QtCore.pyqtSlot(int) + def on_tab_widget_currentChanged(self, index): + if index == 0: + self.setWindowTitle('Flash Bootloader') + elif index == 1: + self.setWindowTitle('Data Identifier') + elif index == 2: + self.setWindowTitle('Diagnostic Trouble Code') -- Gitblit v1.8.0