Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ public static Context getMainContext() {
public static String qrzXmlPassword = ""; //QRZ XML API password
public static boolean pskOverlayEnabled = false; //PSK Reporter map overlay (issue #33)
public static boolean synFrequency = false;//Same-frequency transmit
public static boolean holdTxFreq = false;//Hold TX freq: don't move the TX offset to a station you answer (WSJT-X "Hold Tx Freq")
public static int transmitDelay = 500;//Transmit delay; also allows decoding time for the previous cycle
public static int pttDelay = 100;//PTT response time; radios typically need some response time after PTT command, default 100ms
public static int lateStartTolerance = 2000;//Max ms into a cycle that a manual TX may start; leading audio is clipped so TX still ends on the cycle boundary. 0-4000.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2378,6 +2378,11 @@ protected Void doInBackground(Void... voids) {
if (name.equalsIgnoreCase("synFreq")) {
GeneralVariables.synFrequency = !(result.equals("") || result.equals("0"));
}
if (name.equalsIgnoreCase("holdTxFreq")) {
// Parse like synFreq above: any non-empty, non-"0" value is true,
// so the two boolean configs handle stored values consistently.
GeneralVariables.holdTxFreq = !(result.equals("") || result.equals("0"));
}
if (name.equalsIgnoreCase("transDelay")) {
if (result.matches("^\\d{1,4}$")) {//Regex: 1-4 digit number
GeneralVariables.transmitDelay = Integer.parseInt(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,10 @@ public void setTransmit(TransmitCallsign transmitCallsign
if (transmitCallsign.frequency == 0) {
transmitCallsign.frequency = GeneralVariables.getBaseFrequency();
}
if (GeneralVariables.synFrequency) {// if same-frequency mode, match target callsign frequency
// Same-frequency mode moves our TX offset onto the station we answer — unless
// "Hold TX freq" is on (WSJT-X "Hold Tx Freq"), in which case we keep calling
// on our own offset. Tester reported the auto-move felt inverted.
if (shouldFollowTargetFreq(GeneralVariables.synFrequency, GeneralVariables.holdTxFreq)) {
setBaseFrequency(transmitCallsign.frequency);
}

Expand All @@ -345,6 +348,16 @@ public void setBaseFrequency(float freq) {
databaseOpr.writeConfig("freq", String.format("%.0f", freq), null);
}

/**
* Whether to move our TX offset onto the frequency of the station we're about to
* answer. True only in TX=RX (synFrequency) mode AND when "Hold TX freq" is off —
* holding TX freq (WSJT-X "Hold Tx Freq") keeps us calling on our own offset.
* Pure decision logic so it can be unit-tested without the Android runtime.
*/
static boolean shouldFollowTargetFreq(boolean synFrequency, boolean holdTxFreq) {
return synFrequency && !holdTxFreq;
}

/**
* Build an Ft8Message for a Field Day exchange (i3=0, n3=3 or 4).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ fun TransmissionSettings(
onBack: () -> Unit,
) {
var synFrequency by remember { mutableStateOf(GeneralVariables.synFrequency) }
var holdTxFreq by remember { mutableStateOf(GeneralVariables.holdTxFreq) }
var watchdogMs by remember { mutableIntStateOf(GeneralVariables.launchSupervision) }
var noReplyLimit by remember { mutableIntStateOf(GeneralVariables.noReplyLimit) }

Expand Down Expand Up @@ -141,6 +142,19 @@ fun TransmissionSettings(
},
)
SectionDivider()
SettingsRow(
label = stringResource(R.string.settings_hold_tx_freq),
description = stringResource(R.string.settings_hold_tx_freq_desc),
toggle = holdTxFreq,
onToggleChange = { checked ->
holdTxFreq = checked
GeneralVariables.holdTxFreq = checked
mainViewModel.databaseOpr.writeConfig(
"holdTxFreq", if (checked) "1" else "0", null,
)
},
)
SectionDivider()
SettingsRow(
label = stringResource(R.string.settings_tx_watchdog),
description = stringResource(R.string.settings_tx_watchdog_desc),
Expand Down
2 changes: 2 additions & 0 deletions ft8af/app/src/main/res/values/strings_compose.xml
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,8 @@
<!-- ===== Settings: transmission ===== -->
<string name="settings_tx_rx_split">TX/RX Split</string>
<string name="settings_tx_rx_split_desc">Transmit on a different frequency than receive</string>
<string name="settings_hold_tx_freq">Hold TX freq</string>
<string name="settings_hold_tx_freq_desc">Keep your TX offset when answering a station instead of moving it to theirs</string>
<string name="settings_tx_watchdog">TX Watchdog</string>
<string name="settings_tx_watchdog_desc">Auto-stop transmit after timeout</string>
<string name="settings_stop_after">Stop After</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,4 +340,28 @@ public void huntFilter_potaOnlyOn_keepsPota() {
// A genuine POTA CQ stays eligible when the filter is active.
assertThat(FT8TransmitSignal.huntFilterExcludes(true, true)).isFalse();
}

// ---- shouldFollowTargetFreq ---------------------------------------------
// TX=RX (synFrequency) mode moves our TX offset onto the station we answer.
// "Hold TX freq" (WSJT-X Hold Tx Freq) must override that and keep us on our own
// offset. So we follow the target ONLY when synFrequency is on AND hold is off.

@Test
public void followTarget_splitOn_holdOff_follows() {
assertThat(FT8TransmitSignal.shouldFollowTargetFreq(
/*synFrequency*/ true, /*holdTxFreq*/ false)).isTrue();
}

@Test
public void followTarget_splitOn_holdOn_holds() {
// The reported request: keep my TX offset even with split on.
assertThat(FT8TransmitSignal.shouldFollowTargetFreq(true, true)).isFalse();
}

@Test
public void followTarget_splitOff_neverFollows() {
// Without split there's nothing to follow, hold flag irrelevant.
assertThat(FT8TransmitSignal.shouldFollowTargetFreq(false, false)).isFalse();
assertThat(FT8TransmitSignal.shouldFollowTargetFreq(false, true)).isFalse();
}
}
Loading