sdwire 0.3.1__tar.gz → 0.5.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.
- sdwire-0.5.0/.gitignore +162 -0
- sdwire-0.5.0/PKG-INFO +211 -0
- sdwire-0.5.0/README.md +194 -0
- sdwire-0.5.0/pyproject.toml +44 -0
- {sdwire-0.3.1 → sdwire-0.5.0}/sdwire/backend/block_device_utils.py +38 -0
- {sdwire-0.3.1 → sdwire-0.5.0}/sdwire/backend/detect.py +29 -6
- sdwire-0.5.0/sdwire/backend/device/power.py +86 -0
- sdwire-0.5.0/sdwire/backend/device/sdwire.py +156 -0
- {sdwire-0.3.1 → sdwire-0.5.0}/sdwire/backend/device/sdwirec.py +4 -0
- sdwire-0.5.0/sdwire/backend/device/usb_sysfs.py +48 -0
- sdwire-0.5.0/sdwire/backend/utils.py +185 -0
- {sdwire-0.3.1 → sdwire-0.5.0}/sdwire/constants.py +4 -0
- {sdwire-0.3.1 → sdwire-0.5.0}/sdwire/main.py +25 -0
- sdwire-0.3.1/PKG-INFO +0 -113
- sdwire-0.3.1/README.md +0 -96
- sdwire-0.3.1/pyproject.toml +0 -25
- sdwire-0.3.1/sdwire/backend/device/sdwire.py +0 -99
- sdwire-0.3.1/sdwire/backend/utils.py +0 -131
- {sdwire-0.3.1 → sdwire-0.5.0}/LICENSE +0 -0
- {sdwire-0.3.1 → sdwire-0.5.0}/sdwire/__init__.py +0 -0
- {sdwire-0.3.1 → sdwire-0.5.0}/sdwire/backend/__init__.py +0 -0
- {sdwire-0.3.1 → sdwire-0.5.0}/sdwire/backend/device/usb_device.py +0 -0
sdwire-0.5.0/.gitignore
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
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
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# poetry
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
102
|
+
#poetry.lock
|
|
103
|
+
|
|
104
|
+
# pdm
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
106
|
+
#pdm.lock
|
|
107
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
108
|
+
# in version control.
|
|
109
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
110
|
+
.pdm.toml
|
|
111
|
+
.pdm-python
|
|
112
|
+
.pdm-build/
|
|
113
|
+
|
|
114
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
115
|
+
__pypackages__/
|
|
116
|
+
|
|
117
|
+
# Celery stuff
|
|
118
|
+
celerybeat-schedule
|
|
119
|
+
celerybeat.pid
|
|
120
|
+
|
|
121
|
+
# SageMath parsed files
|
|
122
|
+
*.sage.py
|
|
123
|
+
|
|
124
|
+
# Environments
|
|
125
|
+
.env
|
|
126
|
+
.venv
|
|
127
|
+
env/
|
|
128
|
+
venv/
|
|
129
|
+
ENV/
|
|
130
|
+
env.bak/
|
|
131
|
+
venv.bak/
|
|
132
|
+
|
|
133
|
+
# Spyder project settings
|
|
134
|
+
.spyderproject
|
|
135
|
+
.spyproject
|
|
136
|
+
|
|
137
|
+
# Rope project settings
|
|
138
|
+
.ropeproject
|
|
139
|
+
|
|
140
|
+
# mkdocs documentation
|
|
141
|
+
/site
|
|
142
|
+
|
|
143
|
+
# mypy
|
|
144
|
+
.mypy_cache/
|
|
145
|
+
.dmypy.json
|
|
146
|
+
dmypy.json
|
|
147
|
+
|
|
148
|
+
# Pyre type checker
|
|
149
|
+
.pyre/
|
|
150
|
+
|
|
151
|
+
# pytype static type analyzer
|
|
152
|
+
.pytype/
|
|
153
|
+
|
|
154
|
+
# Cython debug symbols
|
|
155
|
+
cython_debug/
|
|
156
|
+
|
|
157
|
+
# PyCharm
|
|
158
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
159
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
160
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
161
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
162
|
+
#.idea/
|
sdwire-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sdwire
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: CLI application to interact with Badgerd SDWire devices
|
|
5
|
+
Author-email: Talha Can Havadar <havadartalha@gmail.com>
|
|
6
|
+
License-Expression: GPL-3.0-only
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
12
|
+
Requires-Python: <4,>=3.12
|
|
13
|
+
Requires-Dist: click<9,>=8.1.7
|
|
14
|
+
Requires-Dist: pyftdi<0.57,>=0.56.0
|
|
15
|
+
Requires-Dist: pyusb<2,>=1.2.1
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# CLI for Badgerd SDWire Devices
|
|
19
|
+
|
|
20
|
+
Application also supports legacy SDWireC and non-Badger'd sdwires as well as
|
|
21
|
+
new Badgerd SDwire Gen2 devices.
|
|
22
|
+
|
|
23
|
+
Please see below for usage:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
❯ sdwire --help
|
|
27
|
+
Usage: sdwire [OPTIONS] COMMAND [ARGS]...
|
|
28
|
+
|
|
29
|
+
SDWire CLI - Control SDWire devices from command line.
|
|
30
|
+
|
|
31
|
+
Options:
|
|
32
|
+
--debug Enable debug output
|
|
33
|
+
--version Show the version and exit.
|
|
34
|
+
--help Show this message and exit.
|
|
35
|
+
|
|
36
|
+
Commands:
|
|
37
|
+
block-dev Print the block device path of the SD card, for use in scripts.
|
|
38
|
+
list List all connected SDWire devices with their block device...
|
|
39
|
+
state Query and display the state of all connected SDWire devices.
|
|
40
|
+
switch dut/target => connects the sdcard interface to target device
|
|
41
|
+
|
|
42
|
+
❯ sdwire switch --help
|
|
43
|
+
Usage: sdwire switch [OPTIONS] COMMAND [ARGS]...
|
|
44
|
+
|
|
45
|
+
dut/target => connects the sdcard interface to target device
|
|
46
|
+
|
|
47
|
+
ts/host => connects the sdcard interface to host machine
|
|
48
|
+
|
|
49
|
+
off => disconnects the sdcard interface from both host and target
|
|
50
|
+
|
|
51
|
+
Options:
|
|
52
|
+
-s, --serial TEXT Serial number of the sdwire device, if there is only one
|
|
53
|
+
sdwire connected then it will be used by default
|
|
54
|
+
--help Show this message and exit.
|
|
55
|
+
|
|
56
|
+
Commands:
|
|
57
|
+
dut dut/target => connects the sdcard interface to target device
|
|
58
|
+
host ts/host => connects the sdcard interface to host machine
|
|
59
|
+
off off => disconnects the sdcard interface from both host and target
|
|
60
|
+
target dut/target => connects the sdcard interface to target device
|
|
61
|
+
ts ts/host => connects the sdcard interface to host machine
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Installing
|
|
65
|
+
|
|
66
|
+
Using pip
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
pip install sdwire
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Using apt
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
sudo add-apt-repository ppa:tchavadar/badgerd
|
|
76
|
+
sudo apt install python3-sdwire
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Using a container (podman)
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
podman pull ghcr.io/badger-embedded/sdwire-cli:latest
|
|
83
|
+
# or build locally from the repository root
|
|
84
|
+
podman build -t sdwire -f Containerfile .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Running in a container
|
|
88
|
+
|
|
89
|
+
The image's entrypoint is `sdwire`, so arguments are passed directly. The
|
|
90
|
+
container needs access to the host USB devices (and block devices for
|
|
91
|
+
`sdwire list`), the simplest way is `--privileged`:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
podman run --rm --privileged ghcr.io/badger-embedded/sdwire-cli list
|
|
95
|
+
podman run --rm --privileged ghcr.io/badger-embedded/sdwire-cli switch dut
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Replace the image name with `sdwire` if you built it locally. A shell alias
|
|
99
|
+
makes it feel like a native install:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
alias sdwire='podman run --rm --privileged ghcr.io/badger-embedded/sdwire-cli'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
> **udev rules are required on the host.** udev runs on the host, not in the
|
|
106
|
+
> container, so install `udev/90-sdwire.rules` there for proper USB access and
|
|
107
|
+
> SDWire3 power management (autosuspend):
|
|
108
|
+
>
|
|
109
|
+
> ```
|
|
110
|
+
> sudo cp udev/90-sdwire.rules /etc/udev/rules.d/
|
|
111
|
+
> sudo udevadm control --reload-rules && sudo udevadm trigger
|
|
112
|
+
> ```
|
|
113
|
+
>
|
|
114
|
+
> Without them, USB access and card switching may fail with permission errors.
|
|
115
|
+
|
|
116
|
+
## Listing SDWire Devices
|
|
117
|
+
|
|
118
|
+
`sdwire list` command will search through usb devices connected to the system
|
|
119
|
+
and prints out the list of gen2 and legacy devices.
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
❯ sdwire list
|
|
123
|
+
Serial Product Info
|
|
124
|
+
sdwire_gen2_101 [SDWire-Gen2::Badgerd Technologies]
|
|
125
|
+
bdgrd_sdwirec_522 [sd-wire::SRPOL]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Switching SD Card Connection
|
|
129
|
+
|
|
130
|
+
`sdwire switch` command switches the sd card connection to specified direction.
|
|
131
|
+
If there is more than one sdwire connected to then you need specify which sdwire
|
|
132
|
+
you want to alter with `--serial` or `-s` options.
|
|
133
|
+
|
|
134
|
+
If there is only one sdwire connected then you dont need to specify the serial,
|
|
135
|
+
it will pick the one connected automatically. See the examples below.
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
❯ sdwire list
|
|
139
|
+
Serial Product Info
|
|
140
|
+
sdwire_gen2_101 [SDWire-Gen2::Badgerd Technologies]
|
|
141
|
+
bdgrd_sdwirec_522 [sd-wire::SRPOL]
|
|
142
|
+
|
|
143
|
+
❯ sdwire switch -s bdgrd_sdwirec_522 target
|
|
144
|
+
|
|
145
|
+
❯ sdwire switch target
|
|
146
|
+
Usage: sdwire switch [OPTIONS] COMMAND [ARGS]...
|
|
147
|
+
Try 'sdwire switch --help' for help.
|
|
148
|
+
|
|
149
|
+
Error: There is more then 1 sdwire device connected, please use --serial|-s to specify!
|
|
150
|
+
|
|
151
|
+
❯ sdwire list
|
|
152
|
+
Serial Product Info
|
|
153
|
+
bdgrd_sdwirec_522 [sd-wire::SRPOL]
|
|
154
|
+
|
|
155
|
+
❯ sdwire switch host
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Getting the Block Device Path
|
|
159
|
+
|
|
160
|
+
`sdwire block-dev` prints only the block device path of the SD card (e.g.
|
|
161
|
+
`/dev/sdb`), so it can be used directly in scripts. Errors and warnings go to
|
|
162
|
+
stderr, so stdout stays clean. Like `switch`, use `--serial`/`-s` when more than
|
|
163
|
+
one sdwire is connected.
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
❯ sdwire switch -s bdgrd_sdwirec_522 host
|
|
167
|
+
❯ sudo bmaptool copy disk.img "$(sdwire block-dev -s bdgrd_sdwirec_522)"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Right after `sdwire switch host` the block device needs a moment to become
|
|
171
|
+
usable: SDWire3 re-enumerates (~2 s) and SDWireC needs the kernel to detect the
|
|
172
|
+
card (up to ~2 s). `block-dev` waits up to 5 seconds for it. If the device
|
|
173
|
+
reports target mode it fails immediately instead of waiting. On macOS, an
|
|
174
|
+
existing disk node is assumed to be usable.
|
|
175
|
+
|
|
176
|
+
| Exit code | Meaning |
|
|
177
|
+
| --------- | -------------------------------------------------------------------------- |
|
|
178
|
+
| 0 | Path printed to stdout |
|
|
179
|
+
| 1 | Device found but no usable block device (target mode, no SD card, timeout) |
|
|
180
|
+
| 2 | No device, unknown serial, or more than one device without `--serial` |
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
❯ sdwire switch target
|
|
184
|
+
❯ sdwire block-dev
|
|
185
|
+
Error: 20120501030900000.1 is in target mode, run 'sdwire switch host' first
|
|
186
|
+
❯ echo $?
|
|
187
|
+
1
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### SDWire3 and Linux USB power management
|
|
191
|
+
|
|
192
|
+
On Linux, the SDWire3 only hands the SD card to the target while the USB device
|
|
193
|
+
is runtime-suspended. `sdwire switch target` enables this automatically
|
|
194
|
+
(`power/autosuspend_delay_ms=0`, `power/control=auto`) and verifies that
|
|
195
|
+
`power/runtime_status` becomes `suspended`; otherwise it exits with an error.
|
|
196
|
+
Writing to sysfs requires root, or install `udev/90-sdwire.rules`, which applies
|
|
197
|
+
the setting when the device is plugged in.
|
|
198
|
+
|
|
199
|
+
To do it by hand (replace `2-8` with your device's sysfs name, e.g. `5-1`):
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
echo 0 | sudo tee /sys/bus/usb/devices/2-8/power/autosuspend_delay_ms
|
|
203
|
+
echo auto | sudo tee /sys/bus/usb/devices/2-8/power/control
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Testing
|
|
207
|
+
|
|
208
|
+
Unit tests: `uv run pytest tests`.
|
|
209
|
+
|
|
210
|
+
End-to-end tests run the installed CLI against simulated devices (umockdev) or
|
|
211
|
+
real hardware. See [tests/e2e/README.md](tests/e2e/README.md).
|
sdwire-0.5.0/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# CLI for Badgerd SDWire Devices
|
|
2
|
+
|
|
3
|
+
Application also supports legacy SDWireC and non-Badger'd sdwires as well as
|
|
4
|
+
new Badgerd SDwire Gen2 devices.
|
|
5
|
+
|
|
6
|
+
Please see below for usage:
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
❯ sdwire --help
|
|
10
|
+
Usage: sdwire [OPTIONS] COMMAND [ARGS]...
|
|
11
|
+
|
|
12
|
+
SDWire CLI - Control SDWire devices from command line.
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--debug Enable debug output
|
|
16
|
+
--version Show the version and exit.
|
|
17
|
+
--help Show this message and exit.
|
|
18
|
+
|
|
19
|
+
Commands:
|
|
20
|
+
block-dev Print the block device path of the SD card, for use in scripts.
|
|
21
|
+
list List all connected SDWire devices with their block device...
|
|
22
|
+
state Query and display the state of all connected SDWire devices.
|
|
23
|
+
switch dut/target => connects the sdcard interface to target device
|
|
24
|
+
|
|
25
|
+
❯ sdwire switch --help
|
|
26
|
+
Usage: sdwire switch [OPTIONS] COMMAND [ARGS]...
|
|
27
|
+
|
|
28
|
+
dut/target => connects the sdcard interface to target device
|
|
29
|
+
|
|
30
|
+
ts/host => connects the sdcard interface to host machine
|
|
31
|
+
|
|
32
|
+
off => disconnects the sdcard interface from both host and target
|
|
33
|
+
|
|
34
|
+
Options:
|
|
35
|
+
-s, --serial TEXT Serial number of the sdwire device, if there is only one
|
|
36
|
+
sdwire connected then it will be used by default
|
|
37
|
+
--help Show this message and exit.
|
|
38
|
+
|
|
39
|
+
Commands:
|
|
40
|
+
dut dut/target => connects the sdcard interface to target device
|
|
41
|
+
host ts/host => connects the sdcard interface to host machine
|
|
42
|
+
off off => disconnects the sdcard interface from both host and target
|
|
43
|
+
target dut/target => connects the sdcard interface to target device
|
|
44
|
+
ts ts/host => connects the sdcard interface to host machine
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Installing
|
|
48
|
+
|
|
49
|
+
Using pip
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
pip install sdwire
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Using apt
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
sudo add-apt-repository ppa:tchavadar/badgerd
|
|
59
|
+
sudo apt install python3-sdwire
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Using a container (podman)
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
podman pull ghcr.io/badger-embedded/sdwire-cli:latest
|
|
66
|
+
# or build locally from the repository root
|
|
67
|
+
podman build -t sdwire -f Containerfile .
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Running in a container
|
|
71
|
+
|
|
72
|
+
The image's entrypoint is `sdwire`, so arguments are passed directly. The
|
|
73
|
+
container needs access to the host USB devices (and block devices for
|
|
74
|
+
`sdwire list`), the simplest way is `--privileged`:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
podman run --rm --privileged ghcr.io/badger-embedded/sdwire-cli list
|
|
78
|
+
podman run --rm --privileged ghcr.io/badger-embedded/sdwire-cli switch dut
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Replace the image name with `sdwire` if you built it locally. A shell alias
|
|
82
|
+
makes it feel like a native install:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
alias sdwire='podman run --rm --privileged ghcr.io/badger-embedded/sdwire-cli'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
> **udev rules are required on the host.** udev runs on the host, not in the
|
|
89
|
+
> container, so install `udev/90-sdwire.rules` there for proper USB access and
|
|
90
|
+
> SDWire3 power management (autosuspend):
|
|
91
|
+
>
|
|
92
|
+
> ```
|
|
93
|
+
> sudo cp udev/90-sdwire.rules /etc/udev/rules.d/
|
|
94
|
+
> sudo udevadm control --reload-rules && sudo udevadm trigger
|
|
95
|
+
> ```
|
|
96
|
+
>
|
|
97
|
+
> Without them, USB access and card switching may fail with permission errors.
|
|
98
|
+
|
|
99
|
+
## Listing SDWire Devices
|
|
100
|
+
|
|
101
|
+
`sdwire list` command will search through usb devices connected to the system
|
|
102
|
+
and prints out the list of gen2 and legacy devices.
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
❯ sdwire list
|
|
106
|
+
Serial Product Info
|
|
107
|
+
sdwire_gen2_101 [SDWire-Gen2::Badgerd Technologies]
|
|
108
|
+
bdgrd_sdwirec_522 [sd-wire::SRPOL]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Switching SD Card Connection
|
|
112
|
+
|
|
113
|
+
`sdwire switch` command switches the sd card connection to specified direction.
|
|
114
|
+
If there is more than one sdwire connected to then you need specify which sdwire
|
|
115
|
+
you want to alter with `--serial` or `-s` options.
|
|
116
|
+
|
|
117
|
+
If there is only one sdwire connected then you dont need to specify the serial,
|
|
118
|
+
it will pick the one connected automatically. See the examples below.
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
❯ sdwire list
|
|
122
|
+
Serial Product Info
|
|
123
|
+
sdwire_gen2_101 [SDWire-Gen2::Badgerd Technologies]
|
|
124
|
+
bdgrd_sdwirec_522 [sd-wire::SRPOL]
|
|
125
|
+
|
|
126
|
+
❯ sdwire switch -s bdgrd_sdwirec_522 target
|
|
127
|
+
|
|
128
|
+
❯ sdwire switch target
|
|
129
|
+
Usage: sdwire switch [OPTIONS] COMMAND [ARGS]...
|
|
130
|
+
Try 'sdwire switch --help' for help.
|
|
131
|
+
|
|
132
|
+
Error: There is more then 1 sdwire device connected, please use --serial|-s to specify!
|
|
133
|
+
|
|
134
|
+
❯ sdwire list
|
|
135
|
+
Serial Product Info
|
|
136
|
+
bdgrd_sdwirec_522 [sd-wire::SRPOL]
|
|
137
|
+
|
|
138
|
+
❯ sdwire switch host
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Getting the Block Device Path
|
|
142
|
+
|
|
143
|
+
`sdwire block-dev` prints only the block device path of the SD card (e.g.
|
|
144
|
+
`/dev/sdb`), so it can be used directly in scripts. Errors and warnings go to
|
|
145
|
+
stderr, so stdout stays clean. Like `switch`, use `--serial`/`-s` when more than
|
|
146
|
+
one sdwire is connected.
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
❯ sdwire switch -s bdgrd_sdwirec_522 host
|
|
150
|
+
❯ sudo bmaptool copy disk.img "$(sdwire block-dev -s bdgrd_sdwirec_522)"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Right after `sdwire switch host` the block device needs a moment to become
|
|
154
|
+
usable: SDWire3 re-enumerates (~2 s) and SDWireC needs the kernel to detect the
|
|
155
|
+
card (up to ~2 s). `block-dev` waits up to 5 seconds for it. If the device
|
|
156
|
+
reports target mode it fails immediately instead of waiting. On macOS, an
|
|
157
|
+
existing disk node is assumed to be usable.
|
|
158
|
+
|
|
159
|
+
| Exit code | Meaning |
|
|
160
|
+
| --------- | -------------------------------------------------------------------------- |
|
|
161
|
+
| 0 | Path printed to stdout |
|
|
162
|
+
| 1 | Device found but no usable block device (target mode, no SD card, timeout) |
|
|
163
|
+
| 2 | No device, unknown serial, or more than one device without `--serial` |
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
❯ sdwire switch target
|
|
167
|
+
❯ sdwire block-dev
|
|
168
|
+
Error: 20120501030900000.1 is in target mode, run 'sdwire switch host' first
|
|
169
|
+
❯ echo $?
|
|
170
|
+
1
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### SDWire3 and Linux USB power management
|
|
174
|
+
|
|
175
|
+
On Linux, the SDWire3 only hands the SD card to the target while the USB device
|
|
176
|
+
is runtime-suspended. `sdwire switch target` enables this automatically
|
|
177
|
+
(`power/autosuspend_delay_ms=0`, `power/control=auto`) and verifies that
|
|
178
|
+
`power/runtime_status` becomes `suspended`; otherwise it exits with an error.
|
|
179
|
+
Writing to sysfs requires root, or install `udev/90-sdwire.rules`, which applies
|
|
180
|
+
the setting when the device is plugged in.
|
|
181
|
+
|
|
182
|
+
To do it by hand (replace `2-8` with your device's sysfs name, e.g. `5-1`):
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
echo 0 | sudo tee /sys/bus/usb/devices/2-8/power/autosuspend_delay_ms
|
|
186
|
+
echo auto | sudo tee /sys/bus/usb/devices/2-8/power/control
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Testing
|
|
190
|
+
|
|
191
|
+
Unit tests: `uv run pytest tests`.
|
|
192
|
+
|
|
193
|
+
End-to-end tests run the installed CLI against simulated devices (umockdev) or
|
|
194
|
+
real hardware. See [tests/e2e/README.md](tests/e2e/README.md).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "sdwire"
|
|
3
|
+
version = "0.5.0"
|
|
4
|
+
description = "CLI application to interact with Badgerd SDWire devices"
|
|
5
|
+
authors = [{ name = "Talha Can Havadar", email = "havadartalha@gmail.com" }]
|
|
6
|
+
requires-python = ">=3.12,<4"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
license = "GPL-3.0-only"
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Programming Language :: Python :: 3",
|
|
11
|
+
"Programming Language :: Python :: 3.12",
|
|
12
|
+
"Programming Language :: Python :: 3.13",
|
|
13
|
+
"Programming Language :: Python :: 3.14",
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"click>=8.1.7,<9",
|
|
17
|
+
"pyusb>=1.2.1,<2",
|
|
18
|
+
"pyftdi>=0.56.0,<0.57",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
sdwire = "sdwire:main.main"
|
|
23
|
+
|
|
24
|
+
[dependency-groups]
|
|
25
|
+
dev = [
|
|
26
|
+
"black>=24.8.0,<25",
|
|
27
|
+
"pytest>=9.2.0,<10",
|
|
28
|
+
]
|
|
29
|
+
# harness of the end-to-end tests (tests/e2e), installed on its own in CI
|
|
30
|
+
e2e = [
|
|
31
|
+
"pytest>=9.2.0,<10",
|
|
32
|
+
"pytest-timeout>=2.4.0,<3",
|
|
33
|
+
"syrupy>=6.1.1,<7",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build.targets.sdist]
|
|
37
|
+
include = ["sdwire"]
|
|
38
|
+
|
|
39
|
+
[tool.hatch.build.targets.wheel]
|
|
40
|
+
include = ["sdwire"]
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["hatchling"]
|
|
44
|
+
build-backend = "hatchling.build"
|
|
@@ -5,6 +5,7 @@ to their corresponding block device paths (e.g., /dev/sda on Linux, /dev/disk2 o
|
|
|
5
5
|
It uses USB hierarchy and topology information for accurate device mapping.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import os
|
|
8
9
|
import platform
|
|
9
10
|
import logging
|
|
10
11
|
import re
|
|
@@ -23,6 +24,43 @@ from sdwire.constants import (
|
|
|
23
24
|
|
|
24
25
|
log = logging.getLogger(__name__)
|
|
25
26
|
|
|
27
|
+
SYSFS_ROOT = "/sys"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _read_sysfs(path: str) -> Optional[str]:
|
|
31
|
+
try:
|
|
32
|
+
with open(path) as f:
|
|
33
|
+
return f.read().strip()
|
|
34
|
+
except OSError:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _sysfs_block_dir(block_dev: str, sysfs_root: str) -> str:
|
|
39
|
+
return os.path.join(sysfs_root, "class", "block", os.path.basename(block_dev))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def is_block_dev_usable(block_dev: str, sysfs_root: str = SYSFS_ROOT) -> bool:
|
|
43
|
+
"""Return True when the block device has a medium and is ready for I/O.
|
|
44
|
+
|
|
45
|
+
Card readers (e.g. SDWireC) keep their block device while no medium is
|
|
46
|
+
present, reporting a size of 0. Uses sysfs only, so no permissions on the
|
|
47
|
+
device node are needed. Without sysfs (macOS) existence of the node is
|
|
48
|
+
the best available signal.
|
|
49
|
+
"""
|
|
50
|
+
if not os.path.isdir(os.path.join(sysfs_root, "class", "block")):
|
|
51
|
+
return os.path.exists(block_dev)
|
|
52
|
+
base = _sysfs_block_dir(block_dev, sysfs_root)
|
|
53
|
+
size = _read_sysfs(os.path.join(base, "size"))
|
|
54
|
+
if not size or not size.isdigit() or int(size) == 0:
|
|
55
|
+
return False
|
|
56
|
+
state = _read_sysfs(os.path.join(base, "device", "state"))
|
|
57
|
+
return state in (None, "running")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def is_block_dev_readonly(block_dev: str, sysfs_root: str = SYSFS_ROOT) -> bool:
|
|
61
|
+
base = _sysfs_block_dir(block_dev, sysfs_root)
|
|
62
|
+
return _read_sysfs(os.path.join(base, "ro")) == "1"
|
|
63
|
+
|
|
26
64
|
|
|
27
65
|
def map_usb_device_to_block_device(usb_device: usb.core.Device) -> Optional[str]:
|
|
28
66
|
"""Map a USB device to its corresponding system block device path using USB hierarchy.
|