@@ -57,7 +57,7 @@ Java_org_operatorfoundation_audiocoder_CJarInterface_WSPREncodeToPCM
5757 // Frequency spacing between the symbols - 1.4548
5858 double frequency = 1500 + ((int ) j_offset) + symbols[i] * 1.4548 ;
5959
60- // TODO: Create a new function that converts frequency (double) to ints ( * 100 + casting to UInt64) to Bytes and returns a byte array of the frequencies
60+ // TODO: Create a new version of this function that converts frequency (double) to ints ( * 100 + casting to UInt64) to Bytes and returns a byte array of the frequencies
6161 // Frequency array size = # of symbols * 8 bytes (size of 64 bit integer)
6262 double theta = frequency * TAU / (double ) 12000 ;
6363 // 'volume' is UInt16 with range 0 thru Uint16.MaxValue ( = 65 535)
@@ -80,6 +80,116 @@ Java_org_operatorfoundation_audiocoder_CJarInterface_WSPREncodeToPCM
8080 return ret;
8181}
8282
83+ /* *
84+ * WSPR Frequency Encoder
85+ *
86+ * Encodes WSPR message into an array of frequencies that can be sent directly to custom radio hardware.
87+ *
88+ * @param env JNI environment pointer
89+ * @param cls Java class reference
90+ * @param j_calls Callsign string
91+ * @param j_local Grid square locator
92+ * @param j_powr Power level in dbm (0-60)
93+ * @param j_offset Frequency offset in Hz (added to base 1500 Hz)
94+ * @param lsb_mode LSB mode flag - inverts symbol order if true
95+ *
96+ * @return jbyteArray containing 162 frequencies as 64-bit integers (* 100)
97+ * Total array size: 162 symbols * 8 bytes = 1,296 bytes
98+ * Each frequency is stored as big-endien 64-bit integer with 0.01 Hz precision
99+ */
100+ extern " C" JNIEXPORT jbyteArray
101+ JNICALL
102+ Java_org_operatorfoundation_audiocoder_CJarInterface_WSPREncodeToFrequencies (JNIEnv *env, jclass cls, jstring j_calls, jstring j_local, jint j_powr, jint j_offset, jboolean lsb_mode) {
103+ // Array to hold the 162 WSPR symbols (0-3 values representing frequency shifts)
104+ uint8_t symbols[WSPR_SYMBOL_COUNT];
105+
106+ // Convert Java strings to C strings
107+ const char *callsign = env->GetStringUTFChars (j_calls, 0 );
108+ const char *loca = env->GetStringUTFChars (j_local, 0 );
109+
110+ // Format power as 2-digit string (required by encoder)
111+ char powr[3 ];
112+ snprintf (powr, 3 , " %02d" , (int ) j_powr);
113+
114+ __android_log_print (ANDROID_LOG_INFO,
115+ APPNAME,
116+ " WSPR Frequency Encode: %s %s %s" , callsign, loca, powr);
117+
118+ // Encode WSPR message into symbol array
119+ int encode_result = LB_WSPR_Encode2symbolz (symbols, callsign, loca, powr);
120+ __android_log_print (ANDROID_LOG_INFO,
121+ APPNAME,
122+ " WSPR encode result: %d" , encode_result);
123+
124+ // Release Java string references
125+ env->ReleaseStringUTFChars (j_calls, callsign);
126+ env->ReleaseStringUTFChars (j_local, loca);
127+
128+ // Allocate array for frequency data (162 frequencies x 8 bytes each)
129+ const int FREQUENCY_ARRAY_SIZE = WSPR_SYMBOL_COUNT * sizeof (int64_t );
130+ int64_t *frequencies = (int64_t *) malloc (FREQUENCY_ARRAY_SIZE);
131+
132+ if (frequencies == NULL )
133+ {
134+ __android_log_print (ANDROID_LOG_ERROR,
135+ APPNAME,
136+ " Failed to allocate frequency array" );
137+ return NULL ;
138+ }
139+
140+ // Convert each symbol to its corresponding frequency
141+ for (int i = 0 ; i < WSPR_SYMBOL_COUNT; i++)
142+ {
143+ uint8_t symbol = symbols[i];
144+
145+ // Apply LSB mode inversion if requested
146+ if (lsb_mode)
147+ {
148+ symbol = (uint8_t ) (3 - symbol);
149+ }
150+
151+ // Calculate the frequency for this symbol.
152+ // Base frequency: 1500 Hz
153+ // User offset: j_offset Hz
154+ // Symbol spacing: 1.4648 Hz between tones (WSPR standard)
155+ double frequency_hz = 1500.0 + ((double ) j_offset) + (symbol * 1.4648 );
156+
157+ // Convert to 64-bit signed integer with 0.01 Hz precision (multiply by 100)
158+ frequencies[i] = (int64_t ) (frequency_hz * 100.0 );
159+
160+ // Debug: Log the first few frequencies
161+ if (i < 5 )
162+ {
163+ __android_log_print (ANDROID_LOG_DEBUG,
164+ APPNAME,
165+ " Symbol[%d] = %d, Frequency = %.4f Hz, Encoded = %lld" , i, symbol, frequency_hz, (long long )frequencies[i]);
166+ }
167+ }
168+
169+ jbyteArray result = env->NewByteArray (FREQUENCY_ARRAY_SIZE);
170+ if (result == NULL )
171+ {
172+ __android_log_print (ANDROID_LOG_ERROR,
173+ APPNAME,
174+ " Failed to create Java byte array for WSPR encoding." );
175+ free (frequencies);
176+ return NULL ;
177+ }
178+
179+ // Copy frequency data to Java byte array
180+ env->SetByteArrayRegion (result, 0 , FREQUENCY_ARRAY_SIZE, (jbyte *) frequencies);
181+
182+ // Don't forget to clean up after yourself!
183+ free (frequencies);
184+
185+ __android_log_print (ANDROID_LOG_INFO, APPNAME,
186+ " WSPR frequency encoding complete: %d frequencies, %d bytes" ,
187+ WSPR_SYMBOL_COUNT, FREQUENCY_ARRAY_SIZE);
188+
189+ return result;
190+ }
191+
192+
83193
84194extern " C"
85195JNIEXPORT jint JNICALL
0 commit comments