riffpi 0.2.4__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.
Files changed (79) hide show
  1. riffpi-0.2.4/.github/FUNDING.yml +15 -0
  2. riffpi-0.2.4/.github/workflows/docs.yml +32 -0
  3. riffpi-0.2.4/.github/workflows/lint-and-build.yml +33 -0
  4. riffpi-0.2.4/.github/workflows/release.yml +50 -0
  5. riffpi-0.2.4/.github/workflows/tag-release.yml +19 -0
  6. riffpi-0.2.4/.gitignore +14 -0
  7. riffpi-0.2.4/.python-version +1 -0
  8. riffpi-0.2.4/CLAUDE.md +156 -0
  9. riffpi-0.2.4/LICENSE.md +313 -0
  10. riffpi-0.2.4/PKG-INFO +96 -0
  11. riffpi-0.2.4/README.md +72 -0
  12. riffpi-0.2.4/cern_ohl_w_v2_howto.pdf +0 -0
  13. riffpi-0.2.4/combined_test.py +236 -0
  14. riffpi-0.2.4/docs/architecture.md +114 -0
  15. riffpi-0.2.4/docs/images/img1.jpg +0 -0
  16. riffpi-0.2.4/docs/images/img2.jpg +0 -0
  17. riffpi-0.2.4/docs/images/img3.jpg +0 -0
  18. riffpi-0.2.4/docs/images/pcb-bottom.svg +10958 -0
  19. riffpi-0.2.4/docs/images/pcb-top.svg +27366 -0
  20. riffpi-0.2.4/docs/images/schematic.svg +67373 -0
  21. riffpi-0.2.4/docs/index.md +33 -0
  22. riffpi-0.2.4/docs/installation.md +161 -0
  23. riffpi-0.2.4/docs/usage.md +78 -0
  24. riffpi-0.2.4/joystick_as_mouse_test.py +178 -0
  25. riffpi-0.2.4/joystick_test.py +46 -0
  26. riffpi-0.2.4/keypad_int_test.py +68 -0
  27. riffpi-0.2.4/keypad_test.py +50 -0
  28. riffpi-0.2.4/kicad_board/.gitignore +60 -0
  29. riffpi-0.2.4/kicad_board/.kinotes/KiNotes_kicad_board.md +27 -0
  30. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105647_todos.json +44 -0
  31. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105648_todos.json +44 -0
  32. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105649_todos.json +44 -0
  33. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105650_todos.json +44 -0
  34. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105651_todos.json +44 -0
  35. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105652_todos.json +44 -0
  36. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105653_todos.json +44 -0
  37. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105703_todos.json +44 -0
  38. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105703_version_log.json +4 -0
  39. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105712_KiNotes_kicad_board.md +26 -0
  40. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105712_settings.json +59 -0
  41. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105712_todos.json +44 -0
  42. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105712_version_log.json +4 -0
  43. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105715_version_log.json +4 -0
  44. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105721_KiNotes_kicad_board.md +27 -0
  45. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105721_settings.json +59 -0
  46. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105721_todos.json +44 -0
  47. riffpi-0.2.4/kicad_board/.kinotes/backups/20260406_105721_version_log.json +4 -0
  48. riffpi-0.2.4/kicad_board/.kinotes/multieff_worklog_20260406.md +2 -0
  49. riffpi-0.2.4/kicad_board/.kinotes/settings.json +59 -0
  50. riffpi-0.2.4/kicad_board/.kinotes/todos.json +44 -0
  51. riffpi-0.2.4/kicad_board/.kinotes/version_log.json +4 -0
  52. riffpi-0.2.4/kicad_board/fabrication-toolkit-options.json +1 -0
  53. riffpi-0.2.4/kicad_board/multieff.kicad_dru +133 -0
  54. riffpi-0.2.4/kicad_board/multieff.kicad_pcb +20692 -0
  55. riffpi-0.2.4/kicad_board/multieff.kicad_prl +130 -0
  56. riffpi-0.2.4/kicad_board/multieff.kicad_pro +645 -0
  57. riffpi-0.2.4/kicad_board/multieff.kicad_sch +12336 -0
  58. riffpi-0.2.4/kicad_board/multieff.rules +84 -0
  59. riffpi-0.2.4/leds_int_test.py +106 -0
  60. riffpi-0.2.4/leds_test.py +69 -0
  61. riffpi-0.2.4/mkdocs.yml +24 -0
  62. riffpi-0.2.4/multieffect_int.py +237 -0
  63. riffpi-0.2.4/pyproject.toml +65 -0
  64. riffpi-0.2.4/rotary_encoder_int.py +225 -0
  65. riffpi-0.2.4/rotary_encoder_int_test.py +67 -0
  66. riffpi-0.2.4/rotary_encoder_test.py +66 -0
  67. riffpi-0.2.4/rotary_encoders_int_test.py +112 -0
  68. riffpi-0.2.4/rotary_encoders_test.py +57 -0
  69. riffpi-0.2.4/src/riffpi/__init__.py +3 -0
  70. riffpi-0.2.4/src/riffpi/cli.py +33 -0
  71. riffpi-0.2.4/src/riffpi/daemon.py +246 -0
  72. riffpi-0.2.4/src/riffpi/expression_pedal.py +88 -0
  73. riffpi-0.2.4/src/riffpi/joystick.py +198 -0
  74. riffpi-0.2.4/src/riffpi/keypad.py +169 -0
  75. riffpi-0.2.4/src/riffpi/mcp_button.py +27 -0
  76. riffpi-0.2.4/src/riffpi/mcp_led.py +22 -0
  77. riffpi-0.2.4/src/riffpi/rotary_encoder.py +168 -0
  78. riffpi-0.2.4/src/riffpi/service.py +92 -0
  79. riffpi-0.2.4/test_int.py +190 -0
