From 58fb688593fd88cf6d917760b33402040e4d3c11 Mon Sep 17 00:00:00 2001 From: Rui Oliveira Date: Fri, 24 Jul 2026 15:41:34 +0100 Subject: [PATCH] Fix bugs in setting the Tx frequency Uses 0x25 01 command to set the Tx frequency, which is the correct command when in split mode. --- .../core/data/framework/Ic705Controller.kt | 13 ++++++++++++- .../core/data/framework/IcomCivProtocol.kt | 14 +++++++++++++- .../core/data/framework/RadioTrackingService.kt | 10 +++++----- .../core/domain/repository/IRadioController.kt | 12 +++++++++--- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/Ic705Controller.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/Ic705Controller.kt index 69d9cfe1..010c115e 100644 --- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/Ic705Controller.kt +++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/Ic705Controller.kt @@ -204,12 +204,23 @@ class Ic705Controller( * always writing to the active VFO is the correct strategy. */ override suspend fun setWorkingFrequency(frequencyHz: Long): Boolean = withContext(Dispatchers.IO) { - Log.d(tag, "setWorkingFrequency: ${frequencyHz}Hz") + Log.d(tag, "setWorkingFrequency (0x25/00): ${frequencyHz}Hz") val cmd = IcomCivProtocol.buildSetWorkingFreqCommand(frequencyHz) Log.d(tag, "CMD setWorkingFreq → ${IcomCivProtocol.toHex(cmd)}") ioMutex.withLock { sendAndWaitAck(cmd) } } + /** + * Set TX VFO frequency via CMD 0x25 sub 0x01 (unselected VFO). + * Used in split mode while PTT is pressed. + */ + override suspend fun setTxVfoFrequency(frequencyHz: Long): Boolean = withContext(Dispatchers.IO) { + Log.d(tag, "setTxVfoFrequency (0x25/01): ${frequencyHz}Hz") + val cmd = IcomCivProtocol.buildSetUnselectedVfoFreqCommand(frequencyHz) + Log.d(tag, "CMD setTxVfoFreq → ${IcomCivProtocol.toHex(cmd)}") + ioMutex.withLock { sendAndWaitAck(cmd) } + } + // ── Internal I/O helpers ──────────────────────────────────────────────── /** diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/IcomCivProtocol.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/IcomCivProtocol.kt index 73b25948..0f400c1b 100644 --- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/IcomCivProtocol.kt +++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/IcomCivProtocol.kt @@ -73,8 +73,10 @@ object IcomCivProtocol { const val SUB_SPLIT_ON: Byte = 0x01 /** Sub for CMD_TX_STATUS: query TX/RX state. */ const val SUB_TX_STATE: Byte = 0x00 - /** Sub for CMD_SELECTED_VFO_FREQ: selected VFO frequency. */ + /** Sub for CMD_SELECTED_VFO_FREQ: selected (active) VFO frequency. */ const val SUB_SELECTED_VFO: Byte = 0x00 + /** Sub for CMD_SELECTED_VFO_FREQ: unselected (inactive / TX in split) VFO frequency. */ + const val SUB_UNSELECTED_VFO: Byte = 0x01 /** Sub for CMD_MISC_SETTING: CTCSS/DTCS tone squelch. */ const val SUB_CTCSS_SETTING: Byte = 0x42.toByte() @@ -167,6 +169,16 @@ object IcomCivProtocol { return frame(CMD_SELECTED_VFO_FREQ, SUB_SELECTED_VFO, *encodeFrequencyBcd(frequencyHz)) } + /** + * Set unselected-VFO frequency via CMD 0x25 sub 0x01. + * In split mode while PTT is pressed the IC-705 makes VFO-B active, so + * this command targets VFO-A (the RX VFO) — and vice-versa when in RX. + * Use this to update the TX VFO when PTT is on. + */ + fun buildSetUnselectedVfoFreqCommand(frequencyHz: Long): ByteArray { + return frame(CMD_SELECTED_VFO_FREQ, SUB_UNSELECTED_VFO, *encodeFrequencyBcd(frequencyHz)) + } + /** Read operating frequency (CMD 0x03). */ fun buildReadFreqCommand(): ByteArray = frame(CMD_READ_FREQ) diff --git a/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/RadioTrackingService.kt b/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/RadioTrackingService.kt index 42ae5a5e..67f8e770 100644 --- a/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/RadioTrackingService.kt +++ b/core/data/src/main/java/com/rtbishop/look4sat/core/data/framework/RadioTrackingService.kt @@ -387,17 +387,17 @@ class RadioTrackingService( when (isPtt) { true -> { // PTT ON → radio's active VFO is VFO-B (TX) - // Update TX frequency on active VFO only + // Use 0x25/01 (unselected VFO) to target VFO-B directly if (txRadioFreq != null) { - Log.d(tag, "Split loop TX update: ${txRadioFreq}Hz") - radio.setWorkingFrequency(txRadioFreq) + Log.d(tag, "Split loop TX update (0x25/01): ${txRadioFreq}Hz") + radio.setTxVfoFrequency(txRadioFreq) } } false -> { // PTT OFF → radio's active VFO is VFO-A (RX) - // Update RX frequency on active VFO only + // Use 0x25/00 (selected/active VFO) to update RX if (rxRadioFreq != null) { - Log.d(tag, "Split loop RX update: ${rxRadioFreq}Hz") + Log.d(tag, "Split loop RX update (0x25/00): ${rxRadioFreq}Hz") radio.setWorkingFrequency(rxRadioFreq) } } diff --git a/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/repository/IRadioController.kt b/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/repository/IRadioController.kt index e76e28e9..89d2c83f 100644 --- a/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/repository/IRadioController.kt +++ b/core/domain/src/main/java/com/rtbishop/look4sat/core/domain/repository/IRadioController.kt @@ -62,10 +62,16 @@ interface IRadioController { suspend fun setSplitMode(enabled: Boolean): Boolean = false /** - * Set the frequency of the currently active VFO. - * On radios that support it (IC-705: CMD 0x25 sub 0x00) this updates - * the active VFO without switching. + * Set the frequency of the currently active VFO (CMD 0x25 sub 0x00). * Default: delegates to [setFrequency]. */ suspend fun setWorkingFrequency(frequencyHz: Long): Boolean = setFrequency(frequencyHz) + + /** + * Set the frequency of the inactive (TX) VFO via CMD 0x25 sub 0x01. + * Used in split mode when PTT is pressed: the radio has made VFO-B + * the active VFO, so sub 0x01 targets it directly. + * Default: delegates to [setWorkingFrequency]. + */ + suspend fun setTxVfoFrequency(frequencyHz: Long): Boolean = setWorkingFrequency(frequencyHz) }