pyccp 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,89 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ workflow_call:
7
+ schedule:
8
+ - cron: "0 0 * * 3"
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ lint:
15
+ name: Lint
16
+ runs-on: ubuntu-latest
17
+
18
+ steps:
19
+ - name: Check out repository
20
+ uses: actions/checkout@v7
21
+
22
+ - name: Set up Python
23
+ uses: actions/setup-python@v7
24
+ with:
25
+ python-version: "3.15"
26
+
27
+ - name: Set up uv
28
+ uses: astral-sh/setup-uv@v10.3.0
29
+ with:
30
+ enable-cache: true
31
+
32
+ - name: Install Hatch
33
+ run: uv tool install hatch
34
+
35
+ - name: Run linting
36
+ run: hatch check code
37
+
38
+ format:
39
+ name: Format
40
+ runs-on: ubuntu-latest
41
+
42
+ steps:
43
+ - name: Check out repository
44
+ uses: actions/checkout@v7
45
+
46
+ - name: Set up Python
47
+ uses: actions/setup-python@v7
48
+ with:
49
+ python-version: "3.15"
50
+
51
+ - name: Set up uv
52
+ uses: astral-sh/setup-uv@v10.3.0
53
+ with:
54
+ enable-cache: true
55
+
56
+ - name: Install Hatch
57
+ run: uv tool install hatch
58
+
59
+ - name: Run formatting check
60
+ run: hatch check fmt
61
+
62
+ test:
63
+ name: Test - Python ${{ matrix.python-version }}
64
+ runs-on: ubuntu-latest
65
+
66
+ strategy:
67
+ fail-fast: false
68
+ matrix:
69
+ python-version: [ "3.11", "3.12", "3.13", "3.14", "3.15" ]
70
+
71
+ steps:
72
+ - name: Check out repository
73
+ uses: actions/checkout@v7
74
+
75
+ - name: Set up Python ${{ matrix.python-version }}
76
+ uses: actions/setup-python@v7
77
+ with:
78
+ python-version: ${{ matrix.python-version }}
79
+
80
+ - name: Set up uv
81
+ uses: astral-sh/setup-uv@v10.3.0
82
+ with:
83
+ enable-cache: true
84
+
85
+ - name: Install Hatch
86
+ run: uv tool install hatch --with hatch-pip-compile
87
+
88
+ - name: Run tests
89
+ run: hatch test -py=${{ matrix.python-version }}
@@ -0,0 +1,42 @@
1
+ name: Publish
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+
7
+ jobs:
8
+ ci:
9
+ uses: ./.github/workflows/ci.yml
10
+
11
+ publish:
12
+ name: Publish to PyPI
13
+ runs-on: ubuntu-latest
14
+ needs: ci
15
+ environment:
16
+ name: pypi
17
+ url: https://pypi.org/project/pyccp/
18
+ permissions:
19
+ id-token: write
20
+
21
+ steps:
22
+ - name: Check out repository
23
+ uses: actions/checkout@v7
24
+
25
+ - name: Set up Python
26
+ uses: actions/setup-python@v7
27
+ with:
28
+ python-version: "3.15"
29
+
30
+ - name: Set up uv
31
+ uses: astral-sh/setup-uv@v10.3.3
32
+ with:
33
+ enable-cache: true
34
+
35
+ - name: Install Hatch
36
+ run: uv tool install hatch
37
+
38
+ - name: Build package
39
+ run: hatch build
40
+
41
+ - name: Publish package distributions to PyPI
42
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,42 @@
1
+ name: "Test Publish"
2
+
3
+ on: workflow_dispatch
4
+
5
+ jobs:
6
+ ci:
7
+ uses: ./.github/workflows/ci.yml
8
+
9
+ publish:
10
+ name: Publish to TestPyPI
11
+ runs-on: ubuntu-latest
12
+ needs: ci
13
+ environment:
14
+ name: testpypi
15
+ url: https://test.pypi.org/project/pyccp/
16
+ permissions:
17
+ id-token: write
18
+
19
+ steps:
20
+ - name: Check out repository
21
+ uses: actions/checkout@v7
22
+
23
+ - name: Set up Python
24
+ uses: actions/setup-python@v7
25
+ with:
26
+ python-version: "3.15"
27
+
28
+ - name: Set up uv
29
+ uses: astral-sh/setup-uv@v10.3.3
30
+ with:
31
+ enable-cache: true
32
+
33
+ - name: Install Hatch
34
+ run: uv tool install hatch
35
+
36
+ - name: Build package
37
+ run: hatch build
38
+
39
+ - name: Publish package to TestPyPI
40
+ uses: pypa/gh-action-pypi-publish@release/v1
41
+ with:
42
+ repository-url: https://test.pypi.org/legacy/
@@ -0,0 +1,32 @@
1
+ # IDEA
2
+ /.idea/
3
+
4
+ # Python
5
+ /.venv/
6
+ __pycache__/
7
+ *.py[cod]
8
+ *$py.class
9
+ requirements.*
10
+
11
+ # C extensions
12
+ *.so
13
+
14
+ # Distribution / packaging
15
+ .Python
16
+ build/
17
+ develop-eggs/
18
+ dist/
19
+ downloads/
20
+ eggs/
21
+ .eggs/
22
+ lib/
23
+ lib64/
24
+ parts/
25
+ sdist/
26
+ var/
27
+ wheels/
28
+ share/python-wheels/
29
+ *.egg-info/
30
+ .installed.cfg
31
+ *.egg
32
+ MANIFEST
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vladimir Petrigo
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 all
13
+ 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 THE
21
+ SOFTWARE.
pyccp-0.10.0/PKG-INFO ADDED
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.5
2
+ Name: pyccp
3
+ Version: 0.10.0
4
+ Summary: CAN Calibration Protocol for Python
5
+ Author-email: Vladimir Petrigo <vladimir.petrigo@gmail.com>
6
+ License-File: LICENSE.md
7
+ Keywords: asam,automotive,ccp,ecu
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Programming Language :: Python :: 3.15
16
+ Classifier: Topic :: Scientific/Engineering
17
+ Classifier: Topic :: Software Development
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: python-can<5,>=4
20
+ Description-Content-Type: text/markdown
21
+
22
+ [![CI](https://github.com/vpetrigo/pyccp/actions/workflows/ci.yml/badge.svg)](https://github.com/vpetrigo/pyccp/actions/workflows/ci.yml)
23
+ [![PyPI - Version](https://img.shields.io/pypi/v/pyccp)](https://pypi.org/project/pyccp)
24
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyccp)
25
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyccp?period=monthly&units=INTERNATIONAL_SYSTEM&left_color=GREY&right_color=GREEN&left_text=downloads%2Fmonth)](https://pepy.tech/projects/pyccp)
26
+
27
+ # CAN Calibration Protocol for Python
28
+
29
+ Python implementation of the CAN Calibration Protocol (CCP) v2.1 Master, built
30
+ on [python-can](https://python-can.readthedocs.io/). Inspired by [pySART/pyccp](https://github.com/pySART/pyccp).
31
+
32
+ ## Install
33
+
34
+ ```toml
35
+ dependencies = [
36
+ "pyccp==0.10.0"
37
+ ]
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ```python
43
+ import can
44
+ from pyccp import Master
45
+ from pyccp.ccp import ReturnCodes
46
+
47
+ bus = can.Bus(interface="socketcan", channel="can0")
48
+
49
+ with Master(bus, cro=0x7E1, dto=0x815) as master:
50
+ resp = master.connect(address=0x39)
51
+ assert resp is not None and resp.code == ReturnCodes.ACKNOWLEDGE
52
+
53
+ resp = master.set_mta(address=0x1000)
54
+ assert resp is not None and resp.code == ReturnCodes.ACKNOWLEDGE
55
+
56
+ resp = master.clear_memory(block_size=0x200)
57
+ chunks = [b"abcdef", b"ghi", b""]
58
+
59
+ for chunk in chunks:
60
+ resp = master.program6(chunk)
61
+ assert resp is not None and resp.code == ReturnCodes.ACKNOWLEDGE
62
+ ```
63
+
64
+ ## DAQ & Events
65
+
66
+ ```python
67
+ from pyccp import Master, DAQMessage, CommandResponse
68
+
69
+ with Master(bus, cro=0x7E1, dto=0x815) as master:
70
+ # Register a callback for DAQ messages
71
+ master.on_daq(0x816, lambda msg: print(f"DAQ: {msg.daq_id:#04X}, ODT: {msg.pid}, data: {msg.data.hex()}"))
72
+ # Connect and configure DAQ list
73
+ ```
74
+
75
+ ## Logging
76
+
77
+ ```python
78
+ import logging
79
+
80
+ logging.getLogger("pyccp").setLevel(logging.DEBUG)
81
+ ```
82
+
83
+ ## Tests
84
+
85
+ ```sh
86
+ hatch test -py 3.15
87
+ ```
pyccp-0.10.0/README.md ADDED
@@ -0,0 +1,66 @@
1
+ [![CI](https://github.com/vpetrigo/pyccp/actions/workflows/ci.yml/badge.svg)](https://github.com/vpetrigo/pyccp/actions/workflows/ci.yml)
2
+ [![PyPI - Version](https://img.shields.io/pypi/v/pyccp)](https://pypi.org/project/pyccp)
3
+ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyccp)
4
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyccp?period=monthly&units=INTERNATIONAL_SYSTEM&left_color=GREY&right_color=GREEN&left_text=downloads%2Fmonth)](https://pepy.tech/projects/pyccp)
5
+
6
+ # CAN Calibration Protocol for Python
7
+
8
+ Python implementation of the CAN Calibration Protocol (CCP) v2.1 Master, built
9
+ on [python-can](https://python-can.readthedocs.io/). Inspired by [pySART/pyccp](https://github.com/pySART/pyccp).
10
+
11
+ ## Install
12
+
13
+ ```toml
14
+ dependencies = [
15
+ "pyccp==0.10.0"
16
+ ]
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```python
22
+ import can
23
+ from pyccp import Master
24
+ from pyccp.ccp import ReturnCodes
25
+
26
+ bus = can.Bus(interface="socketcan", channel="can0")
27
+
28
+ with Master(bus, cro=0x7E1, dto=0x815) as master:
29
+ resp = master.connect(address=0x39)
30
+ assert resp is not None and resp.code == ReturnCodes.ACKNOWLEDGE
31
+
32
+ resp = master.set_mta(address=0x1000)
33
+ assert resp is not None and resp.code == ReturnCodes.ACKNOWLEDGE
34
+
35
+ resp = master.clear_memory(block_size=0x200)
36
+ chunks = [b"abcdef", b"ghi", b""]
37
+
38
+ for chunk in chunks:
39
+ resp = master.program6(chunk)
40
+ assert resp is not None and resp.code == ReturnCodes.ACKNOWLEDGE
41
+ ```
42
+
43
+ ## DAQ & Events
44
+
45
+ ```python
46
+ from pyccp import Master, DAQMessage, CommandResponse
47
+
48
+ with Master(bus, cro=0x7E1, dto=0x815) as master:
49
+ # Register a callback for DAQ messages
50
+ master.on_daq(0x816, lambda msg: print(f"DAQ: {msg.daq_id:#04X}, ODT: {msg.pid}, data: {msg.data.hex()}"))
51
+ # Connect and configure DAQ list
52
+ ```
53
+
54
+ ## Logging
55
+
56
+ ```python
57
+ import logging
58
+
59
+ logging.getLogger("pyccp").setLevel(logging.DEBUG)
60
+ ```
61
+
62
+ ## Tests
63
+
64
+ ```sh
65
+ hatch test -py 3.15
66
+ ```
@@ -0,0 +1,93 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "pyccp"
7
+ version = "0.10.0"
8
+ description = "CAN Calibration Protocol for Python"
9
+ authors = [{ name = "Vladimir Petrigo", email = "vladimir.petrigo@gmail.com" }]
10
+ license-files = ["LICENSE.md"]
11
+ readme = "README.md"
12
+ requires-python = ">=3.11"
13
+ keywords = ["automotive", "ecu", "ccp", "asam"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "Topic :: Software Development",
18
+ "Topic :: Scientific/Engineering",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3.14",
24
+ "Programming Language :: Python :: 3.15",
25
+ ]
26
+ dependencies = [
27
+ "python-can >=4,<5"
28
+ ]
29
+
30
+ [tool.hatch.envs.hatch-test]
31
+ default-args = ["tests"]
32
+
33
+ [[tool.hatch.envs.hatch-test.matrix]]
34
+ python = ["3.11", "3.12", "3.13", "3.14", "3.15"]
35
+
36
+ [tool.ruff.lint]
37
+ select = ["E", "F"]
38
+
39
+ [tool.ruff]
40
+ line-length = 88
41
+
42
+ [tool.hatch.env]
43
+ requires = [
44
+ "hatch-pip-compile",
45
+ ]
46
+
47
+ [tool.hatch.envs.default]
48
+ type = "pip-compile"
49
+ installer = "uv"
50
+ pip-compile-hashes = true
51
+ pip-compile-resolver = "uv"
52
+ pip-compile-installer = "uv"
53
+ path = ".venv"
54
+
55
+ [tool.hatch.envs.type-check]
56
+ dependencies = [
57
+ "mypy>=1.0"
58
+ ]
59
+ type = "pip-compile"
60
+ installer = "uv"
61
+ pip-compile-hashes = true
62
+ pip-compile-resolver = "uv"
63
+ pip-compile-installer = "uv"
64
+ path = ".venv"
65
+ lock-filename = "requirements.type.txt"
66
+
67
+ [tool.hatch.envs.type-check.scripts]
68
+ check = "mypy src/"
69
+
70
+ [tool.setuptools.packages.find]
71
+ where = ["src/pyccp"]
72
+
73
+ [tool.hatch.build.targets.sdist]
74
+
75
+ [tool.hatch.build.targets.wheel]
76
+ packages = ["src/pyccp"]
77
+
78
+ [tool.hatch.metadata]
79
+ allow-direct-references = true
80
+
81
+ [tool.mypy]
82
+ python_version = "3.11"
83
+ warn_return_any = false
84
+ warn_unused_configs = true
85
+ disallow_untyped_defs = false
86
+
87
+ # Ignore missing type stubs for third-party libraries
88
+ # [[tool.mypy.overrides]]
89
+ # module = [
90
+ # "pyccp.*",
91
+ # "wrapt",
92
+ # ]
93
+ # ignore_missing_imports = true
@@ -0,0 +1,5 @@
1
+ """CAN Calibration Protocol tools; applications configure logging handlers."""
2
+
3
+ import logging
4
+
5
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import dataclasses
5
+ import enum
6
+
7
+ MAX_CRO = 0x0008
8
+ MAX_DTO = 0x0008
9
+
10
+ CCP_VERSION = (2, 1)
11
+
12
+
13
+ @dataclasses.dataclass(frozen=True)
14
+ class Command:
15
+ """
16
+ Immutable command configuration.
17
+
18
+ Represents a command by its numeric code and the timeout value associated
19
+ with executing or handling that command. Instances are frozen by the data class
20
+ declaration, so the recorded values are intended to remain stable after
21
+ creation.
22
+
23
+ :ivar code: Numeric identifier for the command.
24
+ :ivar timeout: Timeout value associated with the command in milliseconds.
25
+ """
26
+
27
+ code: int
28
+ timeout: int
29
+
30
+
31
+ # Mandatory Commands
32
+ CONNECT = Command(0x01, 25)
33
+ GET_CCP_VERSION = Command(0x1B, 25)
34
+ EXCHANGE_ID = Command(0x17, 25)
35
+ SET_MTA = Command(0x02, 25)
36
+ DNLOAD = Command(0x03, 25)
37
+ UPLOAD = Command(0x04, 25)
38
+ GET_DAQ_SIZE = Command(0x14, 25)
39
+ SET_DAQ_PTR = Command(0x15, 25)
40
+ WRITE_DAQ = Command(0x16, 25)
41
+ START_STOP = Command(0x06, 25)
42
+ DISCONNECT = Command(0x07, 25)
43
+ # Optional Commands
44
+ GET_SEED = Command(0x12, 25)
45
+ UNLOCK = Command(0x13, 25)
46
+ DNLOAD_6 = Command(0x23, 25)
47
+ SHORT_UP = Command(0x0F, 25)
48
+ SELECT_CAL_PAGE = Command(0x11, 25)
49
+ SET_S_STATUS = Command(0x0C, 25)
50
+ GET_S_STATUS = Command(0x0D, 25)
51
+ BUILD_CHKSUM = Command(0x0E, 30000)
52
+ CLEAR_MEMORY = Command(0x10, 30000)
53
+ PROGRAM = Command(0x18, 100)
54
+ PROGRAM_6 = Command(0x22, 100)
55
+ MOVE = Command(0x19, 30000)
56
+ TEST = Command(0x05, 25)
57
+ GET_ACTIVE_CAL_PAGE = Command(0x09, 25)
58
+ START_STOP_ALL = Command(0x08, 25)
59
+ DIAG_SERVICE = Command(0x20, 500)
60
+ ACTION_SERVICE = Command(0x21, 5000)
61
+
62
+
63
+ class ReturnCodes(enum.IntEnum):
64
+ ACKNOWLEDGE = 0x00
65
+ DAQ_PROCESSOR_OVERLOAD = 0x01 # C0
66
+ COMMAND_PROCESSOR_BUSY = 0x10 # C1 NONE (wait until ACK or timeout)
67
+ DAQ_PROCESSOR_BUSY = 0x11 # C1 NONE (wait until ACK or timeout)
68
+ INTERNAL_TIMEOUT = 0x12 # C1 NONE (wait until ACK or timeout)
69
+ KEY_REQUEST = 0x18 # C1 NONE (embedded seed&key)
70
+ SESSION_STATUS_REQUEST = 0x19 # C1 NONE (embedded SET_S_STATUS)
71
+ COLD_START_REQUEST = 0x20 # C2 COLD START
72
+ CAL_DATA_INIT_REQUEST = 0x21 # C2 cal. data initialization
73
+ DAQ_LIST_INIT_REQUEST = 0x22 # C2 DAQ list initialization
74
+ CODE_UPDATE_REQUEST = 0x23 # C2 (COLD START)
75
+ UNKNOWN_COMMAND = 0x30 # C3 (FAULT)
76
+ COMMAND_SYNTAX = 0x31 # C3 FAULT
77
+ PARAMETER_OUT_OF_RANGE = 0x32 # C3 FAULT
78
+ ACCESS_DENIED = 0x33 # C3 FAULT
79
+ OVERLOAD = 0x34 # C3 FAULT
80
+ ACCESS_LOCKED = 0x35 # C3 FAULT
81
+ RESOURCE_FUNCTION_NOT_AVAILABLE = 0x36 # C3 FAULT
82
+
83
+
84
+ class DisconnectType(enum.IntEnum):
85
+ TEMPORARY = 0x00
86
+ PERMANENT = 0x01
87
+
88
+
89
+ class SecondaryResource(enum.IntEnum):
90
+ """
91
+ Enumeration for secondary resource types.
92
+
93
+ This enumeration defines constants representing different types of secondary
94
+ resources that can be used or required in various systems or operations.
95
+
96
+ :cvar CAL: Represents the calibration resource.
97
+ :cvar DAQ: Represents the data acquisition resource.
98
+ :cvar PGM: Represents the programming resource.
99
+ """
100
+
101
+ CAL = 1 << 0
102
+ DAQ = 1 << 1
103
+ PGM = 1 << 6
104
+
105
+
106
+ class DTO:
107
+ class Type(enum.IntEnum):
108
+ COMMAND_RETURN_MESSAGE = 255
109
+ EVENT_MESSAGE = 254
110
+
111
+
112
+ def verify_ctr(ctr: int, response: bytes) -> bool:
113
+ if len(response) < 3:
114
+ return False
115
+
116
+ return ctr == response[2]