mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-10-18 21:34:03 +02:00
Restore the turn-antenna button and send the PSTRotator azimuth with one decimal (#126)
* Send the PSTRotator azimuth with one decimal instead of truncating it
setAzimuth cast the azimuth to int, so 145.7 degrees turned the antenna
to 145. It is now rounded to one decimal and formatted with Locale.ROOT,
so a German default locale cannot turn the dot into a comma; a value that
rounds up to 360.0 is sent as 0.0. The loopback test pinned the old
truncation and now expects the decimal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bring back the turn-antenna button lost in the Compose migration
The JavaFX station panel had "Turn ant1 to <call>", the only caller of
ChatController.rotateTo; removing JavaFX (fe4215bc) dropped it, so the
antenna could no longer be turned from KST4Contest at all. The Compose
panel gets the button again, enabled when a rotator callback is wired and
the selected station has a finite heading.
Review follow-ups for the decimal azimuth: formatAzimuth refuses NaN and
infinite values and wraps any finite value into [0, 360). The "reached"
check before the SPID retry uses a 1.0 degree tolerance, because the
target now carries a decimal while many controllers report whole degrees.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Keep rotateTo's Javadoc on the method and word the German label as a bearing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e1e6fe7297
commit
2898c530d9
12 files changed
+150
-5
No files matched your search
@@ -321,6 +321,13 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
rotatorClient.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* How close the reported position must be to count as "reached". The target carries a
|
||||
* decimal, while many rotor controllers report whole degrees: with 0.5 a target of 145.7
|
||||
* and a report of 145 would count as missed and could trigger the retry.
|
||||
*/
|
||||
static final double ROTATOR_REACHED_TOLERANCE_DEGREES = 1.0;
|
||||
|
||||
/**
|
||||
* Sends a new azimuth to PSTRotator without blocking the JavaFX thread.
|
||||
*
|
||||
@@ -399,7 +406,7 @@ public class ChatController implements ThreadStatusCallback, PstRotatorEventList
|
||||
double currentAzimuth = lastReportedRotatorAzimuth;
|
||||
|
||||
if (Double.isFinite(currentAzimuth)
|
||||
&& angularDistance(currentAzimuth, targetAzimuth) < 0.5) {
|
||||
&& angularDistance(currentAzimuth, targetAzimuth) < ROTATOR_REACHED_TOLERANCE_DEGREES) {
|
||||
|
||||
LOGGER.log(
|
||||
Level.FINE,
|
||||
|
||||
@@ -6,6 +6,7 @@ import kst4contest.model.ThreadStateMessage;
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -192,8 +193,24 @@ public class PstRotatorClient implements Runnable {
|
||||
// Öffentliche Steuermethoden
|
||||
|
||||
public void setAzimuth(double degrees) {
|
||||
// Formatierung ohne unnötige Nachkommastellen, falls nötig
|
||||
sendCommand("AZIMUTH", String.valueOf((int) degrees));
|
||||
sendCommand("AZIMUTH", formatAzimuth(degrees));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an azimuth with one decimal and a dot as separator, independent of the
|
||||
* default locale, wrapped into [0, 360): 360.0 is sent as 0.0, -10 as 350.0. The
|
||||
* azimuth used to be truncated to whole degrees, so 145.7 turned the antenna to 145.
|
||||
*
|
||||
* @throws IllegalArgumentException for NaN or an infinite value, which has no heading
|
||||
*/
|
||||
static String formatAzimuth(double degrees) {
|
||||
if (!Double.isFinite(degrees)) {
|
||||
throw new IllegalArgumentException("Azimuth is not a finite number: " + degrees);
|
||||
}
|
||||
double rounded = Math.round(degrees * 10.0) / 10.0;
|
||||
double wrapped = ((rounded % 360.0) + 360.0) % 360.0;
|
||||
// Rounding can leave a tiny negative remainder that would print as -0.0.
|
||||
return String.format(Locale.ROOT, "%.1f", wrapped == 0.0 ? 0.0 : wrapped);
|
||||
}
|
||||
|
||||
public void setElevation(double degrees) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package kst4contest.controller;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** The azimuth sent to PSTRotator: one decimal, dot separator, within [0, 360). */
|
||||
class PstRotatorClientAzimuthFormatTest {
|
||||
|
||||
@Test
|
||||
void keepsOneDecimalInsteadOfTruncating() {
|
||||
assertEquals("145.7", PstRotatorClient.formatAzimuth(145.7));
|
||||
assertEquals("145.0", PstRotatorClient.formatAzimuth(145.0));
|
||||
assertEquals("0.0", PstRotatorClient.formatAzimuth(0.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void roundsToTheNearestTenth() {
|
||||
assertEquals("145.7", PstRotatorClient.formatAzimuth(145.66));
|
||||
assertEquals("145.7", PstRotatorClient.formatAzimuth(145.70000000000002));
|
||||
assertEquals("12.3", PstRotatorClient.formatAzimuth(12.34));
|
||||
}
|
||||
|
||||
@Test
|
||||
void aValueRoundingUpTo360IsSentAsZero() {
|
||||
assertEquals("0.0", PstRotatorClient.formatAzimuth(359.96));
|
||||
assertEquals("359.9", PstRotatorClient.formatAzimuth(359.94));
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrapsAnyFiniteValueIntoOneTurn() {
|
||||
assertEquals("0.0", PstRotatorClient.formatAzimuth(720.0));
|
||||
assertEquals("10.0", PstRotatorClient.formatAzimuth(370.0));
|
||||
assertEquals("350.0", PstRotatorClient.formatAzimuth(-10.0));
|
||||
assertEquals("0.0", PstRotatorClient.formatAzimuth(-0.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void refusesAValueWithoutAHeading() {
|
||||
assertThrows(IllegalArgumentException.class, () -> PstRotatorClient.formatAzimuth(Double.NaN));
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> PstRotatorClient.formatAzimuth(Double.POSITIVE_INFINITY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesADotEvenUnderAGermanDefaultLocale() {
|
||||
Locale previous = Locale.getDefault();
|
||||
try {
|
||||
Locale.setDefault(Locale.GERMANY);
|
||||
assertEquals("145.7", PstRotatorClient.formatAzimuth(145.7));
|
||||
} finally {
|
||||
Locale.setDefault(previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,8 +108,8 @@ class PstRotatorClientLoopbackTest {
|
||||
client.setTrackingMode(true);
|
||||
client.setTrackingMode(false);
|
||||
|
||||
// The azimuth is truncated to whole degrees; the elevation is not.
|
||||
assertEquals("<PST><AZIMUTH>145</AZIMUTH></PST>", receiveCommand());
|
||||
// The azimuth keeps one decimal; it used to be truncated to whole degrees.
|
||||
assertEquals("<PST><AZIMUTH>145.7</AZIMUTH></PST>", receiveCommand());
|
||||
assertEquals("<PST><ELEVATION>10.5</ELEVATION></PST>", receiveCommand());
|
||||
assertEquals("<PST><STOP>1</STOP></PST>", receiveCommand());
|
||||
assertEquals("<PST><PARK>1</PARK></PST>", receiveCommand());
|
||||
|
||||
Reference in new issue
Block a user