Fix bugs in setting Rx frequency

This commit is contained in:
Rui Oliveira committed 2026-07-24 20:08:46 +01:00
1 parent f9b1a97a37
commit dc596b4348
2 files changed
+44 -7

No files matched your search

@@ -244,19 +244,25 @@ class Ic705Controller(
/** /**
* Drain whatever bytes the radio has buffered within a [timeoutMs] window. * Drain whatever bytes the radio has buffered within a [timeoutMs] window.
* Uses non-blocking `available()` polling to avoid blocking indefinitely. * Exits early as soon as a complete CI-V frame addressed to us is present
* in the buffer (i.e., FE FE E0 A4 … FD), so we don't waste the remaining
* timeout on responses that already arrived.
*/ */
private suspend fun drainWithTimeout(timeoutMs: Long): ByteArray { private suspend fun drainWithTimeout(timeoutMs: Long): ByteArray {
val result = mutableListOf<Byte>() val result = mutableListOf<Byte>()
val deadline = System.currentTimeMillis() + timeoutMs val deadline = System.currentTimeMillis() + timeoutMs
val stream = inputStream ?: return ByteArray(0) val stream = inputStream ?: return ByteArray(0)
while (System.currentTimeMillis() < deadline) { while (System.currentTimeMillis() < deadline) {
try { try {
val available = stream.available() val available = stream.available()
if (available > 0) { if (available > 0) {
val chunk = ByteArray(available) val chunk = ByteArray(available)
val read = stream.read(chunk) val read = stream.read(chunk)
if (read > 0) result.addAll(chunk.take(read)) if (read > 0) {
result.addAll(chunk.take(read))
// Exit early once we have a complete frame for us
if (hasCompleteFrameForUs(result)) break
}
} else { } else {
delay(POLL_INTERVAL_MS) delay(POLL_INTERVAL_MS)
} }
@@ -269,6 +275,30 @@ class Ic705Controller(
return result.toByteArray() return result.toByteArray()
} }
/**
* Returns true if [buf] contains a complete CI-V frame addressed to the
* controller (FE FE [ADDR_CTRL] [ADDR_IC705] … FD).
* CI-V data bytes cannot be 0xFD, so the first 0xFD after the header is
* always the frame terminator.
*/
private fun hasCompleteFrameForUs(buf: List<Byte>): Boolean {
var i = 0
while (i < buf.size - 4) {
if (buf[i] == IcomCivProtocol.PREAMBLE &&
buf[i + 1] == IcomCivProtocol.PREAMBLE &&
buf[i + 2] == IcomCivProtocol.ADDR_CTRL &&
buf[i + 3] == IcomCivProtocol.ADDR_IC705
) {
for (k in i + 4 until buf.size) {
if (buf[k] == IcomCivProtocol.END_OF_MSG) return true
}
return false // header found but no FD yet
}
i++
}
return false
}
private fun write(bytes: ByteArray): Boolean { private fun write(bytes: ByteArray): Boolean {
return try { return try {
outputStream?.write(bytes) outputStream?.write(bytes)
@@ -283,11 +283,18 @@ object IcomCivProtocol {
/** /**
* Parse TX status from a CMD_TX_STATUS reply payload. * Parse TX status from a CMD_TX_STATUS reply payload.
*
* The IC-705 responds to a `1C 00` query with:
* FE FE E0 A4 1C 00 <status> FD
* After [parseResponse] strips the frame header the payload is:
* payload[0] = 0x00 (sub-command echo)
* payload[1] = status byte (0x00 = RX, 0x01 = TX)
*
* Returns true if transmitting, false if receiving, null on error. * Returns true if transmitting, false if receiving, null on error.
*/ */
fun parseTxStatus(payload: ByteArray): Boolean? { fun parseTxStatus(payload: ByteArray): Boolean? {
if (payload.isEmpty()) return null if (payload.size < 2) return null
return when (payload[0]) { return when (payload[1]) {
0x00.toByte() -> false // RX 0x00.toByte() -> false // RX
0x01.toByte() -> true // TX 0x01.toByte() -> true // TX
else -> null else -> null