fpga-isv 0.1.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.
- fpga_isv-0.1.0/LICENSE +21 -0
- fpga_isv-0.1.0/PKG-INFO +151 -0
- fpga_isv-0.1.0/README.md +131 -0
- fpga_isv-0.1.0/fpga_isv/__init__.py +7 -0
- fpga_isv-0.1.0/fpga_isv/__main__.py +6 -0
- fpga_isv-0.1.0/fpga_isv/examples/ulx3s/README.md +21 -0
- fpga_isv-0.1.0/fpga_isv/examples/ulx3s/ULX3S_v303_top.png +0 -0
- fpga_isv-0.1.0/fpga_isv/examples/ulx3s/ulx3s.json +39 -0
- fpga_isv-0.1.0/fpga_isv/examples.py +39 -0
- fpga_isv-0.1.0/fpga_isv/viewer.py +609 -0
- fpga_isv-0.1.0/fpga_isv.egg-info/PKG-INFO +151 -0
- fpga_isv-0.1.0/fpga_isv.egg-info/SOURCES.txt +17 -0
- fpga_isv-0.1.0/fpga_isv.egg-info/dependency_links.txt +1 -0
- fpga_isv-0.1.0/fpga_isv.egg-info/entry_points.txt +2 -0
- fpga_isv-0.1.0/fpga_isv.egg-info/requires.txt +1 -0
- fpga_isv-0.1.0/fpga_isv.egg-info/top_level.txt +1 -0
- fpga_isv-0.1.0/pyproject.toml +42 -0
- fpga_isv-0.1.0/setup.cfg +4 -0
- fpga_isv-0.1.0/tests/test_protocol.py +82 -0
fpga_isv-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DFiant Inc.
|
|
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.
|
fpga_isv-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fpga-isv
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: fpga-isv (ISV = Interactive Sim Viewer): a config-driven graphical panel viewer for interactive-sim.
|
|
5
|
+
Author-email: Oron Port <oron.port@dfiant.works>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/DFiantWorks/interactive-sim-viewer
|
|
8
|
+
Project-URL: interactive-sim, https://github.com/DFiantWorks/interactive-sim
|
|
9
|
+
Keywords: fpga,simulation,viewer,hdl,interactive-sim,ulx3s
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: X11 Applications
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: pillow
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# fpga-isv — Interactive Sim Viewer
|
|
22
|
+
|
|
23
|
+
A cross-platform **graphical panel viewer** for
|
|
24
|
+
[interactive-sim](https://github.com/DFiantWorks/interactive-sim). It draws a board *photo* (or a
|
|
25
|
+
blank *panel* you mock up), overlays the LEDs and buttons at their pixel positions, and connects
|
|
26
|
+
that virtual panel to a running HDL simulation: **design-driven flags light the LEDs**, and
|
|
27
|
+
**clicking a button feeds a control back into the design**.
|
|
28
|
+
|
|
29
|
+
`fpga-isv` is a *pure client of the interactive-sim socket API* — it knows nothing about HDL or
|
|
30
|
+
simulators. Anything that speaks the same newline-delimited-JSON protocol works with it. The
|
|
31
|
+
[ULX3S](https://github.com/ulx3s/ulx3s) board ships as the bundled reference example.
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
fpga-isv --example ulx3s
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## How it connects
|
|
38
|
+
|
|
39
|
+
The viewer **listens** on a TCP port; the simulation **connects to it** (set
|
|
40
|
+
`INTERACTIVE_STREAM=host:port` for the sim). This means you can:
|
|
41
|
+
|
|
42
|
+
- **open and close the viewer at any time** — the sim's backend keeps reconnecting;
|
|
43
|
+
- **stop or restart the simulation** while the viewer stays up — on each (re)connect the sim
|
|
44
|
+
replays its full state (every component + last values), so the panel repopulates automatically.
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
fpga-isv --example ulx3s --host 0.0.0.0 --port 7777
|
|
48
|
+
# then run a simulation with INTERACTIVE_STREAM=127.0.0.1:7777
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
Three ways, depending on whether you have Python:
|
|
54
|
+
|
|
55
|
+
| Method | Command | Needs |
|
|
56
|
+
|--------|---------|-------|
|
|
57
|
+
| **Standalone binary** (zero prereqs) | download from [Releases](https://github.com/DFiantWorks/interactive-sim-viewer/releases) | nothing |
|
|
58
|
+
| **pipx** (Python users) | `pipx install fpga-isv` | a Python that ships `tkinter` |
|
|
59
|
+
| **Homebrew** (macOS / Linux) | `brew tap DFiantWorks/fpga-isv https://github.com/DFiantWorks/homebrew-fpga-isv && brew install fpga-isv` | Homebrew |
|
|
60
|
+
|
|
61
|
+
The standalone binary bundles its own Python + Tcl/Tk + Pillow, so it runs with no prerequisites.
|
|
62
|
+
`pipx`/source installs need a Python with `tkinter` (stdlib, but a separate OS package on some
|
|
63
|
+
Linux distros, e.g. `apt install python3-tk`); Pillow is pulled in automatically and is required
|
|
64
|
+
for JPEG photos and cropped / non-integer-scaled images (PNG/GIF panels work on stdlib Tk alone).
|
|
65
|
+
|
|
66
|
+
> **macOS note:** the released binaries are currently **unsigned**. Launched by another process
|
|
67
|
+
> directly they run fine; launched via Finder/`open` from a browser-downloaded copy, Gatekeeper
|
|
68
|
+
> blocks them until you clear quarantine — `xattr -dr com.apple.quarantine ./fpga-isv` or
|
|
69
|
+
> right-click → Open once. **Homebrew** installs strip quarantine, so `brew install` avoids the
|
|
70
|
+
> prompt entirely; `pipx` has no binary to quarantine.
|
|
71
|
+
|
|
72
|
+
## Config
|
|
73
|
+
|
|
74
|
+
A panel is described by one JSON file. All coordinates are in **original-image pixels**;
|
|
75
|
+
`image.scale` scales the photo/panel and every coordinate together for display, and `image.crop`
|
|
76
|
+
trims a photo to the board — the map stays in original-image pixels so it is independent of crop
|
|
77
|
+
and window size.
|
|
78
|
+
|
|
79
|
+
A **photo** panel:
|
|
80
|
+
|
|
81
|
+
```jsonc
|
|
82
|
+
{
|
|
83
|
+
"title": "ULX3S",
|
|
84
|
+
"image": { "url": "board.png", "crop": [160, 195, 1650, 1010], "scale": 0.72 },
|
|
85
|
+
"leds": { "on_color": "#ff5a36", "shape": "rect", "w": 26, "h": 32,
|
|
86
|
+
"items": [ { "name": "leds", "bit": 0, "x": 632, "y": 480 }, /* ... */ ] },
|
|
87
|
+
"buttons":[ { "name": "btn_pwr", "shape": "circle", "x": 1375, "y": 401, "r": 42, "key": "p" } ]
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
A **blank panel** mockup (no photo — lay controls out from scratch):
|
|
92
|
+
|
|
93
|
+
```jsonc
|
|
94
|
+
{
|
|
95
|
+
"title": "My Panel",
|
|
96
|
+
"image": { "width": 1200, "height": 800, "bg": "#101418" },
|
|
97
|
+
"leds": { "on_color": "#56d364", "items": [ { "name": "led_err", "bit": 0, "x": 100, "y": 80 } ] },
|
|
98
|
+
"buttons":[ { "name": "btn_run", "shape": "rect", "x": 200, "y": 300, "w": 120, "h": 60, "toggle": true } ]
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- `image.url` may be a remote URL (optionally with `cache`), an absolute path, or a path
|
|
103
|
+
**relative to the config file**. Use `width`/`height`/`bg` instead of `url` for a blank panel.
|
|
104
|
+
- An LED **item** lights when bit `bit` of flag `name` is `1`, so an N-bit bus is N items with
|
|
105
|
+
different bit indices and a 1-bit flag is one item.
|
|
106
|
+
- A **button** sends `1` on press and `0` on release (momentary); `"toggle": true` flips and
|
|
107
|
+
latches. `"key"` mirrors it to a keyboard key (Tk keysym, e.g. `p`, `space`, `Up`).
|
|
108
|
+
|
|
109
|
+
### Mapping a new photo
|
|
110
|
+
|
|
111
|
+
Run with `--calibrate` and click the image: each click prints the original-image pixel coordinate
|
|
112
|
+
(and marks it on the canvas), so you can read off the x/y for every LED and button.
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
fpga-isv --config my_board.json --calibrate
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## CLI
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
fpga-isv (--example NAME | --config PATH) [--host 0.0.0.0] [--port 7777] [--refresh] [--calibrate]
|
|
122
|
+
fpga-isv --list-examples
|
|
123
|
+
fpga-isv --version
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Wire protocol
|
|
127
|
+
|
|
128
|
+
Newline-delimited JSON, one message per line (defined by interactive-sim; every sim→viewer
|
|
129
|
+
message carries `t`, the simulation time in µs):
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
sim -> viewer {"ev":"reg", "t":1234.5,"name":"btn_run","kind":"ctrl","width":1}
|
|
133
|
+
{"ev":"flag", "t":1234.5,"name":"leds","val":42}
|
|
134
|
+
{"ev":"time", "t":1234.5}
|
|
135
|
+
{"ev":"close","t":1234.5,"name":"btn_run"}
|
|
136
|
+
viewer -> sim {"name":"btn_run","val":1}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Develop
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
pip install -e . pytest
|
|
143
|
+
python -m pytest -q # headless protocol/config/geometry tests
|
|
144
|
+
python -m fpga_isv --example ulx3s
|
|
145
|
+
pyinstaller packaging/fpga_isv.spec # build the standalone binary into dist/
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT (see [LICENSE](LICENSE)). The bundled ULX3S photo is from the
|
|
151
|
+
[ULX3S project](https://github.com/ulx3s/ulx3s).
|
fpga_isv-0.1.0/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# fpga-isv — Interactive Sim Viewer
|
|
2
|
+
|
|
3
|
+
A cross-platform **graphical panel viewer** for
|
|
4
|
+
[interactive-sim](https://github.com/DFiantWorks/interactive-sim). It draws a board *photo* (or a
|
|
5
|
+
blank *panel* you mock up), overlays the LEDs and buttons at their pixel positions, and connects
|
|
6
|
+
that virtual panel to a running HDL simulation: **design-driven flags light the LEDs**, and
|
|
7
|
+
**clicking a button feeds a control back into the design**.
|
|
8
|
+
|
|
9
|
+
`fpga-isv` is a *pure client of the interactive-sim socket API* — it knows nothing about HDL or
|
|
10
|
+
simulators. Anything that speaks the same newline-delimited-JSON protocol works with it. The
|
|
11
|
+
[ULX3S](https://github.com/ulx3s/ulx3s) board ships as the bundled reference example.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
fpga-isv --example ulx3s
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## How it connects
|
|
18
|
+
|
|
19
|
+
The viewer **listens** on a TCP port; the simulation **connects to it** (set
|
|
20
|
+
`INTERACTIVE_STREAM=host:port` for the sim). This means you can:
|
|
21
|
+
|
|
22
|
+
- **open and close the viewer at any time** — the sim's backend keeps reconnecting;
|
|
23
|
+
- **stop or restart the simulation** while the viewer stays up — on each (re)connect the sim
|
|
24
|
+
replays its full state (every component + last values), so the panel repopulates automatically.
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
fpga-isv --example ulx3s --host 0.0.0.0 --port 7777
|
|
28
|
+
# then run a simulation with INTERACTIVE_STREAM=127.0.0.1:7777
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
Three ways, depending on whether you have Python:
|
|
34
|
+
|
|
35
|
+
| Method | Command | Needs |
|
|
36
|
+
|--------|---------|-------|
|
|
37
|
+
| **Standalone binary** (zero prereqs) | download from [Releases](https://github.com/DFiantWorks/interactive-sim-viewer/releases) | nothing |
|
|
38
|
+
| **pipx** (Python users) | `pipx install fpga-isv` | a Python that ships `tkinter` |
|
|
39
|
+
| **Homebrew** (macOS / Linux) | `brew tap DFiantWorks/fpga-isv https://github.com/DFiantWorks/homebrew-fpga-isv && brew install fpga-isv` | Homebrew |
|
|
40
|
+
|
|
41
|
+
The standalone binary bundles its own Python + Tcl/Tk + Pillow, so it runs with no prerequisites.
|
|
42
|
+
`pipx`/source installs need a Python with `tkinter` (stdlib, but a separate OS package on some
|
|
43
|
+
Linux distros, e.g. `apt install python3-tk`); Pillow is pulled in automatically and is required
|
|
44
|
+
for JPEG photos and cropped / non-integer-scaled images (PNG/GIF panels work on stdlib Tk alone).
|
|
45
|
+
|
|
46
|
+
> **macOS note:** the released binaries are currently **unsigned**. Launched by another process
|
|
47
|
+
> directly they run fine; launched via Finder/`open` from a browser-downloaded copy, Gatekeeper
|
|
48
|
+
> blocks them until you clear quarantine — `xattr -dr com.apple.quarantine ./fpga-isv` or
|
|
49
|
+
> right-click → Open once. **Homebrew** installs strip quarantine, so `brew install` avoids the
|
|
50
|
+
> prompt entirely; `pipx` has no binary to quarantine.
|
|
51
|
+
|
|
52
|
+
## Config
|
|
53
|
+
|
|
54
|
+
A panel is described by one JSON file. All coordinates are in **original-image pixels**;
|
|
55
|
+
`image.scale` scales the photo/panel and every coordinate together for display, and `image.crop`
|
|
56
|
+
trims a photo to the board — the map stays in original-image pixels so it is independent of crop
|
|
57
|
+
and window size.
|
|
58
|
+
|
|
59
|
+
A **photo** panel:
|
|
60
|
+
|
|
61
|
+
```jsonc
|
|
62
|
+
{
|
|
63
|
+
"title": "ULX3S",
|
|
64
|
+
"image": { "url": "board.png", "crop": [160, 195, 1650, 1010], "scale": 0.72 },
|
|
65
|
+
"leds": { "on_color": "#ff5a36", "shape": "rect", "w": 26, "h": 32,
|
|
66
|
+
"items": [ { "name": "leds", "bit": 0, "x": 632, "y": 480 }, /* ... */ ] },
|
|
67
|
+
"buttons":[ { "name": "btn_pwr", "shape": "circle", "x": 1375, "y": 401, "r": 42, "key": "p" } ]
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
A **blank panel** mockup (no photo — lay controls out from scratch):
|
|
72
|
+
|
|
73
|
+
```jsonc
|
|
74
|
+
{
|
|
75
|
+
"title": "My Panel",
|
|
76
|
+
"image": { "width": 1200, "height": 800, "bg": "#101418" },
|
|
77
|
+
"leds": { "on_color": "#56d364", "items": [ { "name": "led_err", "bit": 0, "x": 100, "y": 80 } ] },
|
|
78
|
+
"buttons":[ { "name": "btn_run", "shape": "rect", "x": 200, "y": 300, "w": 120, "h": 60, "toggle": true } ]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- `image.url` may be a remote URL (optionally with `cache`), an absolute path, or a path
|
|
83
|
+
**relative to the config file**. Use `width`/`height`/`bg` instead of `url` for a blank panel.
|
|
84
|
+
- An LED **item** lights when bit `bit` of flag `name` is `1`, so an N-bit bus is N items with
|
|
85
|
+
different bit indices and a 1-bit flag is one item.
|
|
86
|
+
- A **button** sends `1` on press and `0` on release (momentary); `"toggle": true` flips and
|
|
87
|
+
latches. `"key"` mirrors it to a keyboard key (Tk keysym, e.g. `p`, `space`, `Up`).
|
|
88
|
+
|
|
89
|
+
### Mapping a new photo
|
|
90
|
+
|
|
91
|
+
Run with `--calibrate` and click the image: each click prints the original-image pixel coordinate
|
|
92
|
+
(and marks it on the canvas), so you can read off the x/y for every LED and button.
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
fpga-isv --config my_board.json --calibrate
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## CLI
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
fpga-isv (--example NAME | --config PATH) [--host 0.0.0.0] [--port 7777] [--refresh] [--calibrate]
|
|
102
|
+
fpga-isv --list-examples
|
|
103
|
+
fpga-isv --version
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Wire protocol
|
|
107
|
+
|
|
108
|
+
Newline-delimited JSON, one message per line (defined by interactive-sim; every sim→viewer
|
|
109
|
+
message carries `t`, the simulation time in µs):
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
sim -> viewer {"ev":"reg", "t":1234.5,"name":"btn_run","kind":"ctrl","width":1}
|
|
113
|
+
{"ev":"flag", "t":1234.5,"name":"leds","val":42}
|
|
114
|
+
{"ev":"time", "t":1234.5}
|
|
115
|
+
{"ev":"close","t":1234.5,"name":"btn_run"}
|
|
116
|
+
viewer -> sim {"name":"btn_run","val":1}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Develop
|
|
120
|
+
|
|
121
|
+
```sh
|
|
122
|
+
pip install -e . pytest
|
|
123
|
+
python -m pytest -q # headless protocol/config/geometry tests
|
|
124
|
+
python -m fpga_isv --example ulx3s
|
|
125
|
+
pyinstaller packaging/fpga_isv.spec # build the standalone binary into dist/
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT (see [LICENSE](LICENSE)). The bundled ULX3S photo is from the
|
|
131
|
+
[ULX3S project](https://github.com/ulx3s/ulx3s).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# ULX3S reference example
|
|
2
|
+
|
|
3
|
+
The bundled reference panel for **fpga-isv**: a photo of the
|
|
4
|
+
[ULX3S](https://github.com/ulx3s/ulx3s) FPGA board with the 8 user LEDs and the
|
|
5
|
+
direction / fire / power buttons mapped to their positions on the board.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
fpga-isv --example ulx3s
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Then run a matching interactive-sim simulation (e.g. the `ulx3s_demo` in the
|
|
12
|
+
[interactive-sim](https://github.com/DFiantWorks/interactive-sim) repo) so the sim
|
|
13
|
+
connects to the viewer (`INTERACTIVE_STREAM=host:port`). The 8-bit `leds` flag lights
|
|
14
|
+
the LED row; clicking a button (or its mirrored key) sends a momentary `1`/`0`.
|
|
15
|
+
|
|
16
|
+
- `ulx3s.json` — the panel config (LED/button pixel map, in original-image pixels).
|
|
17
|
+
- `ULX3S_v303_top.png` — the board photo (from the ULX3S project), committed so the
|
|
18
|
+
example is self-contained and works offline.
|
|
19
|
+
|
|
20
|
+
To map a different photo, copy this config, point `image.url` at your image, and run
|
|
21
|
+
`fpga-isv --config your.json --calibrate` to read off pixel coordinates by clicking.
|
|
Binary file
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Reference example for fpga-isv: a photo of the ULX3S board with the 8 user LEDs and the buttons mapped. Coordinates are in ORIGINAL image pixels (this photo is 1852x1214); image.crop trims the photo and image.scale scales it, but the map stays in original-image pixels so it is independent of crop/scale. The image is the committed local PNG (resolved against this config's dir). Run with --calibrate and click the photo to read off pixel coordinates for retuning or mapping a different photo.",
|
|
3
|
+
|
|
4
|
+
"title": "ULX3S",
|
|
5
|
+
|
|
6
|
+
"image": {
|
|
7
|
+
"url": "ULX3S_v303_top.png",
|
|
8
|
+
"crop": [160, 195, 1650, 1010],
|
|
9
|
+
"scale": 0.72
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
"leds": {
|
|
13
|
+
"on_color": "#ff5a36",
|
|
14
|
+
"shape": "rect",
|
|
15
|
+
"w": 26,
|
|
16
|
+
"h": 32,
|
|
17
|
+
"glow": true,
|
|
18
|
+
"items": [
|
|
19
|
+
{ "name": "leds", "bit": 0, "x": 632, "y": 480 },
|
|
20
|
+
{ "name": "leds", "bit": 1, "x": 595, "y": 480 },
|
|
21
|
+
{ "name": "leds", "bit": 2, "x": 558, "y": 480 },
|
|
22
|
+
{ "name": "leds", "bit": 3, "x": 521, "y": 480 },
|
|
23
|
+
{ "name": "leds", "bit": 4, "x": 484, "y": 480 },
|
|
24
|
+
{ "name": "leds", "bit": 5, "x": 447, "y": 480 },
|
|
25
|
+
{ "name": "leds", "bit": 6, "x": 410, "y": 480 },
|
|
26
|
+
{ "name": "leds", "bit": 7, "x": 373, "y": 480 }
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
"buttons": [
|
|
31
|
+
{ "name": "btn_pwr", "shape": "circle", "x": 1375, "y": 401, "r": 42, "key": "p" },
|
|
32
|
+
{ "name": "btn_fire1", "shape": "circle", "x": 406, "y": 623, "r": 34, "key": "space" },
|
|
33
|
+
{ "name": "btn_fire2", "shape": "circle", "x": 572, "y": 628, "r": 34, "key": "Return" },
|
|
34
|
+
{ "name": "btn_up", "shape": "circle", "x": 1210, "y": 777, "r": 36, "key": "Up" },
|
|
35
|
+
{ "name": "btn_down", "shape": "circle", "x": 1206, "y": 907, "r": 36, "key": "Down" },
|
|
36
|
+
{ "name": "btn_left", "shape": "circle", "x": 1039, "y": 906, "r": 36, "key": "Left" },
|
|
37
|
+
{ "name": "btn_right", "shape": "circle", "x": 1377, "y": 910, "r": 36, "key": "Right" }
|
|
38
|
+
]
|
|
39
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Locate the bundled example panels.
|
|
2
|
+
|
|
3
|
+
Each example is a subdirectory of ``examples/`` holding ``<name>.json`` (the board/panel
|
|
4
|
+
config) plus any assets it references (e.g. a board photo). The directory resolves three ways:
|
|
5
|
+
|
|
6
|
+
* frozen by PyInstaller -> ``<_MEIPASS>/fpga_isv/examples`` (see packaging/fpga_isv.spec)
|
|
7
|
+
* installed / run from src -> ``<this package dir>/examples``
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def examples_dir():
|
|
15
|
+
"""Absolute path to the bundled examples directory."""
|
|
16
|
+
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
|
17
|
+
return os.path.join(sys._MEIPASS, "fpga_isv", "examples")
|
|
18
|
+
return os.path.join(os.path.dirname(os.path.abspath(__file__)), "examples")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def list_examples():
|
|
22
|
+
"""Sorted names of bundled examples (subdirs that contain ``<name>.json``)."""
|
|
23
|
+
root = examples_dir()
|
|
24
|
+
if not os.path.isdir(root):
|
|
25
|
+
return []
|
|
26
|
+
names = []
|
|
27
|
+
for name in sorted(os.listdir(root)):
|
|
28
|
+
if os.path.isfile(os.path.join(root, name, name + ".json")):
|
|
29
|
+
names.append(name)
|
|
30
|
+
return names
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def example_config_path(name):
|
|
34
|
+
"""Path to ``examples/<name>/<name>.json``; raises ValueError if it doesn't exist."""
|
|
35
|
+
path = os.path.join(examples_dir(), name, name + ".json")
|
|
36
|
+
if not os.path.isfile(path):
|
|
37
|
+
available = ", ".join(list_examples()) or "(none bundled)"
|
|
38
|
+
raise ValueError(f"unknown example {name!r}; available: {available}")
|
|
39
|
+
return path
|