[feat](trx-rs): add FT4 decoder support
Reuse the existing ft8_lib C library (FTX_PROTOCOL_FT4) and FT8 decoder infrastructure to add FT4 decoding across the full stack. Changes: - trx-ft8: add protocol param to ft8_decoder_create; add Ft8Decoder::new_ft4() - trx-core: DecodedMessage::Ft4 variant, AUDIO_MSG_FT4_DECODE (0x14), ft4_decode_enabled/ft4_decode_reset_seq state, SetFt4DecodeEnabled/ ResetFt4Decoder commands, protocol mapping - trx-server: DecoderHistories::ft4, run_ft4_decoder (7.5s slots via now*2/15), run_background_ft4_decoder, history push/replay, decoder task spawn - trx-frontend-http: ft4_history in FrontendRuntimeContext, toggle/clear endpoints, /ft4.js route, bookmark/scheduler/background decode support, DecodeHistoryPayload ft4 field - web: ft4.js plugin (7.5s period timer, reuses FT8 CSS/map infra), FT4 subtab in index.html, app.js dispatch (onServerFt4/Batch, restoreFt4History), decode-history-worker HISTORY_GROUP_KEYS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
@@ -108,7 +108,7 @@ typedef struct
|
||||
float freq_hz;
|
||||
} ft8_decode_result_t;
|
||||
|
||||
ft8_decoder_t* ft8_decoder_create(int sample_rate, float f_min, float f_max, int time_osr, int freq_osr)
|
||||
ft8_decoder_t* ft8_decoder_create(int sample_rate, float f_min, float f_max, int time_osr, int freq_osr, int protocol)
|
||||
{
|
||||
ft8_decoder_t* dec = (ft8_decoder_t*)calloc(1, sizeof(ft8_decoder_t));
|
||||
if (!dec)
|
||||
@@ -120,7 +120,7 @@ ft8_decoder_t* ft8_decoder_create(int sample_rate, float f_min, float f_max, int
|
||||
dec->cfg.sample_rate = sample_rate;
|
||||
dec->cfg.time_osr = time_osr;
|
||||
dec->cfg.freq_osr = freq_osr;
|
||||
dec->cfg.protocol = FTX_PROTOCOL_FT8;
|
||||
dec->cfg.protocol = (protocol == 0) ? FTX_PROTOCOL_FT4 : FTX_PROTOCOL_FT8;
|
||||
|
||||
hashtable_init();
|
||||
monitor_init(&dec->mon, &dec->cfg);
|
||||
|
||||
@@ -37,6 +37,7 @@ extern "C" {
|
||||
f_max: c_float,
|
||||
time_osr: c_int,
|
||||
freq_osr: c_int,
|
||||
protocol: c_int,
|
||||
) -> *mut c_void;
|
||||
fn ft8_decoder_free(dec: *mut c_void);
|
||||
fn ft8_decoder_block_size(dec: *const c_void) -> c_int;
|
||||
@@ -69,6 +70,7 @@ impl Ft8Decoder {
|
||||
F_MAX_HZ,
|
||||
TIME_OSR as c_int,
|
||||
FREQ_OSR as c_int,
|
||||
1, // FTX_PROTOCOL_FT8
|
||||
);
|
||||
let inner = NonNull::new(ptr).ok_or_else(|| "ft8_decoder_create failed".to_string())?;
|
||||
let block_size = ft8_decoder_block_size(inner.as_ptr()) as usize;
|
||||
@@ -84,6 +86,30 @@ impl Ft8Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_ft4(sample_rate: u32) -> Result<Self, String> {
|
||||
unsafe {
|
||||
let ptr = ft8_decoder_create(
|
||||
sample_rate as c_int,
|
||||
F_MIN_HZ,
|
||||
F_MAX_HZ,
|
||||
TIME_OSR as c_int,
|
||||
FREQ_OSR as c_int,
|
||||
0, // FTX_PROTOCOL_FT4
|
||||
);
|
||||
let inner = NonNull::new(ptr).ok_or_else(|| "ft8_decoder_create failed".to_string())?;
|
||||
let block_size = ft8_decoder_block_size(inner.as_ptr()) as usize;
|
||||
if block_size == 0 {
|
||||
ft8_decoder_free(inner.as_ptr());
|
||||
return Err("invalid FT4 block size".to_string());
|
||||
}
|
||||
Ok(Self {
|
||||
inner,
|
||||
block_size,
|
||||
sample_rate,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block_size(&self) -> usize {
|
||||
self.block_size
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user