@@ -0,0 +1,15 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: kleag# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4
+ patreon: # Replace with a single Patreon username
5
+ open_collective: # Replace with a single Open Collective username
6
+ ko_fi: # Replace with a single Ko-fi username
7
+ tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8
+ community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9
+ liberapay: # Replace with a single Liberapay username
10
+ issuehunt: # Replace with a single IssueHunt username
11
+ lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12
+ polar: # Replace with a single Polar username
13
+ buy_me_a_coffee: kleag# Replace with a single Buy Me a Coffee username
14
+ thanks_dev: # Replace with a single thanks.dev username
15
+ custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
@@ -0,0 +1,32 @@
1
+ name: docs
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ paths:
8
+ - "docs/**"
9
+ - "mkdocs.yml"
10
+ - "README.md"
11
+ - ".github/workflows/docs.yml"
12
+
13
+ permissions:
14
+ contents: write
15
+
16
+ jobs:
17
+ deploy:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Configure Git Credentials
23
+ run: |
24
+ git config user.name github-actions[bot]
25
+ git config user.email 41898282+github-actions[bot]@users.noreply.github.com
26
+
27
+ - uses: actions/setup-python@v5
28
+ with:
29
+ python-version: "3.x"
30
+
31
+ - run: pip install mkdocs-material
32
+ - run: mkdocs gh-deploy --force
@@ -0,0 +1,33 @@
1
+ name: lint-and-build
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+
9
+ jobs:
10
+ lint-and-build:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.11"
18
+
19
+ - name: Install dev tooling
20
+ run: pip install ruff build twine
21
+
22
+ # Note: the package's runtime dependencies (Adafruit Blinka, gpiozero, ...) actively
23
+ # probe for real Raspberry Pi hardware on import, so they cannot be installed/imported
24
+ # on a generic GitHub-hosted runner. This job only lints and validates packaging, it
25
+ # does not import riffpi itself.
26
+ - name: Lint
27
+ run: ruff check src/
28
+
29
+ - name: Build sdist and wheel
30
+ run: python -m build
31
+
32
+ - name: Check package metadata
33
+ run: twine check dist/*
@@ -0,0 +1,50 @@
1
+ name: release
2
+
3
+ on:
4
+ # Not `release: published`: tag-release.yml creates that release using the default
5
+ # GITHUB_TOKEN, and GitHub's anti-recursion rule means events created via GITHUB_TOKEN
6
+ # don't trigger other workflows. workflow_run isn't subject to that restriction, so we
7
+ # chain off tag-release.yml's completion instead.
8
+ workflow_run:
9
+ workflows: ["tag-release"]
10
+ types: [completed]
11
+
12
+ jobs:
13
+ build:
14
+ if: github.event.workflow_run.conclusion == 'success'
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ with:
19
+ ref: ${{ github.event.workflow_run.head_sha }}
20
+
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.11"
24
+
25
+ - name: Install build tooling
26
+ run: pip install build
27
+
28
+ - name: Build sdist and wheel
29
+ run: python -m build
30
+
31
+ - uses: actions/upload-artifact@v4
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+
36
+ publish:
37
+ needs: build
38
+ runs-on: ubuntu-latest
39
+ environment: pypi
40
+ permissions:
41
+ # Required for PyPI Trusted Publishing (OIDC) - no API token stored in this repo.
42
+ id-token: write
43
+ steps:
44
+ - uses: actions/download-artifact@v4
45
+ with:
46
+ name: dist
47
+ path: dist/
48
+
49
+ - name: Publish to PyPI
50
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,19 @@
1
+ name: tag-release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "*.*.*"
7
+
8
+ jobs:
9
+ create-release:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: write
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+
16
+ - name: Create GitHub Release
17
+ env:
18
+ GH_TOKEN: ${{ github.token }}
19
+ run: gh release create "${{ github.ref_name }}" --title "${{ github.ref_name }}" --generate-notes
@@ -0,0 +1,14 @@
1
+ __pycache__
2
+ *.swp
3
+ *.s
4
+ .theia
5
+ *.kdev4
6
+ *.rpt
7
+ fp-info-cache
8
+ *.gbr*
9
+ multieff.dsn
10
+ multieff.ses
11
+ *-backups
12
+ site/
13
+ dist/
14
+ *.egg-info/
@@ -0,0 +1 @@
1
+ 3.11
riffpi-0.2.4/CLAUDE.md ADDED
@@ -0,0 +1,156 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project overview
6
+
7
+ RiffPi (PyPI/import name `riffpi`; the GitHub repo is `kleag/riffpi`, formerly `kleag/kleagmfx`)
8
+ is a DIY guitar
9
+ multi-effect foot controller built around a Raspberry Pi 5 + Pisound sound card, running Guitarix
10
+ as the effects engine. This repo holds:
11
+
12
+ - `src/riffpi/`: the installable Python package — the control daemon that reads the physical
13
+ controls (foot switches, rotary encoders, keypad, joystick, expression pedal) and drives
14
+ Guitarix over a virtual MIDI port.
15
+ - Root-level `*_test.py` / `*_int.py` files: standalone manual/legacy hardware scripts, **not**
16
+ part of the installed package (see Testing and Architecture below).
17
+ - KiCad hardware design files for the controller PCB (`kicad_board/`).
18
+ - MkDocs documentation source (`docs/`), published to GitHub Pages.
19
+
20
+ The hardware talks to the Pi over I2C: two MCP23017 GPIO expanders (`0x20`, `0x21`) for buttons/
21
+ LEDs/encoders/keypad, and an ADS1115 ADC for the analog joystick and expression pedal. Full
22
+ wiring/pin maps live in `docs/architecture.md`; Raspberry Pi OS setup (I2C enablement, `uinput`
23
+ permissions, systemd service, etc.) is in `docs/installation.md`.
24
+
25
+ ## Environment & running
26
+
27
+ - Python >=3.11, packaged with `hatchling` (`[build-system]` in `pyproject.toml`). Build with
28
+ `python -m build` or `uv build`; install locally with `pip install -e .`.
29
+ - Hardware-dependent libraries (`board`, `busio`, `digitalio`, `adafruit_*`, `gpiozero`, `uinput`,
30
+ ...) only work on an actual Raspberry Pi with I2C enabled and the user in the `input` group.
31
+ **None of this code can be run or imported on a non-Pi dev machine** — Blinka (`board`/`busio`)
32
+ actively probes for real hardware on import and raises if it doesn't find a supported board.
33
+ Reason about the package by reading; verify changes with `python -m py_compile` and `ruff
34
+ check src/`, not by importing/running it.
35
+ - Entry point: the `riffpi` console script (`riffpi.cli:main`, installed via
36
+ `[project.scripts]`), an argparse dispatcher over three subcommands — `run` (default when no
37
+ subcommand is given), `install-service`, `uninstall-service`. `riffpi run` calls
38
+ `riffpi.daemon.run()`, which opens a virtual ALSA/JACK MIDI port named `KleagMFX` via `mido`,
39
+ links it to Guitarix (`gx_head_amp`) through PipeWire (`pw-link`), then spawns one thread per
40
+ input device (buttons, joystick, keypad, expression pedal, each rotary encoder) plus a
41
+ MIDI-input listener thread that keeps LED/encoder state in sync when Guitarix itself changes a
42
+ CC value.
43
+ - `riffpi install-service` / `riffpi uninstall-service` (implemented in `riffpi/service.py`)
44
+ write/remove `~/.config/systemd/user/riffpi.service` and enable/disable it via `systemctl
45
+ --user`. `pip install` never does this on its own — it's a deliberate, separate opt-in step;
46
+ don't wire service installation into packaging/install hooks. See `docs/installation.md` for
47
+ the full flow and PipeWire/udev/wifi power-management setup.
48
+
49
+ ## Testing
50
+
51
+ There is no pytest/unittest suite. Root-level files named `*_test.py` (and `test_int.py`) are
52
+ standalone manual exercise scripts for a single piece of hardware — run directly on the Pi
53
+ (`python3 rotary_encoder_test.py`) with real hardware attached, and verified by watching printed
54
+ output / physical LEDs, not by assertions. They are **not** part of the `src/riffpi` package and
55
+ aren't shipped in the wheel/sdist. When changing a driver module, prefer updating or running its
56
+ matching `*_test.py` script over trying to add automated tests.
57
+
58
+ CI (`.github/workflows/lint-and-build.yml`) runs `ruff check src/` plus `python -m build` +
59
+ `twine check dist/*` on every push/PR — lint and packaging validation only. It cannot actually
60
+ import or run `riffpi` (see the Blinka caveat above), so this is the practical ceiling for
61
+ automated verification without a self-hosted Pi runner.
62
+
63
+ ## Docs site & release
64
+
65
+ - `docs/` is an MkDocs (Material theme) site, configured by `mkdocs.yml`.
66
+ `.github/workflows/docs.yml` runs `mkdocs gh-deploy --force`, but only on pushes to `main` that
67
+ touch `docs/`, `mkdocs.yml`, or `README.md`.
68
+ - `.github/workflows/release.yml` builds and publishes to PyPI via Trusted Publishing (OIDC) —
69
+ no stored token. Requires the `riffpi` PyPI project to have this repo registered as a trusted
70
+ publisher (a one-time manual step on pypi.org, done as a "pending publisher" before the
71
+ project existed — PyPI creates the project on the first successful publish).
72
+ - Version bumps use `bumpver` (`[tool.bumpver]` in `pyproject.toml`), which commits, tags
73
+ (bare `MAJOR.MINOR.PATCH`, no `v` prefix), and pushes — it does **not** create a GitHub
74
+ Release itself. `.github/workflows/tag-release.yml` watches for those tag pushes and runs
75
+ `gh release create` (using the default `GITHUB_TOKEN`) to publish a GitHub Release from the
76
+ tag. `release.yml` is triggered off `workflow_run: tag-release` completing, **not**
77
+ `release: published` — a release created via `GITHUB_TOKEN` doesn't fire other event
78
+ triggers (GitHub's anti-recursion rule), so chaining on `release: published` silently never
79
+ ran. `release.yml`'s `build` job checks out `github.event.workflow_run.head_sha` to build the
80
+ tagged commit. Full chain: `bumpver update` → tag pushed → `tag-release.yml` creates the
81
+ GitHub Release → its completion triggers `release.yml` → builds and publishes to PyPI.
82
+
83
+ ## Code architecture
84
+
85
+ ### Two parallel implementations per device: package vs. root-level register-level scripts
86
+
87
+ Most physical inputs have **two independent implementations**:
88
+
89
+ - The production version, in `src/riffpi/` (imported by `riffpi.daemon`), built on the Adafruit
90
+ CircuitPython stack (`adafruit_mcp230xx`, `digitalio.Direction`/`Pull`, `busio.I2C`) —
91
+ `rotary_encoder.py`, `keypad.py`, `joystick.py`, `expression_pedal.py`, `mcp_button.py`,
92
+ `mcp_led.py`.
93
+ - Root-level `*_int.py` scripts (e.g. `rotary_encoder_int.py`, `multieffect_int.py`,
94
+ `test_int.py`) that talk to the MCP23017 directly over `smbus2`/`lgpio` register writes and use
95
+ hardware interrupts (`GPINTEN`, `lgpio.callback` on falling edges) instead of polling. These are
96
+ an alternate/experimental lower-latency approach, not wired into the main daemon and not part
97
+ of the installed package.
98
+
99
+ When asked to fix or extend a device driver, check whether the change belongs in the
100
+ `src/riffpi/` version, the root-level `_int` register-level version, or both — they duplicate
101
+ logic independently and are **not** kept in sync automatically.
102
+
103
+ ### Control flow in `riffpi/daemon.py`
104
+
105
+ - `main()` does all hardware/MIDI init (previously module-level code in the pre-packaging
106
+ `multieffect.py`) then spawns the worker threads; module-level functions (`handle_effect_toggle`,
107
+ `midi_input_thread`, `buttons_thread`, `main_thread_loop`, `send_cc`, ...) reach the objects
108
+ `main()` creates (`midi_out`, `midi_in`, `buttons`, `leds`, `encoders`, `task_queue`,
109
+ `PRESET_ENCODER_INDEX`) via `global`, matching the module's original flat-script style rather
110
+ than passing them around explicitly — keep that pattern if you touch this file rather than
111
+ introducing a class/config-object refactor.
112
+ - Global state: `effect_states` (bool per foot switch + one slot per encoder's button) and
113
+ `current_preset_bank` are shared across threads with no lock beyond the implicit GIL for simple
114
+ list/int mutation; the one place true cross-thread coordination happens is `task_queue`
115
+ (a `queue.Queue` drained by `main_thread_loop`, currently only used for the `"reset"` action
116
+ queued from `keypad.py`).
117
+ - `i2c_lock` (a `threading.Lock`) guards ADS1115 reads shared between `Joystick` and
118
+ `ExpressionPedal`, since both poll the same `ads` instance from different threads.
119
+ - Foot switch buttons and each `RotaryEncoder`'s built-in push button all route through the same
120
+ `handle_effect_toggle(idx)` callback, where `idx` is the position in the `buttons` list
121
+ (`[4 foot switches] + [4 encoder buttons]`, in that order). `PRESET_ENCODER_INDEX` is computed
122
+ in `main()` as the buttons-list position of the **last encoder's** button (not a hardcoded
123
+ literal — it was hardcoded to `3` at one point, which actually pointed at the 4th foot switch
124
+ instead; don't reintroduce that). That button is special-cased to cycle Guitarix preset banks
125
+ A-D instead of toggling an effect.
126
+ - MIDI CC numbers are the integration contract with Guitarix: `SWITCH_CC=64` (+idx per foot
127
+ switch), `ENCODER_CC_NUMBERS=[20,21,22,23]`, `PRESET_BANK_CC=32`, `PRESET_CHANGE_CC=0`,
128
+ expression pedal `MIDI_CC_NUMBER=24`. The `midi_input_thread` listens on the same virtual port
129
+ for CC echoes from Guitarix and updates local LED/encoder state to stay in sync when a preset
130
+ change alters effect state externally. Full mapping table: `docs/usage.md`.
131
+ - Physical pin maps for buttons/LEDs/encoders are hardcoded per-MCP as `(mcp_number, pin)` tuples
132
+ at the top of `daemon.py` — cross-reference against the pinout comments above
133
+ `encoder_configs` (which board is "1st/2nd/3rd/4th from left to right") and the tables in
134
+ `docs/architecture.md` before changing wiring.
135
+
136
+ ### Device driver modules (`src/riffpi/`)
137
+
138
+ Each driver is a small class taking its shared hardware handles (`mcp`, `ads`, `i2c_lock`,
139
+ `midi_out`) in its constructor and exposing a blocking `poll()`/`poll_thread()`/`*_thread()`
140
+ method meant to be run in its own daemon thread; each also has an `if __name__ == "__main__"`
141
+ block for standalone hardware testing of just that module (only usable when run from a checkout,
142
+ not through the installed console script).
143
+
144
+ - `rotary_encoder.py`: quadrature decoding via a transition lookup table (`CW_transitions`/
145
+ `CCW_transitions` — 4-bit keys of `(last_state<<2)|current_state`), sends relative MIDI CC deltas.
146
+ - `keypad.py`: 4x4 matrix scan; digits accumulate into a preset number with a
147
+ `DIGIT_SEQUENCE_TIMEOUT` debounce window, `A`-`D` select preset banks, `*`/`#` emit virtual
148
+ mouse left/right clicks via `uinput`.
149
+ - `joystick.py`: reads the ADS1115 (`AnalogIn`), median-smooths raw voltage per axis
150
+ (`SMOOTHING_WINDOW`), auto-calibrates center voltage at startup (`calibrate_center()`), and
151
+ shapes deflection into relative `uinput` mouse motion via a dead zone (`DEAD_ZONE`) + power
152
+ curve (`POWER_CURVE`, must stay `>1` — a curve `<1` has infinite slope at zero and produces a
153
+ "dead then jumpy" feel; see the comments on the class constants).
154
+ - `expression_pedal.py`: reads the ADS1115, median-smooths readings, sends MIDI CC.
155
+ - `mcp_button.py` / `mcp_led.py`: thin per-pin wrappers around an MCP23017 pin for debounced
156
+ button state (`when_pressed` callback) and LED output.
@@ -0,0 +1,313 @@
1
+ CERN Open Hardware Licence Version 2 - Weakly Reciprocal
2
+
3
+
4
+ Preamble
5
+
6
+ CERN has developed this licence to promote collaboration among
7
+ hardware designers and to provide a legal tool which supports the
8
+ freedom to use, study, modify, share and distribute hardware designs
9
+ and products based on those designs. Version 2 of the CERN Open
10
+ Hardware Licence comes in three variants: CERN-OHL-P (permissive); and
11
+ two reciprocal licences: this licence, CERN-OHL-W (weakly reciprocal)
12
+ and CERN-OHL-S (strongly reciprocal).
13
+
14
+ The CERN-OHL-W is copyright CERN 2020. Anyone is welcome to use it, in
15
+ unmodified form only.
16
+
17
+ Use of this Licence does not imply any endorsement by CERN of any
18
+ Licensor or their designs nor does it imply any involvement by CERN in
19
+ their development.
20
+
21
+
22
+ 1 Definitions
23
+
24
+ 1.1 'Licence' means this CERN-OHL-W.
25
+
26
+ 1.2 'Compatible Licence' means
27
+
28
+ a) any earlier version of the CERN Open Hardware licence, or
29
+
30
+ b) any version of the CERN-OHL-S or the CERN-OHL-W, or
31
+
32
+ c) any licence which permits You to treat the Source to which
33
+ it applies as licensed under CERN-OHL-S or CERN-OHL-W
34
+ provided that on Conveyance of any such Source, or any
35
+ associated Product You treat the Source in question as being
36
+ licensed under CERN-OHL-S or CERN-OHL-W as appropriate.
37
+
38
+ 1.3 'Source' means information such as design materials or digital
39
+ code which can be applied to Make or test a Product or to
40
+ prepare a Product for use, Conveyance or sale, regardless of its
41
+ medium or how it is expressed. It may include Notices.
42
+
43
+ 1.4 'Covered Source' means Source that is explicitly made available
44
+ under this Licence.
45
+
46
+ 1.5 'Product' means any device, component, work or physical object,
47
+ whether in finished or intermediate form, arising from the use,
48
+ application or processing of Covered Source.
49
+
50
+ 1.6 'Make' means to create or configure something, whether by
51
+ manufacture, assembly, compiling, loading or applying Covered
52
+ Source or another Product or otherwise.
53
+
54
+ 1.7 'Available Component' means any part, sub-assembly, library or
55
+ code which:
56
+
57
+ a) is licensed to You as Complete Source under a Compatible
58
+ Licence; or
59
+
60
+ b) is available, at the time a Product or the Source containing
61
+ it is first Conveyed, to You and any other prospective
62
+ licensees
63
+
64
+ i) with sufficient rights and information (including any
65
+ configuration and programming files and information
66
+ about its characteristics and interfaces) to enable it
67
+ either to be Made itself, or to be sourced and used to
68
+ Make the Product; or
69
+ ii) as part of the normal distribution of a tool used to
70
+ design or Make the Product.
71
+
72
+ 1.8 'External Material' means anything (including Source) which:
73
+
74
+ a) is only combined with Covered Source in such a way that it
75
+ interfaces with the Covered Source using a documented
76
+ interface which is described in the Covered Source; and
77
+
78
+ b) is not a derivative of or contains Covered Source, or, if it
79
+ is, it is solely to the extent necessary to facilitate such
80
+ interfacing.
81
+
82
+ 1.9 'Complete Source' means the set of all Source necessary to Make
83
+ a Product, in the preferred form for making modifications,
84
+ including necessary installation and interfacing information
85
+ both for the Product, and for any included Available Components.
86
+ If the format is proprietary, it must also be made available in
87
+ a format (if the proprietary tool can create it) which is
88
+ viewable with a tool available to potential licensees and
89
+ licensed under a licence approved by the Free Software
90
+ Foundation or the Open Source Initiative. Complete Source need
91
+ not include the Source of any Available Component, provided that
92
+ You include in the Complete Source sufficient information to
93
+ enable a recipient to Make or source and use the Available
94
+ Component to Make the Product.
95
+
96
+ 1.10 'Source Location' means a location where a Licensor has placed
97
+ Covered Source, and which that Licensor reasonably believes will
98
+ remain easily accessible for at least three years for anyone to
99
+ obtain a digital copy.
100
+
101
+ 1.11 'Notice' means copyright, acknowledgement and trademark notices,
102
+ Source Location references, modification notices (subsection
103
+ 3.3(b)) and all notices that refer to this Licence and to the
104
+ disclaimer of warranties that are included in the Covered
105
+ Source.
106
+
107
+ 1.12 'Licensee' or 'You' means any person exercising rights under
108
+ this Licence.
109
+
110
+ 1.13 'Licensor' means a natural or legal person who creates or
111
+ modifies Covered Source. A person may be a Licensee and a
112
+ Licensor at the same time.
113
+
114
+ 1.14 'Convey' means to communicate to the public or distribute.
115
+
116
+
117
+ 2 Applicability
118
+
119
+ 2.1 This Licence governs the use, copying, modification, Conveying
120
+ of Covered Source and Products, and the Making of Products. By
121
+ exercising any right granted under this Licence, You irrevocably
122
+ accept these terms and conditions.
123
+
124
+ 2.2 This Licence is granted by the Licensor directly to You, and
125
+ shall apply worldwide and without limitation in time.
126
+
127
+ 2.3 You shall not attempt to restrict by contract or otherwise the
128
+ rights granted under this Licence to other Licensees.
129
+
130
+ 2.4 This Licence is not intended to restrict fair use, fair dealing,
131
+ or any other similar right.
132
+
133
+
134
+ 3 Copying, Modifying and Conveying Covered Source
135
+
136
+ 3.1 You may copy and Convey verbatim copies of Covered Source, in
137
+ any medium, provided You retain all Notices.
138
+
139
+ 3.2 You may modify Covered Source, other than Notices, provided that
140
+ You irrevocably undertake to make that modified Covered Source
141
+ available from a Source Location should You Convey a Product in
142
+ circumstances where the recipient does not otherwise receive a
143
+ copy of the modified Covered Source. In each case subsection 3.3
144
+ shall apply.
145
+
146
+ You may only delete Notices if they are no longer applicable to
147
+ the corresponding Covered Source as modified by You and You may
148
+ add additional Notices applicable to Your modifications.
149
+
150
+ 3.3 You may Convey modified Covered Source (with the effect that You
151
+ shall also become a Licensor) provided that You:
152
+
153
+ a) retain Notices as required in subsection 3.2;
154
+
155
+ b) add a Notice to the modified Covered Source stating that You
156
+ have modified it, with the date and brief description of how
157
+ You have modified it;
158
+
159
+ c) add a Source Location Notice for the modified Covered Source
160
+ if You Convey in circumstances where the recipient does not
161
+ otherwise receive a copy of the modified Covered Source; and
162
+
163
+ d) license the modified Covered Source under the terms and
164
+ conditions of this Licence (or, as set out in subsection
165
+ 8.3, a later version, if permitted by the licence of the
166
+ original Covered Source). Such modified Covered Source must
167
+ be licensed as a whole, but excluding Available Components
168
+ contained in it or External Material to which it is
169
+ interfaced, which remain licensed under their own applicable
170
+ licences.
171
+
172
+
173
+ 4 Making and Conveying Products
174
+
175
+ 4.1 You may Make Products, and/or Convey them, provided that You
176
+ either provide each recipient with a copy of the Complete Source
177
+ or ensure that each recipient is notified of the Source Location
178
+ of the Complete Source. That Complete Source includes Covered
179
+ Source and You must accordingly satisfy Your obligations set out
180
+ in subsection 3.3. If specified in a Notice, the Product must
181
+ visibly and securely display the Source Location on it or its
182
+ packaging or documentation in the manner specified in that
183
+ Notice.
184
+
185
+ 4.2 Where You Convey a Product which incorporates External Material,
186
+ the Complete Source for that Product which You are required to
187
+ provide under subsection 4.1 need not include any Source for the
188
+ External Material.
189
+
190
+ 4.3 You may license Products under terms of Your choice, provided
191
+ that such terms do not restrict or attempt to restrict any
192
+ recipients' rights under this Licence to the Covered Source.
193
+
194
+
195
+ 5 Research and Development
196
+
197
+ You may Convey Covered Source, modified Covered Source or Products to
198
+ a legal entity carrying out development, testing or quality assurance
199
+ work on Your behalf provided that the work is performed on terms which
200
+ prevent the entity from both using the Source or Products for its own
201
+ internal purposes and Conveying the Source or Products or any
202
+ modifications to them to any person other than You. Any modifications
203
+ made by the entity shall be deemed to be made by You pursuant to
204
+ subsection 3.2.
205
+
206
+
207
+ 6 DISCLAIMER AND LIABILITY
208
+
209
+ 6.1 DISCLAIMER OF WARRANTY -- The Covered Source and any Products
210
+ are provided 'as is' and any express or implied warranties,
211
+ including, but not limited to, implied warranties of
212
+ merchantability, of satisfactory quality, non-infringement of
213
+ third party rights, and fitness for a particular purpose or use
214
+ are disclaimed in respect of any Source or Product to the
215
+ maximum extent permitted by law. The Licensor makes no
216
+ representation that any Source or Product does not or will not
217
+ infringe any patent, copyright, trade secret or other
218
+ proprietary right. The entire risk as to the use, quality, and
219
+ performance of any Source or Product shall be with You and not
220
+ the Licensor. This disclaimer of warranty is an essential part
221
+ of this Licence and a condition for the grant of any rights
222
+ granted under this Licence.
223
+
224
+ 6.2 EXCLUSION AND LIMITATION OF LIABILITY -- The Licensor shall, to
225
+ the maximum extent permitted by law, have no liability for
226
+ direct, indirect, special, incidental, consequential, exemplary,
227
+ punitive or other damages of any character including, without
228
+ limitation, procurement of substitute goods or services, loss of
229
+ use, data or profits, or business interruption, however caused
230
+ and on any theory of contract, warranty, tort (including
231
+ negligence), product liability or otherwise, arising in any way
232
+ in relation to the Covered Source, modified Covered Source
233
+ and/or the Making or Conveyance of a Product, even if advised of
234
+ the possibility of such damages, and You shall hold the
235
+ Licensor(s) free and harmless from any liability, costs,
236
+ damages, fees and expenses, including claims by third parties,
237
+ in relation to such use.
238
+
239
+
240
+ 7 Patents
241
+
242
+ 7.1 Subject to the terms and conditions of this Licence, each
243
+ Licensor hereby grants to You a perpetual, worldwide,
244
+ non-exclusive, no-charge, royalty-free, irrevocable (except as
245
+ stated in subsections 7.2 and 8.4) patent licence to Make, have
246
+ Made, use, offer to sell, sell, import, and otherwise transfer
247
+ the Covered Source and Products, where such licence applies only
248
+ to those patent claims licensable by such Licensor that are
249
+ necessarily infringed by exercising rights under the Covered
250
+ Source as Conveyed by that Licensor.
251
+
252
+ 7.2 If You institute patent litigation against any entity (including
253
+ a cross-claim or counterclaim in a lawsuit) alleging that the
254
+ Covered Source or a Product constitutes direct or contributory
255
+ patent infringement, or You seek any declaration that a patent
256
+ licensed to You under this Licence is invalid or unenforceable
257
+ then any rights granted to You under this Licence shall
258
+ terminate as of the date such process is initiated.
259
+
260
+
261
+ 8 General
262
+
263
+ 8.1 If any provisions of this Licence are or subsequently become
264
+ invalid or unenforceable for any reason, the remaining
265
+ provisions shall remain effective.
266
+
267
+ 8.2 You shall not use any of the name (including acronyms and
268
+ abbreviations), image, or logo by which the Licensor or CERN is
269
+ known, except where needed to comply with section 3, or where
270
+ the use is otherwise allowed by law. Any such permitted use
271
+ shall be factual and shall not be made so as to suggest any kind
272
+ of endorsement or implication of involvement by the Licensor or
273
+ its personnel.
274
+
275
+ 8.3 CERN may publish updated versions and variants of this Licence
276
+ which it considers to be in the spirit of this version, but may
277
+ differ in detail to address new problems or concerns. New
278
+ versions will be published with a unique version number and a
279
+ variant identifier specifying the variant. If the Licensor has
280
+ specified that a given variant applies to the Covered Source
281
+ without specifying a version, You may treat that Covered Source
282
+ as being released under any version of the CERN-OHL with that
283
+ variant. If no variant is specified, the Covered Source shall be
284
+ treated as being released under CERN-OHL-S. The Licensor may
285
+ also specify that the Covered Source is subject to a specific
286
+ version of the CERN-OHL or any later version in which case You
287
+ may apply this or any later version of CERN-OHL with the same
288
+ variant identifier published by CERN.
289
+
290
+ You may treat Covered Source licensed under CERN-OHL-W as
291
+ licensed under CERN-OHL-S if and only if all Available
292
+ Components referenced in the Covered Source comply with the
293
+ corresponding definition of Available Component for CERN-OHL-S.
294
+
295
+ 8.4 This Licence shall terminate with immediate effect if You fail
296
+ to comply with any of its terms and conditions.
297
+
298
+ 8.5 However, if You cease all breaches of this Licence, then Your
299
+ Licence from any Licensor is reinstated unless such Licensor has
300
+ terminated this Licence by giving You, while You remain in
301
+ breach, a notice specifying the breach and requiring You to cure
302
+ it within 30 days, and You have failed to come into compliance
303
+ in all material respects by the end of the 30 day period. Should
304
+ You repeat the breach after receipt of a cure notice and
305
+ subsequent reinstatement, this Licence will terminate
306
+ immediately and permanently. Section 6 shall continue to apply
307
+ after any termination.
308
+
309
+ 8.6 This Licence shall not be enforceable except by a Licensor
310
+ acting as such, and third party beneficiary rights are
311
+ specifically excluded.
312
+
313
+