|
| 1 | +# Changelog |
| 2 | + |
| 3 | +All notable changes to hackrfpy are documented here. |
| 4 | + |
| 5 | +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), |
| 6 | +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 7 | + |
| 8 | +## [Unreleased] |
| 9 | + |
| 10 | +Work on the current development branch. Entries move to a versioned section on |
| 11 | +release. |
| 12 | + |
| 13 | +### Added |
| 14 | +- Type annotations across the entire shipped package, and `mypy` promoted to a |
| 15 | + blocking CI gate (`disallow_untyped_defs`). The package has always shipped a |
| 16 | + `py.typed` marker, which tells downstream type-checkers the inline annotations |
| 17 | + are real; previously only 1 of ~114 definitions was annotated, so that marker |
| 18 | + was a false promise. It is now enforced. |
| 19 | +- `HostOps` protocol (`_host.py`) making the contract between `HackRF` and the |
| 20 | + command mixins explicit and type-checkable. The mixins call ~27 methods on |
| 21 | + `self` that live on the host class; that dependency was previously implicit in |
| 22 | + a comment. Runtime composition and MRO are unchanged. |
| 23 | +- Continuous integration: GitHub Actions workflow running the test suite across |
| 24 | + Windows, Linux, and macOS on Python 3.11-3.13, plus a ruff + mypy lint job. |
| 25 | +- CLI test suite covering argument parsing, the mode state file, preset |
| 26 | + resolution, `info`/`detect`/`doctor`, `rx`/`tx`/`sweep` dispatch, and the |
| 27 | + module-level exit-code mapping. Overall coverage raised from 73% to 86% |
| 28 | + (`cli.py` from 12% to ~98%). |
| 29 | +- Community health files: `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, |
| 30 | + `SECURITY.md`, issue templates, and a pull request template. |
| 31 | + |
| 32 | +### Changed |
| 33 | +- Library diagnostics now go through the standard `logging` module instead of |
| 34 | + `print()`. Records are emitted on the `hackrfpy` logger: warnings at |
| 35 | + `WARNING`, verbose progress messages at `INFO`. A consumer can now route, |
| 36 | + reformat, or silence hackrfpy's output like any other library. |
| 37 | + - **Diagnostics no longer touch stdout.** `print_message` previously wrote to |
| 38 | + stdout, so `hrf sweep -v > out.csv` prepended `[*] mode: rx` into the CSV. |
| 39 | + stdout is now reserved for data (sweep CSV, IQ on `-r -`) and explicitly |
| 40 | + requested output (`--print-cmd`). Diagnostics go to stderr. |
| 41 | + - Console behavior is unchanged for scripts and the CLI: warnings still appear |
| 42 | + with no setup at all, and `verbose=True` / `-v` still prints progress. If the |
| 43 | + host application has configured logging, hackrfpy stays out of the way and |
| 44 | + simply propagates records to it. |
| 45 | +- Packaging classifiers: removed the contradictory `Operating System :: |
| 46 | + OS Independent` (the library shells out to the Windows `hackrf-tools` |
| 47 | + binaries and Linux/macOS operation is unverified), leaving `Operating System |
| 48 | + :: Microsoft :: Windows`. Development status raised from `3 - Alpha` to |
| 49 | + `5 - Production/Stable` to match the 1.0.0 release. |
| 50 | +- Ruff configuration added (`line-length = 100`, `select = ["E", "F", "W"]`), and |
| 51 | + the codebase made lint-clean so the CI lint job is meaningful. |
| 52 | + |
| 53 | +### Fixed |
| 54 | +- The `atexit` backstop never reaped an orphaned `PersistentReceiver`. |
| 55 | + `PersistentReceiver` registers itself in the live-handle registry, whose |
| 56 | + shutdown hook calls `if h.is_alive(): h.stop()` -- but `is_alive()` did not |
| 57 | + exist on the class, so the resulting `AttributeError` was swallowed by the |
| 58 | + hook's bare `except Exception` and the receiver was silently left running. |
| 59 | + Found by the typing pass; `is_alive()` added and pinned with a regression test. |
| 60 | +- Reading from a closed `PersistentReceiver` raised a bare |
| 61 | + `TypeError: 'NoneType' object is not iterable` instead of a typed error; it now |
| 62 | + raises `HackRFDeviceError` with an actionable message. |
| 63 | +- `sweep_stream(..., print_cmd=True)` would hand `StreamCtx` a `None` and crash; |
| 64 | + it now raises `HackRFValueError` pointing at `sweep(..., print_cmd=True)`. |
| 65 | +- Unbounded memory growth on long-lived RX/TX handles: `_Process` drained child |
| 66 | + stdout/stderr into lists that were never trimmed, so an open-ended capture or |
| 67 | + repeat transmit retained every per-second stats line for the life of the |
| 68 | + process. Both drain paths now share a 64 KB cap (`_DRAIN_CAP`). |
| 69 | +- `transmit()` now verifies the source file exists *before* arming TX and |
| 70 | + spawning `hackrf_transfer`, raising `HackRFEnvironmentError` instead of |
| 71 | + failing with a generic non-zero exit from the tool. The TX-mode gate is still |
| 72 | + checked first, and `print_cmd` dry runs skip the check. |
| 73 | +- SigMF sidecars now declare the `hackrf` namespace in `core:extensions`. |
| 74 | + Previously the `hackrf:*` gain keys were written without declaring the |
| 75 | + extension, which strict SigMF validators reject. |
| 76 | +- Removed unreachable dead code in `core.py` (an orphaned `return load_iq(...)` |
| 77 | + after a `return`, referencing three undefined names). |
| 78 | +- The test suite no longer writes a stray `capture.sigmf-meta` into the working |
| 79 | + directory on every run. |
| 80 | +- `CITATION.cff` version and release date corrected to `1.0.0` / `2026-06-16`, |
| 81 | + aligning the citation metadata with `pyproject.toml` and the tagged release. |
| 82 | + |
| 83 | +<!-- |
| 84 | +Roadmap for this branch (append entries above as each lands): |
| 85 | + - Added: type annotations across the public API; mypy promoted to a CI gate |
| 86 | + (makes the shipped py.typed marker accurate). |
| 87 | + - CI: --cov-fail-under=85; confirm the Windows leg exercises the CTRL_BREAK |
| 88 | + lifecycle path. |
| 89 | + - Docs: note that a single HackRF instance is not safe to share across |
| 90 | + threads (deferred pending broader testing). |
| 91 | +--> |
| 92 | + |
| 93 | +## [1.0.0] - 2026-06-16 |
| 94 | + |
| 95 | +Initial public release. |
| 96 | + |
| 97 | +### Added |
| 98 | +- Python wrapper and non-GUI command-line tool (`hrf`) for the HackRF One, |
| 99 | + driving the `hackrf-tools` binaries directly (no libhackrf bindings). |
| 100 | +- Receive: bounded and streaming capture, with decode to `complex64` and |
| 101 | + self-describing SigMF (`.sigmf-meta`) sidecars. |
| 102 | +- Spectrum sweep with streaming CSV parsing. |
| 103 | +- Transmit: file playback and constant-wave source, guarded by an explicit |
| 104 | + operating-mode gate (transmit refuses unless the instance is switched to TX |
| 105 | + mode, which emits a one-time safety banner) and a TX gain ceiling. |
| 106 | +- Device management passthroughs (clock, Opera Cake, SPI flash, debug) and |
| 107 | + preflight `info` / `detect` / `doctor` helpers. |
| 108 | +- Cross-platform process lifecycle handling with best-effort clean interrupt |
| 109 | + (SIGINT on POSIX, CTRL_BREAK on Windows) and an atexit backstop for live |
| 110 | + RX/TX handles. |
| 111 | +- Validation layer with hard-range checks, gain snapping to real device steps, |
| 112 | + and a parameter readback (`last_params`) reflecting the values actually used. |
| 113 | + |
| 114 | +[Unreleased]: https://github.com/LC-Linkous/hackRF_python/compare/V1.0.0...HEAD |
| 115 | +[1.0.0]: https://github.com/LC-Linkous/hackRF_python/releases/tag/V1.0.0 |
0 commit comments