use crate::codec::crc::{ft8_add_crc, ft8_crc14, ft8_extract_crc};
use crate::codec::gray::{gray4_decode, gray4_encode};
use crate::codec::ldpc::{self, ldpc_decode_soft, ldpc_encode};
use crate::modulate::Ft4Frame;
use crate::modulate::ft4::FT4_DATA_SYMS;
pub type Ft4Bits = [u8; 10];
const FT4_XOR: [u8; 10] = [0x4A, 0x5E, 0x89, 0xB4, 0xB0, 0x8A, 0x79, 0x55, 0xBE, 0x28];
pub struct Ft4Codec;
impl Ft4Codec {
pub fn encode(payload: &Ft4Bits) -> Ft4Frame {
let mut scrambled = [0u8; 10];
for i in 0..10 {
scrambled[i] = payload[i] ^ FT4_XOR[i];
}
let mut a91 = [0u8; ldpc::K_BYTES];
ft8_add_crc(&scrambled, &mut a91);
let mut codeword = [0u8; ldpc::N_BYTES];
ldpc_encode(&a91, &mut codeword);
let mut tones = [0u8; FT4_DATA_SYMS];
let mut mask: u8 = 0x80;
let mut byte_idx = 0usize;
for tone in tones.iter_mut() {
let mut bits2: u8 = 0;
for bit_pos in (0u8..2).rev() {
if codeword[byte_idx] & mask != 0 {
bits2 |= 1 << bit_pos;
}
mask >>= 1;
if mask == 0 {
mask = 0x80;
byte_idx += 1;
}
}
*tone = gray4_encode(bits2);
}
Ft4Frame::new(tones)
}
pub fn decode_hard(frame: &Ft4Frame) -> Option<Ft4Bits> {
let llr = Self::frame_to_llr_hard(frame);
Self::decode_llr(&llr)
}
pub fn decode_soft(llr: &[f32; ldpc::N]) -> Option<Ft4Bits> {
Self::decode_llr(llr)
}
pub fn frame_to_llr_hard(frame: &Ft4Frame) -> [f32; ldpc::N] {
let mut llr = [0.0f32; ldpc::N];
for (sym_idx, &tone) in frame.0.iter().enumerate() {
let bin = gray4_decode(tone);
for bit_pos in 0..2usize {
let bit = (bin >> (1 - bit_pos)) & 1;
llr[sym_idx * 2 + bit_pos] = if bit == 0 { 10.0 } else { -10.0 };
}
}
llr
}
fn decode_llr(llr: &[f32; ldpc::N]) -> Option<Ft4Bits> {
let mut plain = [0u8; ldpc::N];
let errors = ldpc_decode_soft(llr, 20, &mut plain);
if errors != 0 {
return None;
}
let mut a91 = [0u8; ldpc::K_BYTES];
for i in 0..ldpc::K {
if plain[i] == 1 {
a91[i / 8] |= 0x80 >> (i % 8);
}
}
let extracted = ft8_extract_crc(&a91);
let mut buf = a91;
buf[9] &= 0xF8;
buf[10] = 0;
buf[11] = 0;
let computed = ft8_crc14(&buf, 82);
if extracted != computed {
return None;
}
let mut payload = [0u8; 10];
for i in 0..10 {
payload[i] = a91[i] ^ FT4_XOR[i];
}
payload[9] &= 0xF8;
Some(payload)
}
}