Skip to content

Commit d880108

Browse files
committed
First commit
0 parents  commit d880108

8 files changed

Lines changed: 782 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: ["**"]
6+
pull_request:
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
test:
14+
runs-on: ubuntu-latest
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
python-version: ["3.9","3.10","3.11","3.12","3.13"]
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- uses: actions/setup-python@v5
24+
with:
25+
python-version: ${{ matrix.python-version }}
26+
cache: pip
27+
cache-dependency-path: pyproject.toml
28+
29+
- name: Install package + dev deps
30+
run: |
31+
python -m pip install --upgrade pip
32+
pip install -e .[dev]
33+
34+
- name: Lint (ruff)
35+
run: |
36+
ruff --version
37+
ruff check can_waveshare tests --output-format=github || true
38+
39+
- name: Run tests
40+
run: pytest -q
41+
42+
- name: Verify entry point is discoverable
43+
run: |
44+
python - <<'PY'
45+
import importlib.metadata as md, can
46+
eps = md.entry_points().select(group='can.interface')
47+
names = {ep.name for ep in eps}
48+
assert 'waveshare' in names, names
49+
cls = [ep for ep in eps if ep.name == 'waveshare'][0].load()
50+
assert issubclass(cls, can.BusABC), cls
51+
print("Entry point present and loadable:", cls)
52+
PY
53+
54+
55+
- name: Build sdist & wheel
56+
run: |
57+
python -m pip install --upgrade build
58+
python -m build
59+
60+
- name: Check install from wheel
61+
run: |
62+
pip install --force-reinstall --no-deps dist/*.whl
63+
python - <<'PY'
64+
import importlib.metadata as md, can
65+
eps = md.entry_points().select(group='can.interface')
66+
assert any(ep.name=='waveshare' for ep in eps), eps
67+
print("Installed wheel exposes entry point OK.")
68+
PY
69+

.gitignore

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# --- Python bytecode / caches ---
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
.python-version
6+
7+
# --- Build / packaging artifacts ---
8+
build/
9+
dist/
10+
*.egg-info/
11+
.eggs/
12+
pip-wheel-metadata/
13+
.wheelhouse/
14+
15+
# --- Virtual environments ---
16+
.venv/
17+
venv/
18+
env/
19+
ENV/
20+
21+
# --- Test / coverage ---
22+
.pytest_cache/
23+
.coverage
24+
.coverage.*
25+
htmlcov/
26+
coverage.xml
27+
.tox/
28+
.nox/
29+
30+
# --- Type checking / lint caches ---
31+
.mypy_cache/
32+
.pytype/
33+
.ruff_cache/
34+
.pyright/
35+
.dmypy.json
36+
.pyre/
37+
38+
# --- Logs ---
39+
*.log
40+
41+
# --- Docs / sites (we keep docs/ markdown, ignore built site) ---
42+
site/
43+
docs/_build/
44+
45+
# --- IDE / editor ---
46+
.vscode/
47+
.idea/
48+
*.code-workspace
49+
50+
# --- OS cruft ---
51+
.DS_Store
52+
Thumbs.db
53+
54+
# --- Editor swap files ---
55+
*.swp
56+
*.swo
57+
58+
# --- Notebooks ---
59+
.ipynb_checkpoints/
60+
61+
# --- Local env files / secrets ---
62+
.env
63+
.env.*
64+
*.env
65+
66+
# --- Temporary scratch ---
67+
tmp/
68+
temp/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Klaudiusz Staniek
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
20+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+
DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# can-waveshare
2+
3+
**python-can** backend for the **Waveshare 2-CH-CAN-TO-ETH** bridge that uses a fixed **13‑byte** TCP wire format.
4+
Works with `python -m can.viewer/logger/player` and plain `can.Bus(...)`.
5+
6+
> Transport: TCP server on the device (e.g., `:20001` for CAN1, `:20002` for CAN2).
7+
> Frames: 13 bytes: `[flags/dlc][id:4][data:0..8 padded]`
8+
9+
## Install
10+
11+
```bash
12+
pip install can-waveshare
13+
# or from source (editable):
14+
pip install -e .[dev]
15+
```
16+
17+
## Use with CLI
18+
19+
```bash
20+
# Most portable: pass channel as host:port
21+
python -m can.viewer -i waveshare -c 172.31.11.67:20001
22+
23+
# Or forward kwargs directly to the bus:
24+
python -m can.viewer -i waveshare --bus-kwargs host=172.31.11.67 port=20001
25+
```
26+
27+
### Config via `~/.canrc`
28+
29+
The stock CLIs read only the **[default]** section. Put this in `~/.canrc`:
30+
31+
```ini
32+
[default]
33+
interface = waveshare
34+
channel = 172.31.11.67:20001
35+
```
36+
37+
Then:
38+
39+
```bash
40+
python -m can.viewer
41+
```
42+
43+
If you want multiple profiles, either (a) swap rc files or (b) write a tiny launcher in code and use `Bus(config_context="waveshare2")` to select other sections.
44+
45+
## Use in code
46+
47+
```python
48+
import can
49+
50+
# explicit kwargs:
51+
with can.Bus(interface="waveshare", host="172.31.11.67", port=20001) as bus:
52+
bus.send(can.Message(arbitration_id=0x123, data=b"\x11\x22\x33", is_extended_id=False))
53+
print(bus.recv(1.0))
54+
55+
# or via channel (parses host:port, tcp://host:port, [ipv6]:port, or aliases can1/can2):
56+
with can.Bus(interface="waveshare", channel="172.31.11.67:20001") as bus:
57+
print(bus.recv(1.0))
58+
```
59+
60+
## Features & Notes
61+
62+
- CAN 2.0 (0..8 data bytes). **CAN‑FD not supported** by Waveshare wire format.
63+
- Software filters (`can_filters`) supported in the backend.
64+
- Best‑effort own‑echo suppression when `receive_own_messages=False` (default). Set `True` to see echoes.
65+
- Periodic TX via `bus.send_periodic(...)` works (python-can broadcast manager calls `send()` repeatedly).
66+
67+
## License
68+
69+
MIT

can_waveshare/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .bus import WaveShareBus as Bus, WaveShareBus
2+
3+
__all__ = ["WaveShareBus", "Bus"]

0 commit comments

Comments
 (0)