fix(wavelog): preserve six-character grids in v1 ADIF upload

WaveLog v1 truncated every grid to four characters with gridsquare.take(4),
while v2 sent the same grid at full precision. QRZ backfill provides six-character
locators (e.g. OM89ab / FN31pr), so the v1 path - the one used by the user's
server in practice - degraded position precision from roughly 4.6 km to around
100 km and stored different data depending on which API version answered.

Send the complete grid through v1 as well. The ADIF length field is already
computed from the actual value, so six/eight-character locators need no special
handling.

TDD proof:
  old take(4): v1_adif_preservesSixCharacterGrid FAILED
  fixed:       WaveLogApiPayloadTest BUILD SUCCESSFUL
  full suite:  :core:domain:test BUILD SUCCESSFUL
This commit is contained in:
mckero committed 2026-08-14 14:56:23 +00:00
1 parent 09e728fa1b
commit e1233dceaa
2 files changed
+23 -2

No files matched your search

@@ -225,7 +225,7 @@ object WaveLogApi {
}
/** v1 ADIF string (freq in MHz, length = UTF-8 byte count, sat_name normalized) */
private fun toAdif(qso: WavelogQso, gridsquare: String, satName: String): String {
internal fun toAdif(qso: WavelogQso, gridsquare: String, satName: String): String {
fun field(name: String, value: String): String {
val bytes = value.toByteArray(Charsets.UTF_8).size
return "<$name:$bytes>$value"
@@ -243,7 +243,11 @@ object WaveLogApi {
append(field("time_on", utcTimeCompact(qso.timeUtcMs)))
append(field("rst_sent", "59"))
append(field("rst_rcvd", "59"))
if (gridsquare.isNotBlank()) append(field("gridsquare", gridsquare.take(4)))
// Send the grid at full precision. Truncating to 4 characters threw
// away the 6-character locator the QRZ lookup provides, coarsening the
// stored position from ~4.6 km to ~100 km and making a QSO logged via
// v1 disagree with the same QSO logged via v2 (which sends it whole).
if (gridsquare.isNotBlank()) append(field("gridsquare", gridsquare))
if (satName.isNotBlank()) {
append(field("sat_name", satName))
if (satMode.isNotBlank()) append(field("sat_mode", satMode))
@@ -39,6 +39,23 @@ class WaveLogApiPayloadTest {
assertEquals(uplinkHz.toDouble(), adifFreq, 1.0)
}
@Test
fun v1_adif_preservesSixCharacterGrid() {
val qso = WavelogQso(
id = "test",
timeUtcMs = 0L,
call = "BG7NTA",
mode = "FM",
freqTxHz = uplinkHz,
freqRxHz = downlinkHz,
satName = "SO-50"
)
val adif = WaveLogApi.toAdif(qso, "OM89ab", "SO-50")
assertTrue(adif.contains("<gridsquare:6>OM89ab"))
}
/** Mirrors WaveLog Logbook_model::parse_frequency: int = Hz, "12.3M" suffix = MHz. */
private fun parseLikeWaveLog(raw: String): Long {
val s = raw.trim()