├── .clang-format ├── .github └── workflows │ ├── tests.yml │ └── wheels.yml ├── .gitignore ├── .gitmodules ├── .readthedocs.yaml ├── .travis.yml ├── .vscode ├── c_cpp_properties.json ├── extensions.json └── launch.json ├── IntrepidCS.png ├── LICENSE.md ├── MANIFEST.in ├── README.md ├── build_all.bat ├── build_libicsneo.py ├── build_mac.sh ├── doc ├── .gitignore ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── conf.py │ ├── examples.rst │ ├── generate_documentation.py │ ├── header.rst │ └── index.rst ├── examples ├── canfd_transmit_example.py ├── iso15765_example.py ├── lin22.ldf ├── lin_settings_example.py ├── open_device_example.py ├── transmit_can_example.py ├── transmit_can_xtd_example.py ├── transmit_canfd_example.py ├── transmit_ethernet_example.py ├── transmit_lin_example.py └── transmit_lin_ldf_example.py ├── extract_icsneo40_defines.py ├── generate_icsneo40_structs.py ├── ics_utility.py ├── include ├── defines.h ├── dll.h ├── exceptions.h ├── ics │ ├── icsnVC40.h │ ├── icsnVC40.h.patch │ └── test_structs.h ├── methods.h ├── object_spy_message.h └── setup_module_auto_defines.h ├── msvc ├── python_ics.sln └── python_ics.vcxproj ├── pyproject.toml ├── requirements.txt ├── run_tests.bat ├── setup.py ├── src ├── defines.cpp ├── dll.cpp ├── exceptions.cpp ├── ics │ └── py_neo_device_ex.py ├── icsdebug.py ├── main.cpp ├── methods.cpp ├── object_spy_message.cpp └── setup_module_auto_defines.cpp ├── tests ├── __init__.py ├── obsolete │ ├── cmvspy.h │ ├── cmvspy.py │ ├── cmvspyconvert.py │ ├── test_coremini.py │ ├── test_find_devices.py │ ├── test_get_device_status.py │ ├── test_network_fire.py │ ├── test_open_close.py │ └── test_structs.py └── runner │ ├── Readme.md │ ├── __init__.py │ ├── test_network.py │ ├── test_open_close.py │ └── test_settings.py ├── travis └── build-wheels.sh └── uv.lock /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Mozilla 2 | AlwaysBreakAfterDefinitionReturnType: None 3 | AlwaysBreakAfterReturnType: None 4 | ColumnLimit: '120' 5 | SpaceAfterCStyleCast: 'false' 6 | SpaceAfterTemplateKeyword: 'false' 7 | SpaceBeforeAssignmentOperators: 'true' 8 | SpaceBeforeCpp11BracedList: 'true' 9 | TabWidth: 4 10 | IndentWidth: 4 11 | ConstructorInitializerIndentWidth: 4 12 | ContinuationIndentWidth: 4 13 | UseTab: Never 14 | MaxEmptyLinesToKeep: 1 15 | SortIncludes: false -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Run Unit Tests 2 | on: 3 | push: 4 | branches: 5 | -'arm/**' 6 | pull_request: 7 | branches: 8 | -'arm/**' 9 | 10 | jobs: 11 | test_arm64: 12 | if: github.repository == 'intrepidcs/python_ics' 13 | name: Linux ARM64 unit tests 14 | runs-on: [ self-hosted, Linux, ARM64, Hardware ] 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | submodules: recursive 19 | fetch-depth: 0 # needed for history/tags 20 | 21 | - name: Setup Python 22 | run: | 23 | python -m venv .venv 24 | source .venv/bin/activate 25 | python -m pip install --upgrade pip 26 | pip install . 27 | 28 | - name: Run unit tests 29 | run: | 30 | source .venv/bin/activate 31 | sudo setcap cap_net_admin,cap_net_raw+ep $(realpath $(which python)) 32 | python -m unittest discover -s tests.runner --verbose -------------------------------------------------------------------------------- /.github/workflows/wheels.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build_wheels: 7 | name: Build wheels on ${{ matrix.os }} 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [ubuntu-24.04, windows-2022, macOS-14] 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | submodules: recursive 17 | fetch-depth: 0 # needed for history/tags 18 | 19 | # Enable emulation for aarch64 20 | - name: Set up QEMU 21 | if: runner.os == 'Linux' 22 | uses: docker/setup-qemu-action@v3 23 | with: 24 | platforms: all 25 | 26 | # Used to host cibuildwheel 27 | - name: Set up Python 3.12 28 | uses: actions/setup-python@v5 29 | with: 30 | python-version: '3.12' 31 | 32 | - name: Get python_ics version 33 | uses: mtkennerly/dunamai-action@v1 34 | with: 35 | env-var: PYTHON_ICS_VERSION 36 | args: --format "v{base}-{commit}-{timestamp}" 37 | - name: Print python_ics version 38 | run: echo $PYTHON_ICS_VERSION 39 | 40 | - name: Install cibuildwheel 41 | run: python -m pip install cibuildwheel==2.22.0 42 | 43 | - name: Build wheels 44 | run: python -m cibuildwheel --output-dir wheelhouse 45 | 46 | - name: Upload Artifacts 47 | uses: actions/upload-artifact@v4 48 | with: 49 | name: python_ics-${{ matrix.os }}-${{ env.PYTHON_ICS_VERSION }} 50 | path: ./wheelhouse/*.whl 51 | if-no-files-found: error 52 | 53 | - name: Download artifacts 54 | uses: actions/download-artifact@v4 55 | with: 56 | pattern: python_ics-* 57 | merge-multiple: true 58 | path: ./wheelhouse/ 59 | 60 | deploy_pypi: 61 | name: "Deploy PyPI" 62 | runs-on: ubuntu-latest 63 | needs: build_wheels 64 | if: | 65 | github.ref_name == 'master' || 66 | startsWith(github.event.ref, 'refs/tags/v') 67 | steps: 68 | - uses: actions/checkout@v4 69 | with: 70 | fetch-depth: 0 71 | 72 | - name: Install uv 73 | uses: astral-sh/setup-uv@v5 74 | with: 75 | enable-cache: true 76 | cache-dependency-glob: uv.lock 77 | 78 | - name: Set up Python 79 | run: | 80 | uv python install 3.12 81 | uv venv -p 3.12 82 | source .venv/bin/activate 83 | uv pip install check-wheel-contents twine 84 | 85 | - uses: actions/download-artifact@v4 86 | with: 87 | pattern: python_ics-* 88 | merge-multiple: true 89 | path: ./wheelhouse/ 90 | 91 | - name: "Publish to PyPI" 92 | if: | 93 | github.ref_name == 'master' || 94 | startsWith(github.event.ref, 'refs/tags/v') 95 | run: | 96 | source .venv/bin/activate 97 | uv pip install check-wheel-contents twine 98 | check-wheel-contents ./wheelhouse/*.whl 99 | twine upload -u __token__ -p ${{ secrets.PYPI_TOKEN }} --verbose ./wheelhouse/* -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # python virtual environment 2 | .venv/ 3 | 4 | icsnVC40_processed.h 5 | icsnVC40.h.* 6 | *.whl 7 | 8 | # Byte-compiled / optimized / DLL files 9 | __pycache__/ 10 | *.py[cod] 11 | *$py.class 12 | 13 | # C extensions 14 | *.so 15 | 16 | # Distribution / packaging 17 | .Python 18 | env/ 19 | build/ 20 | develop-eggs/ 21 | dist/ 22 | downloads/ 23 | eggs/ 24 | .eggs/ 25 | lib/ 26 | lib64/ 27 | parts/ 28 | sdist/ 29 | var/ 30 | gen/ 31 | *.egg-info/ 32 | .installed.cfg 33 | *.egg 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *,cover 54 | .hypothesis/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # IPython Notebook 78 | .ipynb_checkpoints 79 | 80 | # pyenv 81 | .python-version 82 | 83 | # celery beat schedule file 84 | celerybeat-schedule 85 | 86 | # dotenv 87 | .env 88 | 89 | # virtualenv 90 | venv/ 91 | ENV/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | 96 | # Rope project settings 97 | .ropeproject 98 | 99 | #msvc 100 | msvc/Debug* 101 | msvc/Release* 102 | msvc/ipch* 103 | 104 | # macOS 105 | .DS_Store 106 | *.dylib 107 | 108 | # in-tree builds 109 | /libusb 110 | /libicsneo 111 | /libpcap -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/ice"] 2 | path = src/ice 3 | url = https://github.com/ic3man5/ice.git 4 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | apt_packages: 11 | - curl 12 | - flex 13 | - bison 14 | - clang 15 | - clang-format 16 | - build-essential 17 | - cmake 18 | tools: 19 | python: "3.11" 20 | 21 | # You can also specify other tool versions: 22 | # nodejs: "20" 23 | # rust: "1.70" 24 | # golang: "1.20" 25 | 26 | # VCS submodules configuration. 27 | submodules: 28 | include: all 29 | 30 | # Build documentation in the "docs/" directory with Sphinx 31 | sphinx: 32 | configuration: doc/source/conf.py 33 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs 34 | builder: "html" 35 | # Fail on all warnings to avoid broken references 36 | # fail_on_warning: true 37 | 38 | # Optionally build your docs in additional formats such as PDF and ePub 39 | formats: 40 | - pdf 41 | - epub 42 | 43 | # Optional but recommended, declare the Python requirements required 44 | # to build your documentation 45 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 46 | python: 47 | install: 48 | - method: pip 49 | path: . 50 | - requirements: doc/requirements.txt -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | notifications: 2 | email: false 3 | 4 | matrix: 5 | include: 6 | - sudo: required 7 | services: 8 | - docker 9 | env: DOCKER_IMAGE=quay.io/pypa/manylinux_2_24_x86_64 10 | PLAT=manylinux_2_24_x86_64 11 | - sudo: required 12 | services: 13 | - docker 14 | env: DOCKER_IMAGE=quay.io/pypa/manylinux_2_24_x86_64 15 | PRE_CMD=linux32 16 | PLAT=manylinux_2_24_i686 17 | - sudo: required 18 | services: 19 | - docker 20 | env: DOCKER_IMAGE=quay.io/pypa/manylinux_2_28_x86_64 21 | PLAT=manylinux_2_28_x86_64 22 | 23 | install: 24 | - docker pull $DOCKER_IMAGE 25 | 26 | script: 27 | - docker run --rm -e PLAT=$PLAT -v `pwd`:/io $DOCKER_IMAGE $PRE_CMD /io/travis/build-wheels.sh 28 | - ls wheelhouse/ -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Win32", 5 | "includePath": [ 6 | "${default}", 7 | "${workspaceFolder}/include", 8 | "${workspaceFolder}/include/ics", 9 | "${workspaceFolder}/src/ice/include" 10 | ], 11 | "defines": [ 12 | "_DEBUG", 13 | "UNICODE", 14 | "_UNICODE", 15 | "EXTERNAL_PROJECT" 16 | ], 17 | "windowsSdkVersion": "10.0.19041.0", 18 | "compilerPath": "cl.exe", 19 | "cStandard": "c17", 20 | "cppStandard": "c++17", 21 | "intelliSenseMode": "windows-msvc-x64" 22 | } 23 | ], 24 | "version": 4 25 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-python.python", 4 | "charliermarsh.ruff", 5 | "mikoz.black-py", 6 | "xaver.clang-format", 7 | "webfreak.debug", 8 | "tamasfe.even-better-toml", 9 | "fill-labs.dependi" 10 | ] 11 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: Generate icsneo40 structs", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "generate_icsneo40_structs.py", 12 | "console": "integratedTerminal", 13 | "args": ["include/ics/icsnVC40.h", ], 14 | }, 15 | { 16 | "name": "Python: Generate test structures", 17 | "type": "python", 18 | "request": "launch", 19 | "program": "generate_icsneo40_structs.py", 20 | "console": "integratedTerminal", 21 | "args": ["include/ics/test_structs.h", ], 22 | }, 23 | { 24 | "name": "Python: test_structs.py", 25 | "type": "python", 26 | "request": "launch", 27 | "program": "test_structs.py", 28 | "cwd": "${workspaceFolder}/test", 29 | "console": "integratedTerminal", 30 | "args": [], 31 | }, 32 | { 33 | "name": "Python: extract icsneo40 defines", 34 | "type": "python", 35 | "request": "launch", 36 | "program": "extract_icsneo40_defines.py", 37 | "console": "integratedTerminal", 38 | "args": ["include/ics/icsnVC40.h", ], 39 | }, 40 | { 41 | "name": "Python: Debug icsdebug.py", 42 | "type": "debugpy", 43 | "request": "launch", 44 | "program": "src/icsdebug.py", 45 | "console": "integratedTerminal" 46 | }, 47 | { 48 | "name": "Debugger Attach", 49 | "type": "cppvsdbg", 50 | "request": "attach", 51 | "pid": "${command:pickProcess}", 52 | }, 53 | /* 54 | { 55 | "name": "Debugger Attach lldb", 56 | "type": "lldb", 57 | "request": "attach", 58 | "pid": "${command:pickProcess}", 59 | } 60 | */ 61 | { 62 | "name": "Debugger attach gdbserver", 63 | "type": "gdb", 64 | "request": "attach", 65 | "executable": "python icsdebug.py", 66 | "target": "127.0.0.1:1234", 67 | "remote": true, 68 | "cwd": "${workspaceRoot}", 69 | "gdbpath": "gdb", 70 | "autorun": [] 71 | }, 72 | ] 73 | } -------------------------------------------------------------------------------- /IntrepidCS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intrepidcs/python_ics/b5a295c7a8cbbf2beba85d11d1ecdc3dfd6b701c/IntrepidCS.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include include *.h 2 | include *.py 3 | graft include 4 | graft src 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/intrepidcs/python_ics/blob/master/IntrepidCS.png?raw=true) 2 | 3 | ![](https://github.com/intrepidcs/python_ics/actions/workflows/wheels.yml/badge.svg) 4 | 5 | # Description 6 | 7 | Python wrapper for interfacing to IntrepidCS Hardware. 8 | 9 | # Installing 10 | 11 | - `pip install python_ics` 12 | 13 | ## Platform specific Installation notes 14 | 15 | ### Windows 16 | 17 | - Windows requires icsneo40.dll to be installed in the PATH. This can be obtained through vspy3 or our hardware installation kit found here: https://cdn.intrepidcs.net/updates/files/RP1210KitInstall.zip 18 | 19 | ### Linux 20 | 21 | - Linux builds use [libicsneo](https://github.com/intrepidcs/libicsneo) and are built against [manylinux](https://github.com/pypa/manylinux) using cibuildwheel. 22 | - libicsneolegacy.so is bundled with the wheel and python_ics will automatically use it. 23 | 24 | ### MacOS 25 | 26 | - Mac builds use [libicsneo](https://github.com/intrepidcs/libicsneo) and are built using cibuildwheel 27 | - libicsneolegacy.dylib is bundled with the wheel and python_ics will automatically use it. 28 | 29 | # Basic usage 30 | 31 | ```python 32 | import ics 33 | 34 | devices = ics.find_devices() 35 | print(f"Found {len(devices)} devices...") 36 | for device in devices: 37 | # Print, open, load default settings, close 38 | print(device) 39 | device.open() 40 | device.load_default_settings() 41 | device.close() 42 | ``` 43 | 44 | # Documentation 45 | 46 | http://python-ics.readthedocs.io/ 47 | 48 | 49 | # Building from source 50 | 51 | - Building from source requires clang and clang-format to be present on the build machine. 52 | - python_ics has submodules, please be sure to initial all submodules also. 53 | 54 | ```powershell 55 | PS > git clone git@github.com:intrepidcs/python_ics.git 56 | 57 | PS > cd python_ics 58 | 59 | PS > git submodule update --init 60 | 61 | PS > clang --version 62 | clang version 11.1.0 63 | Target: x86_64-pc-windows-msvc 64 | Thread model: posix 65 | InstalledDir: C:\Program Files\LLVM\bin 66 | 67 | PS > clang-format --version 68 | clang-format version 11.1.0 69 | 70 | PS > python -m pip install . 71 | ``` 72 | 73 | # Debugging on Windows with Visual Studio Code 74 | 75 | - Build and install python_ics for debug. When installing python choose the following: 76 | - Customize Installation -> Advanced Options 77 | - Check Download debugging symbols 78 | - Check Download debug binaries 79 | - Build python with debug: 80 | - Install Visual Studio 2019 build tools(NOTE: As of 2/5/24, it looks like MSVC 2022 does not build correctly with setuptools and debug configurations). You should be able to build from source already. 81 | - Create virtual environment and activate it (powershell): 82 | - `python -m venv .venv` 83 | - `.\.venv\Scripts\Activate.ps1` 84 | - Install dependencies: 85 | - `python -m pip install -r requirements.txt` 86 | - Build in debug (`-g` flag): 87 | - `python setup.py build -g` 88 | - Install into our virtual environment: 89 | - `python setup.py install --force` 90 | - Inside visual studio code: 91 | - Open the root python_ics directory 92 | - `code C:\Path\To\python_ics` 93 | - Make sure the python extension is installed (ctrl+shift+x) 94 | - [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) 95 | - [Python Debugger](https://marketplace.visualstudio.com/items?itemName=ms-python.debugpy) 96 | - Select the python interpreter from our virtual environment (bottom right with a python file open in the editor). 97 | - Open and place a breakpoint in `src/icsdebug.py` 98 | - launch "Python: Debug icsdebug.py" 99 | - Note the PID that is outputted to terminal (Can also add `os.getpid()` to watch window) 100 | - Place a breakpoint inside the function you'd like to debug in `methods.cpp` 101 | - launch "Debugger Attach" (`launch.json`) and enter the pid when prompted. 102 | - enjoy! 103 | 104 | # License - MIT 105 | 106 | Copyright (c) Intrepid Control Systems, Inc. 107 | 108 | Permission is hereby granted, free of charge, to any person obtaining a copy 109 | of this software and associated documentation files (the "Software"), to deal 110 | in the Software without restriction, including without limitation the rights 111 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 112 | copies of the Software, and to permit persons to whom the Software is 113 | furnished to do so, subject to the following conditions: 114 | 115 | The above copyright notice and this permission notice shall be included in all 116 | copies or substantial portions of the Software. 117 | 118 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 119 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 120 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 121 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 122 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 123 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 124 | SOFTWARE. 125 | -------------------------------------------------------------------------------- /build_all.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | mode con cols=140 lines=70 3 | 4 | rmdir /s /q build 5 | 6 | mkdir old_dist 7 | move dist\* old_dist\ 8 | 9 | C:\Python\Python36-32\scripts\pip install wheel twine --upgrade 10 | C:\Python\Python37-32\scripts\pip install wheel twine --upgrade 11 | C:\Python\Python38-32\scripts\pip install wheel twine --upgrade 12 | C:\Python\Python39-32\scripts\pip install wheel twine --upgrade 13 | C:\Python\Python310-32\scripts\pip install wheel twine --upgrade 14 | C:\Python\Python311-32\scripts\pip install wheel twine --upgrade 15 | 16 | C:\Python\Python36-64\scripts\pip install wheel twine --upgrade 17 | C:\Python\Python37-64\scripts\pip install wheel twine --upgrade 18 | C:\Python\Python38-64\scripts\pip install wheel twine --upgrade 19 | C:\Python\Python39-64\scripts\pip install wheel twine --upgrade 20 | C:\Python\Python310-64\scripts\pip install wheel twine --upgrade 21 | C:\Python\Python311-64\scripts\pip install wheel twine --upgrade 22 | 23 | C:\Python\Python36-32\python setup.py sdist bdist_wheel 24 | C:\Python\Python37-32\python setup.py sdist bdist_wheel 25 | C:\Python\Python38-32\python setup.py sdist bdist_wheel 26 | C:\Python\Python39-32\python setup.py sdist bdist_wheel 27 | C:\Python\Python310-32\python setup.py sdist bdist_wheel 28 | C:\Python\Python311-32\python setup.py sdist bdist_wheel 29 | 30 | C:\Python\Python36-64\python setup.py sdist bdist_wheel 31 | C:\Python\Python37-64\python setup.py sdist bdist_wheel 32 | C:\Python\Python38-64\python setup.py sdist bdist_wheel 33 | C:\Python\Python39-64\python setup.py sdist bdist_wheel 34 | C:\Python\Python310-64\python setup.py sdist bdist_wheel 35 | C:\Python\Python311-64\python setup.py sdist bdist_wheel 36 | 37 | 38 | REM C:\Python\Python37-32\scripts\twine upload dist/* -r pypitest 39 | -------------------------------------------------------------------------------- /build_libicsneo.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import multiprocessing 3 | import os 4 | import shutil 5 | import sys 6 | from pathlib import Path 7 | 8 | ROOT = Path.cwd() 9 | CPUS = str(multiprocessing.cpu_count()) 10 | 11 | LIBUSB_VERSION = "1.0.27" 12 | LIBUSB_ROOT = f"{ROOT}/libusb/{LIBUSB_VERSION}" 13 | LIBUSB_SOURCE = f"{LIBUSB_ROOT}/source" 14 | LIBUSB_BUILD = f"{LIBUSB_ROOT}/build" 15 | LIBUSB_INSTALL = f"{LIBUSB_ROOT}/install" 16 | 17 | LIBICSNEO_VERSION = "830fe1a" 18 | LIBICSNEO_ROOT = f"{ROOT}/libicsneo/{LIBICSNEO_VERSION}" 19 | LIBICSNEO_SOURCE = f"{LIBICSNEO_ROOT}/source" 20 | LIBICSNEO_BUILD = f"{LIBICSNEO_ROOT}/build" 21 | LIBICSNEO_INSTALL = f"{LIBICSNEO_ROOT}/install" 22 | print(f"LIBICSNEO PATH: {LIBICSNEO_ROOT}") 23 | 24 | LIBPCAP_VERSION = "1.10.4" 25 | LIBPCAP_ROOT = f"{ROOT}/libpcap/{LIBPCAP_VERSION}" 26 | LIBPCAP_SOURCE = f"{LIBPCAP_ROOT}/source" 27 | LIBPCAP_BUILD = f"{LIBPCAP_ROOT}/build" 28 | LIBPCAP_INSTALL = f"{LIBPCAP_ROOT}/install" 29 | 30 | def checkout(): 31 | if not os.path.isdir(LIBICSNEO_SOURCE): 32 | os.makedirs(LIBICSNEO_ROOT, exist_ok=True) 33 | subprocess.check_output(["git", "clone", "https://github.com/intrepidcs/libicsneo.git", LIBICSNEO_SOURCE], cwd=LIBICSNEO_ROOT) 34 | subprocess.check_output(["git", "checkout", LIBICSNEO_VERSION], cwd=LIBICSNEO_SOURCE) 35 | 36 | if not os.path.isdir(LIBUSB_SOURCE): 37 | os.makedirs(LIBUSB_ROOT, exist_ok=True) 38 | subprocess.check_output(["curl", "-LO", f"https://github.com/libusb/libusb/releases/download/v{LIBUSB_VERSION}/libusb-{LIBUSB_VERSION}.tar.bz2"], cwd=LIBUSB_ROOT) 39 | subprocess.check_output(["tar", "-xf", f"libusb-{LIBUSB_VERSION}.tar.bz2"], cwd=LIBUSB_ROOT) 40 | subprocess.check_output(["mv", f"libusb-{LIBUSB_VERSION}", "source"], cwd=LIBUSB_ROOT) 41 | subprocess.check_output(["rm", f"libusb-{LIBUSB_VERSION}.tar.bz2"], cwd=LIBUSB_ROOT) 42 | 43 | if not os.path.isdir(LIBPCAP_SOURCE): 44 | os.makedirs(LIBPCAP_ROOT, exist_ok=True) 45 | subprocess.check_output(["curl", "-LO", f"https://www.tcpdump.org/release/libpcap-{LIBPCAP_VERSION}.tar.gz"], cwd=LIBPCAP_ROOT) 46 | subprocess.check_output(["tar", "-xf", f"libpcap-{LIBPCAP_VERSION}.tar.gz"], cwd=LIBPCAP_ROOT) 47 | subprocess.check_output(["mv", f"libpcap-{LIBPCAP_VERSION}", "source"], cwd=LIBPCAP_ROOT) 48 | subprocess.check_output(["rm", f"libpcap-{LIBPCAP_VERSION}.tar.gz"], cwd=LIBPCAP_ROOT) 49 | 50 | def _build_libusb(): 51 | os.makedirs(LIBUSB_BUILD, exist_ok=True) 52 | env = os.environ.copy() 53 | if sys.platform == "darwin": 54 | env["CFLAGS"] = "-arch x86_64 -arch arm64 -mmacosx-version-min=10.13" 55 | env["CXXFLAGS"] = "-arch x86_64 -arch arm64 -mmacosx-version-min=10.13" 56 | else: 57 | env["CFLAGS"] = "-fPIC" 58 | env["CXXFLAGS"] = "-fPIC" 59 | subprocess.check_output([ 60 | f"{LIBUSB_SOURCE}/configure", 61 | "--disable-shared", 62 | "--enable-static", 63 | f"--prefix={LIBUSB_INSTALL}", 64 | "--disable-udev" 65 | ], cwd=LIBUSB_BUILD, env=env) 66 | 67 | subprocess.check_output(["make", "-j" + CPUS], cwd=LIBUSB_BUILD) 68 | subprocess.check_output(["make", "install"], cwd=LIBUSB_BUILD) 69 | 70 | def _build_libpcap(): 71 | os.makedirs(LIBPCAP_BUILD, exist_ok=True) 72 | env = os.environ.copy() 73 | if sys.platform == "darwin": 74 | env["CFLAGS"] = "-arch x86_64 -arch arm64 -mmacosx-version-min=10.13" 75 | env["CXXFLAGS"] = "-arch x86_64 -arch arm64 -mmacosx-version-min=10.13" 76 | else: 77 | env["CFLAGS"] = "-fPIC" 78 | env["CXXFLAGS"] = "-fPIC" 79 | subprocess.check_output([ 80 | f"{LIBPCAP_SOURCE}/configure", 81 | "--disable-shared", 82 | "--disable-usb", 83 | "--disable-netmap", 84 | "--disable-bluetooth", 85 | "--disable-dbus", 86 | "--disable-rdma", 87 | "--without-dag", 88 | "--without-septel", 89 | "--without-snf", 90 | "--without-turbocap", 91 | "--without-dpdk", 92 | "--without-libnl", 93 | f"--prefix={LIBPCAP_INSTALL}", 94 | ], cwd=LIBPCAP_BUILD, env=env) 95 | 96 | subprocess.check_output(["make", "-j" + CPUS], cwd=LIBPCAP_BUILD) 97 | subprocess.check_output(["make", "install"], cwd=LIBPCAP_BUILD) 98 | 99 | def _build_libicsneo_linux(): 100 | print("Cleaning libicsneo...") 101 | subprocess.check_output(["git", "clean", "-xdf"], cwd="libicsneo") 102 | subprocess.check_output(["mkdir", "-p", "libicsneo/build"]) 103 | 104 | print("cmake libicsneo...") 105 | subprocess.check_output( 106 | [ 107 | "cmake", 108 | "-DCMAKE_BUILD_TYPE=Release", 109 | "-DLIBICSNEO_BUILD_ICSNEOLEGACY=ON", 110 | f"-DCMAKE_PREFIX_PATH={LIBUSB_INSTALL};{LIBPCAP_INSTALL}", 111 | "-S", LIBICSNEO_SOURCE, 112 | "-B", LIBICSNEO_BUILD, 113 | "-Wno-dev", 114 | ] 115 | ) 116 | print("cmake build libicsneo...") 117 | subprocess.check_output( 118 | ["cmake", "--build", LIBICSNEO_BUILD, "--target", "icsneolegacy", "--parallel", CPUS] 119 | ) 120 | 121 | def _build_libicsneo_macos(): 122 | subprocess.check_output( 123 | [ 124 | "cmake", 125 | "-DCMAKE_BUILD_TYPE=Release", 126 | "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64", 127 | "-DLIBICSNEO_BUILD_ICSNEOLEGACY=ON", 128 | "-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13", 129 | f"-DCMAKE_PREFIX_PATH={LIBUSB_INSTALL};{LIBPCAP_INSTALL}", 130 | "-S", LIBICSNEO_SOURCE, 131 | "-B", LIBICSNEO_BUILD 132 | ] 133 | ) 134 | 135 | subprocess.check_output( 136 | ["cmake", "--build", LIBICSNEO_BUILD, "--target", "icsneolegacy", "--parallel", CPUS] 137 | ) 138 | 139 | def build(): 140 | print("Building libusb...") 141 | _build_libusb() 142 | print("Building libpcap...") 143 | _build_libpcap() 144 | if sys.platform == "darwin": 145 | _build_libicsneo_macos() 146 | elif sys.platform == "linux": 147 | _build_libicsneo_linux() 148 | 149 | def copy(): 150 | if sys.platform == "darwin": 151 | shutil.copyfile(f"{LIBICSNEO_BUILD}/libicsneolegacy.dylib", "gen/ics/libicsneolegacy.dylib") 152 | elif sys.platform == "linux": 153 | shutil.copyfile(f"{LIBICSNEO_BUILD}/libicsneolegacy.so", "gen/ics/libicsneolegacy.so") 154 | 155 | 156 | def clean(): 157 | shutil.rmtree("libicsneo") 158 | shutil.rmtree("libusb") 159 | shutil.rmtree("libpcap") 160 | 161 | if __name__ == "__main__": 162 | if "--clean" in sys.argv: 163 | clean() 164 | exit(0) 165 | 166 | print("Checking out libicsneo...") 167 | checkout() 168 | print("Building libicsneo...") 169 | build() 170 | print("Copy libicsneo...") 171 | copy() 172 | -------------------------------------------------------------------------------- /build_mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | python_directory="/Library/Frameworks/Python.framework/Versions" 4 | python_versions=("3.7" "3.8" "3.9" "3.10" "3.11") 5 | 6 | # dependencies 7 | brew install cmake clang-format 8 | ret_value=$? 9 | if [ $ret_value -ne 0 ]; then 10 | echo "Failed to install clang/clang-format..." 11 | exit $ret_value 12 | fi 13 | 14 | # Stash any changes we don't have committed. 15 | git stash 16 | ret_value=$? 17 | if [ $ret_value -ne 0 ]; then 18 | echo "Failed to stash changes through git..." 19 | exit $ret_value 20 | fi 21 | 22 | # Make sure all the python versions are installed 23 | for version in "${python_versions[@]}" 24 | do 25 | python_exec="${python_directory}/${version}/bin/python3" 26 | # echo $python_exec 27 | $python_exec --version 28 | echo "Installing python dependencies..." 29 | $python_exec -m pip install wheel 30 | ret_value=$? 31 | if [ $ret_value -ne 0 ]; then 32 | echo "Python requirements for ${version} failed!" 33 | exit $ret_value 34 | fi 35 | echo "Building python ${version}..." 36 | $python_exec setup.py bdist_wheel --universal 37 | ret_value=$? 38 | if [ $ret_value -ne 0 ]; then 39 | echo "Builing python_ics module with Python ${version} failed!" 40 | exit $ret_value 41 | fi 42 | done 43 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | # sphinx build folder 2 | _build 3 | 4 | # Compiled source # 5 | ################### 6 | *.com 7 | *.class 8 | *.dll 9 | *.exe 10 | *.o 11 | *.so 12 | 13 | # Packages # 14 | ############ 15 | # it's better to unpack these files and commit the raw source 16 | # git has its own built in compression methods 17 | *.7z 18 | *.dmg 19 | *.gz 20 | *.iso 21 | *.jar 22 | *.rar 23 | *.tar 24 | *.zip 25 | 26 | # Logs and databases # 27 | ###################### 28 | *.log 29 | *.sql 30 | *.sqlite 31 | 32 | # OS generated files # 33 | ###################### 34 | .DS_Store? 35 | ehthumbs.db 36 | Icon? 37 | Thumbs.db 38 | 39 | # Editor backup files # 40 | ####################### 41 | *~ -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python_ics.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python_ics.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/python_ics" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/python_ics" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | set I18NSPHINXOPTS=%SPHINXOPTS% source 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\python_ics.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\python_ics.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | cython>=0.20 2 | m2r2 3 | docutils>=0.18.1,<0.21 4 | furo -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # ics documentation build configuration file, created by 5 | # sphinx-quickstart on Tue Sep 2 15:54:20 2014. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | import sys 17 | import os 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | # sys.path.insert(0, os.path.abspath('.')) 23 | sys.path.insert(0, os.path.abspath(".")) 24 | 25 | # -- General configuration ------------------------------------------------ 26 | 27 | # If your documentation needs a minimal Sphinx version, state it here. 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | "sphinx.ext.autosummary", 35 | "sphinx.ext.autodoc", 36 | "m2r2", 37 | ] 38 | 39 | # Add any paths that contain templates here, relative to this directory. 40 | templates_path = ["_templates"] 41 | 42 | # The suffix of source filenames. 43 | source_suffix = [".rst", ".md"] 44 | 45 | # The encoding of source files. 46 | # source_encoding = 'utf-8-sig' 47 | 48 | # The master toctree document. 49 | master_doc = "index" 50 | 51 | # General information about the project. 52 | project = "ics" 53 | copyright = "Intrepid Control Systems, Inc." 54 | 55 | # The version info for the project you're documenting, acts as replacement for 56 | # |version| and |release|, also used in various other places throughout the 57 | # built documents. 58 | # 59 | # The short X.Y version. 60 | version = "918.14" 61 | # The full version, including alpha/beta/rc tags. 62 | release = version 63 | 64 | # The language for content autogenerated by Sphinx. Refer to documentation 65 | # for a list of supported languages. 66 | # language = None 67 | 68 | # There are two options for replacing |today|: either, you set today to some 69 | # non-false value, then it is used: 70 | # today = '' 71 | # Else, today_fmt is used as the format for a strftime call. 72 | # today_fmt = '%B %d, %Y' 73 | 74 | # List of patterns, relative to source directory, that match files and 75 | # directories to ignore when looking for source files. 76 | exclude_patterns = [] 77 | 78 | # The reST default role (used for this markup: `text`) to use for all 79 | # documents. 80 | # default_role = None 81 | 82 | # If true, '()' will be appended to :func: etc. cross-reference text. 83 | # add_function_parentheses = True 84 | 85 | # If true, the current module name will be prepended to all description 86 | # unit titles (such as .. function::). 87 | # add_module_names = True 88 | 89 | # If true, sectionauthor and moduleauthor directives will be shown in the 90 | # output. They are ignored by default. 91 | # show_authors = False 92 | 93 | # The name of the Pygments (syntax highlighting) style to use. 94 | pygments_style = "sphinx" 95 | 96 | # A list of ignored prefixes for module index sorting. 97 | # modindex_common_prefix = [] 98 | 99 | # If true, keep warnings as "system message" paragraphs in the built documents. 100 | # keep_warnings = False 101 | 102 | 103 | # -- Options for HTML output ---------------------------------------------- 104 | 105 | # The theme to use for HTML and HTML Help pages. See the documentation for 106 | # a list of builtin themes. 107 | #html_theme = 'sphinx_rtd_theme' 108 | #html_theme = "classic" 109 | html_theme = "furo" 110 | 111 | # Theme options are theme-specific and customize the look and feel of a theme 112 | # further. For a list of options available for each theme, see the 113 | # documentation. 114 | #html_theme_options = {"body_max_width": "80%"} 115 | 116 | # Add any paths that contain custom themes here, relative to this directory. 117 | # html_theme_path = [] 118 | 119 | # The name for this set of Sphinx documents. If None, it defaults to 120 | # " v documentation". 121 | # html_title = None 122 | 123 | # A shorter title for the navigation bar. Default is the same as html_title. 124 | # html_short_title = None 125 | 126 | # The name of an image file (relative to this directory) to place at the top 127 | # of the sidebar. 128 | # html_logo = None 129 | 130 | # The name of an image file (within the static path) to use as favicon of the 131 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 132 | # pixels large. 133 | # html_favicon = None 134 | 135 | # Add any paths that contain custom static files (such as style sheets) here, 136 | # relative to this directory. They are copied after the builtin static files, 137 | # so a file named "default.css" will overwrite the builtin "default.css". 138 | # html_static_path = ['_static'] 139 | 140 | # Add any extra paths that contain custom files (such as robots.txt or 141 | # .htaccess) here, relative to this directory. These files are copied 142 | # directly to the root of the documentation. 143 | # html_extra_path = [] 144 | 145 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 146 | # using the given strftime format. 147 | # html_last_updated_fmt = '%b %d, %Y' 148 | 149 | # If true, SmartyPants will be used to convert quotes and dashes to 150 | # typographically correct entities. 151 | # html_use_smartypants = True 152 | 153 | # Custom sidebar templates, maps document names to template names. 154 | # html_sidebars = {} 155 | 156 | # Additional templates that should be rendered to pages, maps page names to 157 | # template names. 158 | # html_additional_pages = {} 159 | 160 | # If false, no module index is generated. 161 | # html_domain_indices = True 162 | 163 | # If false, no index is generated. 164 | # html_use_index = True 165 | 166 | # If true, the index is split into individual pages for each letter. 167 | # html_split_index = False 168 | 169 | # If true, links to the reST sources are added to the pages. 170 | # html_show_sourcelink = True 171 | 172 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 173 | # html_show_sphinx = True 174 | 175 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 176 | # html_show_copyright = True 177 | 178 | # If true, an OpenSearch description file will be output, and all pages will 179 | # contain a tag referring to it. The value of this option must be the 180 | # base URL from which the finished HTML is served. 181 | # html_use_opensearch = '' 182 | 183 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 184 | # html_file_suffix = None 185 | 186 | # Output file base name for HTML help builder. 187 | htmlhelp_basename = "icsdoc" 188 | 189 | 190 | # -- Options for LaTeX output --------------------------------------------- 191 | 192 | latex_elements = { 193 | # The paper size ('letterpaper' or 'a4paper'). 194 | #'papersize': 'letterpaper', 195 | # The font size ('10pt', '11pt' or '12pt'). 196 | #'pointsize': '10pt', 197 | # Additional stuff for the LaTeX preamble. 198 | #'preamble': '', 199 | } 200 | 201 | # Grouping the document tree into LaTeX files. List of tuples 202 | # (source start file, target name, title, 203 | # author, documentclass [howto, manual, or own class]). 204 | latex_documents = [ 205 | ("index", "ics.tex", "python\\_ics Documentation", "David Rebbe", "manual"), 206 | ] 207 | 208 | # The name of an image file (relative to this directory) to place at the top of 209 | # the title page. 210 | # latex_logo = None 211 | 212 | # For "manual" documents, if this is true, then toplevel headings are parts, 213 | # not chapters. 214 | # latex_use_parts = False 215 | 216 | # If true, show page references after internal links. 217 | # latex_show_pagerefs = False 218 | 219 | # If true, show URL addresses after external links. 220 | # latex_show_urls = False 221 | 222 | # Documents to append as an appendix to all manuals. 223 | # latex_appendices = [] 224 | 225 | # If false, no module index is generated. 226 | # latex_domain_indices = True 227 | 228 | 229 | # -- Options for manual page output --------------------------------------- 230 | 231 | # One entry per manual page. List of tuples 232 | # (source start file, name, description, authors, manual section). 233 | man_pages = [("index", "ics", "ics Documentation", ["David Rebbe"], 1)] 234 | 235 | # If true, show URL addresses after external links. 236 | # man_show_urls = False 237 | 238 | 239 | # -- Options for Texinfo output ------------------------------------------- 240 | 241 | # Grouping the document tree into Texinfo files. List of tuples 242 | # (source start file, target name, title, author, 243 | # dir menu entry, description, category) 244 | texinfo_documents = [ 245 | ("index", "ics", "ics Documentation", "David Rebbe", "ics", "One line description of project.", "Miscellaneous"), 246 | ] 247 | 248 | # Documents to append as an appendix to all manuals. 249 | # texinfo_appendices = [] 250 | 251 | # If false, no module index is generated. 252 | # texinfo_domain_indices = True 253 | 254 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 255 | # texinfo_show_urls = 'footnote' 256 | 257 | # If true, do not generate a @detailmenu in the "Top" node's menu. 258 | # texinfo_no_detailmenu = False 259 | 260 | autodoc_member_order = "groupwise" 261 | -------------------------------------------------------------------------------- /doc/source/examples.rst: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | Examples 3 | ############################################################################## 4 | 5 | Examples can be found at https://github.com/intrepidcs/python_ics/tree/master/examples 6 | 7 | For extra information on data structures and underlying functionality, please visit neoVI DLL Documentation under https://intrepidcs.com/support/support-resources/ 8 | 9 | Opening a device 10 | ============================================================================== 11 | 12 | The ``open_device_example.py`` example shows how to successfully open and close an Intrepid device. 13 | 14 | Transmitting and Receiving a CAN message 15 | ============================================================================== 16 | 17 | The following examples show how to interact with CAN messages on an Intrepid device. 18 | 19 | - ``transmit_can_example.py``: Basic example showing how to transmit and receive standard CAN frame 20 | - ``transmit_can_xtd_example.py``: Builds off of the CAN example and adds extended Arbitration ID attributes 21 | - ``canfd_transmit_example.py``: Bare minimum example on how to transmit over CANFD. 22 | 23 | 24 | ISO 15765-2 Example 25 | ============================================================================== 26 | 27 | The ``iso15765_example.py`` example shows how to setup basic ISO 15765-2 receive filters and transmitting an ISO 15765-2 message. 28 | 29 | After opening an Intrepid device ``ics.iso15765_enable_networks`` should be called to enable ISO 15765-2. 30 | 31 | Receive filtering can be established by passing a custom ``ics.CmISO157652RxMessage()`` to ``ics.iso15765_receive_message()``. 32 | 33 | Similarly transmitting an ISO 15765-2 frame can be accomplished by passing a custom ``ics.CmISO157652TxMessage()`` to ``ics.iso15765_transmit_message()``. 34 | 35 | 36 | Missing an example? 37 | ============================================================================== 38 | 39 | Need an example on something that isn't covered here? Please submit an issue on github or feel free to send over a Pull Request of your own. -------------------------------------------------------------------------------- /doc/source/generate_documentation.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import ics 3 | 4 | 5 | def generate_structures(): 6 | # data = '.. autosummary::\n' 7 | """ 8 | \t.. automodule:: ics.structures.{name}.{name}\n\t\t:members:\n\t\t:undoc-members:\n\n" 9 | """ 10 | data = "" 11 | for name, value in inspect.getmembers(ics.structures, inspect.ismodule): 12 | # data += f"\t.. automodule:: ics.structures.{name}\n\t\t:members:\n\t\t:show-inheritance:\n\t\t:undoc-members:\n\n" 13 | data += f"\t.. autoclass:: ics.structures.{name}.{name}\n\t\t:members:\n\t\t:undoc-members:\n\n" 14 | return data 15 | 16 | 17 | def generate_functions(): 18 | data = "" 19 | functions = inspect.getmembers(ics, inspect.isroutine) 20 | new_style_functions = [] 21 | icsneo_style_functions = [] 22 | inbetween_style_functions = [] 23 | for function_name, function_type in functions: 24 | if function_name.startswith("icsneo"): 25 | icsneo_style_functions.append(function_name) 26 | elif "_" in function_name: 27 | new_style_functions.append(function_name) 28 | else: 29 | inbetween_style_functions.append(function_name) 30 | 31 | data += ".. autosummary::\n" 32 | for name in new_style_functions + inbetween_style_functions + icsneo_style_functions: 33 | if name: 34 | data += f"\tics.{name}\n" 35 | return data 36 | 37 | 38 | def generate_variables(): 39 | data = "" 40 | for variable in [item for item in dir(ics) if not item.startswith("__") and item.isupper()]: 41 | data += f"\t.. py:data:: {str(variable)}\n\t\t:annotation: = {str(getattr(ics, variable))}\n\n" 42 | return data 43 | 44 | 45 | def generate_documentation(): 46 | return inspect.cleandoc( 47 | f""".. include:: header.rst 48 | .. include:: examples.rst 49 | 50 | ############################################################################## 51 | PyNeoDeviceEx 52 | ############################################################################## 53 | .. autoclass:: ics.PyNeoDeviceEx 54 | :members: 55 | :show-inheritance: 56 | :undoc-members: 57 | 58 | ############################################################################## 59 | Module Documentation 60 | ############################################################################## 61 | .. automodule:: ics.ics 62 | :members: 63 | :show-inheritance: 64 | :undoc-members: 65 | 66 | ############################################################################## 67 | Module Functions 68 | ############################################################################## 69 | 70 | {generate_functions()} 71 | 72 | ############################################################################## 73 | Module Structures 74 | ############################################################################## 75 | 76 | {generate_structures()} 77 | 78 | ############################################################################## 79 | Module Variables 80 | ############################################################################## 81 | 82 | {generate_variables()} 83 | 84 | """ 85 | ) 86 | 87 | 88 | with open("index.rst", "w+") as f: 89 | f.write(generate_documentation()) 90 | print("Done.") 91 | -------------------------------------------------------------------------------- /doc/source/header.rst: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | README 3 | ############################################################################## 4 | .. mdinclude:: ../../README.md 5 | 6 | 7 | ############################################################################## 8 | PyInstaller 9 | ############################################################################## 10 | 11 | Due to the added complexity underneath when building, PyInstaller ``hidden_imports.py`` should be used now in your spec script: 12 | 13 | .. code-block:: python 14 | 15 | # -*- mode: python ; coding: utf-8 -*- 16 | 17 | import ics 18 | 19 | block_cipher = None 20 | 21 | 22 | a = Analysis(['test.py'], 23 | pathex=['.'], 24 | binaries=[], 25 | datas=[], 26 | hiddenimports=ics.hiddenimports.hidden_imports, 27 | hookspath=[], 28 | runtime_hooks=[], 29 | excludes=[], 30 | win_no_prefer_redirects=False, 31 | win_private_assemblies=False, 32 | cipher=block_cipher, 33 | noarchive=False) 34 | pyz = PYZ(a.pure, a.zipped_data, 35 | cipher=block_cipher) 36 | exe = EXE(pyz, 37 | a.scripts, 38 | [], 39 | exclude_binaries=True, 40 | name='test', 41 | debug=False, 42 | bootloader_ignore_signals=False, 43 | strip=False, 44 | upx=True, 45 | console=True ) 46 | coll = COLLECT(exe, 47 | a.binaries, 48 | a.zipfiles, 49 | a.datas, 50 | strip=False, 51 | upx=True, 52 | upx_exclude=[], 53 | name='test') 54 | 55 | ############################################################################## 56 | Breaking Changes v915 57 | ############################################################################## 58 | 59 | The icsneo40 library has migrated to the NeoDeviceEx structure and python_ics has finally been updated to reflect these changes. A new class `ics.PyNeoDeviceEx` now inherits `ics.structures.neo_device_ex.neo_device_ex` and allows a more pythonic way of coding. 60 | 61 | Previous: 62 | 63 | .. code-block:: python 64 | 65 | import ics 66 | # Open the first device 67 | device = ics.open_device() 68 | # Load default settings 69 | ics.load_default_settings(device) 70 | # Close the device 71 | ics.close_device(device) 72 | # When device goes out of scope, its automatically cleaned up here by garbage collection if not closed 73 | 74 | New: 75 | 76 | .. code-block:: python 77 | 78 | import ics 79 | # Open the first device 80 | device = ics.open_device() 81 | # Load default settings 82 | device.load_default_settings() 83 | # Close the device 84 | device.close() 85 | # When device goes out of scope, its automatically cleaned up here by garbage collection if not closed 86 | 87 | 88 | `ics.PyNeoDeviceEx` includes accessors to provide backwards compatibility with the old NeoDevice class so all existing code should still be functional. 89 | 90 | ############################################################################## 91 | Breaking Changes v903 92 | ############################################################################## 93 | 94 | ISO 15765-2 95 | ============================================================================== 96 | 97 | old naming conventions have been updated to reflex closer to the actual codebase. 98 | 99 | .. code-block:: python 100 | 101 | # Old: 102 | tx_msg = ics.CmISO157652TxMessage() 103 | rx_msg = ics.CmISO157652RxMessage() 104 | 105 | # New: 106 | tx_msg = ics.st_cm_iso157652_tx_message.st_cm_iso157652_tx_message() 107 | rx_msg = ics.st_cm_iso157652_rx_message.st_cm_iso157652_rx_message() 108 | 109 | ``ics.st_cm_iso157652_tx_message.st_cm_iso157652_tx_message()`` data structure is now a ctypes.c_ubytes array instead of a python list. 110 | 111 | .. code-block:: python 112 | 113 | # Old: 114 | msg.data = [x for x in range(number_of_bytes)] 115 | 116 | # New: 117 | my_data = [x for x in range(number_of_bytes)] 118 | msg.data = (ctypes.c_ubyte*len(msg.data))(*my_data) 119 | 120 | >>> msg.data 121 | 122 | 123 | Settings 124 | ============================================================================== 125 | 126 | v903 and up have converted over to a new auto generation of ``icsnVC40.h``. This enables faster support for newer Intrepid devices and less error prone. With this switch we have moved to using ``ics.s_device_settings``. 127 | 128 | .. code-block:: python 129 | 130 | # Old behavior: 131 | device = ics.open_device() 132 | settings = ics.get_device_settings(device) 133 | # settings is a Vcan3Settings type 134 | settings.can1.Baudrate = 1 135 | ics.set_device_settings(device, settings) 136 | 137 | # New behavior 138 | device = ics.open_device() 139 | settings = ics.get_device_settings(device) 140 | # settings is a s_device_settings type 141 | settings.vcan3.can1.Baudrate = 1 142 | ics.set_device_settings(device, settings) 143 | 144 | ############################################################################## 145 | Getting Started 146 | ############################################################################## 147 | 148 | Please see https://github.com/intrepidcs/python_ics/tree/master/examples for simple examples on how to use this module. Most function documentation has a simple example on how its intended to be used. Every function was designed to be as close as possible to it's C counterpart unless it was deemed to make the function more pythonic in nature. 149 | 150 | For those experienced with the C API ``ics.open_device`` (``icsneoOpenNeoDevice()``) behavior has been changed the most (no parameters makes it auto utilize ``ics.find_devices`` (``icsneoFindNeoDevices()``) and open the first device). Also since python is a object oriented language the module utilizes this and auto cleans up device handles when going out of scope so there is usually no need to call ``ics.close_device()``. 151 | -------------------------------------------------------------------------------- /examples/canfd_transmit_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | 3 | if __name__ == "__main__": 4 | # Create a CAN Message like normal but set the StatusBitFields 5 | msg = ics.SpyMessage() 6 | msg.ArbIDOrHeader = 0x01 7 | msg.NetworkID = ics.NETID_HSCAN 8 | msg.Protocol = ics.SPY_PROTOCOL_CANFD 9 | msg.StatusBitField = ics.SPY_STATUS_CANFD 10 | msg.StatusBitField3 = ics.SPY_STATUS3_CANFD_BRS 11 | msg.ExtraDataPtr = tuple([x for x in range(64)]) 12 | 13 | # Open Device and transmit the message 14 | device = ics.open_device() 15 | ics.transmit_messages(device, msg) 16 | -------------------------------------------------------------------------------- /examples/iso15765_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | import ctypes 3 | 4 | enable_print_message = False 5 | enable_use_server = True 6 | 7 | 8 | # Helper Functions ########################################################## 9 | 10 | def print_message(msg): 11 | if not enable_print_message: 12 | if isinstance(msg, ics.SpyMessage): 13 | print("\tArbID: {}\tData: {}".format(hex(msg.ArbIDOrHeader), [hex(x) for x in msg.Data])) 14 | return 15 | print("\t" + str(type(msg))) 16 | for attribute in dir(msg): 17 | if attribute.startswith("_"): 18 | continue 19 | length = len(attribute) 20 | if attribute == "data": 21 | print("\t\t{}:{}{}".format(attribute, " " * (30 - length), msg.data[: msg.num_bytes])) 22 | else: 23 | value = getattr(msg, attribute) 24 | try: 25 | value = hex(value) 26 | except: 27 | pass 28 | print("\t\t{}:{}{}".format(attribute, " " * (30 - length), value)) 29 | print() 30 | 31 | 32 | def open_device(index=0): 33 | device = None 34 | if enable_use_server: 35 | # ics.open_device() won't open a device if we have handles open already 36 | # so we need to find them and specify which ones to connect to. 37 | devices = ics.find_devices() 38 | print( 39 | "Opening Device {} (Open Client handles: {})...".format( 40 | devices[index], devices[index].NumberOfClients 41 | ) 42 | ) 43 | ics.open_device(devices[index]) 44 | device = devices[index] 45 | else: 46 | print("Opening Device...") 47 | device = ics.open_device() 48 | print(f"Opened Device {device}.") 49 | return device 50 | 51 | 52 | # Iso15765 Fuctions ######################################################### 53 | def transmit_iso15765_msg(device, netid=ics.NETID_HSCAN, is_canfd=False): 54 | number_of_bytes = 64 55 | msg = ics.st_cm_iso157652_tx_message.st_cm_iso157652_tx_message() 56 | msg.id = 0x7E0 57 | msg.vs_netid = netid 58 | msg.num_bytes = number_of_bytes 59 | msg.padding = 0xAA 60 | # Flow Control 61 | msg.fc_id = 0x7E8 62 | msg.fc_id_mask = 0xFFF 63 | msg.flowControlExtendedAddress = 0xFE 64 | msg.fs_timeout = 0x10 # ms 65 | msg.fs_wait = 0x3000 # ms 66 | msg.blockSize = 0 67 | msg.stMin = 0 68 | # paddingEnable 69 | msg.paddingEnable = 1 70 | # CANFD: Enable + BRS 71 | if is_canfd: 72 | msg.iscanFD = 1 73 | msg.isBRSEnabled = 1 74 | # tx_dl 75 | msg.tx_dl = 1 76 | # Data 77 | my_data = [x for x in range(number_of_bytes)] 78 | msg.data = (ctypes.c_ubyte * len(msg.data))(*my_data) 79 | 80 | # Transmit the message 81 | print("Transmitting iso15765 message on {}...".format(device)) 82 | ics.iso15765_transmit_message(device, netid, msg, 3000) 83 | # Wait for the messages to be transmitted, this can be calculated a lot better but works here. 84 | time.sleep((((number_of_bytes / 8) * msg.fs_timeout) / 1000.0) + 0.5) 85 | # print_message(msg) 86 | print("Transmitted iso15765 message on {}.".format(device)) 87 | 88 | 89 | def setup_rx_iso15765_msg(device, netid=ics.NETID_HSCAN, is_canfd=False): 90 | msg = ics.st_cm_iso157652_rx_message.st_cm_iso157652_rx_message() 91 | 92 | msg.id = 0x7E0 93 | msg.vs_netid = netid 94 | msg.padding = 0xAA 95 | msg.id_mask = 0xFFF 96 | msg.fc_id = 0x7E8 97 | msg.blockSize = 100 98 | msg.stMin = 10 99 | msg.cf_timeout = 1000 100 | # enableFlowControlTransmission = 1 101 | msg.enableFlowControlTransmission = 1 102 | # paddingEnable 103 | msg.paddingEnable = 1 104 | # CANFD: Enable + BRS 105 | if is_canfd: 106 | msg.iscanFD = 1 107 | msg.isBRSEnabled = 1 108 | print_message(msg) 109 | print("Setting up iso15765 message on {}...".format(dev_name(device))) 110 | ics.iso15765_receive_message(device, netid, msg) 111 | print("Setup iso15765 message on {}.".format(dev_name(device))) 112 | 113 | 114 | def get_iso15765_msgs(device): 115 | msgs, error_count = ics.get_messages(device) 116 | print("Received {} messages with {} errors.".format(len(msgs), error_count)) 117 | for i, m in enumerate(msgs): 118 | print("Message #{}\t".format(i + 1), end="") 119 | print_message(m) 120 | 121 | 122 | if __name__ == "__main__": 123 | import time 124 | 125 | netid = ics.NETID_HSCAN 126 | 127 | tx_device = open_device(0) 128 | rx_device = open_device(1) 129 | 130 | ics.iso15765_enable_networks(tx_device, netid) 131 | ics.iso15765_enable_networks(rx_device, netid) 132 | setup_rx_iso15765_msg(rx_device) 133 | transmit_iso15765_msg(tx_device) 134 | get_iso15765_msgs(rx_device) 135 | 136 | ics.iso15765_disable_networks(tx_device) 137 | ics.iso15765_disable_networks(rx_device) 138 | -------------------------------------------------------------------------------- /examples/lin22.ldf: -------------------------------------------------------------------------------- 1 | /*******************************************************/ 2 | /* This is the example LDF from LIN 2.2A specification */ 3 | /*******************************************************/ 4 | 5 | // Source: https://lin-cia.org/fileadmin/microsites/lin-cia.org/resources/documents/LIN_2.2A.pdf 6 | 7 | LIN_description_file; 8 | LIN_protocol_version = "2.2"; 9 | LIN_language_version = "2.2"; 10 | LIN_speed = 19.2 kbps; 11 | Channel_name = "DB"; 12 | 13 | Nodes { 14 | Master: CEM, 5 ms, 0.1 ms; 15 | Slaves: LSM, RSM; 16 | } 17 | 18 | Signals { 19 | InternalLightsRequest: 2, 0, CEM, LSM, RSM; 20 | RightIntLightsSwitch: 8, 0, RSM, CEM; 21 | LeftIntLightsSwitch: 8, 0, LSM, CEM; 22 | LSMerror: 1, 0, LSM, CEM; 23 | RSMerror: 1, 0, RSM, CEM; 24 | IntTest: 2, 0, LSM, CEM; 25 | } 26 | 27 | Frames { 28 | CEM_Frm1: 0x01, CEM, 1 { 29 | InternalLightsRequest, 0; 30 | } 31 | LSM_Frm1: 0x02, LSM, 2 { 32 | LeftIntLightsSwitch, 8; 33 | } 34 | LSM_Frm2: 0x03, LSM, 1 { 35 | LSMerror, 0; 36 | IntTest, 1; 37 | } 38 | RSM_Frm1: 0x04, RSM, 2 { 39 | RightIntLightsSwitch, 8; 40 | } 41 | RSM_Frm2: 0x05, RSM, 1 { 42 | RSMerror, 0; 43 | } 44 | } 45 | 46 | Event_triggered_frames { 47 | Node_Status_Event : Collision_resolver, 0x06, RSM_Frm1, LSM_Frm1; 48 | } 49 | 50 | Node_attributes { 51 | RSM { 52 | LIN_protocol = "2.0"; 53 | configured_NAD = 0x20; 54 | product_id = 0x4E4E, 0x4553, 1; 55 | response_error = RSMerror; 56 | P2_min = 150 ms; 57 | ST_min = 50 ms; 58 | configurable_frames { 59 | Node_Status_Event=0x000; CEM_Frm1 = 0x0001; RSM_Frm1 = 0x0002; 60 | RSM_Frm2 = 0x0003; 61 | } 62 | } 63 | LSM { 64 | LIN_protocol = "2.2"; 65 | configured_NAD = 0x21; 66 | initial_NAD = 0x01; 67 | product_id = 0x4A4F, 0x4841; 68 | response_error = LSMerror; 69 | fault_state_signals = IntTest; 70 | P2_min = 150 ms; 71 | ST_min = 50 ms; 72 | configurable_frames { 73 | Node_Status_Event; 74 | CEM_Frm1; 75 | LSM_Frm1; 76 | LSM_Frm2; 77 | } 78 | } 79 | } 80 | 81 | Schedule_tables { 82 | Configuration_Schedule { 83 | AssignNAD {LSM} delay 15 ms; 84 | AssignFrameIdRange {LSM, 0} delay 15 ms; 85 | AssignFrameId {RSM, CEM_Frm1} delay 15 ms; 86 | AssignFrameId {RSM, RSM_Frm1} delay 15 ms; 87 | AssignFrameId {RSM, RSM_Frm2} delay 15 ms; 88 | } 89 | Normal_Schedule { 90 | CEM_Frm1 delay 15 ms; 91 | LSM_Frm2 delay 15 ms; 92 | RSM_Frm2 delay 15 ms; 93 | Node_Status_Event delay 10 ms; 94 | } 95 | MRF_schedule { 96 | MasterReq delay 10 ms; 97 | } 98 | SRF_schedule { 99 | SlaveResp delay 10 ms; 100 | } 101 | Collision_resolver { // Keep timing of other frames if collision 102 | CEM_Frm1 delay 15 ms; 103 | LSM_Frm2 delay 15 ms; 104 | RSM_Frm2 delay 15 ms; 105 | RSM_Frm1 delay 10 ms; // Poll the RSM node 106 | CEM_Frm1 delay 15 ms; 107 | LSM_Frm2 delay 15 ms; 108 | RSM_Frm2 delay 15 ms; 109 | LSM_Frm1 delay 10 ms; // Poll the LSM node 110 | } 111 | } 112 | 113 | Signal_encoding_types { 114 | Dig2Bit { 115 | logical_value, 0, "off"; 116 | logical_value, 1, "on"; 117 | logical_value, 2, "error"; 118 | logical_value, 3, "void"; 119 | } 120 | ErrorEncoding { 121 | logical_value, 0, "OK"; 122 | logical_value, 1, "error"; 123 | } 124 | FaultStateEncoding { 125 | logical_value, 0, "No test result"; 126 | logical_value, 1, "failed"; 127 | logical_value, 2, "passed"; 128 | logical_value, 3, "not used"; 129 | } 130 | LightEncoding { 131 | logical_value, 0, "Off"; 132 | physical_value, 1, 254, 1, 100, "lux"; 133 | logical_value, 255, "error"; 134 | } 135 | } 136 | Signal_representation { 137 | Dig2Bit: InternalLightsRequest; 138 | ErrorEncoding: RSMerror, LSMerror; 139 | LightEncoding: RightIntLightsSwitch, LeftIntLightsSwitch; 140 | } -------------------------------------------------------------------------------- /examples/lin_settings_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | from ics.structures.s_device_settings import s_device_settings 3 | from ics.structures.e_device_settings_type import e_device_settings_type 4 | 5 | 6 | def get_device_specific_settings(s: s_device_settings) -> object: 7 | """ 8 | Returns the device specific setting structure for our device in question 9 | """ 10 | setting_map = {} 11 | # We need to map the Union type to the DeviceSettingType 12 | setting_map[e_device_settings_type.DeviceCANHUBSettingsType] = "canhub" 13 | setting_map[e_device_settings_type.DeviceCMProbeSettingsType] = "cmprobe" 14 | setting_map[e_device_settings_type.DeviceECU_AVBSettingsType] = "neoecu_avb" 15 | setting_map[e_device_settings_type.DeviceEEVBSettingsType] = "eevb" 16 | setting_map[e_device_settings_type.DeviceFire2SettingsType] = "cyan" 17 | setting_map[e_device_settings_type.DeviceFireSettingsType] = "fire" 18 | setting_map[e_device_settings_type.DeviceFireVnetSettingsType] = "firevnet" 19 | setting_map[e_device_settings_type.DeviceFlexVnetzSettingsType] = "flexvnetz" 20 | setting_map[e_device_settings_type.DeviceIEVBSettingsType] = "ievb" 21 | setting_map[e_device_settings_type.DeviceNeoECU12SettingsType] = "neoecu12" 22 | setting_map[e_device_settings_type.DeviceOBD2ProSettingsType] = "obd2pro" 23 | setting_map[e_device_settings_type.DeviceRADGalaxySettingsType] = "radgalaxy" 24 | setting_map[e_device_settings_type.DeviceRADGigalogSettingsType] = "radgigalog" 25 | setting_map[e_device_settings_type.DeviceRADGigastarSettingsType] = "radgigastar" 26 | setting_map[e_device_settings_type.DeviceRADMoon2SettingsType] = "radmoon2" 27 | setting_map[e_device_settings_type.DeviceRADPlutoSettingsType] = "pluto" 28 | setting_map[e_device_settings_type.DeviceRADStar2SettingsType] = "radstar2" 29 | setting_map[e_device_settings_type.DeviceRADSuperMoonSettingsType] = "radsupermoon" 30 | setting_map[e_device_settings_type.DeviceRADMoon2SettingsType] = "radmoon2" 31 | setting_map[e_device_settings_type.DeviceRedSettingsType] = "red" 32 | setting_map[e_device_settings_type.DeviceVCAN3SettingsType] = "vcan3" 33 | setting_map[e_device_settings_type.DeviceVCAN412SettingsType] = "vcan412" 34 | setting_map[e_device_settings_type.DeviceVCAN4IndSettingsType] = "vcan4_ind" 35 | setting_map[e_device_settings_type.DeviceVCAN4SettingsType] = "vcan4" 36 | setting_map[e_device_settings_type.DeviceVCANRFSettingsType] = "vcanrf" 37 | setting_map[e_device_settings_type.DeviceVividCANSettingsType] = "vividcan" 38 | setting_map[e_device_settings_type.DeviceRADJupiterSettingsType] = "jupiter" 39 | setting_map[e_device_settings_type.DeviceFire3SettingsType] = "fire3" 40 | setting_map[e_device_settings_type.DeviceFire3FlexraySettingsType] = "fire3Flexray" 41 | setting_map[e_device_settings_type.DeviceRed2SettingsType] = "red2" 42 | setting_map[e_device_settings_type.DeviceRADA2BSettingsType] = "rad_a2b" 43 | setting_map[e_device_settings_type.DeviceOBD2LCSettingsType] = "obd2lc" 44 | 45 | if s.DeviceSettingType not in setting_map: 46 | raise KeyError(f"Error: {s.DeviceSettingType} is not a known type in setting_map") 47 | return getattr(s.Settings, setting_map[s.DeviceSettingType]) 48 | 49 | 50 | def print_settings(device_specific_settings): 51 | if hasattr(device_specific_settings, "lin1"): 52 | print(f"LIN 1 Baudrate: {settings.Settings.fire3.lin1.Baudrate}") 53 | print(f"LIN 1 Master resistor: {device_specific_settings.lin1.MasterResistor}") 54 | else: 55 | print("This device doesn't have a lin1 structure!") 56 | 57 | 58 | if __name__ == "__main__": 59 | try: 60 | # Open the first device 61 | device = ics.open_device() 62 | print(f"Opened Device {device} (Open Client handles: {device.NumberOfClients})...") 63 | except ics.RuntimeError as ex: 64 | print(f"Failed to open first device: {ex}") 65 | exit(1) 66 | 67 | print("Loading default settings...") 68 | ics.load_default_settings(device) 69 | 70 | print("Reading settings...") 71 | settings = ics.get_device_settings(device) 72 | device_specific_settings = get_device_specific_settings(settings) 73 | print_settings(device_specific_settings) 74 | 75 | print("Writing settings...") 76 | device_specific_settings = get_device_specific_settings(settings) 77 | if hasattr(device_specific_settings, "lin1"): 78 | device_specific_settings.lin1.Baudrate = 19200 79 | device_specific_settings.lin1.MasterResistor = 0 80 | else: 81 | print("This device doesn't have a lin1 structure to change!") 82 | ics.set_device_settings(device, settings) 83 | print_settings(device_specific_settings) 84 | 85 | print("Reading settings...") 86 | settings = ics.get_device_settings(device) 87 | device_specific_settings = get_device_specific_settings(settings) 88 | print_settings(device_specific_settings) 89 | -------------------------------------------------------------------------------- /examples/open_device_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | 3 | # Tells our custom open_device() function to do special behavior 4 | # with neoVI Server enabled so we can successfully open devices 5 | enable_use_server = True 6 | 7 | 8 | def open_device(index=0): 9 | device = None 10 | if enable_use_server: 11 | # ics.open_device() won't open a device if we have handles open already 12 | # so we need to find them and specify which ones to connect to. 13 | devices = ics.find_devices() 14 | print( 15 | "Opening Device {} (Open Client handles: {})...".format( 16 | devices[index], devices[index].NumberOfClients 17 | ) 18 | ) 19 | ics.open_device(devices[index]) 20 | device = devices[index] 21 | else: 22 | print("Opening Device...") 23 | device = ics.open_device() 24 | print("Opened Device %s." % device) 25 | return device 26 | 27 | 28 | if __name__ == "__main__": 29 | # Lets figure out how many are connected to the PC and display it 30 | connected_count = len(ics.find_devices()) 31 | print("Found {} connected device(s)...".format(connected_count)) 32 | for i in range(connected_count): 33 | # Lets open the device 34 | device = open_device(i) 35 | # the device will automatically close here 36 | # because the device object is going out of 37 | # scope. 38 | print("Finished.") 39 | -------------------------------------------------------------------------------- /examples/transmit_can_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | 3 | # Tells our custom open_device() function to do special behavior 4 | # with neoVI Server enabled so we can successfully open devices 5 | enable_use_server = True 6 | 7 | 8 | def open_device(index=0): 9 | device = None 10 | if enable_use_server: 11 | # ics.open_device() won't open a device if we have handles open already 12 | # so we need to find them and specify which ones to connect to. 13 | devices = ics.find_devices() 14 | print( 15 | "Opening Device {} (Open Client handles: {})...".format( 16 | devices[index], devices[index].NumberOfClients 17 | ) 18 | ) 19 | ics.open_device(devices[index]) 20 | device = devices[index] 21 | else: 22 | print("Opening Device...") 23 | device = ics.open_device() 24 | print("Opened Device %s." % device) 25 | return device 26 | 27 | 28 | def transmit_can(device): 29 | msg = ics.SpyMessage() 30 | msg.ArbIDOrHeader = 0x01 # CAN Arbitration ID 31 | msg.Data = (1, 2, 3, 4, 5, 6, 7, 8) # Data Bytes go here 32 | msg.NetworkID = ics.NETID_HSCAN # First channel of CAN on the device 33 | 34 | # msg parameter here can also be a tuple of messages 35 | ics.transmit_messages(device, msg) 36 | 37 | 38 | def receive_can(device): 39 | msgs, error_count = ics.get_messages(device) 40 | print("Received {} messages with {} errors.".format(len(msgs), error_count)) 41 | for i, m in enumerate(msgs): 42 | print("Message #{}\t".format(i + 1), end="") 43 | print("\tArbID: {}\tData: {}".format(hex(m.ArbIDOrHeader), [hex(x) for x in m.Data])) 44 | 45 | 46 | if __name__ == "__main__": 47 | import time 48 | 49 | # Lets figure out how many are connected to the PC and display it 50 | connected_count = len(ics.find_devices()) 51 | print("Found {} connected device(s)...".format(connected_count)) 52 | 53 | tx_dev = open_device(0) 54 | rx_dev = open_device(1) 55 | 56 | transmit_can(tx_dev) 57 | receive_can(rx_dev) 58 | 59 | print("Finished.") 60 | -------------------------------------------------------------------------------- /examples/transmit_can_xtd_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | 3 | # Tells our custom open_device() function to do special behavior 4 | # with neoVI Server enabled so we can successfully open devices 5 | enable_use_server = True 6 | 7 | 8 | def dev_name(device): 9 | # Return a friendly name of the device (ie. neoVI FIRE2 CY1234) 10 | if int("0A0000", 36) <= device.SerialNumber <= int("ZZZZZZ", 36): 11 | return device.Name + " " + ics.base36enc(device.SerialNumber) 12 | else: 13 | return device.Name + " " + str(device.SerialNumber) 14 | 15 | 16 | def open_device(index=0): 17 | device = None 18 | if enable_use_server: 19 | # ics.open_device() won't open a device if we have handles open already 20 | # so we need to find them and specify which ones to connect to. 21 | devices = ics.find_devices() 22 | print( 23 | "Opening Device {} (Open Client handles: {})...".format( 24 | dev_name(devices[index]), devices[index].NumberOfClients 25 | ) 26 | ) 27 | ics.open_device(devices[index]) 28 | device = devices[index] 29 | else: 30 | print("Opening Device...") 31 | device = ics.open_device() 32 | print("Opened Device %s." % dev_name(device)) 33 | return device 34 | 35 | 36 | def transmit_can(device): 37 | msg = ics.SpyMessage() 38 | msg.ArbIDOrHeader = 0xFFFFFF # CAN Arbitration ID 39 | msg.Data = (1, 2, 3, 4, 5, 6, 7, 8) # Data Bytes go here 40 | msg.NetworkID = ics.NETID_HSCAN # First channel of CAN on the device 41 | msg.NumberBytesHeader = 4 42 | msg.StatusBitField = ics.SPY_STATUS_XTD_FRAME 43 | 44 | # msg parameter here can also be a tuple of messages 45 | ics.transmit_messages(device, msg) 46 | 47 | 48 | def receive_can(device): 49 | msgs, error_count = ics.get_messages(device) 50 | print("Received {} messages with {} errors.".format(len(msgs), error_count)) 51 | for i, m in enumerate(msgs): 52 | if m.NetworkID != ics.NETID_HSCAN: 53 | continue 54 | print("Message #{}\t".format(i + 1), end="") 55 | print("\tArbID: {}\tData: {}".format(hex(m.ArbIDOrHeader), [hex(x) for x in m.Data])) 56 | 57 | 58 | if __name__ == "__main__": 59 | import time 60 | 61 | # Lets figure out how many are connected to the PC and display it 62 | connected_count = len(ics.find_devices()) 63 | print("Found {} connected device(s)...".format(connected_count)) 64 | 65 | tx_dev = open_device(0) 66 | rx_dev = open_device(1) 67 | 68 | transmit_can(tx_dev) 69 | receive_can(rx_dev) 70 | 71 | print("Finished.") 72 | -------------------------------------------------------------------------------- /examples/transmit_canfd_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | import time 3 | 4 | # Tells our custom open_device() function to do special behavior 5 | # with neoVI Server enabled so we can successfully open devices 6 | enable_use_server = True 7 | 8 | 9 | DATA_BYTES = tuple([x for x in range(64)]) 10 | 11 | 12 | def are_errors_present(msg): 13 | """Helper function to detect if a message error occurred.""" 14 | error_flags = 0 15 | error_flags |= ics.SPY_STATUS_GLOBAL_ERR 16 | error_flags |= ics.SPY_STATUS_CRC_ERROR 17 | error_flags |= ics.SPY_STATUS_CAN_ERROR_PASSIVE 18 | error_flags |= ics.SPY_STATUS_HEADERCRC_ERROR 19 | error_flags |= ics.SPY_STATUS_INCOMPLETE_FRAME 20 | error_flags |= ics.SPY_STATUS_LOST_ARBITRATION 21 | error_flags |= ics.SPY_STATUS_UNDEFINED_ERROR 22 | error_flags |= ics.SPY_STATUS_CAN_BUS_OFF 23 | error_flags |= ics.SPY_STATUS_BUS_RECOVERED 24 | error_flags |= ics.SPY_STATUS_BUS_SHORTED_PLUS 25 | error_flags |= ics.SPY_STATUS_BUS_SHORTED_GND 26 | error_flags |= ics.SPY_STATUS_CHECKSUM_ERROR 27 | error_flags |= ics.SPY_STATUS_BAD_MESSAGE_BIT_TIME_ERROR 28 | error_flags |= ics.SPY_STATUS_TX_NOMATCH 29 | error_flags |= ics.SPY_STATUS_COMM_IN_OVERFLOW 30 | error_flags |= ics.SPY_STATUS_EXPECTED_LEN_MISMATCH 31 | error_flags |= ics.SPY_STATUS_MSG_NO_MATCH 32 | error_flags |= ics.SPY_STATUS_BREAK 33 | error_flags |= ics.SPY_STATUS_AVSI_REC_OVERFLOW 34 | error_flags |= ics.SPY_STATUS_BREAK 35 | if (msg.StatusBitField & error_flags) != 0: 36 | return True 37 | return False 38 | 39 | 40 | def open_device(index=0): 41 | device = None 42 | if enable_use_server: 43 | # ics.open_device() won't open a device if we have handles open already 44 | # so we need to find them and specify which ones to connect to. 45 | devices = ics.find_devices() 46 | print( 47 | "Opening Device {} (Open Client handles: {})...".format( 48 | devices[index], devices[index].NumberOfClients 49 | ) 50 | ) 51 | ics.open_device(devices[index]) 52 | device = devices[index] 53 | else: 54 | print("Opening Device...") 55 | device = ics.open_device() 56 | print("Opened Device %s." % device) 57 | return device 58 | 59 | 60 | def transmit_can(device): 61 | msg = ics.SpyMessage() 62 | msg.ArbIDOrHeader = 0x01 # CAN Arbitration ID 63 | msg.NetworkID = ics.NETID_HSCAN # First channel of CAN on the device 64 | msg.Protocol = ics.SPY_PROTOCOL_CANFD 65 | msg.StatusBitField = ics.SPY_STATUS_CANFD 66 | msg.StatusBitField3 = ics.SPY_STATUS3_CANFD_BRS 67 | msg.ExtraDataPtr = DATA_BYTES 68 | 69 | # Clear the receive buffer for later 70 | _, _ = ics.get_messages(device) 71 | # msg parameter here can also be a tuple of messages 72 | ics.transmit_messages(device, msg) 73 | # Give the bus and buffers time to do their magic. 74 | # In a real application we should poll until we find our actual message. 75 | time.sleep(0.5) 76 | # get all the messages on this device and print out the transmitted messages 77 | print("=" * 80) 78 | print(f"Transmitted Messages on {device}") 79 | print("=" * 80) 80 | msgs, error_count = ics.get_messages(device) 81 | for i, m in enumerate(msgs): 82 | # Only process transmitted messages 83 | if m.StatusBitField & ics.SPY_STATUS_TX_MSG == ics.SPY_STATUS_TX_MSG: 84 | print("Message #{}\t".format(i + 1), end="") 85 | data = m.Data if not m.ExtraDataPtr else m.ExtraDataPtr 86 | netid = m.NetworkID | (m.NetworkID2 << 8) 87 | print( 88 | "NetID: {}\tArbID: {}\tData: {}\tErrors Present: {}".format( 89 | hex(netid), hex(m.ArbIDOrHeader), [hex(x) for x in data], are_errors_present(m) 90 | ) 91 | ) 92 | 93 | 94 | def receive_can(device): 95 | msgs, error_count = ics.get_messages(device) 96 | print("=" * 80) 97 | print(f"Received Messages on {device}") 98 | print("=" * 80) 99 | print("Received {} messages with {} errors.".format(len(msgs), error_count)) 100 | for i, m in enumerate(msgs): 101 | # Ignore transmitted messages 102 | if m.StatusBitField & ics.SPY_STATUS_TX_MSG == ics.SPY_STATUS_TX_MSG: 103 | continue 104 | # if m.Protocol != ics.SPY_PROTOCOL_CANFD: 105 | # continue 106 | print("Message #{}\t".format(i + 1), end="") 107 | data = m.Data if not m.ExtraDataPtr else m.ExtraDataPtr 108 | netid = m.NetworkID | (m.NetworkID2 << 8) 109 | print("NetID: {}\tArbID: {}\tData: {}".format(hex(netid), hex(m.ArbIDOrHeader), [hex(x) for x in data])) 110 | 111 | 112 | if __name__ == "__main__": 113 | # Lets figure out how many are connected to the PC and display it 114 | connected_count = len(ics.find_devices()) 115 | print("Found {} connected device(s)...".format(connected_count)) 116 | 117 | tx_dev = open_device(0) 118 | rx_dev = open_device(1) 119 | 120 | transmit_can(tx_dev) 121 | print() 122 | receive_can(rx_dev) 123 | 124 | print("Finished.") 125 | -------------------------------------------------------------------------------- /examples/transmit_ethernet_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | import time 3 | 4 | # Tells our custom open_device() function to do special behavior 5 | # with neoVI Server enabled so we can successfully open devices 6 | enable_use_server = True 7 | 8 | 9 | DATA_BYTES = tuple([x for x in range(64)]) 10 | 11 | 12 | def are_errors_present(msg): 13 | """Helper function to detect if a message error occurred.""" 14 | error_flags = 0 15 | error_flags |= ics.SPY_STATUS_GLOBAL_ERR 16 | error_flags |= ics.SPY_STATUS_CRC_ERROR 17 | error_flags |= ics.SPY_STATUS_CAN_ERROR_PASSIVE 18 | error_flags |= ics.SPY_STATUS_HEADERCRC_ERROR 19 | error_flags |= ics.SPY_STATUS_INCOMPLETE_FRAME 20 | error_flags |= ics.SPY_STATUS_LOST_ARBITRATION 21 | error_flags |= ics.SPY_STATUS_UNDEFINED_ERROR 22 | error_flags |= ics.SPY_STATUS_CAN_BUS_OFF 23 | error_flags |= ics.SPY_STATUS_BUS_RECOVERED 24 | error_flags |= ics.SPY_STATUS_BUS_SHORTED_PLUS 25 | error_flags |= ics.SPY_STATUS_BUS_SHORTED_GND 26 | error_flags |= ics.SPY_STATUS_CHECKSUM_ERROR 27 | error_flags |= ics.SPY_STATUS_BAD_MESSAGE_BIT_TIME_ERROR 28 | error_flags |= ics.SPY_STATUS_TX_NOMATCH 29 | error_flags |= ics.SPY_STATUS_COMM_IN_OVERFLOW 30 | error_flags |= ics.SPY_STATUS_EXPECTED_LEN_MISMATCH 31 | error_flags |= ics.SPY_STATUS_MSG_NO_MATCH 32 | error_flags |= ics.SPY_STATUS_BREAK 33 | error_flags |= ics.SPY_STATUS_AVSI_REC_OVERFLOW 34 | error_flags |= ics.SPY_STATUS_BREAK 35 | if (msg.StatusBitField & error_flags) != 0: 36 | return True 37 | return False 38 | 39 | 40 | def open_device(index=0): 41 | device = None 42 | if enable_use_server: 43 | # ics.open_device() won't open a device if we have handles open already 44 | # so we need to find them and specify which ones to connect to. 45 | devices = ics.find_devices() 46 | print( 47 | "Opening Device {} (Open Client handles: {})...".format( 48 | devices[index], devices[index].NumberOfClients 49 | ) 50 | ) 51 | ics.open_device(devices[index]) 52 | device = devices[index] 53 | else: 54 | print("Opening Device...") 55 | device = ics.open_device() 56 | print("Opened Device %s." % device) 57 | return device 58 | 59 | 60 | def transmit_ethernet(device): 61 | netid = ics.NETID_ETHERNET 62 | 63 | msg = ics.SpyMessage() 64 | msg.NetworkID = netid 65 | msg.NetworkID2 = netid >> 8 66 | msg.Protocol = ics.SPY_PROTOCOL_ETHERNET 67 | # use broadcast in case we are using a switch (First 6 bytes) 68 | # use ARP packet 69 | # Gigalog requires this for Ethernet 10G to be detected in Vspy (0x08, 0x06) 70 | # Last two bytes are the network id 71 | data = [ 72 | 0x00, 73 | 0xFC, 74 | 0x70, 75 | 0xFF, 76 | 0xFF, 77 | 0xFF, 78 | 0xFF, 79 | 0xFF, 80 | 0xFF, 81 | 0xFF, 82 | 0xFF, 83 | 0xFF, 84 | 0x08, 85 | 0x06, 86 | netid & 0xFF, 87 | (netid >> 8) & 0xFF, 88 | ] 89 | # Append 62 random bytes on the end. 90 | data += [x for x in range(62)] 91 | msg.ExtraDataPtr = tuple(data) 92 | # Wait for each device to have a link - In a real application we should be checking the neoVI status messages 93 | time.sleep(3) 94 | # Clear the receive buffer for later 95 | _, _ = ics.get_messages(device) 96 | # msg parameter here can also be a tuple of messages 97 | ics.transmit_messages(device, msg) 98 | # Give the bus and buffers time to do their magic. 99 | # In a real application we should poll until we find our actual message. 100 | time.sleep(0.5) 101 | # get all the messages on this device and print out the transmitted messages 102 | print("=" * 80) 103 | print(f"Transmitted Messages on {device}") 104 | print("=" * 80) 105 | msgs, error_count = ics.get_messages(device) 106 | for i, m in enumerate(msgs): 107 | # Only process transmitted messages 108 | if m.StatusBitField & ics.SPY_STATUS_TX_MSG == ics.SPY_STATUS_TX_MSG: 109 | print("Message #{}\t".format(i + 1), end="") 110 | data = m.Data if not m.ExtraDataPtr else m.ExtraDataPtr 111 | netid = m.NetworkID | (m.NetworkID2 << 8) 112 | print( 113 | "NetID: {}\tArbID: {}\tData: {}\tErrors Present: {}".format( 114 | hex(netid), hex(m.ArbIDOrHeader), [hex(x) for x in data], are_errors_present(m) 115 | ) 116 | ) 117 | 118 | 119 | def receive_ethernet(device): 120 | msgs, error_count = ics.get_messages(device) 121 | print("=" * 80) 122 | print(f"Received Messages on {device}") 123 | print("=" * 80) 124 | print("Received {} messages with {} errors.".format(len(msgs), error_count)) 125 | for i, m in enumerate(msgs): 126 | # Ignore transmitted messages 127 | if m.StatusBitField & ics.SPY_STATUS_TX_MSG == ics.SPY_STATUS_TX_MSG: 128 | continue 129 | print("Message #{}\t".format(i + 1), end="") 130 | data = m.Data if not m.ExtraDataPtr else m.ExtraDataPtr 131 | netid = m.NetworkID | (m.NetworkID2 << 8) 132 | print("NetID: {}\tArbID: {}\tData: {}".format(hex(netid), hex(m.ArbIDOrHeader), [hex(x) for x in data])) 133 | 134 | 135 | if __name__ == "__main__": 136 | # Lets figure out how many are connected to the PC and display it 137 | connected_count = len(ics.find_devices()) 138 | print("Found {} connected device(s)...".format(connected_count)) 139 | 140 | tx_dev = open_device(0) 141 | rx_dev = open_device(1) 142 | 143 | transmit_ethernet(tx_dev) 144 | print() 145 | receive_ethernet(rx_dev) 146 | 147 | print("Finished.") 148 | -------------------------------------------------------------------------------- /examples/transmit_lin_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | import random 3 | import time 4 | 5 | # Tells our custom open_device() function to do special behavior 6 | # with neoVI Server enabled so we can successfully open devices 7 | enable_use_server = True 8 | 9 | def open_device(index=0): 10 | device = None 11 | if enable_use_server: 12 | # ics.open_device() won't open a device if we have handles open already 13 | # so we need to find them and specify which ones to connect to. 14 | devices = ics.find_devices() 15 | print( 16 | "Opening Device {} (Open Client handles: {})...".format( 17 | devices[index], devices[index].NumberOfClients 18 | ) 19 | ) 20 | ics.open_device(devices[index]) 21 | device = devices[index] 22 | else: 23 | print("Opening Device...") 24 | device = ics.open_device() 25 | print("Opened Device %s." % device) 26 | return device 27 | 28 | 29 | def calc_checksum(msg): 30 | checksum = 0 31 | for byte in msg.Header[1:] + msg.Data: 32 | checksum += byte 33 | if checksum > 255: 34 | checksum -= 255 35 | msg.Data += tuple([~checksum & 0xFF]) 36 | 37 | 38 | def transmit_lin(msg): 39 | calc_checksum(msg) 40 | msg.NumberBytesHeader = len(msg.Header) 41 | msg.NumberBytesData = len(msg.Data) 42 | try: 43 | ics.transmit_messages(device, msg) 44 | except ics.RuntimeError as ex: 45 | print(ex) 46 | raise ex 47 | 48 | 49 | def prepare_message(device): 50 | msg = ics.SpyMessageJ1850() 51 | msg.StatusBitField = ics.SPY_STATUS_INIT_MESSAGE 52 | msg.Protocol = ics.SPY_PROTOCOL_LIN 53 | msg.NetworkID = ics.NETID_LIN 54 | msg.Header = (0x11, 0x11, 0x22) 55 | msg.Data = (0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x88) 56 | transmit_lin(msg) 57 | 58 | 59 | def receive_lin(device): 60 | msgs, error_count = ics.get_messages(device) 61 | print("Received {} messages with {} errors.".format(len(msgs), error_count)) 62 | netids = {ics.NETID_LIN: "LIN 1", ics.NETID_LIN2: "LIN 2"} 63 | for i, m in enumerate(msgs): 64 | print("\nMessage #{}: ".format(i + 1), end="") 65 | netid = netids.get(m.NetworkID) 66 | if netid is not None: 67 | print("{}".format(netid), end="") 68 | if m.StatusBitField & ics.SPY_STATUS_INIT_MESSAGE: 69 | print(" | Init", end="") 70 | data_list = [] 71 | for x in m.Header[1:]: 72 | data_list.append(x) 73 | for y in m.Data: 74 | data_list.append(y) 75 | print("\nID: {} | ".format(hex(m.Header[0])), end="") 76 | if len(data_list): 77 | checksum = data_list.pop() 78 | print("Data: {} | ".format([hex(x) for x in data_list]), end="") 79 | print("Checksum: {}".format(hex(checksum))) 80 | 81 | 82 | if __name__ == "__main__": 83 | import time 84 | 85 | # Lets figure out how many are connected to the PC and display it 86 | connected_count = len(ics.find_devices()) 87 | print("Found {} connected device(s)...".format(connected_count)) 88 | device = open_device(0) 89 | prepare_message(device) 90 | time.sleep(1) 91 | receive_lin(device) 92 | print("Finished.") 93 | -------------------------------------------------------------------------------- /examples/transmit_lin_ldf_example.py: -------------------------------------------------------------------------------- 1 | import ics 2 | import random 3 | import time 4 | import os 5 | import ldfparser 6 | 7 | 8 | def parse_ldf(): 9 | path = os.path.join(os.path.dirname(__file__), "lin22.ldf") 10 | return ldfparser.parse_ldf(path) 11 | 12 | 13 | def open_device(index=0): 14 | device = None 15 | # ics.open_device() won't open a device if we have handles open already 16 | # so we need to find them and specify which ones to connect to. 17 | devices = ics.find_devices() 18 | print( 19 | "Opening Device {} (Open Client handles: {})...".format( 20 | devices[index], devices[index].NumberOfClients 21 | ) 22 | ) 23 | ics.open_device(devices[index]) 24 | device = devices[index] 25 | print("Opened Device %s." % device) 26 | return device 27 | 28 | 29 | def receive_lin(device): 30 | msgs, error_count = ics.get_messages(device) 31 | print("Received {} messages with {} errors.".format(len(msgs), error_count)) 32 | netids = {ics.NETID_LIN: "LIN 1"} # , ics.NETID_LIN2: "LIN 2" } 33 | for i, m in enumerate(msgs): 34 | netid = netids.get(m.NetworkID) 35 | if netid is not None: 36 | # print('\nMessage #{}: '.format(i+1), end='') 37 | print("{}".format(netid), end="") 38 | if m.StatusBitField & ics.SPY_STATUS_INIT_MESSAGE: 39 | print(" | Init") 40 | data_list = [] 41 | for x in m.Header[1:]: 42 | data_list.append(x) 43 | for y in m.Data: 44 | data_list.append(y) 45 | try: 46 | frame_name = ldf.get_frame(m.Header[0] & 0x3F).name 47 | if frame_name is not None: 48 | print("{} | ".format(frame_name), end="") 49 | except: 50 | pass 51 | print("ID: {} | ".format(hex(m.Header[0])), end="") 52 | if len(data_list): 53 | checksum = data_list.pop() 54 | print("Data: {} | ".format([hex(x) for x in data_list]), end="") 55 | print("Checksum: {}".format(hex(checksum))) 56 | print() 57 | return True 58 | 59 | 60 | def send_frame(self, baudrate: int, frame_id: int, data: bytearray, netid: int, is_commander: bool): 61 | # set baudrate with device settings? 62 | msg = ics.SpyMessageJ1850() 63 | if is_commander: 64 | msg.StatusBitField = ics.SPY_STATUS_INIT_MESSAGE 65 | msg.Protocol = ics.SPY_PROTOCOL_LIN 66 | msg.NetworkID = netid 67 | header_bytes = [frame_id] 68 | frame_bytes = [] 69 | if len(data): 70 | hdr_len = min(len(data), 2) 71 | data_len = min((len(data) - hdr_len), 6) 72 | checksum = 0 73 | if hdr_len > 0: 74 | header_bytes += list(data[0:hdr_len]) 75 | if data_len > 0: 76 | frame_bytes += list(data[hdr_len:]) 77 | for byte in header_bytes + frame_bytes: 78 | checksum += byte 79 | if checksum > 255: 80 | checksum -= 255 81 | if len(header_bytes) == 2: 82 | header_bytes.append(~checksum & 0xFF) 83 | else: 84 | frame_bytes.append(~checksum & 0xFF) 85 | msg.Header = tuple(header_bytes) 86 | msg.Data = tuple(frame_bytes) 87 | msg.NumberBytesHeader = len(msg.Header) 88 | msg.NumberBytesData = len(msg.Data) 89 | try: 90 | ics.transmit_messages(self.device, msg) 91 | except ics.RuntimeError as ex: 92 | print(ex) 93 | return False 94 | return True 95 | 96 | 97 | class LINCommander: 98 | def __init__(self, device): 99 | self.device = device 100 | self.frames = {} 101 | 102 | def send_commander_frame(self, baudrate: int, frame_id: int, data: bytearray): 103 | send_frame(self, baudrate, frame_id, data, ics.NETID_LIN, True) 104 | 105 | 106 | class LINResponder: 107 | def __init__(self, device): 108 | self.device = device 109 | self.frames = {} 110 | 111 | def send_responder_frame(self, baudrate: int, frame_id: int, data: bytearray): 112 | send_frame(self, baudrate, frame_id, data, ics.NETID_LIN2, False) 113 | 114 | 115 | if __name__ == "__main__": 116 | import time 117 | 118 | ldf = parse_ldf() 119 | # Lets figure out how many are connected to the PC and display it 120 | connected_count = len(ics.find_devices()) 121 | print("Found {} connected device(s)...".format(connected_count)) 122 | device = open_device(0) 123 | responder_nodes = ldf.get_slaves() 124 | commander_nodes = ldf.get_master() 125 | lin_cmdr = LINCommander(device) 126 | lin_resp = LINResponder(device) 127 | for resp in responder_nodes: 128 | for each in resp.publishes_frames: 129 | lin_resp.frames.update({each.name: each}) 130 | 131 | for cmdr in commander_nodes.publishes_frames: 132 | lin_cmdr.frames.update({cmdr.name: cmdr}) 133 | 134 | collision_schedule = ldf.get_schedule_table("Collision_resolver") 135 | for entry in collision_schedule.schedule: 136 | if entry.frame is not None: 137 | if entry.frame.name in lin_cmdr.frames: 138 | cmdr_data = entry.frame.encode({}) 139 | lin_cmdr.send_commander_frame(ldf.baudrate, entry.frame.frame_id, cmdr_data) 140 | elif entry.frame.name in lin_resp.frames: 141 | resp_data = entry.frame.encode({}) 142 | lin_resp.send_responder_frame(ldf.baudrate, entry.frame.frame_id, resp_data) 143 | time.sleep(150 / 1000) 144 | lin_cmdr.send_commander_frame(ldf.baudrate, entry.frame.frame_id, bytearray()) 145 | time.sleep(150 / 1000) 146 | 147 | # request_frame = ldf.get_unconditional_frame('CEM_Frm1') 148 | # request_data = request_frame.encode({"InternalLightsRequest": 'on'}, ldf.converters) 149 | # lin_cmdr.send_commander_frame(ldf.baudrate, request_frame.frame_id, request_data) 150 | 151 | # responseFrame = ldf.get_unconditional_frame('RSM_Frm1') 152 | # responseData = responseFrame.encode({"RightIntLightsSwitch": 'off'}, ldf.converters) 153 | # lin_resp.send_responder_frame(ldf.baudrate, responseFrame.frame_id, responseData) 154 | receive_lin(device) 155 | time.sleep(1) 156 | print("Finished.") 157 | -------------------------------------------------------------------------------- /extract_icsneo40_defines.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | import os.path 4 | import re 5 | from subprocess import run, PIPE 6 | import pathlib 7 | import shutil 8 | 9 | # Shamelessly stolen from generate_icsneo40_structs.py 10 | # At some point this entire file should probably be collasped into the other 11 | 12 | 13 | def format_file(filename, preprocessor=False): 14 | import os 15 | 16 | processed_fname = os.path.basename(filename) 17 | name, ext = os.path.splitext(processed_fname) 18 | processed_fname = f"{name}_processed{ext}" 19 | # processed_fname = "icsnVC40_processed.h" 20 | # Run it through the preprocessor 21 | # clang -E -P .\include\ics\icsnVC40.h -o output.h 22 | if preprocessor: 23 | result = run(["clang", "-E", "-P", filename, "-o", processed_fname], stdout=PIPE, stderr=PIPE) 24 | result.check_returncode() 25 | else: 26 | original_path = pathlib.Path(filename) 27 | new_path = pathlib.Path(processed_fname) 28 | shutil.copy(str(original_path), str(new_path)) 29 | 30 | # Format the file 31 | result = run( 32 | ["clang-format", "-i", "--style", "{BasedOnStyle: Mozilla, ColumnLimit: '200'}", processed_fname], 33 | stdout=PIPE, 34 | stderr=PIPE, 35 | ) 36 | result.check_returncode() 37 | 38 | return processed_fname 39 | 40 | 41 | def extract(): 42 | use_internal = False 43 | if os.path.isfile("include/ics/icsnVC40Internal.h"): 44 | use_internal = True 45 | print("Using Internal Header!") 46 | 47 | boiler_plate = """ 48 | // 49 | // WARNING: This file was auto generated and should not be modified directly! 50 | // Any changes here will be overwritten! 51 | // 52 | """ 53 | 54 | # write the header file first 55 | with open("include/setup_module_auto_defines.h", "w") as f: 56 | print("#ifndef __SETUP_MODULE_AUTO_DEFINES_H__", file=f) 57 | print("#define __SETUP_MODULE_AUTO_DEFINES_H__", file=f) 58 | if use_internal: 59 | print("\n#ifndef _USE_INTERNAL_HEADER_\n#define _USE_INTERNAL_HEADER_\n#endif\n", file=f) 60 | print("#include ", file=f) 61 | print("\nint setup_module_auto_defines(PyObject * module);\n", file=f) 62 | print("#endif // __SETUP_MODULE_AUTO_DEFINES_H__", file=f) 63 | 64 | ignores = ( 65 | "(", 66 | "#endif", 67 | "#define", 68 | "icscm_", 69 | "GCC_MODIFIER", 70 | "VS_MODIFIER", 71 | "{", 72 | "ICSNVC40_H", 73 | "ICSNVC40INTERNAL__H_", 74 | "SYellowSettings_SIZE", 75 | "IS_64BIT_SYSTEM", 76 | ) 77 | use_enums = True 78 | with open("src/setup_module_auto_defines.cpp", "w") as f: 79 | print(boiler_plate, file=f) 80 | # Include the header files needed for the defines 81 | 82 | print('#include "setup_module_auto_defines.h"\n#include \n#pragma warning(push, 0)\n#include "ics/icsnVC40.h"\n#pragma warning(pop)', file=f) 83 | if use_internal: 84 | print('#pragma warning(push, 0)\n#include "ics/icsnVC40Internal.h"\n#pragma warning(pop)', file=f) 85 | 86 | print("\nint setup_module_auto_defines(PyObject * module)\n{", file=f) 87 | print("\tint result = 0;\n", file=f) 88 | fnames = [] 89 | fnames.append(format_file("include/ics/icsnVC40.h")) 90 | if use_internal: 91 | fnames.append(format_file("include/ics/icsnVC40Internal.h")) 92 | # Let's get to work here! 93 | for header_file in fnames: 94 | # if not os.path.isfile(header_file) and 'Internal' in header_file: 95 | # # Ignore this file 96 | # continue 97 | with open(header_file, "r") as fname: 98 | if "icsnVC40Internal" in header_file: 99 | print( 100 | "\n#ifdef _USE_INTERNAL_HEADER_ /* ALL THESE DEFINES ARE SPECIFIED IN THE INTERNAL HEADER */\n", 101 | file=f, 102 | ) 103 | inside_enum = False 104 | inside_comment = False 105 | line_number = 0 106 | for line in fname: 107 | line_number += 1 108 | if line.lstrip().startswith("//"): 109 | continue 110 | if inside_enum and "}" in line: 111 | inside_enum = False 112 | if use_enums: 113 | print("\t// end of enum - ", line, file=f) 114 | continue 115 | elif inside_comment and "*/" in line: 116 | inside_comment = False 117 | continue 118 | elif inside_enum and not "{" in line: 119 | sline = line.split() 120 | if not sline: 121 | continue 122 | if any(x in sline[0] for x in ignores): 123 | continue 124 | if use_enums: 125 | if "," in sline[0]: 126 | # This removes anything after the comma as we don't need it 127 | sline[0] = sline[0].split(",")[0] 128 | # This removes anything after the equal sign as we don't need it 129 | sline[0] = sline[0].split("=")[0] 130 | print("\tresult += PyModule_AddIntMacro(module, %s);" % sline[0].replace(",", ""), file=f) 131 | continue 132 | if "#define" in line: 133 | sline = line.split("//")[0].split() 134 | # DEBUG: print('\t\t' + str(line_number) + '\t' + str(sline)) 135 | if any(x in sline[1] for x in ignores): 136 | continue 137 | if len(sline) >= 3 and re.match(r"^\d+?\.\d+?$", sline[2]) is not None: 138 | # Value is a float 139 | print( 140 | '\tresult += PyModule_AddObject(module, "{0}", PyFloat_FromDouble({0}));'.format( 141 | sline[1] 142 | ), 143 | file=f, 144 | ) 145 | elif len(sline) == 2: 146 | # There is no value, this is used for preprocessor only 147 | # and really shouldn't care about it in python. Going to set it as 0 "just in case" 148 | print( 149 | '\tresult += PyModule_AddObject(module, "{}", PyLong_FromLong(0));'.format(sline[1]), 150 | file=f, 151 | ) 152 | else: 153 | print("\tresult += PyModule_AddIntMacro(module, %s);" % sline[1], file=f) 154 | 155 | elif "/*" in line: 156 | inside_comment = True 157 | continue 158 | elif "enum" in line.split("//")[0]: 159 | inside_enum = True 160 | if use_enums: 161 | print("\t// enum", file=f) 162 | if "{" in line and "};" in line: 163 | # Special Case here 164 | sline = "".join(line[line.find("{") + 1 : line.find("}")].split()).split(",") 165 | # Remove =X assignments if present. 166 | sline = [x.split("=")[0] for x in sline] 167 | for e in sline: 168 | print("\tresult += PyModule_AddIntMacro(module, %s);" % e, file=f) 169 | inside_enum = False 170 | continue 171 | if "icsnVC40Internal" in header_file: 172 | print("\n#endif // _USE_INTERNAL_HEADER_\n", file=f) 173 | 174 | print("\n\treturn result == 0 ? 1 : 0;\n}", file=f) 175 | 176 | 177 | if __name__ == "__main__": 178 | extract() 179 | -------------------------------------------------------------------------------- /ics_utility.py: -------------------------------------------------------------------------------- 1 | import os 2 | import dunamai 3 | import pathlib 4 | 5 | GEN_DIR = pathlib.Path("./gen") 6 | GEN_ICS_DIR = GEN_DIR / "ics" 7 | 8 | def get_pkg_version() -> str: 9 | """ 10 | Get the package version. 11 | 12 | Returns: 13 | str: The package version. 14 | """ 15 | # version = dunamai.Version.from_git() 16 | # # Set the dev version if the environment variable is set. 17 | # if os.getenv("PYTHON_ICS_DEV_BUILD") is not None: 18 | # pkg_version = version.serialize(format="v{base}.dev{distance}", style=dunamai.Style.Pep440) 19 | # else: 20 | # pkg_version = version.serialize(format="{base}", style=dunamai.Style.Pep440) 21 | return dunamai.Version.from_git().serialize(metadata=False) 22 | # return pkg_version 23 | 24 | def create_version_py(path: pathlib.Path = pathlib.Path("gen/ics/__version.py")) -> None: 25 | """ 26 | Create a version.py file with the package version and full version. 27 | 28 | Args: 29 | path (pathlib.Path, optional): The path to the version.py file. Defaults to pathlib.Path("gen/ics/__version.py"). 30 | 31 | Returns: 32 | None 33 | """ 34 | pkg_version = get_pkg_version() 35 | full_version = dunamai.Version.from_git().serialize(format="v{base}-{commit}-{timestamp}") 36 | print(f"Creating '{path}' with version {pkg_version} and full version {full_version}...") 37 | path.parent.mkdir(parents=True, exist_ok=True) 38 | # Write the version file to disk 39 | with open(path, "w+") as f: 40 | f.write(f"""__version__ = "{pkg_version}"\n""") 41 | f.write(f"""__full_version__ = "{full_version}"\n""") 42 | 43 | def create_ics_init(): 44 | fdata = \ 45 | """# Warning: This file is auto generated. Don't modify if you value your sanity! 46 | try: 47 | import ics.__version 48 | __version__ = ics.__version.__version__ 49 | __full_version__ = ics.__version.__full_version__ 50 | except Exception as ex: 51 | print(ex) 52 | 53 | 54 | from ics.structures import * 55 | from ics.structures.neo_device import NeoDevice, neo_device 56 | from ics.hiddenimports import hidden_imports 57 | try: 58 | from ics.py_neo_device_ex import PyNeoDeviceEx 59 | except ModuleNotFoundError as ex: 60 | print(f"Warning: {ex}") 61 | 62 | try: 63 | # Release environment 64 | #print("Release") 65 | from ics.ics import * 66 | except Exception as ex: 67 | # Build environment 68 | #print("Debug", ex) 69 | from ics import * 70 | """ 71 | init_path = GEN_ICS_DIR / "__init__.py" 72 | print(f"Creating '{init_path}'...") 73 | init_path.parent.mkdir(parents=True, exist_ok=True) 74 | with open(init_path, "w+") as f: 75 | f.write(fdata) 76 | 77 | 78 | if __name__ == "__main__": 79 | create_ics_init() 80 | create_version_py() 81 | print("Version info generated!") -------------------------------------------------------------------------------- /include/defines.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEFINES_H_ 2 | #define _DEFINES_H_ 3 | #include 4 | 5 | #define MODULE_NAME "ics.ics" 6 | #define MODULE_DESCRIPTION "Copyright Intrepid Control Systems, Inc." 7 | 8 | #define MIN_BASE36_SERIAL (16796160) 9 | #define MAX_SERIAL (2176782335) 10 | 11 | // https://bugs.python.org/issue28769 12 | // 2.x = char* PyString_AsString(return_value); 13 | // 3.0-3.6 = char* PyUnicode_AsUTF8(value); 14 | // 3.7 = const char* PyUnicode_AsUTF8(value); 15 | #if (PY_MAJOR_VERSION >= 3) && (PY_MINOR_VERSION >= 7) 16 | #define PyUniStr_AsStrOrUTF8(obj) (char*)PyUnicode_AsUTF8(obj) 17 | #elif (PY_MAJOR_VERSION >= 3) 18 | #define PyUniStr_AsStrOrUTF8(obj) PyUnicode_AsUTF8(obj) 19 | #elif (PY_MAJOR_VERSION == 2) 20 | #define PyUniStr_AsStrOrUTF8(obj) PyString_AsString(obj) 21 | #else 22 | #error Failed to suppport PyUnicode_AsUTF8 23 | #endif 24 | 25 | #ifdef _cplusplus 26 | extern "C" 27 | { 28 | #endif 29 | 30 | int setup_module_defines(PyObject* module); 31 | 32 | #ifdef _cplusplus 33 | } 34 | #endif // extern "C" { 35 | 36 | #endif -------------------------------------------------------------------------------- /include/dll.h: -------------------------------------------------------------------------------- 1 | #ifndef _DLL_H_ 2 | #define _DLL_H_ 3 | 4 | #ifdef _MSC_VER 5 | #pragma warning(disable : 4290) 6 | #endif 7 | 8 | #include 9 | 10 | #ifdef _MSC_VER 11 | #pragma warning(default : 4290) 12 | #endif 13 | 14 | #ifdef _cplusplus 15 | extern "C" 16 | { 17 | #endif 18 | 19 | bool dll_initialize(char* name = NULL); 20 | bool dll_is_initialized(void); 21 | void dll_uninitialize(void); 22 | bool dll_reinitialize(char* name = NULL); 23 | char* dll_get_error(char* error_msg); 24 | ice::Library* dll_get_library(void); 25 | 26 | #ifdef _cplusplus 27 | } 28 | #endif 29 | 30 | #endif // _DLL_H_ 31 | -------------------------------------------------------------------------------- /include/exceptions.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXCEPTIONS_H_ 2 | #define _EXCEPTIONS_H_ 3 | #include 4 | 5 | #ifdef _cplusplus 6 | extern "C" 7 | { 8 | #endif 9 | 10 | int initialize_exceptions(PyObject* module); 11 | PyObject* _set_ics_exception(PyObject* exception, const char* msg, const char* func_name); 12 | #define set_ics_exception(exception, msg) _set_ics_exception(exception, msg, __FUNCTION__); 13 | 14 | PyObject* exception_argument_error(void); 15 | PyObject* exception_runtime_error(void); 16 | 17 | #ifdef _cplusplus 18 | } 19 | #endif // extern "C" { 20 | 21 | #endif // _EXCEPTIONS_H_ 22 | -------------------------------------------------------------------------------- /include/ics/icsnVC40.h.patch: -------------------------------------------------------------------------------- 1 | diff --git a/include/ics/icsnVC40.h b/include/ics/icsnVC40.h 2 | index 5a5bc27..279ae0d 100644 3 | --- a/include/ics/icsnVC40.h 4 | +++ b/include/ics/icsnVC40.h 5 | @@ -4046,6 +4046,9 @@ typedef struct _ethernetNetworkStatus_t 6 | } ethernetNetworkStatus_t; 7 | #pragma pack(pop) 8 | 9 | +#pragma pack(push) 10 | +#pragma pack(4) 11 | + 12 | typedef struct 13 | { 14 | uint8_t backupPowerGood; 15 | @@ -4119,7 +4122,7 @@ typedef union { 16 | icsRadPlutoDeviceStatus plutoStatus; 17 | icsVcan4IndustrialDeviceStatus vcan4indStatus; 18 | } icsDeviceStatus; 19 | - 20 | +#pragma pack(pop) 21 | 22 | typedef struct 23 | { 24 | -------------------------------------------------------------------------------- /include/ics/test_structs.h: -------------------------------------------------------------------------------- 1 | typedef enum _Test { 2 | TestNone = 0, 3 | TestA, 4 | TestB, 5 | TestC, 6 | TestD, 7 | TestE 8 | } Test; 9 | 10 | #pragma pack(push, 1) 11 | 12 | struct _InnerStructure 13 | { 14 | char a; 15 | long b; 16 | Test t; 17 | } InnerStructure; 18 | 19 | #pragma pack(pop) 20 | 21 | typedef struct _TestStructure 22 | { 23 | InnerStructure inner; 24 | 25 | struct _A { 26 | unsigned int a; 27 | unsigned int b; 28 | unsigned int c; 29 | } A; 30 | 31 | union { 32 | struct 33 | { 34 | unsigned d : 1; 35 | unsigned e : 1; 36 | unsigned f : 1; 37 | } B; 38 | unsigned _def; 39 | }; 40 | 41 | union { 42 | uint64_t ghi; 43 | struct 44 | { 45 | uint16_t g; 46 | uint16_t h; 47 | uint16_t i; 48 | }; 49 | } C; 50 | 51 | union D { 52 | uint64_t jkm; 53 | struct 54 | { 55 | uint16_t j; 56 | uint16_t k; 57 | uint16_t m; 58 | }; 59 | }; 60 | 61 | struct 62 | { 63 | uint32_t n : 1; 64 | uint32_t p : 2; 65 | uint32_t q : 3; 66 | } E; 67 | 68 | struct F 69 | { 70 | uint32_t r : 4; 71 | uint32_t s : 8; 72 | uint32_t t : 16; 73 | }; 74 | 75 | } TestStructure; 76 | -------------------------------------------------------------------------------- /include/object_spy_message.h: -------------------------------------------------------------------------------- 1 | #ifndef _OBJECT_SPY_MESSAGE_H_ 2 | #define _OBJECT_SPY_MESSAGE_H_ 3 | // http://docs.python.org/3/extending/newtypes.html 4 | 5 | #include 6 | #include 7 | #if (defined(_WIN32) || defined(__WIN32__)) 8 | #ifndef USING_STUDIO_8 9 | #define USING_STUDIO_8 1 10 | #endif 11 | #include 12 | #else 13 | #include 14 | #endif 15 | 16 | #include 17 | 18 | #include "defines.h" 19 | 20 | #define SPY_MESSAGE_OBJECT_NAME "SpyMessage" 21 | #define SPY_MESSAGE_J1850_OBJECT_NAME "SpyMessageJ1850" 22 | 23 | #if PY_MAJOR_VERSION < 3 24 | #define PyUnicode_CompareWithASCIIString(uni, string) strcmp(PyString_AsString(uni), string) 25 | /* 26 | int PyUnicode_CompareWithASCIIString(PyObject *uni, const char *string) 27 | { 28 | int result = strcmp(PyString_AsString(uni), string); 29 | if (result == 0) { 30 | return 0; 31 | } 32 | return result > 0 ? 1 : -1; 33 | } 34 | */ 35 | #endif 36 | 37 | #pragma pack(push, 1) 38 | typedef struct 39 | { 40 | PyObject_HEAD icsSpyMessage msg; 41 | bool noExtraDataPtrCleanup; 42 | } spy_message_object; 43 | #pragma pack(pop) 44 | 45 | #pragma pack(push, 1) 46 | typedef struct 47 | { 48 | PyObject_HEAD icsSpyMessageJ1850 msg; 49 | bool noExtraDataPtrCleanup; 50 | } spy_message_j1850_object; 51 | #pragma pack(pop) 52 | 53 | 54 | extern PyTypeObject spy_message_object_type; 55 | extern PyTypeObject spy_message_j1850_object_type; 56 | 57 | // Copied from tupleobject.h 58 | #define PySpyMessage_Check(op) PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_BASETYPE) 59 | #define PySpyMessage_CheckExact(op) (Py_TYPE(op) == &spy_message_object_type) 60 | #define PySpyMessageJ1850_CheckExact(op) (Py_TYPE(op) == &spy_message_j1850_object_type) 61 | 62 | #define PySpyMessage_GetObject(obj) ((spy_message_object*)obj) 63 | #define PySpyMessageJ1850_GetObject(obj) ((spy_message_j1850_object*)obj) 64 | 65 | bool setup_spy_message_object(PyObject* module); 66 | 67 | #endif // _OBJECT_SPY_MESSAGE_H_ 68 | -------------------------------------------------------------------------------- /include/setup_module_auto_defines.h: -------------------------------------------------------------------------------- 1 | #ifndef __SETUP_MODULE_AUTO_DEFINES_H__ 2 | #define __SETUP_MODULE_AUTO_DEFINES_H__ 3 | #include 4 | 5 | int setup_module_auto_defines(PyObject * module); 6 | 7 | #endif // __SETUP_MODULE_AUTO_DEFINES_H__ 8 | -------------------------------------------------------------------------------- /msvc/python_ics.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python_ics", "python_ics.vcxproj", "{39C87EAC-CA09-4438-9659-6FEFB1361253}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug34|Win32 = Debug34|Win32 10 | Release|Win32 = Release|Win32 11 | Release34|Win32 = Release34|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {39C87EAC-CA09-4438-9659-6FEFB1361253}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {39C87EAC-CA09-4438-9659-6FEFB1361253}.Debug|Win32.Build.0 = Debug|Win32 16 | {39C87EAC-CA09-4438-9659-6FEFB1361253}.Debug34|Win32.ActiveCfg = Debug34|Win32 17 | {39C87EAC-CA09-4438-9659-6FEFB1361253}.Debug34|Win32.Build.0 = Debug34|Win32 18 | {39C87EAC-CA09-4438-9659-6FEFB1361253}.Release|Win32.ActiveCfg = Release|Win32 19 | {39C87EAC-CA09-4438-9659-6FEFB1361253}.Release|Win32.Build.0 = Release|Win32 20 | {39C87EAC-CA09-4438-9659-6FEFB1361253}.Release34|Win32.ActiveCfg = Release34|Win32 21 | {39C87EAC-CA09-4438-9659-6FEFB1361253}.Release34|Win32.Build.0 = Release34|Win32 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /msvc/python_ics.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug34 6 | Win32 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Release34 14 | Win32 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | 22 | {39C87EAC-CA09-4438-9659-6FEFB1361253} 23 | python_ics 24 | 8.1 25 | 26 | 27 | 28 | DynamicLibrary 29 | true 30 | MultiByte 31 | v141 32 | 33 | 34 | DynamicLibrary 35 | false 36 | true 37 | MultiByte 38 | v141 39 | 40 | 41 | DynamicLibrary 42 | false 43 | true 44 | MultiByte 45 | v141 46 | 47 | 48 | DynamicLibrary 49 | false 50 | true 51 | MultiByte 52 | v141 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | $(VC_IncludePath);$(WindowsSDK_IncludePath);;C:\Python\Python37-32\include 72 | 73 | 74 | $(VC_IncludePath);$(WindowsSDK_IncludePath);;C:\Python\Python37-32\include 75 | 76 | 77 | $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);C:\Python\Python37-32\libs 78 | ics 79 | .pyd 80 | 81 | 82 | $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);C:\Python\Python37-32\libs 83 | ics 84 | .pyd 85 | 86 | 87 | $(VC_IncludePath);$(WindowsSDK_IncludePath);;C:\Python\Python37-32\include 88 | $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);C:\Python\Python37-32\libs 89 | 90 | 91 | $(VC_IncludePath);$(WindowsSDK_IncludePath);;C:\Python\Python37-32\include 92 | $(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);C:\Python\Python37-32\libs 93 | 94 | 95 | 96 | Level3 97 | Disabled 98 | true 99 | ..\include;..\include\ics;..\include\ice;C:\Python37-32\include 100 | 101 | 102 | 103 | 104 | true 105 | 106 | 107 | 108 | 109 | 110 | 111 | Level3 112 | MaxSpeed 113 | true 114 | true 115 | true 116 | ..\include;..\include\ics;..\include\ice;C:\Python37-32\include 117 | 118 | 119 | 120 | 121 | true 122 | true 123 | true 124 | 125 | 126 | 127 | 128 | 129 | 130 | Level3 131 | MaxSpeed 132 | true 133 | true 134 | ..\include;..\include\ics;..\include\ice;C:\Python37-32\include 135 | 136 | 137 | true 138 | 139 | 140 | true 141 | true 142 | true 143 | C:\Python37-32\Lib\site-packages\python_ics-5.0-py3.7-win32.egg\ics\ics.cp37-win32.pyd 144 | 145 | 146 | 147 | 148 | 149 | 150 | Level3 151 | Disabled 152 | true 153 | true 154 | ..\include;..\include\ics;..\include\ice 155 | false 156 | MultiThreadedDLL 157 | WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 158 | true 159 | 160 | 161 | 162 | 163 | true 164 | true 165 | true 166 | C:\Python\Python37-32\Lib\site-packages\python_ics-906.999-py3.7-win32.egg\ics\ics.cp37-win32.pyd 167 | NotSet 168 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 169 | /export:PyInit_ics %(AdditionalOptions) 170 | 8388608 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | true 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "python_ics" 3 | dynamic = ["version"] 4 | authors = [{ name = "David Rebbe", email = "drebbe@intrepidcs.com" }] 5 | maintainers = [{ name = "David Rebbe", email = "drebbe@intrepidcs.com" }] 6 | description = "Python wrapper for interfacing to IntrepidCS Hardware." 7 | keywords = ["intrepidcs", "CAN", "Ethernet", "Automotive", "ICS"] 8 | readme = { file = "README.md", content-type = "text/markdown" } 9 | requires-python = ">=3.9" 10 | license = "MIT" 11 | classifiers = [ 12 | "Development Status :: 5 - Production/Stable", 13 | "Intended Audience :: Developers", 14 | "Operating System :: OS Independent", 15 | "Topic :: Software Development :: Libraries :: Python Modules", 16 | "Programming Language :: Python", 17 | "Programming Language :: Python :: 3", 18 | "Programming Language :: Python :: 3.9", 19 | "Programming Language :: Python :: 3.10", 20 | "Programming Language :: Python :: 3.11", 21 | "Programming Language :: Python :: 3.12", 22 | "Programming Language :: Python :: 3.13", 23 | ] 24 | 25 | [project.urls] 26 | Homepage = "https://intrepidcs.com" 27 | Documentation = "http://python-ics.readthedocs.io/" 28 | Repository = "https://github.com/intrepidcs/python_ics/" 29 | Issues = "https://github.com/intrepidcs/python_ics/issues" 30 | 31 | [tool.setuptools.dynamic] 32 | version = { attr = "ics.__version__" } 33 | 34 | [build-system] 35 | requires = [ 36 | "setuptools", 37 | "wheel", 38 | "dunamai", 39 | ] 40 | 41 | 42 | [tool.cibuildwheel] 43 | build = "{*-win32,*-win_amd64,*-macosx_universal2,*-manylinux_x86_64,*-manylinux_aarch64}" 44 | skip = "cp36-* cp37-* pp* *-manylinux_i686 *-musllinux_*" 45 | environment = { CIBW_BUILD_VERBOSITY = 1, DISTUTILS_DEBUG = 1, MACOSX_DEPLOYMENT_TARGET = "10.13", CIBW_ARCHS_LINUX = "auto aarch64" } 46 | before-build = "python -m pip install wheel" 47 | manylinux-x86_64-image = "quay.io/pypa/manylinux_2_28_x86_64" 48 | manylinux-aarch64-image = "quay.io/pypa/manylinux_2_28_aarch64" 49 | free-threaded-support = true 50 | 51 | [tool.cibuildwheel.linux] 52 | before-build = "dnf install -y cmake clang clang-tools-extra flex bison" 53 | archs = "auto aarch64" 54 | 55 | [tool.cibuildwheel.macos] 56 | archs = ["universal2"] 57 | before-build = "brew install cmake clang-format" 58 | 59 | [tool.cibuildwheel.windows] 60 | before-build = "choco install llvm" 61 | 62 | [tool.black] 63 | line-length = 120 64 | # https://stackoverflow.com/questions/73247204/black-not-respecting-extend-exclude-in-pyproject-toml 65 | force-exclude = ''' 66 | /( 67 | | .vscode 68 | | .venv 69 | | build 70 | | ics 71 | | include 72 | | msvc 73 | | src 74 | )/ 75 | ''' 76 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | setuptools >= 69 2 | dunamai >= 1.19.2 3 | wheel >= 0.42.0 -------------------------------------------------------------------------------- /run_tests.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | REM run_tests.bat 2> test_log.txt 3 | mode con cols=140 lines=70 4 | 5 | ECHO ================================================================== 1>&2 6 | ECHO PYTHON27 1>&2 7 | ECHO ================================================================== 1>&2 8 | C:\Python27\python setup.py test 9 | ECHO ================================================================== 1>&2 10 | ECHO PYTHON33 1>&2 11 | ECHO ================================================================== 1>&2 12 | C:\Python33\python setup.py test 13 | ECHO ================================================================== 1>&2 14 | ECHO PYTHON34 1>&2 15 | ECHO ================================================================== 1>&2 16 | C:\Python34\python setup.py test 17 | ECHO ================================================================== 1>&2 18 | ECHO PYTHON35 1>&2 19 | ECHO ================================================================== 1>&2 20 | C:\Python35\python setup.py test 21 | ECHO ================================================================== 1>&2 22 | ECHO PYTHON36 1>&2 23 | ECHO ================================================================== 1>&2 24 | C:\Python36-32\python setup.py test 25 | 26 | ECHO ================================================================== 1>&2 27 | ECHO PYTHON27-64 1>&2 28 | ECHO ================================================================== 1>&2 29 | C:\Python27-64\python setup.py test 30 | ECHO ================================================================== 1>&2 31 | ECHO PYTHON34-64 1>&2 32 | ECHO ================================================================== 1>&2 33 | C:\Python34-64\python setup.py test 34 | ECHO ================================================================== 1>&2 35 | ECHO PYTHON35-64 1>&2 36 | ECHO ================================================================== 1>&2 37 | C:\Python35-64\python setup.py test 38 | 39 | pause -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from setuptools import setup, Extension 3 | from setuptools.command.build_clib import build_clib 4 | from setuptools.command.build_py import build_py 5 | import os 6 | import sys 7 | import platform 8 | import shutil 9 | import os.path 10 | import extract_icsneo40_defines 11 | import generate_icsneo40_structs 12 | from ics_utility import get_pkg_version, create_version_py, create_ics_init 13 | import pathlib 14 | from typing import List 15 | 16 | # I had this in build_py but there are certain times its not called, for now lets force 17 | # it to run every single time we call setup. Its quick enough where it shouldn't hurt. 18 | create_ics_init() 19 | create_version_py() 20 | generate_icsneo40_structs.generate_all_files() 21 | 22 | # Check for clang stuff here, read the docs doesn't have this so use what is in the repo 23 | if not os.getenv("READTHEDOCS"): 24 | if not shutil.which("clang"): 25 | raise RuntimeError("clang is required for building python_ics.") 26 | if not shutil.which("clang-format"): 27 | raise RuntimeError("clang-format is required for building python_ics.") 28 | 29 | def get_version(): 30 | major = int(get_pkg_version().split(".")[0]) 31 | minor = int(get_pkg_version().split(".")[1]) 32 | return major, minor 33 | 34 | class _build_libicsneo(build_clib): 35 | def run(self): 36 | # checkout and build libicsneo 37 | if platform.system().upper() in ("DARWIN", "LINUX"): 38 | import build_libicsneo 39 | 40 | print("Checking out libicsneo...") 41 | build_libicsneo.checkout() 42 | print("Building libicsneo...") 43 | build_libicsneo.build() 44 | print("Copying libicsneo...") 45 | build_libicsneo.copy() 46 | super().run() 47 | 48 | 49 | class _build_ics_py(build_py): 50 | def run(self): 51 | print("Generating python defines from icsnVC40.h...") 52 | extract_icsneo40_defines.extract() 53 | 54 | print("Copy python source files over to gen...") 55 | src_path = pathlib.Path("./src/") 56 | gen_path = pathlib.Path("./gen/") 57 | for dirpath, dirnames, filenames in os.walk(src_path): 58 | dirpath = pathlib.Path(dirpath) 59 | for name in filenames: 60 | if pathlib.Path(name).suffix == ".py" and 'icsdebug' not in name: 61 | src = (dirpath / name) 62 | dest = (gen_path / dirpath.relative_to(src_path) / name) 63 | print(f"Copying {src} to {dest}{' '*20}", end="") 64 | shutil.copy(src, dest) 65 | print("") 66 | self.run_command("build_libicsneo") 67 | super().run() 68 | 69 | 70 | def get_ics_extension_compiler_arguments() -> List[str]: 71 | """Return a list of compiler arguments to append for compiling the ics extension module""" 72 | # gcc and clang arguments 73 | GCC_COMPILE_ARGS = [ 74 | "-Wno-unknown-pragmas", 75 | ] 76 | # Set compiler flags here 77 | if "WINDOWS" in platform.system().upper(): 78 | compile_args = [ 79 | "/W4", 80 | "/Wall", # Displays all warnings displayed by /W4 and all other warnings that /W4 doesn't include 81 | #"/WX", # Treats all compiler warnings as errors. 82 | "/external:anglebrackets", 83 | "/external:W0", 84 | "/wd4710", 85 | "/wd4711", 86 | "/wd5045", 87 | "/std:c++17", 88 | ] 89 | # mingw and clang python builds won't have MSC in the version string 90 | if "MSC" not in sys.version: 91 | compile_args = GCC_COMPILE_ARGS 92 | elif "LINUX" in platform.system().upper(): 93 | compile_args = GCC_COMPILE_ARGS 94 | elif "DARWIN" in platform.system().upper(): 95 | # Mac doesn't respect the compiler args, but will append with ARCHFLAGS environment variable 96 | os.environ["ARCHFLAGS"] += " -std=c++17" 97 | compile_args = [] 98 | else: 99 | compile_args = [] 100 | return compile_args 101 | 102 | ics_extension = Extension( 103 | "ics.ics", 104 | define_macros=[("MAJOR_VERSION", get_version()[0]), ("MINOR_VERSION", get_version()[1]), ("EXTERNAL_PROJECT", 1)], 105 | include_dirs=["include", "include/ics", "src/ice/include", "src/ice/include/ice"], 106 | libraries=[], 107 | library_dirs=["/usr/local/lib"], 108 | sources=[ 109 | "src/object_spy_message.cpp", 110 | "src/defines.cpp", 111 | "src/exceptions.cpp", 112 | "src/dll.cpp", 113 | "src/setup_module_auto_defines.cpp", 114 | "src/main.cpp", 115 | "src/methods.cpp", 116 | "src/ice/src/ice_library_manager.cpp", 117 | "src/ice/src/ice_library_name.cpp", 118 | "src/ice/src/ice_library.cpp", 119 | ], 120 | extra_compile_args=get_ics_extension_compiler_arguments(), 121 | ) 122 | 123 | package_data = {} 124 | if "DARWIN" in platform.system().upper(): 125 | package_data["ics"] = ["*.dylib"] 126 | elif "LINUX" in platform.system().upper(): 127 | package_data[""] = ["*.so"] 128 | 129 | setup( 130 | name="python_ics", 131 | version=get_pkg_version(), 132 | cmdclass={ 133 | "build_libicsneo": _build_libicsneo, 134 | "build_py": _build_ics_py, 135 | }, 136 | download_url="https://github.com/intrepidcs/python_ics/releases", 137 | packages=["ics", "ics.structures"], 138 | package_dir={"ics": "gen/ics", "ics.structures": "gen/ics/structures"}, 139 | package_data=package_data, 140 | include_package_data=True, 141 | ext_modules=[ics_extension], 142 | ) 143 | -------------------------------------------------------------------------------- /src/defines.cpp: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | 3 | int setup_module_defines(PyObject* module) 4 | { 5 | int result = 0; 6 | if (!module) 7 | return --result; 8 | 9 | result += PyModule_AddStringConstant(module, "BUILD_DATETIME", __DATE__ " " __TIME__); 10 | result += PyModule_AddObject(module, "MIN_BASE36_SERIAL", PyLong_FromUnsignedLong(MIN_BASE36_SERIAL)); 11 | result += PyModule_AddObject(module, "MAX_SERIAL", PyLong_FromUnsignedLong(MAX_SERIAL)); 12 | 13 | if (result == 0) { 14 | return 1; 15 | } 16 | return result; 17 | } 18 | -------------------------------------------------------------------------------- /src/dll.cpp: -------------------------------------------------------------------------------- 1 | #include "dll.h" 2 | #include 3 | #include 4 | 5 | #pragma warning(push) 6 | #pragma warning(disable : 4996) // warning C4996: 'strcpy': This function or variable may be unsafe. 7 | 8 | 9 | 10 | bool dll_reinitialize(char* name) 11 | { 12 | auto& mgr = ice::LibraryManager::instance(); 13 | mgr.add("ics", name, false, true); 14 | 15 | return mgr.exists("ics"); 16 | } 17 | 18 | char* dll_get_error(char* error_msg) 19 | { 20 | auto& mgr = ice::LibraryManager::instance(); 21 | if (!mgr.exists("ics")) { 22 | strcpy(error_msg, "Critical Error: Library isn't loaded!"); 23 | return error_msg; 24 | } 25 | strcpy(error_msg, mgr["ics"]->getLastError().c_str()); 26 | return error_msg; 27 | } 28 | 29 | ice::Library* dll_get_library(void) 30 | { 31 | auto& mgr = ice::LibraryManager::instance(); 32 | if (!mgr.exists("ics")) { 33 | return nullptr; 34 | } 35 | return mgr["ics"]; 36 | } 37 | 38 | #pragma warning(pop) -------------------------------------------------------------------------------- /src/exceptions.cpp: -------------------------------------------------------------------------------- 1 | #include "exceptions.h" 2 | #include "defines.h" 3 | #include 4 | 5 | static PyObject* IcsArgumentError = NULL; 6 | static PyObject* IcsRuntimeError = NULL; 7 | 8 | int initialize_exceptions(PyObject* module) 9 | { 10 | if (!module && IcsArgumentError && IcsRuntimeError) { 11 | return 0; 12 | } 13 | // ArgumentError 14 | IcsArgumentError = PyErr_NewException(MODULE_NAME ".ArgumentError", NULL, NULL); 15 | if (!IcsArgumentError) { 16 | return 0; 17 | } 18 | Py_INCREF(IcsArgumentError); 19 | PyModule_AddObject(module, "ArgumentError", IcsArgumentError); 20 | // RuntimeError 21 | IcsRuntimeError = PyErr_NewException(MODULE_NAME ".RuntimeError", NULL, NULL); 22 | if (!IcsRuntimeError) { 23 | return 0; 24 | } 25 | Py_INCREF(IcsRuntimeError); 26 | PyModule_AddObject(module, "RuntimeError", IcsRuntimeError); 27 | return 1; 28 | } 29 | 30 | PyObject* _set_ics_exception(PyObject* exception, const char* msg, const char* func_name) 31 | { 32 | std::stringstream ss; 33 | std::string function = std::string(func_name); 34 | auto loc = function.find("meth_"); 35 | if (loc != std::string::npos) { 36 | function.erase(loc, 5); 37 | } 38 | ss << "Error: " << function << "(): " << msg; 39 | if (!exception) { 40 | PyErr_SetString(PyExc_Exception, ss.str().c_str()); 41 | } else { 42 | PyErr_SetString(exception, ss.str().c_str()); 43 | } 44 | return NULL; 45 | } 46 | 47 | PyObject* exception_argument_error(void) 48 | { 49 | return IcsArgumentError; 50 | } 51 | 52 | PyObject* exception_runtime_error(void) 53 | { 54 | return IcsRuntimeError; 55 | } 56 | -------------------------------------------------------------------------------- /src/icsdebug.py: -------------------------------------------------------------------------------- 1 | import ics 2 | 3 | def show_clients(): 4 | for d in ics.find_devices(): 5 | print(d, d.NumberOfClients) 6 | 7 | print("Find...") 8 | devices = ics.find_devices() 9 | show_clients() 10 | print("Devices: ", devices) 11 | d = ics.open_device(devices[0]) 12 | show_clients() 13 | print("Opened", d) 14 | print("Loading default settings...", d) 15 | ics.load_default_settings(d) 16 | print("Closing...") 17 | print(ics.close_device(d)) 18 | print("Done.") 19 | 20 | # New Style 21 | d = devices[0] 22 | d.open(config_read=0) 23 | d.load_default_settings() 24 | d.close() 25 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "defines.h" 5 | #include "setup_module_auto_defines.h" 6 | #include "methods.h" 7 | #include "exceptions.h" 8 | #include "object_spy_message.h" 9 | 10 | #define _DOC_ICS_MODULE \ 11 | "Python C Code module for interfacing to the icsneo40 dynamic library. Code tries\n" \ 12 | "to respect PEP 8 (http://python.org/dev/peps/pep-0008). Function naming convention does\n" \ 13 | "not follow the tradition c style icsneo40 naming convention as the python_ics module\n" \ 14 | "name acts as the namespace (icsneo portion of the function) and function names\n" \ 15 | "are suppose to be lowercase with underscores instead of mixedCase like the icsneo API.\n" \ 16 | "\n" \ 17 | "C API can be mimiced almost identically by doing the following:\n" \ 18 | "\t>>> import ics as icsneo\n" \ 19 | "\t>>> devices = icsneo.FindNeoDevices()\n" \ 20 | "\t>>> for device in devices:\n" \ 21 | "\t... print(device)\n" \ 22 | "\t...\n" \ 23 | "\tneoVI FIRE 59886\n" \ 24 | "\n" \ 25 | "Recommended `Python` way by doing the following:\n" \ 26 | "\t>>> import ics\n" \ 27 | "\t>>> devices = ics.find_devices()\n" \ 28 | "\t>>> for device in devices:\n" \ 29 | "\t... print(device)\n" \ 30 | "\t...\n" \ 31 | "\tneoVI FIRE 59886\n" \ 32 | "\n" \ 33 | "It should be noted that :class:`" MODULE_NAME ".PyNeoDeviceEx`" \ 34 | " is used a little bit differently than the C API.\n" \ 35 | ":class:`" MODULE_NAME ".PyNeoDeviceEx` contains two extra members:\n" \ 36 | ":class:`" MODULE_NAME ".PyNeoDeviceEx.AutoHandleClose` and :class:`" MODULE_NAME ".PyNeoDeviceEx._Handle`\n\n" \ 37 | "The handle normally returned from `icsneoOpenNeoDevice()` is stored inside _Handle and setting AutoHandleClose " \ 38 | "to True (Default)\n" \ 39 | "will automatically close the handle when the :class:`" MODULE_NAME ".PyNeoDeviceEx" \ 40 | "` goes out of scope.\n" \ 41 | "\n" \ 42 | "\n" \ 43 | "Installation:\n" \ 44 | "\n" \ 45 | "\tpip install python_ics\n" \ 46 | "\n" \ 47 | "https://pypi.python.org/pypi/python-ics\n" 48 | 49 | static PyModuleDef IcsModule = { 50 | PyModuleDef_HEAD_INIT, MODULE_NAME, _DOC_ICS_MODULE, -1, IcsMethods, NULL, NULL, NULL, NULL 51 | }; 52 | 53 | void initialize_ics_library() { 54 | #if (defined(_WIN32) || defined(__WIN32__)) 55 | // Everything besides windows uses libicsneo 56 | constexpr char LIBRARY_NAME[] = "icsneo40"; 57 | #else 58 | constexpr char LIBRARY_NAME[] = "icsneolegacy"; 59 | #endif 60 | auto& mgr = ice::LibraryManager::instance(); 61 | const auto& library_name = ice::LibraryName(LIBRARY_NAME); 62 | mgr.add("ics", library_name.build(), true); 63 | } 64 | 65 | #ifdef __cplusplus 66 | extern "C" 67 | { 68 | #endif 69 | 70 | PyMODINIT_FUNC PyInit_ics(void) 71 | { 72 | initialize_ics_library(); 73 | 74 | PyObject* module = PyModule_Create(&IcsModule); 75 | 76 | if (!module) { 77 | return module; 78 | } 79 | PyDateTime_IMPORT; 80 | 81 | #ifdef Py_GIL_DISABLED 82 | // Enable the experimental free threaded introduced in 3.13 83 | PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED); 84 | #endif 85 | // Add build constant variables 86 | setup_module_defines(module); 87 | setup_module_auto_defines(module); 88 | 89 | initialize_exceptions(module); 90 | 91 | setup_spy_message_object(module); 92 | 93 | return module; 94 | } 95 | 96 | #ifdef __cplusplus 97 | } 98 | #endif 99 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intrepidcs/python_ics/b5a295c7a8cbbf2beba85d11d1ecdc3dfd6b701c/tests/__init__.py -------------------------------------------------------------------------------- /tests/obsolete/cmvspy.h: -------------------------------------------------------------------------------- 1 | // neoVI3 CoreMini Compressed Execution File 2 | #define CM_EXE_SIZE 512 3 | unsigned char const ucharConfigurationArrayPM[CM_EXE_SIZE] = { 4 | 0x07, 5 | 0x09, 6 | 0x13, 7 | 0x00, 8 | 0x00, 9 | 0x02, 10 | 0x2B, 11 | 0x20, 12 | 0x04, 13 | 0xD2, 14 | 0xBA, 15 | 0xB4, 16 | 0x3F, 17 | 0x43, 18 | 0xFF, 19 | 0xF4, 20 | 0xBD, 21 | 0x2A, 22 | 0x75, 23 | 0xE4, 24 | 0x47, 25 | 0xFA, 26 | 0xE1, 27 | 0xE4, 28 | 0xA8, 29 | 0x82, 30 | 0xCE, 31 | 0x87, 32 | 0x0E, 33 | 0xB3, 34 | 0xEA, 35 | 0x7A, 36 | 0xD5, 37 | 0xF1, 38 | 0x6B, 39 | 0x2E, 40 | 0x1B, 41 | 0x8F, 42 | 0x0B, 43 | 0x82, 44 | 0x17, 45 | 0xE8, 46 | 0x09, 47 | 0x4D, 48 | 0x88, 49 | 0x78, 50 | 0xED, 51 | 0xA4, 52 | 0xC1, 53 | 0x40, 54 | 0x67, 55 | 0x73, 56 | 0xE3, 57 | 0xB0, 58 | 0xB6, 59 | 0xAD, 60 | 0xC6, 61 | 0x7C, 62 | 0x9D, 63 | 0x0C, 64 | 0x64, 65 | 0x71, 66 | 0xF9, 67 | 0xEF, 68 | 0xD0, 69 | 0xFF, 70 | 0xD1, 71 | 0x62, 72 | 0x3A, 73 | 0x7D, 74 | 0x6D, 75 | 0x31, 76 | 0x59, 77 | 0xA6, 78 | 0x9D, 79 | 0x2D, 80 | 0xB1, 81 | 0x2E, 82 | 0x3B, 83 | 0x84, 84 | 0xD3, 85 | 0x53, 86 | 0x56, 87 | 0xC8, 88 | 0x18, 89 | 0x45, 90 | 0x81, 91 | 0xDB, 92 | 0x0A, 93 | 0x3D, 94 | 0x6D, 95 | 0xAB, 96 | 0x06, 97 | 0x4F, 98 | 0x2D, 99 | 0x38, 100 | 0x0A, 101 | 0x3D, 102 | 0x6D, 103 | 0xAB, 104 | 0x06, 105 | 0x4F, 106 | 0x2D, 107 | 0x38, 108 | 0x0A, 109 | 0x3D, 110 | 0x6D, 111 | 0xAB, 112 | 0x06, 113 | 0x4F, 114 | 0x2D, 115 | 0x38, 116 | 0x0A, 117 | 0x3D, 118 | 0x6D, 119 | 0xAB, 120 | 0x06, 121 | 0x4F, 122 | 0x2D, 123 | 0x38, 124 | 0x7B, 125 | 0xE6, 126 | 0x3C, 127 | 0x8F, 128 | 0x4F, 129 | 0x6D, 130 | 0xB6, 131 | 0xE5, 132 | 0x05, 133 | 0x6F, 134 | 0x8C, 135 | 0xCE, 136 | 0xA4, 137 | 0x0A, 138 | 0xDC, 139 | 0x31, 140 | 0xDA, 141 | 0x52, 142 | 0x6F, 143 | 0xE6, 144 | 0xE2, 145 | 0xC2, 146 | 0x3A, 147 | 0xF3, 148 | 0xA7, 149 | 0xF5, 150 | 0x30, 151 | 0x48, 152 | 0xD7, 153 | 0x91, 154 | 0x22, 155 | 0x0E, 156 | 0x6E, 157 | 0x18, 158 | 0xF1, 159 | 0x05, 160 | 0xF1, 161 | 0xEB, 162 | 0xF9, 163 | 0xEF, 164 | 0x93, 165 | 0x7F, 166 | 0x60, 167 | 0x67, 168 | 0x94, 169 | 0x13, 170 | 0xCF, 171 | 0x9D, 172 | 0x78, 173 | 0x8B, 174 | 0xD5, 175 | 0x18, 176 | 0x06, 177 | 0xEE, 178 | 0xA4, 179 | 0xE5, 180 | 0x8D, 181 | 0xBA, 182 | 0x17, 183 | 0x22, 184 | 0x0C, 185 | 0x72, 186 | 0x19, 187 | 0xD2, 188 | 0xE8, 189 | 0xC9, 190 | 0x11, 191 | 0x03, 192 | 0xEE, 193 | 0x0D, 194 | 0x3B, 195 | 0x9A, 196 | 0xBD, 197 | 0x0C, 198 | 0x16, 199 | 0x28, 200 | 0x51, 201 | 0x47, 202 | 0x1A, 203 | 0x42, 204 | 0x0D, 205 | 0xEA, 206 | 0xD3, 207 | 0x56, 208 | 0x72, 209 | 0x00, 210 | 0xD4, 211 | 0x55, 212 | 0xB8, 213 | 0x69, 214 | 0x4C, 215 | 0xCD, 216 | 0xB9, 217 | 0x7F, 218 | 0xDB, 219 | 0x50, 220 | 0xE4, 221 | 0x67, 222 | 0xB5, 223 | 0xFC, 224 | 0x7F, 225 | 0x10, 226 | 0x63, 227 | 0xF2, 228 | 0x33, 229 | 0xA1, 230 | 0xD8, 231 | 0x00, 232 | 0x4D, 233 | 0xEE, 234 | 0xE8, 235 | 0x7A, 236 | 0xE0, 237 | 0xC4, 238 | 0x40, 239 | 0x0C, 240 | 0x90, 241 | 0x9A, 242 | 0xC8, 243 | 0x28, 244 | 0x43, 245 | 0x86, 246 | 0x06, 247 | 0xA8, 248 | 0xC7, 249 | 0xE8, 250 | 0x38, 251 | 0xE7, 252 | 0xC4, 253 | 0x9B, 254 | 0x7D, 255 | 0xC0, 256 | 0x50, 257 | 0x82, 258 | 0x27, 259 | 0x91, 260 | 0x67, 261 | 0xFF, 262 | 0x14, 263 | 0xDF, 264 | 0x62, 265 | 0x49, 266 | 0x0C, 267 | 0x0F, 268 | 0x9E, 269 | 0x1A, 270 | 0xC2, 271 | 0xA7, 272 | 0xF5, 273 | 0x03, 274 | 0x63, 275 | 0x15, 276 | 0x63, 277 | 0xB0, 278 | 0x10, 279 | 0x33, 280 | 0x14, 281 | 0xF9, 282 | 0xEC, 283 | 0x6A, 284 | 0xAA, 285 | 0x7C, 286 | 0xB3, 287 | 0x91, 288 | 0x79, 289 | 0x5C, 290 | 0x09, 291 | 0x79, 292 | 0xDC, 293 | 0x6C, 294 | 0xED, 295 | 0x97, 296 | 0x66, 297 | 0xB7, 298 | 0x49, 299 | 0xD7, 300 | 0xB5, 301 | 0x64, 302 | 0xAD, 303 | 0xCB, 304 | 0x3F, 305 | 0x30, 306 | 0x8B, 307 | 0x69, 308 | 0x5F, 309 | 0xF1, 310 | 0xB5, 311 | 0x23, 312 | 0x2D, 313 | 0x14, 314 | 0xE8, 315 | 0x9A, 316 | 0x2E, 317 | 0xC7, 318 | 0xFE, 319 | 0xEA, 320 | 0xBA, 321 | 0x3F, 322 | 0x4E, 323 | 0x27, 324 | 0x9E, 325 | 0xDA, 326 | 0xC1, 327 | 0x57, 328 | 0xEE, 329 | 0x9B, 330 | 0x88, 331 | 0x77, 332 | 0x8D, 333 | 0xB0, 334 | 0x8C, 335 | 0x55, 336 | 0x3F, 337 | 0x9C, 338 | 0xC3, 339 | 0x3F, 340 | 0xF9, 341 | 0x97, 342 | 0x59, 343 | 0xDA, 344 | 0x15, 345 | 0xAA, 346 | 0xFB, 347 | 0xF6, 348 | 0xAF, 349 | 0xA4, 350 | 0x4B, 351 | 0x50, 352 | 0xC1, 353 | 0xB0, 354 | 0x0A, 355 | 0x93, 356 | 0x1B, 357 | 0xF7, 358 | 0x1F, 359 | 0x44, 360 | 0xB7, 361 | 0xFD, 362 | 0x4E, 363 | 0x2B, 364 | 0x54, 365 | 0xDD, 366 | 0xF2, 367 | 0x55, 368 | 0xB5, 369 | 0xC7, 370 | 0xA9, 371 | 0xF1, 372 | 0x30, 373 | 0x0B, 374 | 0xAF, 375 | 0x29, 376 | 0xF8, 377 | 0xB3, 378 | 0xB0, 379 | 0x99, 380 | 0x00, 381 | 0x00, 382 | 0x00, 383 | 0x00, 384 | 0x00, 385 | 0x00, 386 | 0x00, 387 | 0x00, 388 | 0x00, 389 | 0x00, 390 | 0x00, 391 | 0x00, 392 | 0x00, 393 | 0x00, 394 | 0x00, 395 | 0x00, 396 | 0x00, 397 | 0x00, 398 | 0x00, 399 | 0x00, 400 | 0x00, 401 | 0x00, 402 | 0x00, 403 | 0x00, 404 | 0x00, 405 | 0x00, 406 | 0x00, 407 | 0x00, 408 | 0x00, 409 | 0x00, 410 | 0x00, 411 | 0x00, 412 | 0x00, 413 | 0x00, 414 | 0x00, 415 | 0x00, 416 | 0x00, 417 | 0x00, 418 | 0x00, 419 | 0x00, 420 | 0x00, 421 | 0x00, 422 | 0x00, 423 | 0x00, 424 | 0x00, 425 | 0x00, 426 | 0x00, 427 | 0x00, 428 | 0x00, 429 | 0x00, 430 | 0x00, 431 | 0x00, 432 | 0x00, 433 | 0x00, 434 | 0x00, 435 | 0x00, 436 | 0x00, 437 | 0x00, 438 | 0x00, 439 | 0x00, 440 | 0x00, 441 | 0x00, 442 | 0x00, 443 | 0x00, 444 | 0x00, 445 | 0x00, 446 | 0x00, 447 | 0x00, 448 | 0x00, 449 | 0x00, 450 | 0x00, 451 | 0x00, 452 | 0x00, 453 | 0x00, 454 | 0x00, 455 | 0x00, 456 | 0x00, 457 | 0x00, 458 | 0x00, 459 | 0x00, 460 | 0x00, 461 | 0x00, 462 | 0x00, 463 | 0x00, 464 | 0x00, 465 | 0x00, 466 | 0x00, 467 | 0x00, 468 | 0x00, 469 | 0x00, 470 | 0x00, 471 | 0x00, 472 | 0x00, 473 | 0x00, 474 | 0x00, 475 | 0x00, 476 | 0x00, 477 | 0x00, 478 | 0x00, 479 | 0x00, 480 | 0x00, 481 | 0x00, 482 | 0x00, 483 | 0x00, 484 | 0x00, 485 | 0x00, 486 | 0x00, 487 | 0x00, 488 | 0x00, 489 | 0x00, 490 | 0x00, 491 | 0x00, 492 | 0x00, 493 | 0x00, 494 | 0x00, 495 | 0x00, 496 | 0x00, 497 | 0x00, 498 | 0x00, 499 | 0x00, 500 | 0x00, 501 | 0x00, 502 | 0x00, 503 | 0x00, 504 | 0x00, 505 | 0x00, 506 | 0x00, 507 | 0x00, 508 | 0x00, 509 | 0x00, 510 | 0x00, 511 | 0x00, 512 | 0x00, 513 | 0x00, 514 | 0x00, 515 | 0x00, 516 | }; 517 | 518 | -------------------------------------------------------------------------------- /tests/obsolete/cmvspy.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by 'cmvspyconvert.py' 2 | # from a cmvspy.h file. 3 | # Example usage: 4 | # from cmvspy import data as coremini_data 5 | 6 | data = ( 7 | 0x07, 8 | 0x09, 9 | 0x13, 10 | 0x00, 11 | 0x00, 12 | 0x02, 13 | 0x2B, 14 | 0x20, 15 | 0x04, 16 | 0xD2, 17 | 0xBA, 18 | 0xB4, 19 | 0x3F, 20 | 0x43, 21 | 0xFF, 22 | 0xF4, 23 | 0xBD, 24 | 0x2A, 25 | 0x75, 26 | 0xE4, 27 | 0x47, 28 | 0xFA, 29 | 0xE1, 30 | 0xE4, 31 | 0xA8, 32 | 0x82, 33 | 0xCE, 34 | 0x87, 35 | 0x0E, 36 | 0xB3, 37 | 0xEA, 38 | 0x7A, 39 | 0xD5, 40 | 0xF1, 41 | 0x6B, 42 | 0x2E, 43 | 0x1B, 44 | 0x8F, 45 | 0x0B, 46 | 0x82, 47 | 0x17, 48 | 0xE8, 49 | 0x09, 50 | 0x4D, 51 | 0x88, 52 | 0x78, 53 | 0xED, 54 | 0xA4, 55 | 0xC1, 56 | 0x40, 57 | 0x67, 58 | 0x73, 59 | 0xE3, 60 | 0xB0, 61 | 0xB6, 62 | 0xAD, 63 | 0xC6, 64 | 0x7C, 65 | 0x9D, 66 | 0x0C, 67 | 0x64, 68 | 0x71, 69 | 0xF9, 70 | 0xEF, 71 | 0xD0, 72 | 0xFF, 73 | 0xD1, 74 | 0x62, 75 | 0x3A, 76 | 0x7D, 77 | 0x6D, 78 | 0x31, 79 | 0x59, 80 | 0xA6, 81 | 0x9D, 82 | 0x2D, 83 | 0xB1, 84 | 0x2E, 85 | 0x3B, 86 | 0x84, 87 | 0xD3, 88 | 0x53, 89 | 0x56, 90 | 0xC8, 91 | 0x18, 92 | 0x45, 93 | 0x81, 94 | 0xDB, 95 | 0x0A, 96 | 0x3D, 97 | 0x6D, 98 | 0xAB, 99 | 0x06, 100 | 0x4F, 101 | 0x2D, 102 | 0x38, 103 | 0x0A, 104 | 0x3D, 105 | 0x6D, 106 | 0xAB, 107 | 0x06, 108 | 0x4F, 109 | 0x2D, 110 | 0x38, 111 | 0x0A, 112 | 0x3D, 113 | 0x6D, 114 | 0xAB, 115 | 0x06, 116 | 0x4F, 117 | 0x2D, 118 | 0x38, 119 | 0x0A, 120 | 0x3D, 121 | 0x6D, 122 | 0xAB, 123 | 0x06, 124 | 0x4F, 125 | 0x2D, 126 | 0x38, 127 | 0x7B, 128 | 0xE6, 129 | 0x3C, 130 | 0x8F, 131 | 0x4F, 132 | 0x6D, 133 | 0xB6, 134 | 0xE5, 135 | 0x05, 136 | 0x6F, 137 | 0x8C, 138 | 0xCE, 139 | 0xA4, 140 | 0x0A, 141 | 0xDC, 142 | 0x31, 143 | 0xDA, 144 | 0x52, 145 | 0x6F, 146 | 0xE6, 147 | 0xE2, 148 | 0xC2, 149 | 0x3A, 150 | 0xF3, 151 | 0xA7, 152 | 0xF5, 153 | 0x30, 154 | 0x48, 155 | 0xD7, 156 | 0x91, 157 | 0x22, 158 | 0x0E, 159 | 0x6E, 160 | 0x18, 161 | 0xF1, 162 | 0x05, 163 | 0xF1, 164 | 0xEB, 165 | 0xF9, 166 | 0xEF, 167 | 0x93, 168 | 0x7F, 169 | 0x60, 170 | 0x67, 171 | 0x94, 172 | 0x13, 173 | 0xCF, 174 | 0x9D, 175 | 0x78, 176 | 0x8B, 177 | 0xD5, 178 | 0x18, 179 | 0x06, 180 | 0xEE, 181 | 0xA4, 182 | 0xE5, 183 | 0x8D, 184 | 0xBA, 185 | 0x17, 186 | 0x22, 187 | 0x0C, 188 | 0x72, 189 | 0x19, 190 | 0xD2, 191 | 0xE8, 192 | 0xC9, 193 | 0x11, 194 | 0x03, 195 | 0xEE, 196 | 0x0D, 197 | 0x3B, 198 | 0x9A, 199 | 0xBD, 200 | 0x0C, 201 | 0x16, 202 | 0x28, 203 | 0x51, 204 | 0x47, 205 | 0x1A, 206 | 0x42, 207 | 0x0D, 208 | 0xEA, 209 | 0xD3, 210 | 0x56, 211 | 0x72, 212 | 0x00, 213 | 0xD4, 214 | 0x55, 215 | 0xB8, 216 | 0x69, 217 | 0x4C, 218 | 0xCD, 219 | 0xB9, 220 | 0x7F, 221 | 0xDB, 222 | 0x50, 223 | 0xE4, 224 | 0x67, 225 | 0xB5, 226 | 0xFC, 227 | 0x7F, 228 | 0x10, 229 | 0x63, 230 | 0xF2, 231 | 0x33, 232 | 0xA1, 233 | 0xD8, 234 | 0x00, 235 | 0x4D, 236 | 0xEE, 237 | 0xE8, 238 | 0x7A, 239 | 0xE0, 240 | 0xC4, 241 | 0x40, 242 | 0x0C, 243 | 0x90, 244 | 0x9A, 245 | 0xC8, 246 | 0x28, 247 | 0x43, 248 | 0x86, 249 | 0x06, 250 | 0xA8, 251 | 0xC7, 252 | 0xE8, 253 | 0x38, 254 | 0xE7, 255 | 0xC4, 256 | 0x9B, 257 | 0x7D, 258 | 0xC0, 259 | 0x50, 260 | 0x82, 261 | 0x27, 262 | 0x91, 263 | 0x67, 264 | 0xFF, 265 | 0x14, 266 | 0xDF, 267 | 0x62, 268 | 0x49, 269 | 0x0C, 270 | 0x0F, 271 | 0x9E, 272 | 0x1A, 273 | 0xC2, 274 | 0xA7, 275 | 0xF5, 276 | 0x03, 277 | 0x63, 278 | 0x15, 279 | 0x63, 280 | 0xB0, 281 | 0x10, 282 | 0x33, 283 | 0x14, 284 | 0xF9, 285 | 0xEC, 286 | 0x6A, 287 | 0xAA, 288 | 0x7C, 289 | 0xB3, 290 | 0x91, 291 | 0x79, 292 | 0x5C, 293 | 0x09, 294 | 0x79, 295 | 0xDC, 296 | 0x6C, 297 | 0xED, 298 | 0x97, 299 | 0x66, 300 | 0xB7, 301 | 0x49, 302 | 0xD7, 303 | 0xB5, 304 | 0x64, 305 | 0xAD, 306 | 0xCB, 307 | 0x3F, 308 | 0x30, 309 | 0x8B, 310 | 0x69, 311 | 0x5F, 312 | 0xF1, 313 | 0xB5, 314 | 0x23, 315 | 0x2D, 316 | 0x14, 317 | 0xE8, 318 | 0x9A, 319 | 0x2E, 320 | 0xC7, 321 | 0xFE, 322 | 0xEA, 323 | 0xBA, 324 | 0x3F, 325 | 0x4E, 326 | 0x27, 327 | 0x9E, 328 | 0xDA, 329 | 0xC1, 330 | 0x57, 331 | 0xEE, 332 | 0x9B, 333 | 0x88, 334 | 0x77, 335 | 0x8D, 336 | 0xB0, 337 | 0x8C, 338 | 0x55, 339 | 0x3F, 340 | 0x9C, 341 | 0xC3, 342 | 0x3F, 343 | 0xF9, 344 | 0x97, 345 | 0x59, 346 | 0xDA, 347 | 0x15, 348 | 0xAA, 349 | 0xFB, 350 | 0xF6, 351 | 0xAF, 352 | 0xA4, 353 | 0x4B, 354 | 0x50, 355 | 0xC1, 356 | 0xB0, 357 | 0x0A, 358 | 0x93, 359 | 0x1B, 360 | 0xF7, 361 | 0x1F, 362 | 0x44, 363 | 0xB7, 364 | 0xFD, 365 | 0x4E, 366 | 0x2B, 367 | 0x54, 368 | 0xDD, 369 | 0xF2, 370 | 0x55, 371 | 0xB5, 372 | 0xC7, 373 | 0xA9, 374 | 0xF1, 375 | 0x30, 376 | 0x0B, 377 | 0xAF, 378 | 0x29, 379 | 0xF8, 380 | 0xB3, 381 | 0xB0, 382 | 0x99, 383 | 0x00, 384 | 0x00, 385 | 0x00, 386 | 0x00, 387 | 0x00, 388 | 0x00, 389 | 0x00, 390 | 0x00, 391 | 0x00, 392 | 0x00, 393 | 0x00, 394 | 0x00, 395 | 0x00, 396 | 0x00, 397 | 0x00, 398 | 0x00, 399 | 0x00, 400 | 0x00, 401 | 0x00, 402 | 0x00, 403 | 0x00, 404 | 0x00, 405 | 0x00, 406 | 0x00, 407 | 0x00, 408 | 0x00, 409 | 0x00, 410 | 0x00, 411 | 0x00, 412 | 0x00, 413 | 0x00, 414 | 0x00, 415 | 0x00, 416 | 0x00, 417 | 0x00, 418 | 0x00, 419 | 0x00, 420 | 0x00, 421 | 0x00, 422 | 0x00, 423 | 0x00, 424 | 0x00, 425 | 0x00, 426 | 0x00, 427 | 0x00, 428 | 0x00, 429 | 0x00, 430 | 0x00, 431 | 0x00, 432 | 0x00, 433 | 0x00, 434 | 0x00, 435 | 0x00, 436 | 0x00, 437 | 0x00, 438 | 0x00, 439 | 0x00, 440 | 0x00, 441 | 0x00, 442 | 0x00, 443 | 0x00, 444 | 0x00, 445 | 0x00, 446 | 0x00, 447 | 0x00, 448 | 0x00, 449 | 0x00, 450 | 0x00, 451 | 0x00, 452 | 0x00, 453 | 0x00, 454 | 0x00, 455 | 0x00, 456 | 0x00, 457 | 0x00, 458 | 0x00, 459 | 0x00, 460 | 0x00, 461 | 0x00, 462 | 0x00, 463 | 0x00, 464 | 0x00, 465 | 0x00, 466 | 0x00, 467 | 0x00, 468 | 0x00, 469 | 0x00, 470 | 0x00, 471 | 0x00, 472 | 0x00, 473 | 0x00, 474 | 0x00, 475 | 0x00, 476 | 0x00, 477 | 0x00, 478 | 0x00, 479 | 0x00, 480 | 0x00, 481 | 0x00, 482 | 0x00, 483 | 0x00, 484 | 0x00, 485 | 0x00, 486 | 0x00, 487 | 0x00, 488 | 0x00, 489 | 0x00, 490 | 0x00, 491 | 0x00, 492 | 0x00, 493 | 0x00, 494 | 0x00, 495 | 0x00, 496 | 0x00, 497 | 0x00, 498 | 0x00, 499 | 0x00, 500 | 0x00, 501 | 0x00, 502 | 0x00, 503 | 0x00, 504 | 0x00, 505 | 0x00, 506 | 0x00, 507 | 0x00, 508 | 0x00, 509 | 0x00, 510 | 0x00, 511 | 0x00, 512 | 0x00, 513 | 0x00, 514 | 0x00, 515 | 0x00, 516 | 0x00, 517 | 0x00, 518 | 0x00, 519 | ) 520 | -------------------------------------------------------------------------------- /tests/obsolete/cmvspyconvert.py: -------------------------------------------------------------------------------- 1 | # Converts a cmvspy.h file to a cmvspy.py file for use in python 2 | # usage: cmvspyconvert.py cmvspy.h cmvspy_python.py 3 | # arguments can be omitted 4 | import sys 5 | import re 6 | 7 | file_boiler_plate = ( 8 | """#This file was automatically generated by '%s' 9 | #from a cmvspy.h file. 10 | #Example usage: 11 | # from cmvspy import data as coremini_data\n\n""" 12 | % sys.argv[0] 13 | ) 14 | 15 | if __name__ == "__main__": 16 | try: 17 | cmvspy_filename = sys.argv[1] 18 | except IndexError: 19 | cmvspy_filename = "cmvspy.h" 20 | try: 21 | cmvspy_py_filename = sys.argv[2] 22 | except IndexError: 23 | cmvspy_py_filename = "cmvspy.py" 24 | print("'%s' Will be converted in '%s'" % (cmvspy_filename, cmvspy_py_filename)) 25 | cmvspy_py_file = open(cmvspy_py_filename, "w+") 26 | cmvspy_py_file.write(file_boiler_plate) 27 | cmvspy_py_file.write("data = ( \\\n\t") 28 | hex_regex = re.compile("^\s*0[xX][0-9a-fA-F]+") 29 | BYTES_PER_LINE = 10 30 | bytes_current = 0 31 | with open(cmvspy_filename) as cmvspy_file: 32 | for line in cmvspy_file: 33 | matches = hex_regex.match(line) 34 | if not matches: 35 | continue 36 | cmvspy_py_file.write(matches.group() + ", ") 37 | bytes_current += 1 38 | if bytes_current >= 10: 39 | bytes_current = 0 40 | cmvspy_py_file.write(" \\\n\t") 41 | cmvspy_py_file.write(")\n") 42 | cmvspy_py_file.close() 43 | print("Done.") 44 | -------------------------------------------------------------------------------- /tests/obsolete/test_coremini.py: -------------------------------------------------------------------------------- 1 | import ics 2 | import unittest 3 | import random 4 | import time 5 | import os 6 | 7 | from cmvspy import data 8 | 9 | 10 | class testCoreMini(unittest.TestCase): 11 | def _clear_coremini(self): 12 | if self.dev1.DeviceType == ics.NEODEVICE_VCAN3: 13 | ics.coremini_clear(self.dev1, ics.SCRIPT_LOCATION_VCAN3_MEM) 14 | else: 15 | ics.coremini_clear(self.dev1, ics.SCRIPT_LOCATION_FLASH_MEM) 16 | ics.coremini_clear(self.dev1, ics.SCRIPT_LOCATION_SDCARD) 17 | 18 | @classmethod 19 | def setUpClass(self): 20 | # input() # for debugging purposes 21 | self.dev1 = ics.open_device() 22 | self._clear_coremini(self) 23 | 24 | @classmethod 25 | def tearDownClass(self): 26 | # For some reason tp_dealloc doesn't get called on 27 | # ics.NeoDevice when initialzed in setUpClass(). 28 | # Lets force it here. 29 | self._clear_coremini(self) 30 | del self.dev1 31 | 32 | def testStartStop(self): 33 | def load_coremini(self, contents, location): 34 | self.assertFalse(ics.coremini_get_status(self.dev1)) 35 | ics.coremini_load(self.dev1, contents, location) 36 | ics.coremini_start(self.dev1, location) 37 | self.assertTrue(ics.coremini_get_status(self.dev1)) 38 | time.sleep(2) 39 | ics.coremini_clear(self.dev1, location) 40 | time.sleep(0.1) 41 | self.assertFalse(ics.coremini_get_status(self.dev1)) 42 | 43 | # This allows us to work in other directories and leave the vs3cmb file 44 | # inside same directory as the script. 45 | vs3file = os.path.dirname(os.path.realpath(__file__)) + "/cmvspy.vs3cmb" 46 | if self.dev1.DeviceType == ics.NEODEVICE_VCAN3: 47 | load_coremini(self, data, ics.SCRIPT_LOCATION_VCAN3_MEM) 48 | load_coremini(self, vs3file, ics.SCRIPT_LOCATION_VCAN3_MEM) 49 | elif self.dev1.DeviceType == ics.NEODEVICE_FIRE2: 50 | load_coremini(self, data, ics.SCRIPT_LOCATION_SDCARD) 51 | load_coremini(self, vs3file, ics.SCRIPT_LOCATION_SDCARD) 52 | else: 53 | load_coremini(self, data, ics.SCRIPT_LOCATION_FLASH_MEM) 54 | load_coremini(self, data, ics.SCRIPT_LOCATION_SDCARD) 55 | load_coremini(self, vs3file, ics.SCRIPT_LOCATION_FLASH_MEM) 56 | load_coremini(self, vs3file, ics.SCRIPT_LOCATION_SDCARD) 57 | 58 | def testFblock(self): 59 | if self.dev1.DeviceType == ics.NEODEVICE_VCAN3: 60 | ics.coremini_load(self.dev1, data, ics.SCRIPT_LOCATION_VCAN3_MEM) 61 | elif self.dev1.DeviceType == ics.NEODEVICE_FIRE2: 62 | ics.coremini_load(self.dev1, data, ics.SCRIPT_LOCATION_SDCARD) 63 | else: 64 | ics.coremini_load(self.dev1, data, ics.SCRIPT_LOCATION_FLASH_MEM) 65 | self.assertTrue(ics.coremini_get_fblock_status(self.dev1, 0)) 66 | self.assertIsNone(ics.coremini_stop_fblock(self.dev1, 0)) 67 | self.assertFalse(ics.coremini_get_fblock_status(self.dev1, 0)) 68 | time.sleep(2) 69 | self.assertIsNone(ics.coremini_start_fblock(self.dev1, 0)) 70 | self.assertTrue(ics.coremini_get_fblock_status(self.dev1, 0)) 71 | self._clear_coremini(self) 72 | 73 | 74 | if __name__ == "__main__": 75 | unittest.main() 76 | -------------------------------------------------------------------------------- /tests/obsolete/test_find_devices.py: -------------------------------------------------------------------------------- 1 | import timeit 2 | import unittest 3 | import ics 4 | 5 | # This test requries 2 devices attached, one neoVI FIRE2s and one ValueCAN3 6 | 7 | _DEBUG = False 8 | 9 | 10 | class TestFindDevicesLegacy(unittest.TestCase): 11 | @classmethod 12 | def setUpClass(self): 13 | ics.override_library_name(r"icsneo40-legacy.dll") 14 | if _DEBUG: 15 | import os 16 | 17 | input("Pause... " + str(os.getpid())) 18 | 19 | def test_default_parameters(self): 20 | devices = ics.find_devices() 21 | self.assertTrue(len(devices) == 2) 22 | 23 | def test_default_parameters_time(self): 24 | if not _DEBUG: 25 | self.assertTrue((timeit.timeit("ics.find_devices()", setup="import ics", number=1000)) <= 5.0) 26 | 27 | def test_find_fire2(self): 28 | devices = ics.find_devices(ics.NEODEVICE_FIRE2) 29 | self.assertTrue(len(devices) == 1) 30 | 31 | def test_find_vcan3(self): 32 | devices = ics.find_devices(ics.NEODEVICE_VCAN3) 33 | self.assertTrue(len(devices) == 1) 34 | 35 | def test_find_fire2_and_vcan3(self): 36 | devices = ics.find_devices(ics.NEODEVICE_FIRE2 | ics.NEODEVICE_VCAN3) 37 | self.assertTrue(len(devices) == 2) 38 | 39 | 40 | class TestFindDevicesNewStyle(unittest.TestCase): 41 | @classmethod 42 | def setUpClass(self): 43 | ics.override_library_name(r"icsneo40.dll") 44 | if _DEBUG: 45 | import os 46 | 47 | input("Pause... " + str(os.getpid())) 48 | 49 | def test_default_parameters(self): 50 | devices = ics.find_devices() 51 | self.assertTrue(len(devices) == 2) 52 | 53 | def test_default_parameters_time(self): 54 | if not _DEBUG: 55 | self.assertTrue((timeit.timeit("ics.find_devices()", setup="import ics", number=1000)) <= 5.0) 56 | 57 | def test_find_fire2(self): 58 | devices = ics.find_devices( 59 | [ 60 | ics.NEODEVICE_FIRE2, 61 | ] 62 | ) 63 | self.assertTrue(len(devices) == 1) 64 | 65 | def test_find_vcan3(self): 66 | devices = ics.find_devices( 67 | [ 68 | ics.NEODEVICE_VCAN3, 69 | ] 70 | ) 71 | self.assertTrue(len(devices) == 1) 72 | 73 | def test_find_fire2_and_vcan3(self): 74 | devices = ics.find_devices([ics.NEODEVICE_FIRE2, ics.NEODEVICE_VCAN3]) 75 | self.assertTrue(len(devices) == 2) 76 | 77 | 78 | class TestFindDevicesNewStyleWithLegacyDLL(unittest.TestCase): 79 | @classmethod 80 | def setUpClass(self): 81 | ics.override_library_name(r"icsneo40-legacy.dll") 82 | if _DEBUG: 83 | import os 84 | 85 | input("Pause... " + str(os.getpid())) 86 | 87 | def test_default_parameters(self): 88 | devices = ics.find_devices() 89 | self.assertTrue(len(devices) == 2) 90 | 91 | def test_default_parameters_time(self): 92 | self.assertTrue((timeit.timeit("ics.find_devices()", setup="import ics", number=1000)) <= 5.0) 93 | 94 | def test_find_fire2(self): 95 | devices = ics.find_devices( 96 | [ 97 | ics.NEODEVICE_FIRE2, 98 | ] 99 | ) 100 | self.assertTrue(len(devices) == 2) 101 | 102 | def test_find_vcan3(self): 103 | devices = ics.find_devices( 104 | [ 105 | ics.NEODEVICE_VCAN3, 106 | ] 107 | ) 108 | self.assertTrue(len(devices) == 2) 109 | 110 | def test_find_fire2_and_vcan3(self): 111 | devices = ics.find_devices([ics.NEODEVICE_FIRE2, ics.NEODEVICE_VCAN3]) 112 | self.assertTrue(len(devices) == 2) 113 | 114 | 115 | if __name__ == "__main__": 116 | if _DEBUG: 117 | import os 118 | 119 | input("Pause... " + str(os.getpid())) 120 | unittest.main() 121 | -------------------------------------------------------------------------------- /tests/obsolete/test_get_device_status.py: -------------------------------------------------------------------------------- 1 | import ics 2 | import time 3 | 4 | 5 | def print_device_status(s): 6 | for attr_name in dir(s): 7 | if attr_name.startswith("_"): 8 | continue 9 | print(attr_name, " " * (35 - len(attr_name)), getattr(s, attr_name)) 10 | if attr_name.upper() in ("FIRE2STATUS", "VCAN4STATUS"): 11 | print() 12 | print_device_status(getattr(s, attr_name)) 13 | print() 14 | 15 | 16 | d = ics.open_device() 17 | time.sleep(0.250) # Give the device time to send the frame 18 | s = ics.get_device_status(d) 19 | print_device_status(s) 20 | -------------------------------------------------------------------------------- /tests/obsolete/test_network_fire.py: -------------------------------------------------------------------------------- 1 | import ics 2 | import unittest 3 | import time 4 | import random 5 | 6 | 7 | class testneoVIFIRENetworks(unittest.TestCase): 8 | @classmethod 9 | def setUpClass(self): 10 | devices = ics.find_devices(ics.NEODEVICE_FIRE) 11 | ics.open_device(devices[0]) 12 | ics.open_device(devices[1]) 13 | self.dev1 = devices[0] 14 | self.dev2 = devices[1] 15 | 16 | @classmethod 17 | def setUp(self): 18 | ics.load_default_settings(self.dev1) 19 | ics.load_default_settings(self.dev2) 20 | 21 | # Make sure we start with a "clean" network 22 | ics.get_error_messages(self.dev1) 23 | ics.get_error_messages(self.dev2) 24 | ics.get_messages(self.dev1, False, 0.1) 25 | ics.get_messages(self.dev2, False, 0.1) 26 | 27 | @classmethod 28 | def tearDownClass(self): 29 | # For some reason tp_dealloc doesn't get called on 30 | # ics.NeoDevice when initialzed in setUpClass(). 31 | # Lets force it here. 32 | del self.dev1 33 | del self.dev2 34 | 35 | def testCAN(self): 36 | message = ics.SpyMessage() 37 | message.ArbIDOrHeader = 0xFF 38 | message.Data = (1, 2, 3, 4, 5, 6, 7, 8) 39 | for network in ( 40 | ics.NETID_HSCAN, 41 | ics.NETID_MSCAN, 42 | ics.NETID_HSCAN2, 43 | ics.NETID_HSCAN3, 44 | ics.NETID_LSFTCAN, 45 | ics.NETID_SWCAN, 46 | ): 47 | message.NetworkID = network 48 | try: 49 | self.assertTrue(ics.transmit_messages(self.dev1, message) == None, network) 50 | except ics.RuntimeError as ex: 51 | print(ex, network) 52 | raise ex 53 | self.assertFalse(ics.get_error_messages(self.dev1)) 54 | self.assertFalse(ics.get_error_messages(self.dev2)) 55 | messages, error_count = ics.get_messages(self.dev1, False, 0.1) 56 | self.assertEqual(error_count, 0) 57 | self.assertEqual(len(messages), 1) 58 | self.assertEqual(message.ArbIDOrHeader, messages[0].ArbIDOrHeader) 59 | self.assertEqual(message.NetworkID, messages[0].NetworkID) 60 | self.assertEqual(message.Data, messages[0].Data) 61 | self.assertFalse(ics.get_error_messages(self.dev1)) 62 | self.assertFalse(ics.get_error_messages(self.dev2)) 63 | 64 | def testLIN(self): 65 | message = ics.SpyMessageJ1850() 66 | message.Header = (0x3C, 1, 2) 67 | message.StatusBitField = ics.SPY_STATUS_NETWORK_MESSAGE_TYPE | ics.SPY_STATUS_LIN_MASTER 68 | message.Protocol = ics.SPY_PROTOCOL_LIN 69 | 70 | for network in (ics.NETID_LIN, ics.NETID_LIN2, ics.NETID_LIN3, ics.NETID_LIN4): 71 | message.NetworkID = network 72 | message.Data = tuple([random.randint(x, 0xFF) for x in range(6)]) 73 | # Generate the checksum 74 | checksum = 0 75 | for byte in message.Data + message.Header[1:3]: 76 | checksum += byte 77 | if checksum > 255: 78 | checksum -= 255 79 | message.Data += ((~checksum & 0xFF),) 80 | self.assertTrue(ics.transmit_messages(self.dev1, message) == None) 81 | self.assertFalse(ics.get_error_messages(self.dev1)) 82 | self.assertFalse(ics.get_error_messages(self.dev2)) 83 | messages, error_count = ics.get_messages(self.dev1, False, 0.1) 84 | self.assertEqual(error_count, 0) 85 | self.assertEqual(len(messages), 1) 86 | self.assertEqual(message.Header, messages[0].Header) 87 | self.assertEqual(message.NetworkID, messages[0].NetworkID) 88 | self.assertEqual(message.Data[0:-1], messages[0].Data) 89 | self.assertFalse(ics.get_error_messages(self.dev1)) 90 | self.assertFalse(ics.get_error_messages(self.dev2)) 91 | 92 | def testMISC(self): 93 | # dev1 = output, dev2 = input 94 | def _test_misc(self, state): 95 | arbs = (0x203, 0x204, 0x205, 0x206, 0x201, 0x202) 96 | for arb in arbs: 97 | message = ics.SpyMessage() 98 | message.ArbIDOrHeader = arb 99 | message.NetworkID = ics.NETID_DEVICE 100 | message.Data = (state,) 101 | self.assertEqual(ics.transmit_messages(self.dev1, message), None) 102 | # Wait for the report message to get sent 103 | time.sleep(0.2) 104 | self.assertFalse(ics.get_error_messages(self.dev1)) 105 | self.assertFalse(ics.get_error_messages(self.dev2)) 106 | messages, error_count = ics.get_messages(self.dev2, False, 0.5) 107 | self.assertEqual(error_count, 0) 108 | self.assertNotEqual(len(messages), 0) 109 | self.assertEqual(messages[-1].ArbIDOrHeader, 0x100) 110 | for i, arb in enumerate(arbs): 111 | # print(messages[-1].Data, messages[-1].Data[1]>>i & 1) 112 | self.assertEqual(messages[-1].Data[1] >> i & 1, state, "MISC%d PIN state is wrong" % (arb - 0x200)) 113 | self.assertFalse(ics.get_error_messages(self.dev1)) 114 | self.assertFalse(ics.get_error_messages(self.dev2)) 115 | 116 | # Change the device settings 117 | # dev1 = output, dev2 = input 118 | settings = ics.get_device_settings(self.dev1) 119 | settings.misc_io_initial_ddr = 0x3F 120 | settings.misc_io_initial_latch = 0x3F 121 | ics.set_device_settings(self.dev1, settings) 122 | settings = ics.get_device_settings(self.dev2) 123 | settings.misc_io_initial_ddr = 0x0 124 | settings.misc_io_initial_latch = 0x0 125 | settings.misc_io_on_report_events = 0x7F 126 | settings.misc_io_report_period = 100 127 | ics.set_device_settings(self.dev2, settings) 128 | _test_misc(self, 1) 129 | _test_misc(self, 0) 130 | -------------------------------------------------------------------------------- /tests/obsolete/test_open_close.py: -------------------------------------------------------------------------------- 1 | import ics 2 | import unittest 3 | import time 4 | 5 | 6 | class testneoVIFIRENetworks(unittest.TestCase): 7 | @classmethod 8 | def setUpClass(self): 9 | self.devices = ics.find_devices() 10 | 11 | @classmethod 12 | def setUp(self): 13 | pass # time.sleep(2) 14 | 15 | @classmethod 16 | def tearDownClass(self): 17 | # For some reason tp_dealloc doesn't get called on 18 | # ics.NeoDevice when initialzed in setUpClass(). 19 | # Lets force it here. 20 | del self.devices 21 | 22 | def testAutoClose(self): 23 | devices = ics.find_devices() 24 | for device in devices: 25 | ics.open_device(device) 26 | del devices # emulate NeoDevice list going out of scope 27 | devices = ics.find_devices() 28 | for device in devices: 29 | ics.open_device(device) 30 | 31 | def testOpenCloseByFind(self): 32 | # Open by ics.NeoDevice 33 | for device in self.devices: 34 | ics.open_device(device) 35 | ics.close_device(device) 36 | 37 | def testOpenCloseBySerial(self): 38 | # Open by serial number 39 | for device in self.devices: 40 | d = ics.open_device(device.SerialNumber) 41 | ics.close_device(d) 42 | 43 | def testOpenCloseByFirstFound(self): 44 | # Open by first found 45 | first_devices = [] 46 | for x in range(len(self.devices)): 47 | first_devices.append(ics.open_device()) 48 | # Close by API 49 | for device in first_devices: 50 | ics.close_device(device) 51 | 52 | def testOpenClose100Times(self): 53 | for x in range(100): 54 | try: 55 | ics.open_device(self.devices[0]) 56 | ics.close_device(self.devices[0]) 57 | except Exception as ex: 58 | print(f"Failed at iteration {x}...") 59 | raise ex -------------------------------------------------------------------------------- /tests/obsolete/test_structs.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import os 4 | 5 | # print(os.getcwd()) 6 | print(os.path.abspath("../")) 7 | sys.path.append("../") 8 | 9 | from ics.structures.inner_structure import * 10 | from ics.structures.test_structure import * 11 | from ics.structures.test import * 12 | 13 | 14 | class TestTestEnum(unittest.TestCase): 15 | def test_all(self): 16 | self.assertEqual(test.TestNone, 0) 17 | self.assertEqual(test.TestA, 1) 18 | self.assertEqual(test.TestB, 2) 19 | self.assertEqual(test.TestC, 3) 20 | self.assertEqual(test.TestD, 4) 21 | self.assertEqual(test.TestE, 5) 22 | 23 | 24 | class TestInnerStructure(unittest.TestCase): 25 | def test_all(self): 26 | t = inner_structure() 27 | self.assertTrue(isinstance(t, ctypes.Structure)) 28 | 29 | # default init 30 | self.assertEqual(t.a, b"\x00") 31 | self.assertEqual(t.b, 0) 32 | self.assertEqual(t.t, 0) 33 | t.a = b"Z" 34 | self.assertEqual(t.a, b"Z") 35 | self.assertEqual(t.b, 0) 36 | self.assertEqual(t.t, 0) 37 | t.a = b"\x00" 38 | t.b = 10 39 | self.assertEqual(t.a, b"\x00") 40 | self.assertEqual(t.b, 10) 41 | self.assertEqual(t.t, 0) 42 | t.b = 0 43 | t.t = test.TestD 44 | self.assertEqual(t.a, b"\x00") 45 | self.assertEqual(t.b, 0) 46 | self.assertEqual(t.t, test.TestD) 47 | 48 | 49 | class TestTestStructure(unittest.TestCase): 50 | def test_a(self): 51 | t = A() 52 | self.assertTrue(isinstance(t, ctypes.Structure)) 53 | # default init 54 | self.assertEqual(t.a, 0) 55 | self.assertEqual(t.b, 0) 56 | self.assertEqual(t.c, 0) 57 | t.a = 10 58 | self.assertEqual(t.a, 10) 59 | self.assertEqual(t.b, 0) 60 | self.assertEqual(t.c, 0) 61 | t.a = 0 62 | t.b = 10 63 | self.assertEqual(t.a, 0) 64 | self.assertEqual(t.b, 10) 65 | self.assertEqual(t.c, 0) 66 | t.b = 0 67 | t.c = 10 68 | self.assertEqual(t.a, 0) 69 | self.assertEqual(t.b, 0) 70 | self.assertEqual(t.c, 10) 71 | 72 | def test_b(self): 73 | t = B() 74 | self.assertTrue(isinstance(t, ctypes.Structure)) 75 | # default init 76 | self.assertEqual(t.d, 0) 77 | self.assertEqual(t.e, 0) 78 | self.assertEqual(t.f, 0) 79 | t.d = 1 80 | self.assertEqual(t.d, 1) 81 | self.assertEqual(t.e, 0) 82 | self.assertEqual(t.f, 0) 83 | t.d = 0 84 | t.e = 1 85 | self.assertEqual(t.d, 0) 86 | self.assertEqual(t.e, 1) 87 | self.assertEqual(t.f, 0) 88 | t.e = 0 89 | t.f = 1 90 | self.assertEqual(t.d, 0) 91 | self.assertEqual(t.e, 0) 92 | self.assertEqual(t.f, 1) 93 | 94 | def test_c(self): 95 | t = C() 96 | self.assertTrue(isinstance(t, ctypes.Union)) 97 | # default init 98 | self.assertEqual(t.ghi, 0) 99 | self.assertEqual(t.g, 0) 100 | self.assertEqual(t.h, 0) 101 | self.assertEqual(t.i, 0) 102 | t.g = 1 103 | self.assertEqual(t.ghi, 0x1) 104 | self.assertEqual(t.g, 1) 105 | self.assertEqual(t.h, 0) 106 | self.assertEqual(t.i, 0) 107 | t.g = 0 108 | t.h = 1 109 | self.assertEqual(t.ghi, 0x10000) 110 | self.assertEqual(t.g, 0) 111 | self.assertEqual(t.h, 1) 112 | self.assertEqual(t.i, 0) 113 | t.h = 0 114 | t.i = 1 115 | self.assertEqual(t.ghi, 0x100000000) 116 | self.assertEqual(t.g, 0) 117 | self.assertEqual(t.h, 0) 118 | self.assertEqual(t.i, 1) 119 | t.i = 0 120 | t.ghi = 0x100010001 121 | self.assertEqual(t.ghi, 0x100010001) 122 | self.assertEqual(t.g, 1) 123 | self.assertEqual(t.h, 1) 124 | self.assertEqual(t.i, 1) 125 | 126 | def test_d(self): 127 | t = D() 128 | self.assertTrue(isinstance(t, ctypes.Union)) 129 | # default init 130 | self.assertEqual(t.jkm, 0) 131 | self.assertEqual(t.j, 0) 132 | self.assertEqual(t.k, 0) 133 | self.assertEqual(t.m, 0) 134 | t.j = 1 135 | self.assertEqual(t.jkm, 0x1) 136 | self.assertEqual(t.j, 1) 137 | self.assertEqual(t.k, 0) 138 | self.assertEqual(t.m, 0) 139 | t.j = 0 140 | t.k = 1 141 | self.assertEqual(t.jkm, 0x10000) 142 | self.assertEqual(t.j, 0) 143 | self.assertEqual(t.k, 1) 144 | self.assertEqual(t.m, 0) 145 | t.k = 0 146 | t.m = 1 147 | self.assertEqual(t.jkm, 0x100000000) 148 | self.assertEqual(t.j, 0) 149 | self.assertEqual(t.k, 0) 150 | self.assertEqual(t.m, 1) 151 | t.m = 0 152 | t.jkm = 0x100010001 153 | self.assertEqual(t.jkm, 0x100010001) 154 | self.assertEqual(t.j, 1) 155 | self.assertEqual(t.k, 1) 156 | self.assertEqual(t.m, 1) 157 | 158 | def test_e(self): 159 | t = E() 160 | self.assertTrue(isinstance(t, ctypes.Structure)) 161 | # default init 162 | self.assertEqual(t.n, 0) 163 | self.assertEqual(t.p, 0) 164 | self.assertEqual(t.q, 0) 165 | t.n = 1 166 | self.assertEqual(t.n, 1) 167 | self.assertEqual(t.p, 0) 168 | self.assertEqual(t.q, 0) 169 | t.n = 0 170 | t.p = 1 171 | self.assertEqual(t.n, 0) 172 | self.assertEqual(t.p, 1) 173 | self.assertEqual(t.q, 0) 174 | t.p = 0 175 | t.q = 1 176 | self.assertEqual(t.n, 0) 177 | self.assertEqual(t.p, 0) 178 | self.assertEqual(t.q, 1) 179 | t.q = 0 180 | self.assertEqual(t.n, 0) 181 | self.assertEqual(t.p, 0) 182 | self.assertEqual(t.q, 0) 183 | 184 | def test_f(self): 185 | t = F() 186 | self.assertTrue(isinstance(t, ctypes.Structure)) 187 | # default init 188 | self.assertEqual(t.r, 0) 189 | self.assertEqual(t.s, 0) 190 | self.assertEqual(t.t, 0) 191 | t.r = 1 192 | self.assertEqual(t.r, 1) 193 | self.assertEqual(t.s, 0) 194 | self.assertEqual(t.t, 0) 195 | t.r = 0 196 | t.s = 1 197 | self.assertEqual(t.r, 0) 198 | self.assertEqual(t.s, 1) 199 | self.assertEqual(t.t, 0) 200 | t.s = 0 201 | t.t = 1 202 | self.assertEqual(t.r, 0) 203 | self.assertEqual(t.s, 0) 204 | self.assertEqual(t.t, 1) 205 | t.t = 0 206 | self.assertEqual(t.r, 0) 207 | self.assertEqual(t.s, 0) 208 | self.assertEqual(t.t, 0) 209 | 210 | def test_anonymous(self): 211 | t = test_structure() 212 | self.assertTrue(isinstance(t, ctypes.Structure)) 213 | 214 | # test B 215 | self.assertTrue(isinstance(t.B, ctypes.Structure)) 216 | # default init 217 | self.assertEqual(t._def, 0) 218 | self.assertEqual(t.B.d, 0) 219 | self.assertEqual(t.B.e, 0) 220 | self.assertEqual(t.B.f, 0) 221 | t.B.d = 1 222 | self.assertEqual(t._def, 0x1) 223 | self.assertEqual(t.B.d, 1) 224 | self.assertEqual(t.B.e, 0) 225 | self.assertEqual(t.B.f, 0) 226 | t.B.d = 0 227 | t.B.e = 1 228 | self.assertEqual(t._def, 0x2) 229 | self.assertEqual(t.B.d, 0) 230 | self.assertEqual(t.B.e, 1) 231 | self.assertEqual(t.B.f, 0) 232 | t.B.e = 0 233 | t.B.f = 1 234 | self.assertEqual(t._def, 0x4) 235 | self.assertEqual(t.B.d, 0) 236 | self.assertEqual(t.B.e, 0) 237 | self.assertEqual(t.B.f, 1) 238 | t._def = 0x7 239 | self.assertEqual(t._def, 0x7) 240 | self.assertEqual(t.B.d, 1) 241 | self.assertEqual(t.B.e, 1) 242 | self.assertEqual(t.B.f, 1) 243 | 244 | 245 | if __name__ == "__main__": 246 | try: 247 | unittest.main() 248 | except SystemExit as ex: 249 | print(f"Return code: {int(ex.code)}") 250 | -------------------------------------------------------------------------------- /tests/runner/Readme.md: -------------------------------------------------------------------------------- 1 | Runner tests 2 | === 3 | 4 | This directory is specifically for testing against hardware attached to the runner. 5 | 6 | Each runner consists of the following hardware: 7 | 8 | - neoVI FIRE3 9 | - neoVI FIRE2 10 | - ValueCAN4-2 11 | 12 | 13 | - RAD-Moon2 14 | - RAD-Moon2 15 | -------------------------------------------------------------------------------- /tests/runner/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intrepidcs/python_ics/b5a295c7a8cbbf2beba85d11d1ecdc3dfd6b701c/tests/runner/__init__.py -------------------------------------------------------------------------------- /tests/runner/test_network.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import time 3 | import ics 4 | from ics.py_neo_device_ex import PyNeoDeviceEx 5 | from ics.structures.e_device_settings_type import e_device_settings_type 6 | 7 | unittest.TestLoader.sortTestMethodsUsing = None 8 | 9 | 10 | def are_errors_present(msg): 11 | """Helper function to detect if a message error occurred.""" 12 | error_flags = 0 13 | error_flags |= ics.SPY_STATUS_GLOBAL_ERR 14 | error_flags |= ics.SPY_STATUS_CRC_ERROR 15 | error_flags |= ics.SPY_STATUS_CAN_ERROR_PASSIVE 16 | error_flags |= ics.SPY_STATUS_HEADERCRC_ERROR 17 | error_flags |= ics.SPY_STATUS_INCOMPLETE_FRAME 18 | error_flags |= ics.SPY_STATUS_LOST_ARBITRATION 19 | error_flags |= ics.SPY_STATUS_UNDEFINED_ERROR 20 | error_flags |= ics.SPY_STATUS_CAN_BUS_OFF 21 | error_flags |= ics.SPY_STATUS_BUS_RECOVERED 22 | error_flags |= ics.SPY_STATUS_BUS_SHORTED_PLUS 23 | error_flags |= ics.SPY_STATUS_BUS_SHORTED_GND 24 | error_flags |= ics.SPY_STATUS_CHECKSUM_ERROR 25 | error_flags |= ics.SPY_STATUS_BAD_MESSAGE_BIT_TIME_ERROR 26 | error_flags |= ics.SPY_STATUS_TX_NOMATCH 27 | error_flags |= ics.SPY_STATUS_COMM_IN_OVERFLOW 28 | error_flags |= ics.SPY_STATUS_EXPECTED_LEN_MISMATCH 29 | error_flags |= ics.SPY_STATUS_MSG_NO_MATCH 30 | error_flags |= ics.SPY_STATUS_BREAK 31 | error_flags |= ics.SPY_STATUS_AVSI_REC_OVERFLOW 32 | error_flags |= ics.SPY_STATUS_BREAK 33 | if (msg.StatusBitField & error_flags) != 0: 34 | return True 35 | return False 36 | 37 | 38 | class BaseTests: 39 | """Base classes. These are isolated and won't be run/discovered. Used for inheritance""" 40 | 41 | class TestCAN(unittest.TestCase): 42 | @classmethod 43 | def setUpClass(cls): 44 | cls.netid = None 45 | 46 | @classmethod 47 | def setUp(self): 48 | self.devices = ics.find_devices() 49 | for device in self.devices: 50 | device.open() 51 | device.load_default_settings() 52 | 53 | @classmethod 54 | def tearDown(self): 55 | for device in self.devices: 56 | device.close() 57 | 58 | def test_get_messages(self): 59 | for device in self.devices: 60 | messages, error_count = device.get_messages() 61 | 62 | def test_transmit(self): 63 | data = tuple([x for x in range(64)]) 64 | tx_msg = ics.SpyMessage() 65 | tx_msg.ArbIDOrHeader = 0x01 66 | tx_msg.NetworkID = self.netid 67 | tx_msg.Protocol = ics.SPY_PROTOCOL_CANFD 68 | tx_msg.StatusBitField = ics.SPY_STATUS_CANFD | ics.SPY_STATUS_NETWORK_MESSAGE_TYPE 69 | tx_msg.StatusBitField3 = ics.SPY_STATUS3_CANFD_BRS | ics.SPY_STATUS3_CANFD_FDF 70 | tx_msg.ExtraDataPtr = data 71 | for device in self.devices: 72 | # Clear any messages in the buffer 73 | _, __ = device.get_messages() 74 | device.transmit_messages(tx_msg) 75 | # CAN ACK timeout in firmware is 200ms, so wait 300ms for ACK 76 | time.sleep(0.3) 77 | start = time.time() 78 | messages, error_count = device.get_messages(False, 1) 79 | elapsed = time.time() - start 80 | print(f"Elapsed time rx: {elapsed:.4f}s") 81 | self.assertEqual(error_count, 0, str(device)) 82 | self.assertTrue(len(messages) > 0, str(device)) 83 | # Find the transmit message 84 | tx_messages = [] 85 | for message in messages: 86 | if message.StatusBitField & ics.SPY_STATUS_TX_MSG == ics.SPY_STATUS_TX_MSG: 87 | tx_messages.append(message) 88 | self.assertEqual(len(tx_messages), 1, str(device)) 89 | for message in tx_messages: 90 | # We should only have one transmit message in the buffer 91 | self.assertEqual(tx_msg.ArbIDOrHeader, message.ArbIDOrHeader, str(device)) 92 | self.assertEqual(tx_msg.NetworkID, message.NetworkID, str(device)) 93 | self.assertEqual(tx_msg.ExtraDataPtr, message.ExtraDataPtr, str(device)) 94 | self.assertFalse(are_errors_present(message), f"{str(device)} {hex(message.StatusBitField)}") 95 | self.assertEqual( 96 | tx_msg.StatusBitField | ics.SPY_STATUS_TX_MSG, 97 | message.StatusBitField, 98 | f"{str(device)} {hex(tx_msg.StatusBitField| ics.SPY_STATUS_TX_MSG)} {hex(message.StatusBitField)}", 99 | ) 100 | self.assertEqual( 101 | tx_msg.StatusBitField3, message.StatusBitField3, f"{str(device)} {hex(message.StatusBitField3)}" 102 | ) 103 | 104 | 105 | class TestHSCAN1(BaseTests.TestCAN): 106 | @classmethod 107 | def setUpClass(cls): 108 | cls.netid = ics.NETID_HSCAN 109 | 110 | 111 | class TestHSCAN2(BaseTests.TestCAN): 112 | @classmethod 113 | def setUpClass(cls): 114 | cls.netid = ics.NETID_HSCAN2 115 | 116 | 117 | if __name__ == "__main__": 118 | unittest.main() 119 | -------------------------------------------------------------------------------- /tests/runner/test_open_close.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import ics 3 | 4 | unittest.TestLoader.sortTestMethodsUsing = None 5 | 6 | 7 | class TestOpenClose(unittest.TestCase): 8 | @classmethod 9 | def setUpClass(self): 10 | self.expected_dev_count = 3 11 | self.devices = ics.find_devices() 12 | 13 | @classmethod 14 | def setUp(self): 15 | pass 16 | 17 | @classmethod 18 | def tearDownClass(self): 19 | # For some reason tp_dealloc doesn't get called on 20 | # ics.NeoDevice when initialzed in setUpClass(). 21 | # Lets force it here. 22 | del self.devices 23 | 24 | def _check_devices(self): 25 | self.assertEqual( 26 | len(self.devices), 27 | self.expected_dev_count, 28 | f"Expected {self.expected_dev_count}, found {len(self.devices)} ({self.devices})...", 29 | ) 30 | 31 | def test_find_fire3(self): 32 | self._check_devices() 33 | devices = ics.find_devices([ics.NEODEVICE_FIRE3]) 34 | self.assertTrue(len(devices) == 1) 35 | self.assertEqual(devices[0].DeviceType, ics.NEODEVICE_FIRE3) 36 | 37 | def test_find_fire2(self): 38 | self._check_devices() 39 | devices = ics.find_devices([ics.NEODEVICE_FIRE2]) 40 | self.assertTrue(len(devices) == 1) 41 | self.assertEqual(devices[0].DeviceType, ics.NEODEVICE_FIRE2) 42 | 43 | def test_find_vcan42(self): 44 | self._check_devices() 45 | devices = ics.find_devices([ics.NEODEVICE_VCAN42]) 46 | self.assertTrue(len(devices) == 1) 47 | self.assertEqual(devices[0].DeviceType, ics.NEODEVICE_VCAN42) 48 | 49 | def test_find_fire2_and_vcan42(self): 50 | self._check_devices() 51 | devices = ics.find_devices([ics.NEODEVICE_FIRE2, ics.NEODEVICE_VCAN42]) 52 | self.assertTrue(len(devices) == 2) 53 | 54 | def test_open_close(self): 55 | self._check_devices() 56 | for device in self.devices: 57 | self.assertEqual(device.NumberOfClients, 0) 58 | self.assertEqual(device.MaxAllowedClients, 1) 59 | d = ics.open_device(device) 60 | try: 61 | self.assertEqual(device, d) 62 | self.assertEqual(device.NumberOfClients, 1) 63 | self.assertEqual(device.MaxAllowedClients, 1) 64 | 65 | self.assertEqual(d.NumberOfClients, 1) 66 | self.assertEqual(d.MaxAllowedClients, 1) 67 | finally: 68 | self.assertEqual(device.NumberOfClients, 1) 69 | self.assertEqual(d.NumberOfClients, 1) 70 | ics.close_device(d) 71 | self.assertEqual(device.NumberOfClients, 0) 72 | self.assertEqual(d.NumberOfClients, 0) 73 | 74 | def test_open_close_by_serial(self): 75 | # Open by serial number 76 | for device in self.devices: 77 | d = ics.open_device(device.SerialNumber) 78 | self.assertEqual(d.SerialNumber, device.SerialNumber) 79 | ics.close_device(d) 80 | 81 | def test_open_close_first_found(self): 82 | # Open by first found 83 | first_devices = [] 84 | for x, device in enumerate(self.devices): 85 | try: 86 | self.assertEqual(device.NumberOfClients, 0, f"{device}") 87 | d = ics.open_device() 88 | first_devices.append(d) 89 | self.assertEqual(d.NumberOfClients, 1, f"{device}") 90 | except ics.RuntimeError as ex: 91 | raise RuntimeError(f"Failed to open {device}... Iteration {len(first_devices)} ({ex})") 92 | self.assertEqual(len(self.devices), len(first_devices)) 93 | # Close by API 94 | for device in first_devices: 95 | self.assertEqual(device.NumberOfClients, 1, f"{device}") 96 | ics.close_device(device) 97 | self.assertEqual(device.NumberOfClients, 0, f"{device}") 98 | 99 | def test_open_close_10_times(self): 100 | for device in self.devices: 101 | for x in range(10): 102 | try: 103 | self.assertEqual(device.NumberOfClients, 0) 104 | ics.open_device(device) 105 | self.assertEqual(device.NumberOfClients, 1) 106 | error_count = ics.close_device(device) 107 | self.assertEqual(device.NumberOfClients, 0) 108 | self.assertEqual(error_count, 0, "Error count was not 0 on {device} iteration {x}...") 109 | except Exception as ex: 110 | print(f"Failed at iteration {x} {device}: {ex}...") 111 | raise ex 112 | 113 | if __name__ == "__main__": 114 | unittest.main() 115 | -------------------------------------------------------------------------------- /tests/runner/test_settings.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import ics 3 | from ics.py_neo_device_ex import PyNeoDeviceEx 4 | from ics.structures.e_device_settings_type import e_device_settings_type 5 | 6 | unittest.TestLoader.sortTestMethodsUsing = None 7 | 8 | 9 | class BaseTests: 10 | """Base classes. These are isolated and won't be run/discovered. Used for inheritance""" 11 | 12 | class TestSettings(unittest.TestCase): 13 | @classmethod 14 | def setUpClass(cls): 15 | cls.device_type = None 16 | cls.device_settings_type = None 17 | 18 | def _get_device(self) -> PyNeoDeviceEx: 19 | devices = ics.find_devices([self.device_type]) 20 | self.assertEqual( 21 | len(devices), 22 | 1, 23 | f"Failed to find any device types of {self.device_type}! Expected 1, got {len(devices)}.", 24 | ) 25 | return devices[0] 26 | 27 | def test_load_defaults(self): 28 | device = self._get_device() 29 | device.open() 30 | try: 31 | ics.load_default_settings(device) 32 | finally: 33 | device.close() 34 | 35 | def test_get_set_settings(self): 36 | device = self._get_device() 37 | device.open() 38 | try: 39 | ics.load_default_settings(device) 40 | settings = ics.get_device_settings(device) 41 | self.assertEqual(settings.DeviceSettingType, self.device_settings_type) 42 | ics.set_device_settings(device, settings) 43 | _ = ics.get_device_settings(device) 44 | # TODO: compare both settings 45 | finally: 46 | device.close() 47 | 48 | 49 | class TestFire3Settings(BaseTests.TestSettings): 50 | @classmethod 51 | def setUpClass(cls): 52 | cls.device_type = ics.NEODEVICE_FIRE3 53 | cls.device_settings_type = e_device_settings_type.DeviceFire3SettingsType 54 | 55 | 56 | class TestFire2Settings(BaseTests.TestSettings): 57 | @classmethod 58 | def setUpClass(cls): 59 | cls.device_type = ics.NEODEVICE_FIRE2 60 | cls.device_settings_type = e_device_settings_type.DeviceFire2SettingsType 61 | 62 | 63 | class TestValueCAN42Settings(BaseTests.TestSettings): 64 | @classmethod 65 | def setUpClass(cls): 66 | cls.device_type = ics.NEODEVICE_VCAN42 67 | cls.device_settings_type = e_device_settings_type.DeviceVCAN412SettingsType 68 | 69 | 70 | if __name__ == "__main__": 71 | unittest.main() 72 | -------------------------------------------------------------------------------- /travis/build-wheels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -u -x 3 | 4 | function repair_wheel { 5 | wheel="$1" 6 | if ! auditwheel show "$wheel"; then 7 | echo "Skipping non-platform wheel $wheel" 8 | else 9 | auditwheel repair "$wheel" --plat "$PLAT" -w /io/wheelhouse/ 10 | fi 11 | } 12 | 13 | 14 | # Install a system package required by our library 15 | dnf install -y clang clang-tools-extra flex bison 16 | 17 | # Compile wheels 18 | for PYBIN in /opt/python/*/bin; do 19 | "${PYBIN}/pip" install -r /io/dev-requirements.txt 20 | "${PYBIN}/pip" wheel /io/ --no-deps -w wheelhouse/ 21 | done 22 | 23 | # Bundle external shared libraries into the wheels 24 | for whl in wheelhouse/*.whl; do 25 | repair_wheel "$whl" 26 | done 27 | 28 | # Install packages and test 29 | for PYBIN in /opt/python/*/bin/; do 30 | "${PYBIN}/pip" install python_ics --no-index -f /io/wheelhouse 31 | (cd "$HOME"; "${PYBIN}/nosetests" python_ics) 32 | done -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 1 3 | requires-python = ">=3.9" 4 | 5 | [[package]] 6 | name = "python-ics" 7 | source = { editable = "." } 8 | --------------------------------------------------------------------------------