Add FT2 mode (TX + RX)#168
Open
patrickrb wants to merge 2 commits into
Open
Conversation
FT2 is the new ultra-fast HF digital mode from ft2.it (IU8LMC). It is structurally identical to FT4 — 4-GFSK, four Costas sync blocks, 87 data symbols, 77-bit payload, LDPC(174,91) — but runs at double the FT4 baud: 0.024s symbol period (NSPS 288 @12kHz), ~41.7Hz tone spacing, ~167Hz BW, 3.8s T/R cycle, ~2.52s audio. Confirmed against Decodium's FtxFt2Stage7.cpp. TX + mode plumbing (mirrors the FT4 PR #163): - FT8Common.FT2_MODE + ModeProfile.FT2 (one-entry add). Because FT2's tones are bit-identical to FT4, encode() reuses ft4Encode and synth runs at the FT2 symbol period — no new encode code. - bands.txt FT2-tagged dials (PROVISIONAL: FT8 sub-band placeholders pending the official ft2.it/HamPass list); OperationBand parser resolves the mode tag via ModeProfile.displayName so future modes need no new branch. - Mode pill cycles FT8->FT4->FT2 (iterates ModeProfile entries); PSKReporter mode string derives from displayName. RX — parallel from-source decoder (the prebuilt libft8cn.so has no FT2): - Adds FTX_PROTOCOL_FT2 to the in-tree kgoba ft8_lib (pinned at 6f528128, the same commit the prebuilt was built from): constants.h period/slot, monitor.c symbol-period switch, decode.c FT4 branches broadened to FT2 (shared 4-Costas/105-symbol/XOR layout). - ft2_decode_jni.cpp: FT2 decode JNI wrapper (adapted from the ft8_decoder.cpp reconstruction) with distinct *Ft2 entry points and protocol fixed to FT2. - CMake compiles the from-source decode slice + wrapper into libft8af_usb.so with -fvisibility=hidden so its symbols stay internal and never clash with the prebuilt's exported copies; FT8/FT4 keep using the prebuilt unchanged. - FT8SignalListener routes the decode loop to the FT2 backend when ModeProfile.usesFt2Decoder(); FT8/FT4 paths untouched. This newly tracks the vendored kgoba ft8_lib (previously untracked reference, "reconstruction in progress") because the FT2 build now compiles it. Tests: ModeProfile/OperationBand/UtcTimer FT2 cases. Verified on a Pixel 8: unit tests pass, native decoder links across all 4 ABIs, and a native FT2 round-trip (ft4_encode -> GFSK@0.024s -> FT2 decode) recovers the message on-device (Block size=288, score 40). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #168 +/- ##
==========================================
+ Coverage 6.56% 6.57% +0.01%
- Complexity 695 697 +2
==========================================
Files 272 272
Lines 31563 31601 +38
Branches 4982 4984 +2
==========================================
+ Hits 2071 2077 +6
- Misses 29348 29380 +32
Partials 144 144
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds FT2 as a selectable operating mode alongside FT8/FT4, including transmit parameterization and a dedicated from-source native FT2 decoder backend (to avoid relying on the closed prebuilt decoder which only supports FT8/FT4).
Changes:
- Add
ModeProfile.FT2+ mode-cycling/UI plumbing and mode-tagged band dials. - Introduce a parallel from-source FT2 RX decoder (vendored
ft8_libslice +ft2_decode_jni.cpp) compiled intolibft8af_usb.sowith symbol isolation. - Expand unit test coverage for FT2 timing, mode descriptors, and band parsing.
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| ft8cn/app/src/test/java/com/bg7yoz/ft8cn/timer/UtcTimerTest.java | Adds FT2-slot (3800ms) sequential timing test coverage. |
| ft8cn/app/src/test/java/com/bg7yoz/ft8cn/ModeProfileTest.java | Validates FT2 descriptor constants and FT2-decoder routing flag. |
| ft8cn/app/src/test/java/com/bg7yoz/ft8cn/database/OperationBandTest.java | Adds FT2 mode-tag parsing + per-mode dial frequency selection tests. |
| ft8cn/app/src/main/kotlin/radio/ks3ckc/ft8us/pskreporter/PskReporterSender.kt | Switches PSKReporter “mode” string derivation to ModeProfile. |
| ft8cn/app/src/main/kotlin/radio/ks3ckc/ft8us/FT8USApp.kt | Updates mode pill to cycle through ModeProfile entries. |
| ft8cn/app/src/main/java/com/bg7yoz/ft8cn/ModeProfile.java | Adds FT2 profile and usesFt2Decoder() routing helper. |
| ft8cn/app/src/main/java/com/bg7yoz/ft8cn/ft8listener/ReBuildSignal.java | Loads ft8af_usb and adds FT2 subtract JNI entry point. |
| ft8cn/app/src/main/java/com/bg7yoz/ft8cn/ft8listener/FT8SignalListener.java | Routes decode loop through FT2-vs-prebuilt dispatch helpers; loads ft8af_usb. |
| ft8cn/app/src/main/java/com/bg7yoz/ft8cn/FT8Common.java | Adds FT2 mode id and slot timing constants. |
| ft8cn/app/src/main/java/com/bg7yoz/ft8cn/database/OperationBand.java | Generalizes mode tag parsing to resolve via ModeProfile.displayName. |
| ft8cn/app/src/main/cpp/ft8cn_glue/ft2_decode_jni.cpp | New JNI bridge implementing FT2 decode + deep-subtract atop from-source ft8_lib. |
| ft8cn/app/src/main/cpp/ft8_lib/LICENSE | Adds MIT license for vendored ft8_lib. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/unpack.h | Vendored ft8_lib unpack API header. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/unpack.c | Vendored ft8_lib unpack implementation. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/text.h | Vendored ft8_lib text utilities header. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/text.c | Vendored ft8_lib text utilities implementation. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/pack.h | Vendored ft8_lib pack API header. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/pack.c | Vendored ft8_lib pack implementation. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/message.h | Vendored ft8_lib message types and encode/decode API header. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/ldpc.h | Vendored ft8_lib LDPC header. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/ldpc.c | Vendored ft8_lib LDPC implementation. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/encode.h | Vendored ft8_lib encode header. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/encode.c | Vendored ft8_lib encode implementation. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/decode.h | Vendored ft8_lib decode header. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/decode.c | Vendored ft8_lib decode implementation (with FT2 protocol handling). |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/debug.h | Vendored ft8_lib debug macros header. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/crc.h | Vendored ft8_lib CRC header. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/crc.c | Vendored ft8_lib CRC implementation. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/constants.h | Vendored ft8_lib constants header; adds FTX_PROTOCOL_FT2. |
| ft8cn/app/src/main/cpp/ft8_lib/ft8/constants.c | Vendored ft8_lib constants implementation. |
| ft8cn/app/src/main/cpp/ft8_lib/FT8_LIB_PIN.txt | Records the pinned upstream commit for the vendored ft8_lib snapshot. |
| ft8cn/app/src/main/cpp/ft8_lib/fft/kiss_fftr.h | Vendored KISS FFT real FFT header. |
| ft8cn/app/src/main/cpp/ft8_lib/fft/kiss_fftr.c | Vendored KISS FFT real FFT implementation. |
| ft8cn/app/src/main/cpp/ft8_lib/fft/kiss_fft.h | Vendored KISS FFT header (BSD-3-Clause). |
| ft8cn/app/src/main/cpp/ft8_lib/fft/kiss_fft.c | Vendored KISS FFT implementation (BSD-3-Clause). |
| ft8cn/app/src/main/cpp/ft8_lib/fft/_kiss_fft_guts.h | Vendored KISS FFT internal header. |
| ft8cn/app/src/main/cpp/ft8_lib/common/monitor.h | Vendored ft8_lib monitor API header. |
| ft8cn/app/src/main/cpp/ft8_lib/common/monitor.c | Vendored ft8_lib monitor implementation with FT2 protocol selection. |
| ft8cn/app/src/main/cpp/ft8_lib/common/common.h | Adds an M_PI definition helper header. |
| ft8cn/app/src/main/cpp/CMakeLists.txt | Builds/links the from-source FT2 decoder slice into libft8af_usb.so. |
| ft8cn/app/src/main/assets/bands.txt | Adds provisional FT2 dial entries (mode-tagged). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+157
to
+158
| // Mode string (FT8/FT4/FT2) derived from the message's mode descriptor. | ||
| val mode = ModeProfile.fromId(msg.signalFormat).displayName |
Comment on lines
47
to
53
| static { | ||
| System.loadLibrary("ft8cn"); | ||
| // The FT2 decoder JNI entry points (InitDecoderFt2 etc.) live in ft8af_usb (our | ||
| // from-source ft8_lib build), not the prebuilt ft8cn. Load it so they resolve when | ||
| // the user operates in FT2 mode. Idempotent if GenerateFT8 already loaded it. | ||
| System.loadLibrary("ft8af_usb"); | ||
| } |
Comment on lines
14
to
18
| static { | ||
| System.loadLibrary("ft8cn"); | ||
| // doSubtractSignalFt2 lives in ft8af_usb (the from-source FT2 decoder), not ft8cn. | ||
| System.loadLibrary("ft8af_usb"); | ||
| } |
Comment on lines
+1
to
+11
| #include "monitor.h" | ||
|
|
||
| #define LOG_LEVEL LOG_INFO | ||
| #include <ft8/debug.h> | ||
|
|
||
| #include <stdlib.h> | ||
|
|
||
| static float hann_i(int i, int N) | ||
| { | ||
| float x = sinf((float)M_PI * i / N); | ||
| return x * x; |
Comment on lines
+1
to
+7
| /* | ||
| * Copyright (c) 2003-2010, Mark Borgerding. All rights reserved. | ||
| * This file is part of KISS FFT - https://github.com/mborgerding/kissfft | ||
| * | ||
| * SPDX-License-Identifier: BSD-3-Clause | ||
| * See COPYING file for more information. | ||
| */ |
- PskReporterSender: drop spots with an unknown/corrupt signalFormat instead of mislabelling them as FT8 (ModeProfile.fromId falls back to FT8); restores the prior drop-on-unknown behavior while still supporting FT2. - FT8SignalListener / ReBuildSignal: wrap the native loadLibrary calls in try/catch (mirroring GenerateFT8) so class init doesn't crash when native libs aren't on the path (e.g. JVM unit tests). - monitor.c: include <math.h> (sinf/log10f) and common.h (M_PI fallback) so the vendored source builds on toolchains where <math.h> doesn't define M_PI. - Add ft8_lib/fft/COPYING (KISS FFT BSD-3-Clause) referenced by the kiss_fft headers but previously missing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds FT2 — the ultra-fast HF digital mode from ft2.it (IU8LMC) — as a fully working two-way operating mode (transmit and receive), alongside FT8/FT4.
FT2 is structurally identical to FT4 (4-GFSK, four Costas sync blocks, 87 data symbols, 77-bit payload, LDPC(174,91)) but runs at double the FT4 baud: 0.024s symbol period (NSPS 288 @12kHz), ~41.7 Hz tone spacing, ~167 Hz BW, 3.8s T/R cycle, ~2.52s audio. Parameters confirmed against Decodium-4.0-Core-Shannon's
FtxFt2Stage7.cpp.How
TX + mode plumbing (mirrors the FT4 PR #163's
ModeProfile):FT8Common.FT2_MODE+ a one-lineModeProfile.FT2entry. FT2's tones are bit-identical to FT4, soencode()reusesft4Encodeand synth runs at the FT2 symbol period — no new encode code.bands.txtFT2-tagged dials;OperationBandparser resolves the mode tag viaModeProfile.displayName(future-proof). Mode pill now cycles FT8→FT4→FT2.RX — parallel from-source decoder (the closed prebuilt
libft8cn.sohas no FT2 protocol):FTX_PROTOCOL_FT2to the in-tree kgobaft8_lib(pinned at6f528128, the same commit the prebuilt was built from):constants.hperiod/slot,monitor.csymbol-period switch,decode.cFT4 branches broadened to FT2 (shared 4-Costas/105-symbol/XOR layout).ft2_decode_jni.cppdecode wrapper with distinct*Ft2JNI entry points; CMake compiles the from-source decode slice intolibft8af_usb.sowith-fvisibility=hiddenso its symbols stay internal and never clash with the prebuilt's. FT8/FT4 decode is byte-for-byte unchanged (still the prebuilt).FT8SignalListenerroutes the decode loop to the FT2 backend whenModeProfile.usesFt2Decoder().Verification (Pixel 8)
ModeProfile,OperationBand,UtcTimerFT2 cases).ft4_encode → GFSK@0.024s → FT2 decoderecovers"CQ K1ABC FN42"(Block size = 288 confirms the FT2 symbol period; score 40). This is the gold-standard proof FT2 RX interoperates with real transmitters.The FT2 band frequencies are provisional placeholders (FT8 sub-band dials). ft2.it/Decodium publish only example QSOs and conflicting calling freqs, pointing to a HamPass
ft2-bands.qrgfile. Please provide the official per-band list and I'll swap them in before merge.🤖 Generated with Claude Code