python-can-cansub 2026.7.2__tar.gz → 2026.8.17__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.
- {python_can_cansub-2026.7.2 → python_can_cansub-2026.8.17}/.gitignore +1 -0
- python_can_cansub-2026.8.17/CHANGELOG.md +43 -0
- {python_can_cansub-2026.7.2 → python_can_cansub-2026.8.17}/PKG-INFO +125 -64
- {python_can_cansub-2026.7.2 → python_can_cansub-2026.8.17}/README.md +121 -62
- {python_can_cansub-2026.7.2 → python_can_cansub-2026.8.17}/pyproject.toml +13 -4
- python_can_cansub-2026.8.17/src/python_can_cansub/__init__.py +14 -0
- python_can_cansub-2026.8.17/src/python_can_cansub/cansub.py +1346 -0
- python_can_cansub-2026.8.17/src/python_can_cansub/cansub_csv.py +125 -0
- {python_can_cansub-2026.7.2 → python_can_cansub-2026.8.17}/src/python_can_cansub/cansub_protocol.py +6 -3
- python_can_cansub-2026.8.17/tests/README.md +14 -0
- python_can_cansub-2026.8.17/tests/bus/test_open_close.py +167 -0
- python_can_cansub-2026.8.17/tests/cmdline/test_cmdline.py +146 -0
- python_can_cansub-2026.8.17/tests/conftest.py +79 -0
- python_can_cansub-2026.8.17/tests/detect/test_detect.py +26 -0
- python_can_cansub-2026.8.17/tests/errors/test_error_frames.py +26 -0
- python_can_cansub-2026.8.17/tests/filters/test_filters.py +64 -0
- python_can_cansub-2026.8.17/tests/io/test_csv_io.py +127 -0
- python_can_cansub-2026.8.17/tests/periodic/test_periodic.py +65 -0
- python_can_cansub-2026.8.17/tests/send_recv/test_send_recv.py +110 -0
- python_can_cansub-2026.7.2/CHANGELOG.md +0 -26
- python_can_cansub-2026.7.2/private_repo/README.md +0 -1
- python_can_cansub-2026.7.2/private_repo/README_BUILD.md +0 -6
- python_can_cansub-2026.7.2/private_repo/README_DEV.md +0 -5
- python_can_cansub-2026.7.2/private_repo/README_PYPI.md +0 -58
- python_can_cansub-2026.7.2/private_repo/README_REPO.md +0 -43
- python_can_cansub-2026.7.2/src/python_can_cansub/__init__.py +0 -4
- python_can_cansub-2026.7.2/src/python_can_cansub/cansub.py +0 -975
- {python_can_cansub-2026.7.2 → python_can_cansub-2026.8.17}/src/python_can_cansub/cansub_root_cert.crt +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## 2026.08.17 (API 04.00)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `max_device_time_skew`: device/host clock skew (s) tolerated before setting the device clock on open (`None`=never).
|
|
9
|
+
- `receive_own_messages`: receive the messages transmitted by the bus itself (default `False`).
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Supported device API version changed from `03.00` to `04.00`.
|
|
13
|
+
- The device hostname is now resolved only once on bus open, reducing connection time.
|
|
14
|
+
- `data_bitrate` is now optional. When omitted, transmissions of FD frames are rejected.
|
|
15
|
+
- Updated shutdown sequence (using `DELETE` on the websocket resource after `shutdown_timeout` timeout).
|
|
16
|
+
|
|
17
|
+
### Removed
|
|
18
|
+
- `server_cert`: the server certificate is now always verified against the built-in CANsub root certificate.
|
|
19
|
+
When connecting via an IP address, certificate hostname verification is automatically disabled
|
|
20
|
+
(certificate chain verification remains active).
|
|
21
|
+
|
|
22
|
+
## 2026.07.02 (API 03.00)
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- `server_cert`: path to the server certificate (`.crt` file).
|
|
26
|
+
- `client_cert`: tuple of paths to the client certificate and key (`.crt`, `.key`), used for TLS mutual authentication.
|
|
27
|
+
- Warning when devices with unsupported API versions are found.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- Supported device API version changed from `02.00` to `03.00`.
|
|
31
|
+
|
|
32
|
+
## 2026.06.02 (API 02.00)
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- `CANSUB_ROOT_CERT`: path to the CANsub root certificate.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- Transmit sequences (on the device) are deleted on bus open.
|
|
39
|
+
|
|
40
|
+
## 2026.06.01 (API 02.00)
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- `CyclicSendTask` with `duration=None` now working.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: python-can-cansub
|
|
3
|
-
Version: 2026.
|
|
3
|
+
Version: 2026.8.17
|
|
4
4
|
Summary: CANsub python-can interface
|
|
5
5
|
Project-URL: Homepage, https://csselectronics.com/
|
|
6
6
|
Project-URL: Source, https://github.com/CSS-Electronics/python-can-cansub
|
|
@@ -16,6 +16,8 @@ Requires-Dist: python-can>=4.6.0
|
|
|
16
16
|
Requires-Dist: requests>=2.32.5
|
|
17
17
|
Requires-Dist: wsproto>=1.3.2
|
|
18
18
|
Requires-Dist: zeroconf>=0.131.0
|
|
19
|
+
Provides-Extra: test
|
|
20
|
+
Requires-Dist: pytest>=8.0; extra == 'test'
|
|
19
21
|
Description-Content-Type: text/markdown
|
|
20
22
|
|
|
21
23
|
# python-can-cansub
|
|
@@ -31,11 +33,11 @@ This package registers the CANsub as a standard python-can interface, making it
|
|
|
31
33
|
The python-can-cansub package and the CANsub device communicate over a versioned API. They are compatible when the package supports the API version used by the device firmware.
|
|
32
34
|
|
|
33
35
|
- Each **python-can-cansub** release supports one API version. The supported API version for each release is listed in the [python-can-cansub changelog](https://github.com/CSS-Electronics/python-can-cansub/blob/master/CHANGELOG.md).
|
|
34
|
-
- Each **CANsub firmware** release uses one API version. The API version for each firmware release is listed in the CANsub changelog (provided with the device).
|
|
36
|
+
- Each **CANsub firmware** release uses one API version. The API version for each firmware release is listed in the CANsub changelog (provided with the device documentation).
|
|
35
37
|
|
|
36
|
-
To check compatibility, look up the API version of the
|
|
38
|
+
To check compatibility, look up the API version of the python-can-cansub release and of the device firmware release in their respective changelogs. If they match, they are compatible.
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
Device *auto-detection* (see *Configuration*) skips devices with an unsupported API version and emits a `UserWarning`. Opening a bus on such a device raises `can.exceptions.CanInitializationError`. In either case, update the package or the device firmware so their API versions align.
|
|
39
41
|
|
|
40
42
|
## python-can API
|
|
41
43
|
|
|
@@ -55,16 +57,16 @@ import can
|
|
|
55
57
|
|
|
56
58
|
### Configuration
|
|
57
59
|
|
|
58
|
-
|
|
60
|
+
In python-can, a hardware *configuration* is defined by an `interface` and a `channel` (a single interface can have multiple channels).
|
|
59
61
|
|
|
60
|
-
The CANsub `interface` is
|
|
62
|
+
The CANsub `interface` is always `"cansub"`. The `channel` is constructed from the device's unique hostname and the channel index.
|
|
61
63
|
|
|
62
64
|
| Connection | Hostname | python-can `channel` string |
|
|
63
65
|
|------------|-------------------------|-----------------------------------|
|
|
64
66
|
| USB | `[DEVICE-ID]-usb.local` | `[DEVICE-ID]-usb.local@[channel]` |
|
|
65
67
|
| Ethernet | `[DEVICE-ID]-eth.local` | `[DEVICE-ID]-eth.local@[channel]` |
|
|
66
68
|
|
|
67
|
-
The
|
|
69
|
+
The `[DEVICE-ID]` is printed on the device label. Channel indexing is **1-based** - the first channel is `1`.
|
|
68
70
|
|
|
69
71
|
A configuration is passed to `can.Bus` to open a bus.
|
|
70
72
|
|
|
@@ -79,7 +81,7 @@ configs = [{"interface": "cansub", "channel": "aabbccdd-usb.local@1"},
|
|
|
79
81
|
|
|
80
82
|
#### Auto-detect
|
|
81
83
|
|
|
82
|
-
Example of using `detect_available_configs` to automatically discover
|
|
84
|
+
Example of using `detect_available_configs` to automatically discover all connected CANsub devices and channels via mDNS:
|
|
83
85
|
|
|
84
86
|
```python
|
|
85
87
|
configs = can.detect_available_configs(interfaces=["cansub"])
|
|
@@ -89,75 +91,53 @@ configs = can.detect_available_configs(interfaces=["cansub"])
|
|
|
89
91
|
# {"interface": "cansub", "channel": "11223344-eth.local@2"}]
|
|
90
92
|
```
|
|
91
93
|
|
|
92
|
-
In the above example two CANsub devices are detected, each with two channels. One device is connected via USB and the other via Ethernet.
|
|
94
|
+
In the above example, two CANsub devices are detected, each with two channels. One device is connected via USB and the other via Ethernet.
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
> **Note:** `data_bitrate` is required even on a classic (non-FD) bus. On a non-FD bus, simply set it to e.g. `1_000_000` (1 Mbit/s).
|
|
96
|
+
> **Note:** mDNS discovery relies on inbound UDP port 5353. If a host firewall blocks it, no devices are detected (a fixed configuration still works).
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
### Opening a Bus
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
The python-can-cansub constructor implements the required arguments for can.Bus and adds custom arguments specific to python-can-cansub. See the python-can-cansub constructor docstring for additional information.
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
A bus is opened by passing a configuration to `can.Bus`:
|
|
103
103
|
|
|
104
104
|
```python
|
|
105
105
|
with can.Bus(interface="cansub", channel="aabbccdd-usb.local@1", bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
106
106
|
pass
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
`**config` unpacks a config dict directly into `can.Bus` keyword arguments - convenient with auto-detected configs, and for opening multiple buses:
|
|
110
110
|
|
|
111
111
|
```python
|
|
112
|
-
with can.Bus(
|
|
112
|
+
with (can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus1,
|
|
113
|
+
can.Bus(**configs[1], bitrate=250_000, data_bitrate=1_000_000) as bus2):
|
|
113
114
|
pass
|
|
114
115
|
```
|
|
115
116
|
|
|
116
|
-
|
|
117
|
+
### Bit Timing
|
|
118
|
+
|
|
119
|
+
`bitrate` and `data_bitrate` configure the bus with a fixed sample point of 80%. For full control of the bit timing (sample point, SJW), pass a `can.BitTiming` (classic CAN) or `can.BitTimingFd` (CAN FD) as `timing` instead. The CANsub CAN clock is 80 MHz:
|
|
117
120
|
|
|
118
121
|
```python
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
timing = can.BitTimingFd.from_sample_point(f_clock=80_000_000,
|
|
123
|
+
nom_bitrate=250_000, nom_sample_point=87.5,
|
|
124
|
+
data_bitrate=1_000_000, data_sample_point=87.5)
|
|
125
|
+
|
|
126
|
+
with can.Bus(**configs[0], timing=timing) as bus:
|
|
121
127
|
pass
|
|
122
128
|
```
|
|
123
129
|
|
|
124
|
-
> **Tip:** `**config` unpacks a config dict directly into `can.Bus` keyword arguments:
|
|
125
|
-
>
|
|
126
|
-
> ```python
|
|
127
|
-
> with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
128
|
-
> pass
|
|
129
|
-
> ```
|
|
130
|
-
|
|
131
130
|
### TLS / Certificates
|
|
132
131
|
|
|
133
|
-
The data connection to the device is secured by TLS. When connecting via an IP address (
|
|
134
|
-
|
|
135
|
-
```python
|
|
136
|
-
with can.Bus(interface="cansub", channel="192.168.1.10@1", server_cert=None, bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
137
|
-
pass
|
|
138
|
-
```
|
|
132
|
+
The data connection to the device is secured by TLS, with the device certificate verified against the built-in CANsub root certificate. When connecting via an IP address (which carries no name to verify the certificate hostname against), hostname verification is automatically disabled - the certificate chain is still verified.
|
|
139
133
|
|
|
140
|
-
|
|
134
|
+
When TLS mutual authentication is enabled, `client_cert` can be used to provide a tuple of paths to the client certificate (`.crt` file) and its unencrypted private key (`.key` file):
|
|
141
135
|
|
|
142
136
|
```python
|
|
143
137
|
with can.Bus(**configs[0], client_cert=("/path/to/client.crt", "/path/to/client.key"), bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
144
138
|
pass
|
|
145
139
|
```
|
|
146
140
|
|
|
147
|
-
### Receive and Transmit
|
|
148
|
-
|
|
149
|
-
```python
|
|
150
|
-
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
151
|
-
|
|
152
|
-
# Transmit
|
|
153
|
-
msg_tx = can.Message(is_extended_id=False, arbitration_id=0x123, data=[0x01, 0x02, 0x03, 0x04])
|
|
154
|
-
bus.send(msg_tx)
|
|
155
|
-
|
|
156
|
-
# Receive with timeout
|
|
157
|
-
msg_rx = bus.recv(timeout=1.0)
|
|
158
|
-
print(msg_rx)
|
|
159
|
-
```
|
|
160
|
-
|
|
161
141
|
### Error Frames
|
|
162
142
|
|
|
163
143
|
Error frame reporting is disabled by default; enable it by passing `error_frames=True` to `can.Bus`. Bus errors are then received as a `can.Message` with `is_error_frame` set. The error type is encoded in `arbitration_id`, which can be converted to a `CanSubErrorFrameType` enum:
|
|
@@ -172,6 +152,15 @@ with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000, error_frames
|
|
|
172
152
|
print(f"Bus error: {error_type.name}") # e.g. "Bus error: ACK"
|
|
173
153
|
```
|
|
174
154
|
|
|
155
|
+
### Bus State
|
|
156
|
+
|
|
157
|
+
`bus.state` queries the current channel state: `can.BusState.ACTIVE` (error-active or error-warning), `can.BusState.PASSIVE` (error-passive), or `can.BusState.ERROR` (bus-off). Reading the state of a stopped channel (e.g. after a connection loss) or of a closed bus raises `can.exceptions.CanOperationError`:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
161
|
+
print(bus.state) # e.g. "BusState.ACTIVE"
|
|
162
|
+
```
|
|
163
|
+
|
|
175
164
|
### Filters
|
|
176
165
|
|
|
177
166
|
Apply hardware filters by passing `can_filters` to `can.Bus`. Each filter specifies a `can_id`, a `can_mask`, and whether to match standard (`extended=False`) or extended (`extended=True`) frames. A frame passes if `(frame_id & can_mask) == (can_id & can_mask)`.
|
|
@@ -189,6 +178,65 @@ with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000, can_filters=
|
|
|
189
178
|
|
|
190
179
|
> **Tip:** Applying hardware filters reduces the network load between the CANsub and the connected client.
|
|
191
180
|
|
|
181
|
+
### Receive and Transmit
|
|
182
|
+
|
|
183
|
+
A bus receives the messages transmitted by the other nodes on the CAN bus. Messages transmitted by the bus itself are not received, unless the bus is opened with `receive_own_messages=True`.
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
187
|
+
|
|
188
|
+
# Transmit
|
|
189
|
+
msg_tx = can.Message(is_extended_id=False, arbitration_id=0x123, data=[0x01, 0x02, 0x03, 0x04])
|
|
190
|
+
bus.send(msg_tx)
|
|
191
|
+
|
|
192
|
+
# Receive with timeout
|
|
193
|
+
msg_rx = bus.recv(timeout=1.0)
|
|
194
|
+
print(msg_rx)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### CAN FD
|
|
198
|
+
|
|
199
|
+
CAN FD frames are transmitted by setting `is_fd` (and typically `bitrate_switch`, which switches to `data_bitrate` for the payload). FD payloads can be up to 64 bytes. Transmitting an FD frame requires the bus to be opened with a `data_bitrate` (or an FD bit timing); on a classic CAN bus, FD transmission raises `can.exceptions.CanOperationError`:
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
203
|
+
msg_fd = can.Message(is_extended_id=False, arbitration_id=0x123,
|
|
204
|
+
is_fd=True, bitrate_switch=True, data=bytes(range(64)))
|
|
205
|
+
bus.send(msg_fd)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Error Handling
|
|
209
|
+
|
|
210
|
+
Operations on a failed bus raise `can.exceptions.CanOperationError`: `send()` and `recv()` raise it once the connection to the device is lost (detected within seconds, also on an idle bus). `send()` additionally raises `can.exceptions.CanTimeoutError` when the transmit queue stays full for the full timeout (back-pressure from a slow or blocked CAN bus). Failures to open a bus raise `can.exceptions.CanInitializationError`.
|
|
211
|
+
|
|
212
|
+
A failed bus does not recover, and the package does not reconnect automatically. To recover from a connection loss, close the failed bus and open a new one:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
try:
|
|
216
|
+
msg = bus.recv(timeout=1.0)
|
|
217
|
+
except can.CanOperationError:
|
|
218
|
+
# Connection lost: the bus cannot recover - close it and open a new one
|
|
219
|
+
bus.shutdown()
|
|
220
|
+
bus = can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Closing a Bus
|
|
224
|
+
|
|
225
|
+
Closing a bus (leaving the `with` block, or calling `bus.shutdown()`) waits up to `shutdown_timeout` seconds for the queued messages to be transmitted before asking the device to discard them (see the *Opening a Bus*).
|
|
226
|
+
|
|
227
|
+
Messages received up to (and during) the close remain retrievable with `recv()` after the bus is closed - drain until `None`:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
231
|
+
bus.send(can.Message(is_extended_id=False, arbitration_id=0x123, data=[0x01, 0x02, 0x03, 0x04]))
|
|
232
|
+
|
|
233
|
+
# The bus is closed (all queued messages transmitted)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
> **Tip:** When two buses are connected to the same physical CAN bus (e.g. a transmitter and a receiver), close the transmitting bus first - closing it waits for the queued messages to be transmitted, which requires the other (acknowledging) bus to still be open.
|
|
237
|
+
|
|
238
|
+
> **Tip:** A `can.Notifier` stops dispatching the moment it is stopped - received messages not yet dispatched are discarded (python-can behavior). Stop the notifier only once the traffic has settled, or read the messages with `recv()` instead.
|
|
239
|
+
|
|
192
240
|
### Notifier and Listeners
|
|
193
241
|
|
|
194
242
|
`bus.recv()` blocks until a frame arrives. A `can.Notifier` runs a background thread that dispatches received frames to one or more *listeners*, allowing the main program to continue other work.
|
|
@@ -209,15 +257,17 @@ with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
|
209
257
|
|
|
210
258
|
Periodic transmission jobs can be started with `bus.send_periodic()`.
|
|
211
259
|
|
|
212
|
-
|
|
260
|
+
Periodic transmission is offloaded to the CANsub hardware where possible, providing much better transmission time accuracy than a host-scheduled transmission. A host-side background task is used only as a fallback when hardware transmission is not available.
|
|
261
|
+
|
|
262
|
+
> **Note:** python-can requires all messages in a periodic task to share the same arbitration ID (the payload can differ per frame).
|
|
213
263
|
|
|
214
264
|
```python
|
|
215
265
|
from time import sleep
|
|
216
266
|
|
|
217
267
|
msgs = [
|
|
218
268
|
can.Message(is_extended_id=False, arbitration_id=0x123, data=[0x01, 0x02, 0x03, 0x04]),
|
|
219
|
-
can.Message(is_extended_id=False, arbitration_id=
|
|
220
|
-
can.Message(is_extended_id=False, arbitration_id=
|
|
269
|
+
can.Message(is_extended_id=False, arbitration_id=0x123, data=[0x05, 0x06, 0x07, 0x08]),
|
|
270
|
+
can.Message(is_extended_id=False, arbitration_id=0x123, data=[0x09, 0x0A, 0x0B, 0x0C]),
|
|
221
271
|
]
|
|
222
272
|
|
|
223
273
|
with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
@@ -229,7 +279,7 @@ with can.Bus(**configs[0], bitrate=250_000, data_bitrate=1_000_000) as bus:
|
|
|
229
279
|
sleep(6)
|
|
230
280
|
```
|
|
231
281
|
|
|
232
|
-
### Replaying
|
|
282
|
+
### Replaying Files
|
|
233
283
|
|
|
234
284
|
`can.MessageSync` can be used to replay messages from a log file.
|
|
235
285
|
|
|
@@ -262,9 +312,9 @@ with CanSubCSVReader("log.csv") as reader:
|
|
|
262
312
|
print(msg)
|
|
263
313
|
```
|
|
264
314
|
|
|
265
|
-
## python-can
|
|
315
|
+
## python-can Tools
|
|
266
316
|
|
|
267
|
-
python-can includes several command
|
|
317
|
+
python-can includes several command-line tools. All tools accept `--interface` and `--channel` to select the bus, following the same configuration as the API.
|
|
268
318
|
|
|
269
319
|
The common argument pattern for the CANsub:
|
|
270
320
|
|
|
@@ -272,7 +322,15 @@ The common argument pattern for the CANsub:
|
|
|
272
322
|
--interface cansub --channel aabbccdd-usb.local@1 --bitrate 250000 --data-bitrate 1000000
|
|
273
323
|
```
|
|
274
324
|
|
|
275
|
-
|
|
325
|
+
Bus arguments without a dedicated command-line flag are passed with `--bus-kwargs key=value ...`. For example, listen-only monitoring:
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
--interface cansub --channel 192.168.1.10@1 --bitrate 250000 --data-bitrate 1000000 --bus-kwargs listen_only=True
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
> **Note:** `--bus-kwargs` consumes all values that follow it; place positional arguments (e.g. the `can_player` log file) before it.
|
|
332
|
+
|
|
333
|
+
Note that the *filter* argument supported by some command-line tools matches both standard (11-bit) and extended (29-bit) CAN IDs.
|
|
276
334
|
|
|
277
335
|
### can_logger
|
|
278
336
|
|
|
@@ -298,11 +356,11 @@ Live terminal viewer showing received frames, updated counts, timestamps, and by
|
|
|
298
356
|
can_viewer --interface cansub --channel aabbccdd-usb.local@1 --bitrate 250000 --data-bitrate 1000000
|
|
299
357
|
```
|
|
300
358
|
|
|
301
|
-
On Windows,
|
|
359
|
+
On Windows, `can_viewer` requires `windows-curses` (`pip install windows-curses`).
|
|
302
360
|
|
|
303
361
|
### can_bridge
|
|
304
362
|
|
|
305
|
-
Forward all frames received on one bus to another (e.g
|
|
363
|
+
Forward all frames received on one bus to another (e.g., to bridge two CANsub channels):
|
|
306
364
|
|
|
307
365
|
```bash
|
|
308
366
|
can_bridge --bus1-interface cansub --bus1-channel aabbccdd-usb.local@1 --bus1-bitrate 250000 --bus1-data-bitrate 1000000 \
|
|
@@ -323,7 +381,7 @@ The following packages complement `python-can-cansub` and are included here as i
|
|
|
323
381
|
|
|
324
382
|
### cantools
|
|
325
383
|
|
|
326
|
-
[cantools](https://github.com/cantools/cantools) is a Python package for encoding and decoding CAN messages. Encoding/decoding rules can be created or loaded from DBC
|
|
384
|
+
[cantools](https://github.com/cantools/cantools) is a Python package for encoding and decoding CAN messages. Encoding/decoding rules can be created directly in code, or loaded from DBC and other database file formats. It works directly with `can.Message` objects from python-can.
|
|
327
385
|
|
|
328
386
|
#### Installation
|
|
329
387
|
|
|
@@ -337,20 +395,23 @@ A database can be constructed directly in Python without a database file:
|
|
|
337
395
|
|
|
338
396
|
```python
|
|
339
397
|
import cantools
|
|
340
|
-
|
|
341
|
-
db = cantools.database.Database()
|
|
398
|
+
from cantools.database.conversion import LinearConversion
|
|
342
399
|
|
|
343
400
|
msg_def = cantools.database.can.Message(
|
|
344
401
|
frame_id=0x123,
|
|
345
402
|
name="Message1",
|
|
346
403
|
length=8,
|
|
347
404
|
signals=[
|
|
348
|
-
cantools.database.can.Signal(name="Signal1", start=0,
|
|
349
|
-
|
|
405
|
+
cantools.database.can.Signal(name="Signal1", start=0, length=16,
|
|
406
|
+
conversion=LinearConversion(scale=0.1, offset=0.0, is_float=False),
|
|
407
|
+
minimum=0.0, maximum=100.0),
|
|
408
|
+
cantools.database.can.Signal(name="Signal2", start=16, length=16,
|
|
409
|
+
conversion=LinearConversion(scale=0.1, offset=0.0, is_float=False),
|
|
410
|
+
minimum=0.0, maximum=100.0),
|
|
350
411
|
]
|
|
351
412
|
)
|
|
352
413
|
|
|
353
|
-
db.
|
|
414
|
+
db = cantools.database.Database(messages=[msg_def])
|
|
354
415
|
```
|
|
355
416
|
|
|
356
417
|
#### Load database from DBC file
|