Skip to content

Commit c49458e

Browse files
committed
Begin WSPRCodex
1 parent 1a63f98 commit c49458e

File tree

2 files changed

+80
-9
lines changed

2 files changed

+80
-9
lines changed

Codex/src/main/java/org/operatorfoundation/codex/WSPRCodex.kt

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
package org.operatorfoundation.Codex
1+
package org.operatorfoundation.codex
22

3-
import org.operatorfoundation.codex.Decoder
4-
import org.operatorfoundation.codex.Encoder
53
import org.operatorfoundation.codex.symbols.Number
64
import org.operatorfoundation.codex.symbols.*
75
import java.math.BigInteger
@@ -72,15 +70,38 @@ class WSPRCodex
7270
*/
7371
fun getMaxPayloadBytes(): Int
7472
{
75-
// Calculate total capacity in bits
73+
// DEBUG: Print out what symbols we have and their sizes
74+
println("=== Symbol Configuration Debug ===")
75+
WSPR_SYMBOLS.forEachIndexed { index, symbol ->
76+
println("Symbol $index: $symbol, size: ${symbol.size()}")
77+
}
78+
79+
// Calculate the product of all symbol sizes
80+
// e.g. if we have symbols with sizes [36, 36, 18, 10, 19]
81+
// total capacity = 36 x 36 x 18 x 10 x 19 (total number of unique calculations)
82+
83+
// Convert list of symbols to list of their sizes
7684
val symbolSizes = WSPR_SYMBOLS.map { it.size().toBigInteger() }
77-
val totalCapacity = symbolSizes.fold(BigInteger.ONE) { acc, size -> acc * size }
85+
// Multiply all sizes together
86+
val totalCapacity = symbolSizes.fold(BigInteger.ONE) { acc, size -> acc * size}
87+
88+
// The max integer we can encode is (totalCapacity - 1)
89+
val maxEncodableValue = totalCapacity - BigInteger.ONE
90+
91+
// Convert maxEncodableValue to bytes so we know how many bytes we need (how many bytes it takes to store this number)
92+
val byteArray = maxEncodableValue.toByteArray()
7893

79-
// Convert to bits (log2 of total capacity)
80-
val capacityBits = totalCapacity.bitLength() - 1
94+
// BigInteger sometimes adds an extra leading zero byte for the sign
95+
// Remove the extra byte if it exists
96+
return if (byteArray.isNotEmpty() && byteArray[0] == 0.toByte())
97+
{
98+
byteArray.size - 1
99+
}
100+
else
101+
{
102+
byteArray.size
103+
}
81104

82-
// Convert to bytes (divide by 8)
83-
return capacityBits / 8
84105
}
85106

86107
/**
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.operatorfoundation.codex
2+
3+
import org.junit.jupiter.api.Test
4+
import org.junit.jupiter.api.Assertions.*
5+
import org.junit.jupiter.api.BeforeEach
6+
import org.operatorfoundation.codex.WSPRCodex
7+
import java.math.BigInteger
8+
9+
class WSPRCodexTest
10+
{
11+
private lateinit var codex: WSPRCodex
12+
13+
@BeforeEach
14+
fun setup()
15+
{
16+
codex = WSPRCodex()
17+
}
18+
19+
@Test
20+
fun testMaxPayload()
21+
{
22+
// Verify the calculated maximum payload is reasonable
23+
val maxBytes = WSPRCodex.getMaxPayloadBytes()
24+
25+
println("Maximum WSPR payload capacity: $maxBytes bytes")
26+
27+
// Should be around 28 bytes based on symbol sizes
28+
assertTrue(maxBytes in 20..35, "Expected capacity around 28 bytes, got $maxBytes")
29+
}
30+
31+
@Test
32+
fun testActualCapacity() {
33+
// Try encoding increasingly large byte arrays until we find the limit
34+
var workingSize = 0
35+
36+
for (size in 1..50) {
37+
val testData = ByteArray(size) { 0xFF.toByte() }
38+
try {
39+
codex.encode(testData)
40+
workingSize = size
41+
println("Size $size: SUCCESS")
42+
} catch (e: Exception) {
43+
println("Size $size: FAILED - ${e.message}")
44+
break
45+
}
46+
}
47+
48+
println("Actual working capacity: $workingSize bytes")
49+
}
50+
}

0 commit comments

Comments
 (0)